0

As for an assignment I created a filter that modifies a Config that's connected to an API which prints out Order files. The web application has the option to save the modified Orderlist with a date and number added to it.

I've been asked to add a feature that allows my task giver to remove the order files he wishes to delete. I've asked a question before how I could remove a file through a file input, but this doesn't seem to be efficient considering it'll be eventually thrown in a private server. Now the best idea was to include the directory and print it out in a list, allowing the user to select the file they wish to remove.

With a lot of looking around I tried to find something that suited my resolve to this as best as I could and stumbled on this. It does print out an array and show checkboxes, but the file names(example Order file 26-1-2021 version 1.xml) are not displayed right next to the checkboxes. - My second question: How do I delete the order file you specifically checked through the submit button?

my code

<?php
$dir    = '..\api-ivolved\s_orderlist';
$files1 = scandir($dir, 1);

foreach ($files1 as $filename => $n) {
    echo "<input type=\"checkbox\" name=\"files[]\" value=".$filename."/>";
}

if (isset($_POST['delete'])){
unlink( /* Value here */ );      
}
?>

<form class="deleteFile" method="get" enctype="multipart/form-data">
<input type="submit" id="delete" value="Delete file"/> 
</form>
Talon
  • 49
  • 8
  • 2
    Not quite clear what you're asking here. First, when you say _"show checkboxes, but the names are empty"_ - which names? What does it mean they're empty? I assume you want to say that filenames aren't displayed on the page, but they're never printed anywhere other than checkbox values, so it's expected. Second, what does _"pass the file data to the submit box"_ - what's a "submit box"? – El_Vanja Jan 26 '21 at 16:04
  • 2
    Couple of things though; 1) Your submit input *doesn't have a name*, and so `isset($_POST['delete'])` will never be true. 2) Your checkboxes *aren't part of the form*, because you render them before the opening form tag. – El_Vanja Jan 26 '21 at 16:06
  • 2
    Be warned that calling `unlink` on values a user can supply should not be done without any validation that the file is allowed to be deleted ;) You don't want any user to send a request with any files outside of that folder of files – Nico Haase Jan 26 '21 at 16:24
  • @El_Vanja To answer your questions 1) Yes, the file names aren't displayed as they would when I print the scandir, for example. 2) I meant to say that once the submit button is clicked, it'll remove the selection you have made (I sometimes forget you have to be really specific with things to get the best of help, my bad - I'll edit my question) . With selection I mean the order file you wish to delete. – Talon Jan 26 '21 at 20:43
  • @NicoHaase Thank you for the notice! I'll make sure to prevent that from happening, even though no one will use the application besides the person who gave me the task to build it, it's still worth taking it into account and preventing any issues in case something might happen – Talon Jan 26 '21 at 22:38

2 Answers2

1

It appears you are checking $_POST for the delete flag rather than $_GET. Because your form submits using "get", this will cause it to never detect the delete checkbox. I've added a corresponding "delete" field/checkbox within your form to reference the field you are checking for.

For displaying the filenames besides the textbox, you will need to output this separately. I've added this after the checkbox itself, followed by a line break.

I've also "buffered" your input fields so that they get outputted inside of the form tags (rather than before).

Try something like this:

<?php
$dir    = '..\api-ivolved\s_orderlist';
$files1 = scandir($dir, 1);

// We need to output the fields AFTER the opening form field. We "buffer" them for now and output them later. 
$fields = "":

foreach ($files1 as $filename => $n) {
    // Output the filename beside the textbox.  
    $fields .= "<input type=\"checkbox\" name=\"files[]\" value=".$filename."/>" . htmlspecialchars($filename) . "<br />";
}

if (isset($_GET['delete'])){

   // Make sure files are checked/marked for deletion. 
   if (!empty($_GET['files'])) {

       // Loop through each file and delete
       foreach ($_GET['files'] as $file) {
           unlink($file);      
       } 
   }
}
?>

<form class="deleteFile" method="get" enctype="multipart/form-data">
<?php echo $fields; ?>
<br />
<strong> Delete checked files? </strong> <input type="checkbox" name="delete" value="1"/><br />
<input type="submit" id="delete" value="Delete file"/> 
</form>

It's worth noting to make sure that you have robust permissions checking in your application, since a simple link will cause a file to be deleted. This can technically cause a CSRF vulnerability (a special type of vulnerability that would allow someone to create a image/link on another website with a full link to do unwanted business). To prevent this, look into adding CSRF tokens to check links in your script (various robust guides exist online for this sort of thing) :)

Blake Ottinger
  • 344
  • 1
  • 7
  • I'll most definitely look into it! And it displaying the content I wish to see on my project, I have a few question though to really finalise it. The checkboxes display the array numbers, but not the actual file names that are in the document, can I change that some way/how? - Second question: There is an error regarding the unlink function, it gives the following `error: unlink(6/): No such file or directory in C:\xampp\htdocs\-php-api\api-ivolved\test.php` - The directory will refer to itself, instead of the order folder that is located in the same path – Talon Jan 26 '21 at 21:00
1

The question posed is a little different to the original so I hope the following helps you resolve your confusion.

<?php

    $dir=__DIR__ . '/api/s_orderlist';
    
    if( $_SERVER['REQUEST_METHOD']=='POST' && !empty( $_POST[ 'files' ] ) ){
        ob_clean();
        #process supplied files array - delete each file found. Fail silently
        $files=$_POST['files'];
        foreach( $files as $file ){
            $filepath=sprintf('%s/%s',$dir,$file);
            if( file_exists( $filepath ) )@unlink( $filepath );
        }
        
        #redirect back to the same page using GET to avoid POSTing again if page is reloaded.
        exit( header( sprintf('Location: %s', $_SERVER['SCRIPT_NAME'] ) ) );
    }
?>
<!DOCTYPE html>
<html lang='en'>
    <head>
        <meta charset='utf-8' />
        <title></title>
    </head>
    <body>
        <form method='post'>
            <?php
                
                # find the files in target directory
                $col=glob( $dir . '/*.*' );
                
                #iterate through files, create checkbox for each file
                foreach( $col as $file ){
                    printf(
                        '<label style="width:100%%;display:block;padding:0.5rem">
                            <input type="checkbox" name="files[]" value="%1$s" />%1$s
                        </label>',
                        basename( $file )
                    );
                }

            ?>
            <input type='submit' />         
        </form>
    </body>
</html>
Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46