Get the newest file from directory structure year/month/date/time - php

I store backups of databases in a directory structure
year/month/day/time/backup_name
an example would be
basics_mini/2012/11/05/012232/RATIONAL.0.db2inst1.NODE0000.20110505004037.001 basics_mini/2012/11/06/012251/RATIONAL.0.db2inst1.NODE0000.20110505003930.001
note that timestamp from the backup file cannot be used. Before the automation testing starts the server time is set to 5.5.2011
So the question is how I can get the latest file if I pass the "base directory" (basics_mini) to some function that I am going to code. My thoughts are that I list the base directory and sort by time to get the year. Then I do the same for month, day and time.
I wonder if there is any "easier" solution to that in php.

Well, you can fetch whole directory tree at once and get last elem from it:
$baseFolder = './backup_mini' ;
$arr = glob("{$baseFolder}/*/*/*/*", GLOB_ONLYDIR);
$lastDir = array_pop($arr);

I don't know of any amazingly simple one-liner but it looks like this might be helpful:
$files = array();
$flags = FilesystemIterator::CURRENT_AS_SELF;
$dir = new RecursiveDirectoryIterator('/path/to/basics_mini', $flags);
foreach ($dir as $path) {
if ($path->isFile()) {
$files[$path->getPath()] = $path->getFilename();
}
}
ksort($files);
You might want to use a RecursiveDirectoryIterator because your directory structure is a little more complex.
The FilesystemIterator constants can also be helpful.

Related

get name of single file in a directory using php

Although I can find plenty of examples of listing all of the files in a directory
$dir = '../upload/'.$id.'/ask_temp';
But I need to get the name of a single file so I can store it in a variable to use elsewhere.
There is and only ever will be one file in there.
In regards to ComFreek's answer, make sure to filter out any directory. (. and ..)
I'm assuming you're using at least PHP 5.3
$files = array_filter(scandir($dir), function($val) use($dir)
{
return is_file($dir.'/'.$val);
});
$myFile = $files[0];
Another way is to this, this is probably easier. (first 2 are always '.' and '..')
$files = scandir($dir);
$myFile = $files[2];

How can I find when a folders content was last modified efficiently in php

I need to run a check on a folder to see when it was last modified. By this I mean the last time it, or any of the files it contains where last modified.
I have tried two ways so far:
using the stat() function on the folder, and then grabbing mtime
$stat = stat("directory/path/");
echo $stat["mtime"];
using the filemtime() function on the folder
echo (filemtime("directory/path/"));
Both of these methods return the same value, and this value does not change if I update one of the files. I am guessing this is because the folder structure itself does not change, only the content of one of the files.
I guess I could loop through all the files in the directory and check their modification dates, but there are potentially a lot of files and this doesn't seem very efficient.
Can anyone suggest how I might go about getting a last modification time for a folder and its content in an efficient way?
moi.
I suggest that you loop all files using foreach function and use it, i think there's no function for that purpose. Here's very simple example using that loop:
$directory = glob('gfd/*');
foreach ($directory as $file) {
$mdtime = date('d.m.Y H:i:s', filemtime($file));
}
echo "Folder last modified: $mdtime<br />";
Keep in mind that foreach is pretty fast, and if you have files < 3000, i think there's nothing to worried about. If you don't want to use this, you can always save modification date to file or something like that. :)
Subfolder-compatibility:
function rglob($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, rglob($dir.'/'.basename($pattern), $flags));
}
return $files;
}
See this question: php glob - scan in subfolders for a file

Select a file that was created the last minute

Do you know if there is a function in php where it can find all the files in a given directory, that were created the last 1 minute (or in any case at a specified time?).
For example, to select all the txt files that were created the last 10 minutes in a directory..
I hope it's clear what I mean!
Thanx
D.
There is no creation time as such, only modified-time, which will work reliably across operating systems.
The filectime() and filemtime() filesystem functions in PHP will allow
you to check and see when a file has last been changed.
It will return
a timestamp holding the value of the time the file was last altered
You could iterate through the files in the folder, while checking filemtime().
Something like,
foreach (glob("*.txt") as $filename) {
echo filemtime($filename); //echoes timestamp
}
Get all files in directory, loop them through and apply filetime() function to see when they were created/modified. Copy them to another array and do with them what you please.
You can try
$it = new GlobIterator(__DIR__ . "/*.txt");
$last10mis = 600;
$list = array();
foreach ( $it as $file )
(time() - $file->getMTime()) <= $last10mis and $list[] = strval($file);
var_dump($list); // all txt files modified in the last 10mins
There is a function in PHP called filemtime that will return the modified time in a UNIX timestamp.
http://php.net/manual/en/function.filemtime.php
from there, and in the example ont that page, it should be fairly straightforward to apply to your needs.

php & recursive Iterator : finding a specific file and its path

I'm a newbie in SPL and recursiveIterator... So could you help me?
What I want to achieve :
I would like to find a file in a folders tree and i would like to obtain its path.
My folder tree could seems to be like this :
./ressources
./ressources/Images
./ressources/Images/Image01
./ressources/Images/Image02
./resources/Images/ImagesSub/Image03
./ressources/Docs
./ressources/Docs/Doc01
and so on...
I obtain the name of my File with sql query (warning : they never have an extension).
Now, i want to find the file's location by doing a recursive Iterator on './ressources' folder.
Then, when i've found the file, i would like to return the whole link './ressources/Folder/File'.
I've read Gordon's solution but it doesn't work, I tried only to echo something, but doesn't display anything.
Here is my code :
$doc_id = $bean->id;
$query = "SELECT a.document_revision_id FROM documents as a, document_revisions as b ";
$query .= "WHERE a.document_revision_id = b.id AND a.id = '" . $doc_id . "' LIMIT 1";
$results = $bean->db->query($query, true);
$row = $bean->db->fetchByAssoc($results);
$file_id = $row['document_revision_id'];
$ressources = './ressources/';
$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($ressources, RecursiveDirectoryIterator::KEY_AS_FILENAME), RecursiveIteratorIterator::SELF_FIRST);
foreach ($iter as $entry) {
if ($entry->getFilename() === $file_id){
echo '<script> alert('.$entry->getFilepath().');</script>';
}
}
(i know doing an alert into a echo is bullsh*t, but whith sugar it is quite difficult to display something
Specifications
I'm trying to do this in a SugarCrm CE 6.5.2 logic_hook and it's running on archlinux. And my PHP version is 5.4.6
It is really urgent, so I would be reaaaally happy if you could help me!!
Thanks by advance!
EDIT FROM 12/10/09 2pm:
What is my sugar project and why i can't get the pathname from my database
I created a custom field in Documents module called folder_name_c. You fill it with the name of the folder (under ressources) where you want to upload your document.
I want to allow the user to move the file uploaded from its ancient folder to new one when i edit the document.
When editing a document, I did a after_retrieve hook to permit the logic_hook to work when editing (before, it was just done for edit view)
So, if i get the $bean->folder_name_c, it pick up the field's content. If i try sql, it will pick the folder_name_c only after i click "save".
So, i don't have any clue to get my old folder_name to create an
$old_link = '.ressources/'.$old_folder.'/'.$file_id;
I can only create the
$new_link = '.ressources/'.$bean->folder_name_c.'/'.$file_id;
So, after a long time, i figured out that i could browse my ressources folder and my sub folders to find my file named $file_id and then create the $old_link
FYI, by creating a new custom field under studio in sugar, i gained a lot of time.
I don't want to pass my life on adding a custom_code calling database or else. this is URGENT and recursive iterator seems to be simple and quick.
There is no method such as getFilepath for the (Recursive)DirectoryIterator, just use $entry itself, when used in a string context it's casted to such one (à la __toString):
$file_id = 'test';
$ressources = './ressources/';
// [...]
echo '<script>alert('.$entry.');</script>'; // is casted to a string which contains the full path
// results in alerting ./resources/SubFolder/test
I tested it with the same structure and without extension.
So, I've found out how to use recursive iterators for my problem!
Here is my code :
$ressources = './ressources/';
$directoryIter = new RecursiveDirectoryIterator($ressources);
$iter = new RecursiveIteratorIterator($directoryIter, RecursiveIteratorIterator::SELF_FIRST);
$old_path = '';
$new_path = $ressources.$bean->folder_name_c.'/'.$file_id;
chmod($new_path,0777);
foreach ($iter as $entry) {
if (!$directoryIter->isDot()) {
if ($entry->getFileName() == $file_id) {
$old_path = $entry->getPathName();
chmod($old_path, 0777);
copy($old_path,$new_path);
}
}
}
So i succeed to get my file's origin path! :)
But as always, there is a problem:
I want to cut and paste my file from $old_path to $new_path (as you can see in my code). The copy here works well, but i don't know where i have to unlink() the old_path.. if anyone knows ...
(and if i wrote the copy in the wrong line, just tell me please! :D )

unlink files with a case-insensitive (glob-like) pattern

I have two folders, in one i have the videos and in the second one the configuration files for each video(3 files per video). Now if i want to delete a video i have to delete files by hand.
I found this :
<?php
$filename = 'name.of.the.video.xml';
$term = str_replace(".xml","", $filename);
$dirPath = ("D:/test/");
foreach (glob($dirPath.$term.".*") as $removeFile)
{
unlink ($removeFile);
}
?>
A echo will return:
D:/test/name.of.the.video.jpg
D:/test/name.of.the.video.srt
D:/test/name.of.the.video.xml
Is ok and it help me a lot, but i have a problem here.
Not all files are the same ex:
Name.of.The.video.jpg
Name.Of.The.Video.xml
If i echo the folder looking for that string and is not identic with the $filename will return empty.
So, my question is, how can i make that search Case insensitive?
Thank you.
You are making use of the glob function which is case sensitive. You are using the wrong function therefore to get the list of files.
You should therefore first normalize the filenames in the directory so they all share the same case (e.g. all lowercase). Or you need to use another method to get the directory listing case-insensitive. I suggest the first, however if that is not an option, why don't you glob for all files first and then filter the list of files using preg_grep which allows to specify patterns that are case-insensitive?
Which leads me to the point that it's more practicable to use DirectoryIterator with a RegexIterator:
$filename = 'name.of.the.video.xml';
$term = basename($filename, ".xml");
$files = new DirectoryIterator($dirPath);
$filesFiltered = new RegexIterator($files, sprintf('(^%s\\..*$)i', preg_quote($term)));
foreach($filesFiltered as $file)
{
printf("delete: %s\n", $file);
unlink($file->getPathname());
}
A good example of the flexibility of the Iterators code are your changed requirements: Do that for two directories at once. You just create two DirectoryIterators and append the one to the other with an AppendIterator. Job done. The rest of the code stays the same:
...
$files = new AppendIterator();
$files->append(new DirectoryIterator($dirPath1));
$files->append(new DirectoryIterator($dirPath2));
...
Voilá. Sounds good? glob is okay for some quick jobs that need just it. For everything else with directory operations start to consider the SPL. It has much more power.
Is strcasecmp() a valid function for this? Its a case insensitive str comparison function?
Surely if you know the file name and you can echo it out, you can pass this to unlink()?

Categories