Unlink files with paths

I have this very simple delete function where I can delete multiple files from the database using checkboxes:


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

    $thumbnail_dir = '../test/thumbnails/';
    $photo_dir     = '../test/photos/';
    $image_name    = $_POST['image_name'];
	
    for($i=0;$i<count($_POST['checkbox']);$i++){
	  unlink($thumbnail_dir.$image_name);
	  $del_id = $_POST['checkbox'][$i];
      $del = "DELETE FROM test WHERE photo_id = '{$del_id}'";
      $result = mysql_query($del);
      	
	}
	if($result){
	  echo "<meta http-equiv=\\"refresh\\" content=\\"0;URL=test.php\\">";
	 }	
  }

But the unlink isn’t working. I have the image_name as a hiddenfield in the form. What is wrong with this approach?

I changed it to:


    $image_name    = $_POST['image_name'];
    $thumbpath     = '../test/thumbnails/. $image_name';
    $photopath     = '../test/photos/. $image_name';
	
	unlink("$thumbpath"); 

But still nothing. I am sure this is very easy but I simply don’t see what I am doing wrong?

Did you verify that your loop is triggering and is running the correct number of iterations? Did you verify that $thumbnail_dir.$image_name is a correct file path? How are you determining which files to delete? I did not see anything to determine the on or off value of a checkbox. And if you are deleting only one file (in a hidden field), then why do you have the loop?

Also, in my view you should attempt to make the database entries before deleting from disk because that is where you are likely to have more problems. If you delete the file then the query errs, you now have a database entry that does not have a corresponding file.

You did not get a response probably because your code is not very good. One more thing: when deleting files, for testing purposes it may be best for you to echo out a statement with the file path indicating it would be deleted if the unlink were enabled. You do not want to risk deleting stuff you don’t want to delete–and that is a real possibility.

This is basic debugging which you should be able to do evaluating line by line.

I did not see anything to determine the on or off value of a checkbox.

I assume delete is an array from a table/form.

As cheesedude says echo things out as they might not contain what you expect - the path could be wrong, you could have to many or to few // etc.

I am surprised no-one has mention this yet, but NEVER accept the name of the file your deleting from the user… (Note, this also apply for files your accessing/reading etc.)

A user that has access to that script can delete any file that your web server has access to modify.

To do this, all that is needed is knowing the name and path to the file you want to try to delete, then pass that along to the script instead. I.e. “…/index.php” for example.

Back to your script, are you certain that all of the photos you delete has the same file name? Since you only get the filename once, but loop over the images that are deleted. It is possible your problem is located here, or that the path is wrong. Another possibility is that the rights on the folder is wrong, but that is most probably not the case assuming the photos was uploaded through a form.

Though, I strongly recommend that you change the script. A safe solution is for example storing the real photo name in the database and then just store the file locally as the primary key (photo_id) if it is not directly accessed, or with the real filename if it is. But the change is that when a photo is deleted, you get the filename from the database and delete it. Of course remember to verify that the file has a valid filename when its uploaded.

A am a bit confused about this line. This is a forum isn’t it? When everone would use perfect Coding, CSS, HTML, Javascript, AJAX etc, sitepoint would not exist. For years I have been using a complete different server side scripting. For certain reasons now sometimes I have to use PHP. Maybe the code is not good, but for that reason I ask a question!

Basically the photos are stored in a unsorted list like this:


<ul>
<form>
  <?php
  $gallery = mysql_query("SELECT photo_id, photo FROM test") or die(mysql_error());
  while($rows=mysql_fetch_array($gallery)){
   ?>
  <li>
    <input type="hidden" name="image_name" id="image_name" value="<? echo $rows['photo']; ?>">
    <img src='../gallery/thumbnails/<? echo $rows['photo']; ?>'>
    <input type="checkbox" name="checkbox[]" id="checkbox[]" value="<? echo $rows['photo_id']; ?>">&nbsp;&nbsp;<? echo $rows['photo']; ?>
  </li>
  <?php
  }
 ?>
</form>
</ul>

So in my opinion all photo_id and names are passed, but if I see this wrong please correct me.

Thank you in advance!

If you temporarily change the code to

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

    $thumbnail_dir = '../test/thumbnails/';
    $photo_dir     = '../test/photos/';
    $image_name    = $_POST['image_name'];
if (is_dir($thumbnail_dir)) {
  echo("../test/thumbnails/ is a directory");
} else {
  echo("../test/thumbnails/ is NOT a directory");
}
if (is_dir($photo_dir)) {
  echo("../test/photos/ is a directory");
} else {
  echo("../test/photos/ is NOT a directory");
}
.....

Are they or aren’t they?

BTW you should swap out the deprecated mysql_ for mysqli_ now while you’re working on the code.

There are a few reasons for this to fail. Besides possible path issues, the main logic needs to be fixed. If you are using open keys in your form then ALL image names will be passed and only the selected checkboxes will be sent. This will result in image_name keys not matching. For example selecting the first image (key 0) and 2, 4, 5 results in.

Array
(
    [image_name] => Array
        (
            [0] => image0
            [1] => image1
            [2] => image2
            [3] => image3
            [4] => image4
            [5] => image5
            [6] => image6
        )

    [checkbox] => Array
        (
            [0] => 0
            [1] => 2
            [2] => 4
            [3] => 5
        )

    [delete] => Delete
)

IF however you put the image ID as the key in your form, e.g.

echo '<input type="hidden" name="image_name[' . $image_id . ']" value="' . $image_name . '" />
<input type="checkbox" name="checkbox[' . $image_id . ']" value="' . $image_id . '" />';

Then the checkbox KEYs will match the image_name keys for the checked images.

Array
(
    [image_name] => Array
        (
            [0] => image0
            [1] => image1
            [2] => image2
            [3] => image3
            [4] => image4
            [5] => image5
            [6] => image6
        )

    [checkbox] => Array
        (
            [0] => 0
            [2] => 2
            [4] => 4
            [5] => 5
        )

    [delete] => Delete
)

So then for processing you will use real keys instead a hopeful FOR Loop for matching.

<?php
if(isset($_POST['delete'])){  
	$thumbnail_dir = '../test/thumbnails/';
	$photo_dir     = '../test/photos/';
	
	foreach($_POST['checkbox'] as $id => $del_id):
		$image_name = $_POST['image_name'][$id]; 
		unlink($thumbnail_dir.$image_name);
		$del = "DELETE FROM test WHERE photo_id = '{$del_id}'";
		$result = mysql_query($del);  
	endforeach;
	if($result){
		echo "<meta http-equiv=\\"refresh\\" content=\\"0;URL=test.php\\">";
	}    
}  
?>

There are many thing that are wrong with your code that I’m not going to get into as I believe others have. The cause of your immediate problem is that an absolute path is necessary for unlink since the files reside in a directory above your site root/location of script file.

Found this thread that better explains it.

http://stackoverflow.com/questions/5006569/php-does-unlink-function-works-with-a-path

I’m going to have to disagree with that as I have used a relative path before, backing out of current directory, going into images directory (and sub directories) and even down to root and into a https directory to delete copies of images.

My old C++ Tutor always used to say “Always test for a return value…”
Try this:


  /* Debug Mode - set to maximum and display errors on screen */
    error_reporting(-1); 
    ini_set('diplay_errors',1);


  if(isset($_POST['delete']))
  { 
    $thumbnail_dir = '../test/thumbnails/'; 
    $photo_dir      = '../test/photos/'; 
    $image_name  = $_POST['image_name']; 
     
    for($i=0; $i<count($_POST['checkbox']); $i++)
    { 
      $img = $thumbnail_dir .$image_name; 


      $ok  = file_exists($img);
      if($ok)
      {
        $ok = unlink($thumbnail_dir.$image_name); 
        if($ok)
        {
          $del_id = $_POST['checkbox'][$i]; 
          $del    = "DELETE FROM test WHERE photo_id = '{$del_id}'"; 
          $ok     = mysql_query($del); 
        }  


        if($ok)
        {
          echo "<meta http-equiv=\\"refresh\\" content=\\"0;URL=test.php \\">"; 

        }else{  
         echo is_dir($thumbnail_dir) ? NULL : 'NO DIRECTORY: ' .$thumbnail_dir;

         echo is_dir($photo_dir)       ? NULL : 'NO DIRECTORY: ' .$photo_dir;

         echo file_exists($img)         ? NULL : 'NO IMAGE: ' .$img;
         die;
        }     
  }