Unlink files from server

Hi,

I have a stack of images in a directory on my server that I want to remove.

However, some of the images are referenced in a table in my database, so I want to keep these.

I want to delete any images which are not referenced in my database.
How can I do this?
Would I use an array or search string function in php?

Here’s my code so far:


<?php 

require_once('../db/mysql_connection.php');

echo '<h3>Delete Images</h3>';

echo '<h2>Actually-being-used-right-now files</h2>';

    $query2 = "SELECT iv.id, iv.name, i.* FROM imagesv as iv, images as i WHERE iv.id = i.vid";
    $result2 = mysql_query($query2);
    while ($row2 = mysql_fetch_array($result2)) {
      
      echo $row2['5'];  
      echo $row2['6'];  
      echo $row2['7'];  
      echo $row2['8'];  
      echo $row2['9'];  
      echo $row2['10'];  
      echo $row2['11'];  
      echo $row2['12'];   

       // unlink
    
    }

echo '<h2>All Files</h2>';

if ($handle = opendir('me/path/is/here')) {
    echo "Directory handle: $handle\
";
    echo "Files:\
";

    /* This is the correct way to loop over the directory. */
    while (false !== ($file = readdir($handle))) {
        echo "$file\
";
    }

    /* This is the WRONG way to loop over the directory. */
    while ($file = readdir($handle)) {
        echo "$file\
";
    }

    closedir($handle);
}

?>

Many thanks for any helpers.

Put the image names you got from your DB in an array. Then, for each image in the directory, check if it exists in the array. If not, delete it.

Aaah, yes this is a bit I’m not sure how to do. Can you possibly give me an example of this?

Thank you

In pseudocode:


foreach $file in directory:
  $result = select * from tablename where filename = $file
  if not $result.any?
    unlink $file

No, a query for each file you find in the directory is definitely not the best way to do this.

On second thoughts, if it is a one time operation, then you might not care about the performance, and just choose the easiest way. If so, this one isn’t so bad :smiley:

Which bit? Putting the query result in an array?
Or checking if the file exists in the array?

The whole bit :slight_smile:

I have both sets of data(all images & db images) but just not sure where to go from there.

Something like this:


<?php

$sql = "SELECT iv.id, iv.name, i.* FROM imagesv as iv, images as i WHERE iv.id = i.vid";
$res = mysql_query($sql);

$images_in_db = array();
while ($row = mysql_fetch_assoc($res)) {
    $images_in_db[] = $row['name'];
}


$path = '/my/path/is/here';
$images_in_directory = array();
if ($handle = opendir($path)) {
    while (false !== ($file = readdir($handle))) {
        if($file!='.' && $file!='..') {
            $images_in_directory[] = $file;
        }
    }
    closedir($handle);
}

foreach($images_in_directory as $filename) {
    if(!isset($images_in_db[$filename])) {
        echo "Delete $filename<br />";
        //unlink($path . '/' . $filename);
    }
}

?>

At first it will only echo which files it thinks it should delete, once you’re certain it’s correct you can uncomment the unlink() function.

Any files that are in that directory that aren’t in your database will be deleted, so you may want to check to see if there are files other than images in the directory. If so, you’ll need to skip those :slight_smile:

Wow, brilliant Immerse! I’m off to check that out.

Many thanks for your speedy help.

I’m backing everything up before I hit the big red button. :slight_smile:


$images = array();

while($image = mysql_fetch_assoc($result)){
    array_push(
        $images,
        $image['name']
    );
}

foreach($files as $image){
    if(false === in_array($image, $images)){
        unlink($image);
    }
}

Hey Anthony, that’s brilliant too.

Will take a close look over both shortly.

Thanks again sir :smiley:


array_map('unlink',
     array_diff(glob('*'), $filesFromDB)
);

heh

Another…


<?php

$db    = new mysqli( 'localhost', 'my_user', 'my_password', 'my_db' );
$sql   = $db->prepare( "SELECT count(*) FROM images WHERE file = ?" );
$files = glob( 'path/to/images/*.jpg' );

foreach ( $files as $file ) {
  $sql->bind_param( $file );
  $sql->execute();
  
  if ( $sql->num_rows === 0 )
    unlink( $file );
}

That was my understanding, but otherwise I agree.

Thanks for the replies guys! :slight_smile:

Just wondering, if the db entries contain …/images/ before the filename, how do I get around this issue? substr function?

basename() could be useful for that.