I am going to have one directory with multiple sub-directories.
I want to be able to get the last, one, uploaded/modified flv out of each directory and be able create a formatted list that can be outputted.
I have used glob and foreach to create lists of folder items before but not sure how to accomplish this, and just return one file out of a number of sub-directories.
Any help will be appreciated
Thank you!
<?php
$result = array();
foreach (new DirectoryIterator('/path/to/dir') as $item) {
if (!$item->isDot() && $item->isDir()) {
$result[$item->getFilename()] = $m = null;
foreach (new DirectoryIterator($item->getPathname()) as $subItem) {
if ($subItem->isFile() && $m < $subItem->getMTime()) {
$result[$item->getFilename()] = $subItem->getFilename();
$m = $subItem->getMTime();
}
}
}
}
You're locking for filemtime
Related
I need to search into folders and subfolders in search for files. In this search I need to know the files names and their path, because I have different folders and files inside of those.
I have this name 05-Navy, and inside this folder I have 3 files called 05_Navy_White_BaseColor.jpg, 05_Navy_White_Normal.jpg and 05_Navy_White_OcclusionRoughnessMetallic.jpg.
I need to only get one of them at a time because I need to add they separately to different lists.
Then I came up with the code below:
function getDirContents($dir, &$results = array()) {
$files = scandir($dir);
$findme = '_BaseColor';
$mypathCordas = null;
$findmeCordas = 'Cordas';
foreach ($files as $key => $value) {
$path = realpath($dir . DIRECTORY_SEPARATOR . $value);
$mypathCordas = $path;
$pos = strpos($mypathCordas, $findme);
$posCordas = strpos($mypathCordas, $findmeCordas);
if (!is_dir($path)) {
if($posCordas == true){
if($pos == true){
$results[] = $path;
}
}
}
else if ($value != "." && $value != ".." ) {
if($posCordas == true){
echo "</br>";
getDirContents($path, $results);
//$results[] = $path;
}
}
}
sort( $results );
for($i = 0; $i < count($results); $i++){
echo $results[$i];
echo "</br>";
}
return $results;
}
getDirContents('scenes/Texturas');
as output result I get this: Results1
Which is not ideal at all, the biggest problem is that the list inserts the same values every time it has do add new ones, and as you can see, it doesn't sort one bit, but it shuffles. I did other things, like I have tried to use DirectoryIterator which worked really well, but I couldn't sort at all...
The printing each time something new is on the list might be my for(), but I am relatively new to php, so I can't be sure.
Also, there's this thing where it gets all the path, and I already tried using other methods but got only errors, where I would only need the scenes/texturas/ instead of the absolute path....
I use this code to list all files in directory:
$d = dir($FolderToPlay);
while (($file = $d->read()) !== false){
...
...
}
$d->close();
But, the result is not in the numerical order. How can I fix it?
Get a list of all the filenames, then you can use a sorting function.
$d = glob("$FolderToPlay/*");
natsort($d);
foreach ($d as $file) {
...
}
The easiest way to list all files in a directory is with scarndir() fuction.
You can use it like this:
//Create a variable that contains all your files
$root = scandir($dir);
//Do something with each value, like push them into an array, do regex etc.
foreach($root as $value){
//...
}
Having issues trying to perform a foreach within a while loop in PHP. I'm extracting build names from a database table. Those build names happen to be folder names. Within those folders is a folder (either Client or Clients) and within those are folders named after the clients business name. I want the script to show me the build name (accomplished already with an echo) and then list each folder below the build name.
$build_grab = mysql_query("SELECT b_id,b_name FROM builds", $link);
while($build_row = mysql_fetch_array($build_grab))
{
$b_id = $build_row['b_id'];
$b_name = $build_row['b_name'];
$client_dir = is_dir("/somepath/builds/$b_name/Client/");
$clients_dir = is_dir("/somepath/builds/$b_name/Clients/");
if ($client_dir == '1') {
$client_folders = explode(",", exec("ls -1 /somepath/builds/$b_name/Client/"));
} elseif ($clients_dir == '1') {
$client_folders = str_replace("\n","", explode(",", exec("ls -1 /somepath/builds/$b_name/Clients/")));
};
echo $b_name;
echo "\r\n";
foreach($client_folders as $folder)
{
echo $folder;
echo "\r\n";
}
}
Unfortunately this seems to only give me one (1) client folder name per build and it's always the last client (a-z) in the folder.
Example Output:
build-4.0.0.0Client-fbuild-4.0.0.1Client-dbuild-4.0.0.2Client-j
What am I missing here or better yet, is there a more efficient way of doing this? Any help is greatly appreciated!
You're replacing the $client_folders variable each time. You want to create it as an array before you enter the while loop, then do this
if ($client_dir == '1') {
$client_folders[] = explode(",", exec("ls -1 /somepath/builds/$b_name/Client/"));
} elseif ($clients_dir == '1') {
$client_folders[] = str_replace("\n","", explode(",", exec("ls -1 /somepath/builds/$b_name/Clients/")));
};
By the way, this will only enter the first IF, since the second is exactly the same
Rather than using
$client_folders = str_replace("\n","", explode(",", exec("ls -1 /somepath/builds/$b_name/Clients/")));
I would recommend using the following code to list the folders.
if ($folderHandle = opendir(clients_dir)) {
while ($file = readdir($folderHandle) {
echo "$file\n";
}
closedir($folderHandle);
}
You can change that code to be conditional, but it should give you a good list.
exec() only returns the last line of output from the command. You should use the native PHP functions to read the directory list - either opendir/readdir or glob will work.
if ($client_dir == '1') {
$client_folders = glob("/somepath/builds/$b_name/Client/*", GLOB_ONLYDIR);
} elseif ($clients_dir == '1') {
$client_folders = glob("/somepath/builds/$b_name/Clients/*", GLOB_ONLYDIR);
};
Thanks much to mcrumley, your suggestion of using 'glob' fixed it! Sorry crumley, I am apparently to newb to vote up your response. Perhaps other users can help with that.
Thanks also Chris for suggesting mysqli, I will code with it from here out, late adopter here.
Below the new code that resolved the issue.
$build_grab = $mysqli->query("SELECT b_id,b_name FROM builds");
while($build_row = $build_grab->fetch_array())
{
$b_id = $build_row['b_id'];
$b_name = $build_row['b_name'];
$client_dir = is_dir("/somepath/builds/$b_name/Client/");
$clients_dir = is_dir("/somepath/builds/$b_name/Clients/");
if ($client_dir == '1') {
$client_folders = glob("/somepath/builds/$b_name/Client/*", GLOB_ONLYDIR);
} elseif ($clients_dir == '1') {
$client_folders = glob("/somepath/builds/$b_name/Clients/*", GLOB_ONLYDIR);
};
echo $b_name;
echo "\r\n";
foreach($client_folders as $folder)
{
echo $folder;
echo "\r\n";
}
}
Thanks again for everyones help!
I've managed (well, stackoverflow has shown me how) to search a directory on my server and echo and image. The trouble is the images in the folder are named by an IP camera yy_mm_dd_hh_mm where dd (and other date digits) have either one or two digits. I need them to have a preceeding zero so that I don't end up with, for example, an image taken at 9:50am being treated as a higher value than the photo taken more recently, at 10:05am. (I want it to treat it as 09_50 and 10_05 to fix the issue).
I've looked at search and replace but cannot get this to work within my current code:
function webcam_image () {
foreach (glob( "../camera/IPC_IPCamera*.jpg") as $f ) {
$list[] = $f;
}
sort($list);
echo array_pop($list);
}
example file = IPC_IPCamera_13_7_24_9_57_45.jpg
any help would be much appreciated!
Thanks
Ali
I would ignore the file name altogether and use a DirectoryIterator, fetching the files actual modified date. Something like this might work.
$files = array();
$iterator = new \DirectoryIterator('/path/to/dir');
foreach ($iterator as $file) {
if(! $file->isDot()) $files[$file->getMTime()] = $file->getFilename();
}
ksort($files);
print_r($files);
Take a look here for more information: http://php.net/manual/en/class.directoryiterator.php
If I have understood you correctly, you could handle this by preg_replaceing the files.
So you could loop through your files and do the following
$newFilename = preg_replace('/_([0-9])_/', '_0$1_', $oldFilename);
rename($oldFilename, $newFilename);
You can try something like:
function webcam_image () {
foreach (glob( "../camera/IPC_IPCamera*.jpg") as $f ) {
$digits = explode('_', substr(substr($f, 13), 0, -4));
foreach($digits as &$digit){
$digit = sprintf("%02d", $digit);
}
unset($digit);
$list[] = 'IPC_IPCamera_' . implode('_', $digits) . '.jpg';
}
sort($list);
echo array_pop($list);
}
You can use sprintf()
$list[] = $f;
with the following
$list[] = sprintf("%02s", $f);
Suppose there are 2 directories on my server:
/xyz/public_html/a/
/xyz/public_html/b/
And both of them consist of many files. How do i detect the files that are common to both the folders in terms of their name and file_extension. This program is to be implemented in PHP. Any suggestions?
Using FileSystemIterator, you might do something like this...
<?
$it = new FilesystemIterator('/xyz/public_html/a/');
$commonFiles = array();
foreach ($it as $file) {
if ($file->isDot() || $file->isDir()) continue;
if (file_exists('/xyz/public_html/b/' . $file->getFilename())) {
$commonFiles[] = $file->getFilename();
}
}
Basically, you have to loop through all the files in one directory, and see if any identically-named files exist in the other directory. Remember that the file name includes the extension.
If it’s just two directories, you could use an algorithm similar to the merge algorithm of merge sort where you have two lists of already sorted items and walk them simultaneously while comparing the current items:
$iter1 = new FilesystemIterator('/xyz/public_html/a/');
$iter2 = new FilesystemIterator('/xyz/public_html/b/');
while ($iter1->valid() && $iter2->valid()) {
$diff = strcmp($iter1->current()->getFilename(), $iter2->current()->getFilename());
if ($diff === 0) {
// duplicate found
} else if ($diff < 0) {
$iter1->next();
} else {
$iter2->next();
}
}
Another solution would be to use the uniqueness of array keys so that you put each directory item into an array as key and then check for each item of the other directory if such a key exists:
$arr = array();
$iter1 = new FilesystemIterator('/xyz/public_html/a/');
foreach ($iter1 as $item) {
$arr[$item->getFilename()] = true;
}
$iter2 = new FilesystemIterator('/xyz/public_html/a/');
foreach ($iter2 as $item) {
if (array_key_exists($item->getFilename(), $arr)) {
// duplicate found
}
}
If you just want to find out which are in common, you can easily use scandir twice and find what's in common, for example:
//Remove first two elements, which will be the constant . and .. Not a very sexy solution
$filesInA = array_shift(array_shift(scandir('/xyz/publichtml/a/')));
$filesInB = array_shift(array_shift(scandir('/xyz/publichtml/b/')));
$filesInCommon = array_intersect($filesInA, $filesInB);