When using readdir empty strings returned - php

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.

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.

How can I check if a file exists with a certain string in its filename?

I'd like to be able to search a directory for a file that starts with a specific string, for example:
- foo
- 1_foo.jpg
- 2_bar.png
How would I check directory foo for files that begin with "1_"?
I've tried using file_exists and preg_match like so:
if (file_exists("foo/" . preg_match("/^1_/", "foo/*"))) echo "File exists.";
but this doesn't work.
Sounds like you need the glob() function. The glob() function searches for all the pathnames matching pattern according to the rules used by the libc glob() function, which is similar to the rules used by common shells.
<?php
foreach (glob('1_*.*') as $filename) {
echo "$filename\n";
}
?>
The above example will output something similar to:
1_foo.png
1_bar.png
1_something.png
Sorry, but the filesystem doesn't understand wildcards or regular expressions. To accomplish what you want, you have to open the directory and read its contents, getting a list of all the files in that directory. Then you use standard string utilities to see which filenames match your criteria.
I think PHP's scandir is what you want as a starting point. You can also use glob but that actually forks a shell to get the file list (which in turn will do the C equivalent of scandir()).
You can use the glob() function
<?php
$list = glob('1_*.*');
var_dump($list);
I was having some trouble checking a directory and files and I gather some scripts here and there and this worked for me (Hope it helps u too):
if ($handle = opendir('path/to/folder/'))
{
while ( false !== ($entry = readdir($handle)) ) {
if ( $entry != "." && $entry != ".." ) {
// echo "$entry<br>";
if (preg_match("/^filename[0-9]_[0-9].jpg/", $entry))
{
// $found_it = TRUE;
}
}
}
closedir($handle);
}

PHP hidden directories - Windows

I'm attempting to add a feature to our intranet, which will allow users to log onto the intranet, and access documents stored within a Windows network SAN.
At the moment, I've successfully retrieved all the file and folder names within a specified users 'My Documents'.
I'm having difficulty removing hidden files and folders from the array.
At the moment, I can remove all folders and files starting with ..
However on Windows, they're being marked as 'hidden' in the properties. I've googled and found lots of resources about how to mark a file as hidden, and how to hide files that start with a ., but none on how to remove hidden windows files / folders. One post on stackoverflow mentions to use DirectoryIterator, but at the moment, but haven't explained at all how to use it to check if a files marked as hidden.
We have over 1000 users, with approximately 500MB - 1GB of documents, with multiple layers of directories, so It needs to be relatively fast.
For clarification:
During a recursive iteration on a Windows system, how can I find out whether a directory is hidden or not, without relying on a prepended . symbol?
Ok, so worked it out, with help from the exec() function, so use with care!
I'm using CodeIgniter, so I've modified the directory_helper.php function slightly, as its installed on a windows box, it'll always need to check for the hidden files, but it should also work for non-codeigniter sites:
function directory_map($source_dir, $directory_depth = 0, $hidden = FALSE)
{
if ($fp = #opendir($source_dir))
{
if(!$hidden)
{
$exclude = array();
exec('dir "' . $source_dir . '" /ah /B', $exclude);
}
$filedata = array();
$new_depth = $directory_depth - 1;
$source_dir = rtrim($source_dir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
while (FALSE !== ($file = readdir($fp)))
{
// Remove '.', '..', and hidden files [optional]
if ( ! trim($file, '.') OR ($hidden == FALSE && $file[0] == '.') OR ($hidden === FALSE && in_array($file, $exclude)))
{
continue;
}
if (($directory_depth < 1 OR $new_depth > 0) && #is_dir($source_dir.$file))
{
$filedata[$file] = directory_map($source_dir.$file.DIRECTORY_SEPARATOR, $new_depth, $hidden);
}
else
{
$filedata[] = $file;
}
}
closedir($fp);
return $filedata;
}
return FALSE;
}
This scanned 2207 files, and 446 folders in approx 11 seconds (Ages I know, but the best I could do). Tested it on 500 folders and 200 files, and did it in around 3 seconds.
Its a recursive function which will scan each non-hidden directory. The first thing it does is scan the current directory for all hidden files and folders using the exec('dir *directory* /ah /B') function.
It will then store the results in an array and make sure that the current file/directory being read isn't in that array.

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

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

Why is $count not updating?

$dir_handle = #opendir($url) or die("Unable to open $url");
$count = "0";
while ($file = readdir($dir_handle)) {
if (!is_dir($url.'/'.$file) && ($file="*.jpg" || $file="*.gif" || $file="*.png") && $file!="picture0.*") {
$galleryEventFile[$count] = $file;
$count++;
}
}
closedir($dir_handle);
I think it has something to do with this line:
if (!is_dir($url.'/'.$file) && ($file="*.jpg" || $file="*.gif" || $file="*.png") && $file!="picture0.*")
but im not sure
I can see two things that will be causing you problems:
Assignment/comparison:
You have the code:
if ($file="*.jpg" //etc...
However, a single equal sign will perform an assignment, not a comparison - you need to use two equals signs (==) for this. See http://php.net/manual/en/language.operators.comparison.php. Essentially what you are doing by doing an assignment in an if statement is:
$file = '*.jpg';
if ($file) { }
Wildcard matching of strings
You also can't do wildcard matching like that ($file == "*.jpg) on a string, you could look at using preg_match() and regular expressions instead, e.g.
if (!preg_match('/\.jpg$/i', $file)) {
//not .jpg
}
It might be better to do something like this though:
//get file extension
$extension = pathinfo($file, PATHINFO_EXTENSION);
$allowedExtensions = array('jpg', 'png', 'gif');
//check in allowed list
if (!in_array(strtolower($extension), $allowedExtensions)) {
//not valid
}
First, $count should be a number. Do:
$count = 0;
Second, AFAIK, PHP doesn't support wildcard matching like that. You can't use "*" to match. You'll need to use regular expressions to match in the conditional.
Do as thedz and Tom Haigh have suggested.
Have you also heard about XDebug? This will allow you to setup an environment say using Eclipse and step through your PHP code. I do not develop without using a combination Eclipse and XDebug.
The first thing you want to do is to debug the if line. Remember that if you put *.gif, it is looking to see that the file is actually named "*.gif", rather than looking for 'any' gif file, similar to what Windows does.
What I'd suggest is going through each segment of the if, and get it to pass. then you can start putting it together.

Categories