67

Just curious:

$files = glob(cacheme_directory() . '*');
foreach ($files as $file) {
    $filemtime = filemtime($file);
    if (time() - $filemtime >= 172800) {
        unlink($file);
    }
}

I just want to make sure if the code is correct or not. Thanks.

reformed
  • 4,505
  • 11
  • 62
  • 88
user4951
  • 32,206
  • 53
  • 172
  • 282
  • 3
    please use the search function before asking http://stackoverflow.com/search?q=delete+files+older+php – Gordon Jan 23 '12 at 00:00
  • 2
    possible duplicate of [How to delete files from directory based on creation date in php](http://stackoverflow.com/questions/2205738/how-to-delete-files-from-directory-based-on-creation-date-in-php) – Gordon Jan 23 '12 at 00:02
  • It's not duplicate. The one I wrote is simple and I only want to ask if this is correct or not which is a much easier question. – user4951 Jan 23 '12 at 01:49
  • @JimThio asking whether it works is not a real question. Write a UnitTest or simply try it in a test folder. And yes, this is a duplicate of the linked one. It covers exactly the same grounds. And there is more duplicates in the linked search. – Gordon Jan 23 '12 at 08:28
  • Well I got nice suggestions on how to improve it at least. – user4951 Jan 24 '12 at 01:15

11 Answers11

140

You should add an is_file() check, because sub-directories could reside in the the directory you're checking.

Also, as this answer suggests, you should replace the pre-calculated seconds with a more expressive notation.

$files = glob(cacheme_directory() . '*');
$threshold = strtotime('-2 day');
  
foreach ($files as $file) {
    if (is_file($file)) {
        if ($threshold >= filemtime($file)) {
            unlink($file);
        }
    }
}

Alternatively you could also use the DirectoryIterator, as shown in this answer. In this simple case it doesn't really offer any advantages, but it would be OOP way.

reformed
  • 4,505
  • 11
  • 62
  • 88
buschtoens
  • 8,091
  • 9
  • 42
  • 60
  • 7
    Works like a charm, but why u people always exclude brackets { } I love them :D i can't do without them. Otherwise code is naked – Luka Jan 21 '17 at 12:45
  • You really need to add the backets. This code is not readable and tidy. – Gfra54 Mar 29 '17 at 09:50
  • 7
    I wrote this answer back when I had a short-lived liaison with Python. Brackets have been added. ;) – buschtoens Apr 19 '17 at 06:29
  • If you are on php5.3+, check Maksim.T's answer. – Toto Sep 05 '18 at 13:36
  • A small improvement can be made to calculate the cutoff-time once and comparing against that in the loop, instead of calculating the difference between to datetimes in the loop every time. – Herbert Van-Vliet Jul 22 '22 at 08:26
76

The easiest way is by using DirectoryIterator:

if (file_exists($folderName)) {
    foreach (new DirectoryIterator($folderName) as $fileInfo) {
        if ($fileInfo->isDot()) {
            continue;
        }
        if ($fileInfo->isFile() && time() - $fileInfo->getCTime() >= 2*24*60*60) {
            unlink($fileInfo->getRealPath());
        }
    }
}
reformed
  • 4,505
  • 11
  • 62
  • 88
  • 8
    This works for me, but is slighlty faster if you just calculate time() and 2*24*60*60 once before the while loop and use variables in the loop. – Lisa DeBruine Apr 06 '15 at 11:51
  • I'd just like to say thanks. This honestly should be the chosen answer. – Bravo Delta May 03 '16 at 23:54
  • works great and learned about the DirectoryIterator which is awesome! – William Howley Nov 27 '16 at 23:22
  • 2
    Is the `isDot()` check necessary? Won't the `isFile()` check suffice for that? – ashnazg Jun 28 '18 at 15:38
  • 1
    Note: If your'e using WIndows `getCTime()` is the file creation time, so you might want to use `getMTime()` if you want to use last modified time instead of creation time. – IMB Jul 21 '18 at 11:43
21

FilesystemIterator is a more simple and modern way. FilesystemIterator has an advantage over DirectoryIterator in that it ignores the virtual directories . and ...

Using directory logs as an example:

$fileSystemIterator = new FilesystemIterator('logs');
$now = time();
$threshold = strtotime('-2 day');
foreach ($fileSystemIterator as $file) {
    if ($threshold >= $file->getCTime()) {
        unlink('logs/'.$file->getFilename());
    }
}
reformed
  • 4,505
  • 11
  • 62
  • 88
Maksim.T
  • 531
  • 4
  • 17
14

I reckon this is much tidier and easier to read and modify.

$expire = strtotime('-7 DAYS');

$files = glob($path . '/*');

foreach ($files as $file) {

    // Skip anything that is not a file
    if (!is_file($file)) {
        continue;
    }

    // Skip any files that have not expired
    if (filemtime($file) > $expire) {
        continue;
    }

    unlink($file);
}
Leon
  • 181
  • 1
  • 3
6
/* Delete Cache Files Here */
$dir = "cache/"; /** define the directory **/

/*** cycle through all files in the directory ***/
foreach (glob($dir."*") as $file) {
//foreach (glob($dir.'*.*') as $file){

/*** if file is 24 hours (86400 seconds) old then delete it ***/
if (filemtime($file) < time() - 172800) { // 2 days
    unlink($file);
    }
}

Hope it helps you.

I updated this code in 2023, check it out: https://www.arnlweb.com/forums/server-management/efficient-php-code-for-deleting-files-delete-all-files-older-than-2-days-the-right-way/

Lachit
  • 81
  • 1
  • 5
4

Looks correct to me. I'd just suggest you replace 172800 with 2*24*60*60 for clarity.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
3

Here is an example of how to do it recursively.

function remove_files_from_dir_older_than_x_seconds($dir,$seconds = 3600) {
    $files = glob(rtrim($dir, '/')."/*");
    $now   = time();
    foreach ($files as $file) {
        if (is_file($file)) {
            if ($now - filemtime($file) >= $seconds) {
                echo "removed $file<br>".PHP_EOL;
                unlink($file);
            }
        } else {
            remove_files_from_dir_older_than_x_seconds($file,$seconds);
        }
    }
}

remove_files_from_dir_older_than_x_seconds(dirname(__file__).'/cache/', (60 * 60 * 24 * 1) ); // 1 day
2

@maksim-t answer can be improved a bit:

  1. Calculate the oldest "allowed" from the start, instead of calculating it on every iteration.
  2. Use Modification time, instead of creation time, because otherwise you may remove files, that were updated recently.
  3. Use getPathname instead of getFilename, so that there will be not need for concatenation of the path.
#Initiate iterator
$fileSI = new FilesystemIterator($this->files);
#Get the oldest allowed time
$oldest = time() - ($maxFileAge * 86400);
#Iterate the files
foreach ($fileSI as $file) {
    #Check time
    if ($file->getMTime() <= $oldest) {
        #Remove the file
        @unlink($file->getPathname());
    }
} 
Simbiat
  • 339
  • 2
  • 12
2

Be aware that you'll run into problems if you have a very large number of files in the directory.

If you think this is likely to affect you, consider using a lower level approach such as opendir.

John Carter
  • 53,924
  • 26
  • 111
  • 144
0
/** It deletes old files.
 *  @param string $dir Directory
 *  @param int $secs Files older than $secs seconds
 *  @param string $pattern Files matching $pattern
 */
function delete_oldfiles($dir,$secs,$pattern = "/*")
{
    $now = time();
    foreach(glob("$dir$pattern") as $f) {
      if (is_file($f) && ($now - filemtime($f) > $secs)) unlink($f);
    }
}
Miguel
  • 1
0
(time()-filectime($path.$file)) < 172800 //2 days

If the current time and file are changed time are within 172800 seconds of each other, then.

 if (preg_match('/\.pdf$/i', $file)) {
     unlink($path.$file);
 }

Well, if its there still any confusion you just need to change the operator from the first line of code.