DirectoryIterator scan to exclude '.' and '..' directories still including them? - php

In the script below, I'm trying to copy the folders that exist in the $base directory over to the $target directory. However, in my initial echo test, its returning the . and .. directories even though I'm trying to handle that exception in the conditional.
What am I missing?
$base = dirname(__FILE__).'/themes/';
$target = dirname( STYLESHEETPATH );
$directory_folders = new DirectoryIterator($base);
foreach ($directory_folders as $folder)
{
if ($folder->getPath() !== '.' && $folder->getPath() !=='..' )
{
echo '<br>getPathname: '. $folder->getPathname();
//copy($folder->getPathname(), $target);
}
}die;
However, and this makes no sense to me, if I change the conditional to...
if (!is_dir($folder) && $folder->getPath() !== '.' && $folder->getPath() !=='..' )
It returns the correct folders inside of $base. What?

DirectoryIterator::getPath() returns the full path to the directory -- and not only the last part of it.
If you only want the last portion of that path, you should probably use SplFileInfo::getBasename() in your condition.
Or, for your specific test, you might want to take a look at the DirectoryIterator::isDot() method (quoting) :
Determine if current
DirectoryIterator item is '.' or
'..'

You can use DirectoryIterator::isDot instead:
if (!$folder->isDot())

Related

Edit PHP code to use strpos to find if Big and Needle1 are in filename

Apologies, I screwed up on title and question, I believe both are now fixed. It looked like I was looking for "OR", whereas I am looking for "AND".
I have several files in a folder:
this-is-big-needle1.jpg
a-big-long-needle1.jpg
this-file-is-needle2.jpg
needle3-is-this-file.jpg
The current code && strpos($file,"needle1") is used to search a folder and inlcude all files that that match the strops value eg "needle1" and include these images in an AMP HTML carousel.
So current code searches for "needle1" and will correctly return the first 2 files above but ignore the others.
I have searched and found several general solutions for finding if needle1 OR needle2 are present in filename, but found nothing were both "big" and "needle1" are found in the same filename.
I have tried adding a second strops && strpos($file, "needle1") && strpos($file, "big") but my php skills are very lacking so get easily tripped up with syntax and were to put eg '..' etc
php
$Count5Image5 = 0;
$Image5;
$handle = opendir(dirname(realpath(__FILE__)).'/images/');
while($file = readdir($handle)){
if($file !== '.' && $file !== '..' && strpos($file,"needle1"))
{
Image5[$Count5Image5] = $file;
$Count5Image5++;
}
}
sort($Image5);
for($i=0; $i<$Count5Image5; $i++)
echo '<amp-img src="images/'.$Image5[$i].'" class="xs-12" width="353" height="210" layout="responsive"></amp-img>';
?>
If someone could suggest an edit of my code to find "big" & "needle1" in the same filename (to return top two files) it would be appreciated.
==========
A litte side issue (in case there is an obvious solution) - for some reason existing code will not find any file if the strops value is at the start of the file name eg if I enter value "this-" it will not find any files or if I enter needle3 it will not find any files (string must be after character1 in the string)
Maybe you can replace:
if($file !== '.' && $file !== '..' && strpos($file,"needle1"))
With:
if($file !== '.' && $file !== '..' && ( strpos($file,"needle1") !== false || strpos($file,"needle2") !== false )
This would match all files having needle1 or needle2 in the name.
Please note the !== false I added after each strpos(). This helps you with the side issue you mentioned. strpos returns false if needle is not found and 0 in case the filename starts with the needle. They both evaluate as false in an if statement context ( you can read more here ).
Preg_match alternative
This would be another nice way to match both big and needle no matter the order in which they appear in the filename.
if(preg_match("/(big|needle1)/i", $file) !== 0) {
}
This would match both: this-is-big-needle1.jpg and this-needle1-is-big.jpg as can be seen here: regex test
Alternative
Another nice way of doing it would be to use the glob() function:
That way you could only get the files that match those filenames:
foreach (glob("{*needle1*,*needle2*}.*", GLOB_BRACE) as $filename) {
echo $filename."<br />";
}
Hope that helps.
The issue you are running into is the one the manual references,
This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE. Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.
-https://www.php.net/manual/en/function.strpos.php
So !== is what you should use for the comparison.
Since you are doing pattern matching though I would just use a regex with preg_match.
preg_match('/needle[12]/', $file)
The [] is a character class and allows all characters listed inside it, with some exceptions, https://www.regular-expressions.info/charclass.html.

PHP unlink file with no extension

I am trying to unlink files in a Directory which have no extensions.
I did following, but did not work:
$fileInfo = pathinfo($this->outputPath);
if($fileInfo['extension'] == NULL)
{
unlink($fileInfo['dirname'].$fileInfo['basename']);
}
according to the pathinfo manual :
Note:
If the path does not have an extension, no extension element
will be returned (see second example below).
so you need to check if the returned value has the extension element using isset , note that using empty will pass the dot directories in unix systems, for example if you are iterating some directory empty will consider the . and .. directories as an empty extension elements
// check if not isset
if(isset($fileInfo['extension']) === false) {
// perform some action
}
or if in the future you want to perform some complex search [eg: recursive search for files that does not have extensions] you may use FilesystemIterator
foreach (new FilesystemIterator($dir) as $fileInfo) {
// check if some file extension is null
if ($fileInfo->getExtension() == null) {
// perform some action
}
}
As #CBroe noticed in comments:
Your comparison with NULL is just wrong here.
Check for empty'ness instead:
$fileInfo = pathinfo($this->outputPath);
if(empty($fileInfo['extension']))
{
unlink($fileInfo['dirname'] . DIRECTORY_SEPARATOR . $fileInfo['basename']);
}
Also, you missed a DIRECTORY_SEPARATOR between the dirname and the basename.
Update: As #hassan pointed out, empty is not the proper way to check for this either. That's because of directories . and .. on unix-like systems will pass this test, which is not desired.
So, the proper way to check for files without extension would be:
if(isset($fileInfo['extension']) === false)
{
unlink($fileInfo['dirname'] . DIRECTORY_SEPARATOR . $fileInfo['basename']);
}

rename all files in folder with random name

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().

When using readdir empty strings returned

I am using readdir in the following code to get a list of all file names of images in a directory.
while (false !== ($entry = readdir($frameDir))){
$shapeName = explode('.',$entry);
if (!empty($shapeName[0]) && $shapeName[0] != '.' && $shapeName[0] != '..' && $shapeName[0] != '/'){
$shapeName = $shapeName[0];
$shapes['frames'][] = $shapeName;
}
After this code the script appends the '.png' to make it a valid file name.
As you can see I've tried to eliminate any chances of a blank file name being passed. Though when I run the script I end up getting a blank directory "/shapes/frame/.png" . This only happens for this particular directory. When I use the code on another of the three directories I get results as expected, and the code is the same logic as what is used above.
while (false !== ($entry = readdir($frameDotDir))){
$shapeName = explode('.',$entry);
if (!empty($shapeName[0]) && $shapeName[0] != '.' && $shapeName[0] != '..' && $shapeName[0] != '/'){
$shapeName = $shapeName[0];
$shapes['frame_dots'][] = $entry;
}
}
When checking the filesystem on the server, I can't find any files with blank names.
I am wondering what could be causing my script to be reading blank file names from the diretory.
File names cannot be empty (and will not). You did something wrong in your code. It should look like:
while ($entry = readdir($frameDir)){
// skip files which names starting with a dot
// like '.', '..' or hidden files
if (strpos($entry, '.') !== 0) {
$shapes['frame_dots'][] = $entry;
}
}
You see, less is more ;)
Why don't you use glob() instead of readdir().Just give it a pattern and it will let you process the filenames with much ease instead of doing the one by one scanning work. And in your case, there is no way it will return an empty file name. Also, have a look on glob flags in the documentation, you will be amazed of it's simplicity.
glob("*.png");
Output:
Array ( [0] => shape.png, [1] => shape2.png )
I was having the same problem with blank filenames usind readdir() it turn out to be that the directory name was wrong, turns out linux is case sensitive, in code the directory name starts with "I" and in linux the directory started with "i".
I guess the error was due to not handling opendir() errors. Check your code.

PHP readir results - trying to sort by date created and also get rid of "." and ".."

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);

Categories