i found out that i can use
$files = scandir('c:\myfolder', SCANDIR_SORT_DESCENDING);
$newest_file = $files[0];
to get the latest file in the given directory ('myfolder').
is there an easy way to get the latest file including subdirectorys?
like:
myfolder> dir1 > file_older1.txt
myfolder> dir2 > dir3 > newest_file_in_maindir.txt
myfolder> dir4 > file_older2.txt
Thanks in advance
To the best of my knowledge, you have to recursively check every folder and file to get the last modified file. And you're current solution doesn't check the last modified file but sorts the files in descending order by name.
Meaning if you have a 10 years old file named z.txt it will probably end up on top.
I've cooked up a solution.
The function accepts a directory name and makes sure the directory
exists. It returns null when the directory has no files or any of its subdirectories.
Sets aside the variables $latest and $latestTime where the last modified file is stored.
It loops through the directory, avoiding the . and .. since they can cause an infinite recursion loop.
In the loop the full filename is assembled from the initial directory name and the part.
The filename is checked if it is a directory if so it calls the same function we are in and saves the result.
If the result is null we continue the loop otherwise we save the file as the new filename, which we now know is a file.
After that we check the last modified time using filemtime and see if the $latestTime is smaller meaning the file was modified earlier in time that the current one.
If the new file is indeed younger we save the new values to $latest and $latestTime where $latest is the filename.
When the loop finishes we return the result.
function find_last_modified_file(string $dir): ?string
{
if (!is_dir($dir)) throw new \ValueError('Expecting a valid directory!');
$latest = null;
$latestTime = 0;
foreach (scandir($dir) as $path) if (!in_array($path, ['.', '..'], true)) {
$filename = $dir . DIRECTORY_SEPARATOR . $path;
if (is_dir($filename)) {
$directoryLastModifiedFile = find_last_modified_file($filename);
if (null === $directoryLastModifiedFile) {
continue;
} else {
$filename = $directoryLastModifiedFile;
}
}
$lastModified = filemtime($filename);
if ($lastModified > $latestTime) {
$latestTime = $lastModified;
$latest = $filename;
}
}
return $latest;
}
echo find_last_modified_file(__DIR__);
In step 7 there is an edge case if both files were modified at the exact same time this is up to you how you want to solve. I've opted to leaving the initial file with that modified time instead of updating it.
Related
I want to rename all files in a folder with random numbers or characters.
This my code:
$dir = opendir('2009111');
$i = 1;
// loop through all the files in the directory
while ( false !== ( $file = readdir($dir) ) ) {
// do the rename based on the current iteration
$newName = rand() . (pathinfo($file, PATHINFO_EXTENSION));
rename($file, $newName);
// increase for the next loop
$i++;
}
// close the directory handle
closedir($dir);
but I get this error:
Warning: rename(4 (2).jpg,8243.jpg): The system cannot find the file specified
You're looping through files in the directory 2009111/, but then you refer to them without the directory prefix in rename().
Something like this should work better (though see the warning about data loss below):
$oldName = '2009111/' . $file;
$newName = '2009111/' . rand() . (pathinfo($file, PATHINFO_EXTENSION));
rename($oldName, $newName);
Of course, you may want to put the directory name in a variable or make other similar tweaks. I'm still not clear on why you're trying to do this, and depending on your goals there may be better ways of reaching them.
Warning! The approach you are using could cause data loss! A $newName could be generated that is the same name as an existing file, and rename() overwrites target files.
You should probably make sure $newName doesn't exist before you rename().
I am a newbie at PHP and I'm learning.
I've made a basic script where you can upload an image to a director on the server. I want the image names to get a number at the end so that the name won't be duplicated.
This is my script to add 1 to the name (I'm really bad at "for loops"):
for(x=0; $imageName => 50000; x++){
$imageFolderName = $imageName.$x;
}
Please tell me if I'm doing this totally wrong.
Adding to Niet's answer, you can do a foreach loop on all the files in your folder and prepend a number to the file name like so:
<?
$directory = 'directory_name';
$files = array_diff(scandir($directory), array('.', '..'));
$count = 0;
foreach($files as $file)
{
$count++;
rename($file, $count.'-'.$file);
}
?>
Alternatively you could rename the file to the timestamp of when it was uploaded and prepend some random characters to the file with the rand() function:
<?
$uploaded_name = 'generic-image.jpeg';
$new_name = time().rand(0, 999).$uploaded_name;
?>
You'll need to handle and move the uploaded files before and after the rename, but you get the general gist of how this would work.
Here's a potential trick to avoid looping:
$existingfiles = count(glob("files/*"));
// this assumes you are saving in a directory called files!
$finalName = $imageName.$existingfiles;
So I have a URL which contains &title=blabla
I know how to extract the title, and return it. But I've been searching my ass off to get the full path to the filename when I only have the filename.
So what I must have is an way to search in all directories for an html file called 'blabla' when the only thing it has is blabla. After finding it, it must return the full path.
Anyone who does have an solution for me?
<?php
$file = $_GET['title'];
if ($title = '') {
echo "information.html";
} else {
//here it must search for the filepath and echo it.
echo "$filepath";
}
?>
You can use the solution provided here.
It allows you to recurse through a directory and list all files in the directory and sub-directories. You can then compare to see if it matches the files you are looking for.
$root = '/'; // directory from where to start search
$toSearch = 'file.blah'; // basename of the file you wish to search
$it = new RecursiveDirectoryIterator($root);
foreach(new RecursiveIteratorIterator($it) as $file){
if($file->getBasename() === $toSearch){
printf("Found it! It's %s", $file->getRealPath());
// stop at the first match
break;
}
}
Keep in mind that depending on the number of files you have, this can be slow as hell
For a start this line is at fault
if ($title = '') {
See http://www.php.net/manual/en/reserved.variables.files.php
I have a double question. Part one: I've pulled a nice list of pdf files from a directory and have appended a file called download.php to the "href" link so the pdf files don't try to open as a web page (they do save/save as instead). Trouble is I need to order the pdf files/links by date created. I've tried lots of variations but nothing seems to work! Script below. I'd also like to get rid of the "." and ".." directory dots! Any ideas on how to achieve all of that. Individually, these problems have been solved before, but not with my appended download.php scenario :)
<?php
$dir="../uploads2"; // Directory where files are stored
if ($dir_list = opendir($dir))
{
while(($filename = readdir($dir_list)) !== false)
{
?>
<p><a href="http://www.duncton.org/download.php?file=login/uploads2/<?php echo $filename; ?>"><?php echo $filename;
?></a></p>
<?php
}
closedir($dir_list);
}
?>
While you can filter them out*, the . and .. handles always come first. So you could just cut them away. In particular if you use the simpler scandir() method:
foreach (array_slice(scandir($dir), 2) as $filename) {
One could also use glob("dir/*") which skips dotfiles implicitly. As it returns the full path sorting by ctime then becomes easier as well:
$files = glob("dir/*");
// make filename->ctime mapping
$files = array_combine($files, array_map("filectime", $files));
// sorts filename list
arsort($files);
$files = array_keys($files);
I have a directory containing sub directories which each contain a series of files. I'm looking for a script that will look inside the sub directories and randomly return a specified number of files.
There are a few scripts that can search a single directories (not sub folders), and other scripts that can search sub folders but only return one file.
To put a little context on the situation, the returned files will be included as li's in an rotating banner.
Thanks in advance for any help, hopefully this is possible.
I think I've got there, not exactly what I set out to achieve but works good enough, arguably better for the purpose, I'm using the following function:
<?php function RandomFile($folder='', $extensions='.*'){
// fix path:
$folder = trim($folder);
$folder = ($folder == '') ? './' : $folder;
// check folder:
if (!is_dir($folder)){ die('invalid folder given!'); }
// create files array
$files = array();
// open directory
if ($dir = #opendir($folder)){
// go trough all files:
while($file = readdir($dir)){
if (!preg_match('/^\.+$/', $file) and
preg_match('/\.('.$extensions.')$/', $file)){
// feed the array:
$files[] = $file;
}
}
// close directory
closedir($dir);
}
else {
die('Could not open the folder "'.$folder.'"');
}
if (count($files) == 0){
die('No files where found :-(');
}
// seed random function:
mt_srand((double)microtime()*1000000);
// get an random index:
$rand = mt_rand(0, count($files)-1);
// check again:
if (!isset($files[$rand])){
die('Array index was not found! very strange!');
}
// return the random file:
return $folder . "/" . $files[$rand];
}
$random1 = RandomFile('project-banners/website-design');
while (!$random2 || $random2 == $random1) {
$random2 = RandomFile('project-banners/logo-design');
}
while (!$random3 || $random3 == $random1 || $random3 == $random2) {
$random3 = RandomFile('project-banners/design-for-print');
}
?>
And echoing the results into the container (in this case the ul):
<?php include($random1) ;?>
<?php include($random2) ;?>
<?php include($random3) ;?>
Thanks to quickshiftin for his help, however it was a little above my skill level.
For info the original script which I changed an be found at:
http://randaclay.com/tips-tools/multiple-random-image-php-script/
Scrubbing the filesystem every single time to randomly select a file to display will be really slow. You should index the directory structure ahead of time. You can do this many ways, try a simple find command or if you really want to use PHP my favorite choice would be RecursiveDirectoryIterator plus RecursiveIteratorIterator.
Put all the results into one file and just read from there when you select a file to display. You can use the line numbers as an index, and the rand function to pick a line and thus a file to display. You might want to consider something more evenly distributed than rand though, you know to keep the advertisers happy :)
EDIT:
Adding a simple real-world example:
// define the location of the portfolio directory
define('PORTFOLIO_ROOT', '/Users/quickshiftin/junk-php');
// and a place where we'll store the index
define('FILE_INDEX', '/tmp/porfolio-map.txt');
// if the index doesn't exist, build it
// (this doesn't take into account changes to the portfolio files)
if(!file_exists(FILE_INDEX))
shell_exec('find ' . PORTFOLIO_ROOT . ' > ' . FILE_INDEX);
// read the index into memory (very slow but easy way to do this)
$aIndex = file(FILE_INDEX);
// randomly select an index
$iIndex = rand(0, count($aIndex) - 1);
// spit out the filename
var_dump(trim($aIndex[$iIndex]));