I'm trying to build a <ul> list with a <li> for each directory in a main folder.
here's my code :
<?php
$dir = opendir(getEnv("DOCUMENT_ROOT") . "/folder");
while(($file = readdir($dir)) !== false ){
if( is_dir($file) && $file !== "." && $file !== ".." ){
echo "<li>" . $file . "</li>";
}
}
closedir($dir);
?>
there are two directories in /home/example/folder but there are not recognized as folders (for sure they are !)
if I "echo" the files in the while loop they are printed (they well exist for the script no trouble on that side).
If I try to "filetype" them, a lstat failed error is thrown, I searched on internet the meaning of it and I end up with nothing but technically support that I pain to understand.
Your problem is that inside "folder" directory you can have two directories (a and b),then the reading retrieve "a" and "b" as file names, while is_dir receive a full path filename or a relative filename, you have two options:
pass the full path to filename to the is_dir function (see example code).
pass the relative path (depends on where you put your script).
if( is_dir($dir . "/" . $file) && $file !== "." && $file !== ".." ){ ......
Try:
while($file = readdir($dir)) {
if (...) { }
}
The !== false portion is not required. if readdir reaches the end, it returns a false, and the loop will automatically terminate. Your version is being parsed as:
$file gets the value of (readdir($file) is not false)
e.g. you're assigning the boolean result of readdir($file) !== false, not the return value from readdir.
to expand on my comment below, regarding operator precedence:
PHP's parse tree of your loop setup looks like this, expanded:
$bool = (readdir($dir) !== false);
$file = $bool;
To fix this, either remove the !== false portion entirely, or enforce your own precedence with extra brackets:
($file = readdir($dir)) !== false
Related
I have code that reads the images directory for a user (user 38 below) and returns an array of the file names, skipping the . and .. references.
// $dir = 38/images
$dirHandle = opendir($dir)$dirHandle = opendir($dir)
while (false !== ($fileName = readdir($dirHandle))) {
if ($fileName == "." || $fileName == "..")
continue;
-- Put file on array which gets returned to ajax load call at end --
}
This works fine but it seems to generate the access errors shown below:
Am I doing something fundamentally wrong?
Thanks
Unless you have an index.php file in your 38 and 38/images folders, you are issuing a get over a folder, over which you don't have permissions enough.
Check your script path, and your JS code in order to fix it.
I got to the bottom of this. It happens when a directory of images is being prefetched to the page:
while($fileName = readdir($dirHandle)) {
$filepath = $dir . $fileName;
echo ("<img class='galleryThumb' src='$filepath' >");
}
The trouble occurs when $fileName is "." or "..". The <img class='galleryThumb' src='$filepath' > echoed down with Ajax then has trouble evaluating a src attribute that's a directory rather than a file. I fixed it by adding a check for "." and ".." :
while($fileName = readdir($dirHandle)) {
if ($fileName == "." || $fileName == "..") {
continue;
}
$filepath = $dir . $fileName;
echo ("<img class='galleryThumb' src='$filepath' >");
}
Since you see 403 errors from network panel of javascript debugger, it is javascript, who is accesing these paths. The php code you posted has almost nothing to do with that.
I need to find a file in a directory that matches a certain condition. For example, I know the file name starts with '123-', and ends with .txt, but I have no idea what is in between the two.
I've started the code to get the files in a directory and the preg_match, but am stuck. How can this be updated to find the file I need?
$id = 123;
// create a handler for the directory
$handler = opendir(DOCUMENTS_DIRECTORY);
// open directory and walk through the filenames
while ($file = readdir($handler)) {
// if file isn't this directory or its parent, add it to the results
if ($file !== "." && $file !== "..") {
preg_match("/^".preg_quote($id, '/')."\\-(.+)\\.txt$/" , $file, $name);
// $name = the file I want
}
}
// tidy up: close the handler
closedir($handler);
I wrote up a little script here for ya, Cofey. Try this out for size.
I changed the directory for my own test, so be sure to set it back to your constant.
Directory Contents:
123-banana.txt
123-extra-bananas.tpl.php
123-wow_this_is_cool.txt
no-bananas.yml
Code:
<pre>
<?php
$id = 123;
$handler = opendir(__DIR__ . '\test');
while ($file = readdir($handler))
{
if ($file !== "." && $file !== "..")
{
preg_match("/^({$id}-.*.txt)/i" , $file, $name);
echo isset($name[0]) ? $name[0] . "\n\n" : '';
}
}
closedir($handler);
?>
</pre>
Result:
123-banana.txt
123-wow_this_is_cool.txt
preg_match saves its results to $name as an array, so we need to access by it's key of 0. I do so after first checking to make sure we got a match with isset().
You must test if the match was successful.
Your code inside the loop should be this:
if ($file !== "." && $file !== "..") {
if (preg_match("/^".preg_quote($id, '/')."\\-(.+)\\.txt$/" , $file, $name)) {
// $name[0] is the file name you want.
echo $name[0];
}
}
I have a directory with 1.3 Million files that I need to move into a database. I just need to grab a single filename from the directory WITHOUT scanning the whole directory. It does not matter which file I grab as I will delete it when I am done with it and then move on to the next. Is this possible? All the examples I can find seem to scan the whole directory listing into an array. I only need to grab one at a time for processing... not 1.3 Million every time.
This should do it:
<?php
$h = opendir('./'); //Open the current directory
while (false !== ($entry = readdir($h))) {
if($entry != '.' && $entry != '..') { //Skips over . and ..
echo $entry; //Do whatever you need to do with the file
break; //Exit the loop so no more files are read
}
}
?>
readdir
Returns the name of the next entry in the directory. The entries are returned in the order in which they are stored by the filesystem.
Just obtain the directories iterator and look for the first entry that is a file:
foreach(new DirectoryIterator('.') as $file)
{
if ($file->isFile()) {
echo $file, "\n";
break;
}
}
This also ensures that your code is executed on some other file-system behaviour than the one you expect.
See DirectoryIterator and SplFileInfo.
readdir will do the trick. Check the exampl on that page but instead of doing the readdir call in the loop, just do it once. You'll get the first file in the directory.
Note: you might get ".", "..", and other similar responses depending on the server, so you might want to at least loop until you get a valid file.
do you want return first directory OR first file? both? use this:
create function "pickfirst" with 2 argument (address and mode dir or file?)
function pickfirst($address,$file) { // $file=false >> pick first dir , $file=true >> pick first file
$h = opendir($address);
while (false !== ($entry = readdir($h))) {
if($entry != '.' && $entry != '..' && ( ($file==false && !is_file($address.$entry)) || ($file==true && is_file($address.$entry)) ) )
{ return $entry; break; }
} // end while
} // end function
if you want pick first directory in your address set $file to false and if you want pick first file in your address set $file to true.
good luck :)
So I'm going through reading and writing to files in PHP via PHP Docs and there's an example I didn't quite understand:
http://php.net/manual/en/function.readdir.php
if toward the end it shows an example like this:
<?php
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo "$entry\n";
}
}
closedir($handle);
}
?>
In what case would . or .. ever be read?
The readdir API call iterates over all of the directories. So assuming you loop over the current directory (denoted by ".") then you get into an endless loop. Also, iterating over the parent directory (denoted by "..") is avoided to restrict the list to the current directory and beneath.
Hope that helps.
If you want to read directories using PHP, I would recommend you use the scandir function. Below is a demonstration of scandir
$path = __DIR__.'/images';
$contents = scandir($path);
foreach($contents as $current){
if($current === '.' || $current === '..') continue ;
if(is_dir("$path/$current")){
echo 'I am a directory';
} elseif($path[0] == '.'){
echo "I am a file with a name starting with dot";
} else {
echo 'I am a file';
}
}
Because in a UNIX filesystem, . and .. are like signposts, as far as I know. Certainly to this PHP function, anyway.
Keep them in there, you'll get some weird results (like endless loops, etc.) otherwise!
In *nix . is the present working directory and .. is the directory parent. However any file or directory preceded by a '.' is considered hidden so I prefer something like the following:
...
if ($entry[0] !== '.') {
echo "$entry\n";
}
...
This ensures that you don't parse "up" the directory tree, that you don't endlessly loop the present directory, and that any hidden files/folders are ignored.
I'm coding a simple web report system for my company. I wrote a script for index.php that gets a list of files in the "reports" directory and creates a link to that report automatically. It works fine, but my problem here is that readdir( ) keeps returning the . and .. directory pointers in addition to the directory's contents. Is there any way to prevent this OTHER THAN looping through the returned array and stripping them manually?
Here is the relevant code for the curious:
//Open the "reports" directory
$reportDir = opendir('reports');
//Loop through each file
while (false !== ($report = readdir($reportDir)))
{
//Convert the filename to a proper title format
$reportTitle = str_replace(array('_', '.php'), array(' ', ''), $report);
$reportTitle = strtolower($reportTitle);
$reportTitle = ucwords($reportTitle);
//Output link
echo "$reportTitle<br />";
}
//Close the directory
closedir($reportDir);
In your above code, you could append as a first line in the while loop:
if ($report == '.' or $report == '..') continue;
array_diff(scandir($reportDir), array('.', '..'))
or even better:
foreach(glob($dir.'*.php') as $file) {
# do your thing
}
No, those files belong to a directory and readdir should thus return them. I’d consider every other behaviour to be broken.
Anyway, just skip them:
while (false !== ($report = readdir($reportDir)))
{
if (($report == ".") || ($report == ".."))
{
continue;
}
...
}
I would not know another way, as "." and ".." are proper directories as well. As you're looping anyway to form the proper report URL, you might just put in a little if that ignores . and .. for further processing.
EDIT
Paul Lammertsma was a bit faster than me. That's the solution you want ;-)
I wanted to check for the "." and the ".." directories as well as any files that might not be valid based on what I was storing in the directory so I used:
while (false !== ($report = readdir($reportDir)))
{
if (strlen($report) < 8) continue;
// do processing
}