PHP script to delete thousands of .jpg images? - php

My weak shared web host doesn't support cron or perl and I often need to delete thousands of .jpg images from certain folders. The images are uploaded from webcams. I'm wondering if there is a simple app out there that can find all .jpg images recursively and delete them.
I need to be able to target only images in the following date format : 2011-10-19_00-29-06.jpg ... and only images older than 48 hours.
Apache 2.2.20
DirectAdmin 1.39.2
MySQL 5.1.57
Php 5.2.17

#user427687, Do you mean all the picture format 2011***.jpg? if so, may be my code would work.
<?php
$path = dirname(__FILE__).'/filepath';
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if ((time()-filectime($path.'/'.$file)) < 86400*2) {
if (preg_match('/\2011(.*?).jpg$/i', $file)) {
unlink($path.'/'.$file);
}
if (preg_match('/\2011(.*?).jpeg$/i', $file)) {
unlink($path.'/'.$file);
}
}
}
}
?>

A simple naiive version:
$yesterday = date('Y-m-d', strtotime('yesterday')); // 2011-10-17
$day_before = date('Y-m-d', strtotime('2 days ago')); // 2011-10-16
$images = glob('*.jpg');
foreach($images as $img) {
if (strpos($img, $yesterday) === 0) || (strpos($img, $day_before) === 0)) {
continue;
}
unlink($img);
}
This will delete all files which are date-stamped 3 days or older, by checking if the file is date stamped yesterday or day-before-yesterday. But it will also delete all files created today.
A better version would be:
$images = glob("*.jpg");
foreach ($images as $img) {
$ctime = filectime($img);
if ($ctime < (time() - 86400 * 2)) {
unlink($img);
}
}
This version checks the actual last-modified time on the file, and deletes anything older than 48 hours. It will be slower, however, as the stat() call performed by filectime() will be a non-cheap call.

Something like this should get you started:
class MyRecursiveFilterIterator extends RecursiveFilterIterator {
const EXT = '.jpg';
public function accept() {
// code that checks the extension and the modified date
return $this->current()->getFilename() ...
}
}
$dirItr = new RecursiveDirectoryIterator('/sample/path');
$filterItr = new MyRecursiveFilterIterator($dirItr);
$itr = new RecursiveIteratorIterator($filterItr, RecursiveIteratorIterator::SELF_FIRST);
// to iterate the list
foreach ($itr as $filePath => $fileInfo) {
echo $fileInfo->getFilename() . PHP_EOL;
}

or just with php:
<?php
$last_2_days_in_seconds = 3600 * 48;
foreach (glob("*.jpg") as $filename) {
if((time() - fileatime($filename)) > $last_2_days_in_seconds && preg_match('/^2011/', $filename)) unlink($filename);
}
?>

Related

How to collect the files in a separate folder date wise from a folder in php?

I have a folder which contains tons of files. My goal is to take backup of files year wise according to created or modified date after taking the backup of the files I want to delete the files as well.
Actually my server is containing pdf files of size 20GB and I want to take the backup of the files but there should be folder year wise. But I don't know how to achieve this.
$dir_path = "/pdfs/";
$pdf_arr = scandir($dir_path);
foreach($pdf_arr as $file) {
if($file ! == '.' && $file ! == '..') {
print_r($file);
}
}
// year and month wise backup
public function getLastModifiedFiles() {
$source = public_path("pdfs");
$destination = public_path("destination");
$smallest_time=INF;
$oldest_file='';
if ($handle = opendir($source)) {
while (false !== ($file = readdir($handle))) {
if($file !== '.' && $file !== '..') {
$time = filemtime($source.'/'.$file);
$mm = date('m', $time);
$yr = date('Y', $time);
\File::isDirectory($destination.'/'.$yr."/$mm") or \File::makeDirectory($destination.'/'.$yr."/$mm", 0777, true, true);
$moveFile="$destination/$yr/$mm/$file";
//dd($source.'/'.$file);
if(!is_dir($source.'/'.$file)) {
if (copy($source.'/'.$file, $moveFile))
{
unlink($source.'/'.$file);
}
}
}
}
closedir($handle);
}
}
In my Opinion, this will be the best solution for your requirments:
<?php
// Constans to Define
$active_dir = "pdfs/"; // Directory where your files are stored * WITH ENDING "/"
$backup_dir = "pdfs_backup/"; // Directory where the files should be moved to backup * WITH ENDING "/"
$backup_time_str = "Y"; // "Y" will backup in yearly folder structure (ex 2019), "Y-m" will backup in monthly folder (ex 2019-01), "Y-m-d" will back up in daily folder (ex 2019-01-05)
$min_file_age = time()-(3600*24*365); // only BackUp files older than actual time minus seconds (In this Case 1 Year)
// Start BackUp
backup_files_by_time($active_dir,$backup_dir,$min_file_age,$backup_time_str);
// BackUp Function
function backup_files_by_time($active_dir,$backup_dir,$min_file_age,$backup_time_str="Y") {
$pdf_arr = scandir($active_dir);
foreach($pdf_arr as $file) {
if(file_exists($active_dir.$file)) {
$filetime = filemtime($active_dir.$file);
// File is supposed to be backuped
if ($filetime<$min_file_age) {
// Create Folder if not exists
if (!is_dir($backup_dir.date($backup_time_str,$filetime))) {mkdir($backup_dir.date($backup_time_str,$filetime));}
// Moving File to Backupfolder
rename($active_dir.$file,$backup_dir.date($backup_time_str,$filetime)."/".$file);
}
}
}
}
?>
I would suggest using Symfony Finder component which is really powerful :
$finder = new Finder();
$finder->files()
->in('/pdfs/')
->date('>= 2018-01-01');
foreach($finder as $files) {
// whatever you want to do
}
Information here

The correct way to delete all images files in a folder older than 2 days in PHP

I want to delete all images those are older than 2 days or any number of days I want to add. I will add that file in cron job which will work on X no of days. I have used the below code for preforming this action.
<?php
$folderName='uploads';
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());
}
}
}
?>
This code is not providing any error but Its not deleting images from the folder. I have tried many other codes from Internet but no success. So I need this small help.
you can try this code
<?php
$path = '/path/to/files/';
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
$filelastmodified = filemtime($path . $file);
//24 hours in a day * 3600 seconds per hour
if((time() - $filelastmodified) > 24*3600)
{
unlink($path . $file);
}
}
closedir($handle);
}
?>
You can call shell command from php like this,
find /data/haoqi_backup/db_code/db* -mtime +2 -exec rm {} \;

How to calculate entire directory size with FTP access using PHP

I have a number of different hosting accounts set up for clients and need to calculate the amount of storage space being used on each account, which would update regularly.
I have a database set up to record each clients storage usage.
I attempted this first using a PHP file on each account, run by a Cron Job. If run manually by myself, it would output the correct filesize and update the correct size to the database, although when run from the Cron Job, it would output 0.
I then attempted to run this file from a Cron Job from the main account but figured this wouldn't actually work as my hosting would block files from another server and I would end up with the same result as before.
I am now playing around with FTP access to each account from a Cron Job from the main account which looks something like below, the only problem is I don't know how to calculate directory size rather than single file sizes using FTP access, and don't know how to reiterate this way? Hoping somebody might be able to help here before I end up going around in circles?
I will also add the previous first attempt too.
$ftp_conn = ftp_connect($ftp_host, 21, 420) or die("Could not connect to server");
$ftp_login = ftp_login($ftp_conn, $ftp_username, 'mypassword');
$total_size = 0;
$contents = ftp_nlist($ftp_conn, ".");
// output $contents
foreach($contents as $folder){
while($search == true){
if($folder == '..' || $folder == '.'){
} else {
$file = $folder;
$res = ftp_size($ftp_conn, $file);
if ($res != -1) {
$total_size = $total_size + $res;
} else {
$total_size = $total_size;
}
}
}
}
ftp_close($ftp_conn);
This doesn't work as it doesn't calculate folder sizes and I don't know how to open the reiterate using this method?
This second script did work but would only work if opened manually, and return 0 if run by the cron job.
class Directory_Calculator {
function calculate_whole_directory($directory)
{
if ($handle = opendir($directory))
{
$size = 0;
$folders = 0;
$files = 0;
while (false !== ($file = readdir($handle)))
{
if ($file != "." && $file != "..")
{
if(is_dir($directory.$file))
{
$array = $this->calculate_whole_directory($directory.$file.'/');
$size += $array['size'];
$files += $array['files'];
$folders += $array['folders'];
}
else
{
$size += filesize($directory.$file);
$files++;
}
}
}
closedir($handle);
}
$folders++;
return array('size' => $size, 'files' => $files, 'folders' => $folders);
}
}
/* Path to Directory - IMPORTANT: with '/' at the end */
$directory = '../public_html/';
// return an array with: size, total files & folders
$array = $directory_size->size($directory);
$size_of_site = $array['size'];
echo $size_of_site;
Please bare in mind that I am currently testing and none of the MySQLi or PHP scripts are secure yet.
If your server supports MLSD command and you have PHP 7.2 or newer, you can use ftp_mlsd function:
function calculate_whole_directory($ftp_conn, $directory)
{
$files = ftp_mlsd($ftp_conn, $directory) or die("Cannot list $directory");
$result = 0;
foreach ($files as $file)
{
if (($file["type"] == "cdir") || ($file["type"] == "pdir"))
{
$size = 0;
}
else if ($file["type"] == "dir")
{
$size = calculate_whole_directory($ftp_conn, $directory."/".$file["name"]);
}
else
{
$size = intval($file["size"]);
}
$result += $size;
}
return $result;
}
If you do not have PHP 7.2, you can try to implement the MLSD command on your own. For a start, see user comment of the ftp_rawlist command:
https://www.php.net/manual/en/function.ftp-rawlist.php#101071
If you cannot use MLSD, you will particularly have problems telling if an entry is a file or folder. While you can use the ftp_size trick, as you do, calling ftp_size for each entry can take ages.
But if you need to work against one specific FTP server only, you can use ftp_rawlist to retrieve a file listing in a platform-specific format and parse that.
The following code assumes a common *nix format.
function calculate_whole_directory($ftp_conn, $directory)
{
$lines = ftp_rawlist($ftp_conn, $directory) or die("Cannot list $directory");
$result = 0;
foreach ($lines as $line)
{
$tokens = preg_split("/\s+/", $line, 9);
$name = $tokens[8];
if ($tokens[0][0] === 'd')
{
$size = calculate_whole_directory($ftp_conn, "$directory/$name");
}
else
{
$size = intval($tokens[4]);
}
$result += $size;
}
return $result;
}
Based on PHP FTP recursive directory listing.
Regarding cron: I'd guess that the cron does not start your script with a correct working directory, so you calculate a size of a non-existing directory.
Use an absolute path here:
$directory = '../public_html/';
Though you better add some error checking so that you can see yourself what goes wrong.

Find files in folders and subfolders that were created on the current date

I am trying to find files that were created today. I found most of my answer in other posts, but can't quite get it right. The code below echos all of the files instead of just those that were created today. Any suggestions? Thanks.
$di = new RecursiveDirectoryIterator('/documents/listings');
foreach (new RecursiveIteratorIterator($di) as $filename => $file)
{
if (date ("m-d-Y", filemtime($file)) == date("m-d-Y"))
{ echo $filename . '<br/>'; }
}
First of all, about function filemtime, it returns: file modification time.
But also exists function filectime, it returns: inode change time of file.
As i found filectime more better for your question, but it really returns files not only created today but also edited today.
My code:
<?php
$path = dirname(__FILE__);
$objects = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($objects as $file => $object) {
$basename = basename($file);
if ($basename == '.' or $basename == '..') {
continue;
}
if (is_dir($file)) {
continue;
}
if (date('Y-m-d') === date('Y-m-d', filectime($file))) {
echo $file . PHP_EOL;
}
}
your code is working for me . please check the file create date once.or try with change of directory you created in past
if (!is_dir($file) && date ("m-d-Y", filemtime($file)) == date("m-d-Y"))
Maybe you only want to display the files without the directories? Try this for condition.

Auto delete all files after x-time

How do you auto delete all files under a sub directory after x-time (let say after 24 hours) - without using a cronjob command from server or pl. How can you do this just using PHP code or by just visiting the page without clicking something and the command auto runs.
Response for last comment from my first answer. I'm going to write code sample, so I've created another answer instead of addition one more comment.
To remove files with custom extension you have to implement code:
<?php
$path = dirname(__FILE__).'/files';
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if ((time()-filectime($path.'/'.$file)) < 86400) { // 86400 = 60*60*24
if (preg_match('/\.txt$/i', $file)) {
unlink($path.'/'.$file);
}
}
}
}
?>
Comment: 1. This example uses regular expression /\.txt$/i, which means, that only files with extension txt will be removed. '$' sign means, that filename has to be ended with string '.txt'. Flag 'i' indicates, that comparison will be case-insensitive. More about preg_match() function.
Besides you can use strripos() function to search files with certain extension. Here is code snippet:
<?php
$path = dirname(__FILE__).'/files';
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if ((time()-filectime($path.'/'.$file)) < 86400) { // 86400 = 60*60*24
if (strripos($file, '.txt') !== false) {
unlink($path.'/'.$file);
}
}
}
}
?>
Comment: This example seems more obvious. Result of strripos() also can be achieved with a combining of two functions: strrpos(strtolower($file), '.txt'), but, IMHO, it's a good rule to use less functions in your code to make it more readable and smaller. Please, read attentively warning on the page of strripos() function(return values block).
One more important notice: if you're using UNIX system, file removing could fail because of file permissions. You can check manual about chmod() function.
Good luck.
You can use PHP core functions filectime() and unlink() to check time of file creation and delete its file/files.
EDIT.
Code example:
if ($handle = opendir('/path/to/files')) {
while (false !== ($file = readdir($handle))) {
if (filectime($file)< (time()-86400)) { // 86400 = 60*60*24
unlink($file);
}
}
}
Well here we go, the PHP script that deletes the files that is X number of days old.
<?
$days = 1;
$dir = dirname ( __FILE__ );
$nofiles = 0;
if ($handle = opendir($dir)) {
while (( $file = readdir($handle)) !== false ) {
if ( $file == '.' || $file == '..' || is_dir($dir.'/'.$file) ) {
continue;
}
if ((time() - filemtime($dir.'/'.$file)) > ($days *86400)) {
$nofiles++;
unlink($dir.'/'.$file);
}
}
closedir($handle);
echo "Total files deleted: $nofiles \n";
}
?>
Now paste this code and save it as a php file, upload it to the folder from where you want to delete the files. You can see at the beginning of this php code
$days = 1;
that sets the number of days, for example if you set it to 2 then files older than 2 days will be deleted. Basically this is what happens when you run the script, gets the current directory and reads the file entries, skips ‘.’ for current directory and further checks if there are any other directories,
if ( $file == '.' || $file == '..' || is_dir($dir.'/'.$file) ) {
continue;
}
if the file entry is not a directory then it fetches the file modified time (last modified time) and compares, if it is number of days old
if ((time() - filemtime($dir.'/'.$file)) > ($days *86400)) {
$nofiles++;
unlink($dir.'/'.$file);
}
if the condition becomes true then it deletes the file with the help of unlink( ) php function. Finally closes the directory and exits. I have also added a counter to count the number of files being deleted, which will be displayed at the end of deletion process. So place the php file in the directory that needs the file deletion and execute it.
Hopefully that helps :)
I use shell AT command, it's like a cronjob though
php:
exec("echo rm /somedir/somefile.ext|at now +24 hours");
Here is another example that uses GLOB and it will delete any file
$files = glob('path/to/your/files/*');
foreach($files as $file) { // iterate files
// if file creation time is more than 5 minutes
if ((time() - filectime($file)) > 3600) { // 86400 = 60*60*24
unlink($file);
}
}
or if you want to exclude certain files
$files = preg_grep('#\.txt#', glob('/path/to/your/files/*'), PREG_GREP_INVERT);
After trying to use these examples, I hit a couple of issues:
The comparison operator should be greater than, not less than
filemtime returns the modified time. filectime is the time when a file's inode data is changed; that is, when the permissions, owner, group, or other metadata from the inode is updated, which may lead to unexpected results
I changed the example to use filemtime and fixed the comparison as follows:
<?php
$path = dirname(__FILE__).'/files';
if ($handle = opendir($path)) {
while (false !== ($file = readdir($handle))) {
if ((time()-filemtime($path.'/'.$file)) > 86400) { // 86400 = 60*60*24
if (preg_match('/\.txt$/i', $file)) {
unlink($path.'/'.$file);
}
}
}
}
?>
function deleteCachedData($hours=24)
{
$files = glob(ROOTDIR.DIRECTORY_SEPARATOR.'tmp'.DIRECTORY_SEPARATOR.'*.txt');
foreach($files as $file) {
if(is_file($file) && (time() - filectime($file)) > $hours*3600) {
unlink($file);
}
}
}
$path = 'folder/subfolder/';
/* foreach (glob($path.'.txt') as $file) { */
foreach (glob($path.'*') as $file) {
if(time() - filectime($file) > 86400){
unlink($file);
}
}

Categories