So. I'm trying to make a simple PHP program that will read the contents of a directory. I've been working off W3Schools. And it's been working well, except for one small problem.
When this script runs, it posts two additional filen that don't exist - even if the directory is completely empty .
<?php
$dir = "./userphotos/";
// Open a directory, and read its contents
if (is_dir($dir)){
if ($dh = opendir($dir)){
while (($file = readdir($dh)) !== false){
print <<< HERE
<p>Filename: $file</p>
HERE;
}
closedir($dh);
}
}
?>
Any thoughts?
On Unix machines, each directory contains 2 hidden files.
. and .. these are references to the current and parent directories.
You should look into DirectoryInterator class
$dir = "./userphotos/";
foreach (new DirectoryIterator($dir) as $fileInfo) {
if($fileInfo->isDot() === false) {
echo $fileInfo->getFilename() . "<br>\n";
}
}
This example ignores the "dot" files
Also, you can look into RecursiveDirectoryIterator to do this recursively.
Related
i got a function which gets all subfolders from a specific directory and display subfolders in html output with php.It is working so far but now i have two entrys from the folder above which is diplayed as . and the second entry as .. how i have to modify my script?
<?php
$dir = "pictures/whatsapp/";
// Open a known directory, and proceed to read its contents
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
while (($file = readdir($dh)) !== false) {
// Where to filter or delete the two entrys from folder . and .. ???
echo '<i class="ion-social-whatsapp-outline"></i>'.ucwords(str_replace("-"," ", $file)).'<i class="ion-record"></i>';
}
closedir($dh);
}
}
?>
simply add to loop following line to skip om . and ..
if ($file == "." or $file == "..") continue;
I want to read html file name from directory without any database. I have a code and its working properly, but two blank name it is giving, while I have only 4 file in directory.
<?php
if (is_dir('dir')) {
if ($dh = opendir('dir')) {
while (($file = readdir($dh)) !== false) {
echo "filename:".$file."<br />";
}
}
}?>
I have 4 html file and output should be:
filename:aaaaaa kjnnk_13.html
filename:aaaaaa kjnnk_2.html
filename:aaaaaa kjnnk_6.html
filename:aaaaaa kjnnk_9.html
But I found 2 extra filename:
filename:.
filename:..
filename:aaaaaa kjnnk_13.html
filename:aaaaaa kjnnk_2.html
filename:aaaaaa kjnnk_6.html
filename:aaaaaa kjnnk_9.html
Please help
. is for current dir
.. is for one directory up
When using readdir you will get those 2 extra.
I prefer using glob(). That function lets you filter for html files only too
<?php
$files = glob('dir/*html');
foreach($files as $file) {
echo "filename:".$file."<br />";
}
?>
Alternatively you could use FilesystemIterator which would skip the dot files by default:
$it = new FilesystemIterator('dir');
foreach ($it as $fileinfo) {
echo $fileinfo->getFilename() . "<br/>";
}
more answers in stackoverflow:
What exactly are the benefits of using a PHP 5 DirectoryIterator over PHP 4 "opendir/readdir/closedir"?
PHP: scandir() is too slow
Difference between DirectoryIterator and FileSystemIterator
I have created a directory with some files in there:
index.php
one.txt
two.txt
three.txt
four.txt
In the index.php page, I am currently using this code to echo out all of the files within the directory:
<?php
$blacklist = array("index.php");
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && !in_array($entry, $blacklist)) {
echo "$entry\n";
}
}
closedir($handle);
}
?>
Now, if anyone views the index.php page, this is what they'll see:
one.txt two.txt three.txt four.txt
As you can see from the PHP code, index.php is blacklisted so it is not echoed out.
However, I would like to go a step further than this and echo out the contents of each text file rather than the filenames. With the new PHP code (that I need help with creating), whenever someone visits the index.php page, this is what they'll now see:
(Please ignore what is in the asterisks, they are not a part of the code, they just indicate what each text file contains)
Hello ** this is what the file **one.txt** contains **
ok ** this is what the file **two.txt** contains **
goodbye ** this is what the file **three.txt** contains **
text ** this is what the file **four.txt** contains **
Overall:
I would like to echo out the contents of every file in the directory (they are all text files) aside from index.php.
You could use file_get_contents to put the file into a string.
<?php
$blacklist = array("index.php");
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && !in_array($entry, $blacklist)) {
echo "$entry " . file_get_contents($entry) . "\n";
}
}
closedir($handle);
}
?>
Furthermore, you could use PHP's glob function to filter only the .txt files out, that way you do not have to blacklist files if you're going to be adding more files to that directory that need ignored.
Here is how it would be done using the glob function.
<?php
foreach (glob("*.txt") as $filename) {
echo "$filename " . file_get_contents($filename) . "\n";
}
?>
This would print the contents of the files. You can do some workaround if the path is not the current path and writing some kind of boundary between the files contents.
<?php
$blacklist = array("index.php");
if ($handle = opendir('.')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != ".." && !in_array($entry, $blacklist)) {
echo file_get_contents($entry) . "\n";
}
}
closedir($handle);
}
?>
I hope this helps you.
Never reinvent the wheel. Use composer.
Require symfony/finder
use Symfony\Component\Finder\Finder;
class Foo
{
public function getTextFileContents($dir)
{
$finder = (new Finder())->files()->name('*.txt');
foreach ($finder->in($dir) as $file) {
$contents = $file->getContents();
// do something while file contents...
}
}
}
I would give a chance to some SPL filesystem iterators to accomplish such this task:
$dir = '/home/mydirectory';
$rdi = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
$rdi = new \RegexIterator($rdi, '/\.txt$/i');
$iterator = new \RecursiveIteratorIterator($rdi, \RecursiveIteratorIterator::CHILD_FIRST);
foreach ($iterator as $file) {
echo 'Contents of the '.$file->getPathname().' is: ';
echo file_get_contents($file->getPathname());
}
This will recursively find & iterate all .txt files in given directory, including sub-directories.
Since each $file in iteration is a FilesystemIterator instance, you can use all related methods for additional controls like $file->isLink() (true for symbolic links), $file->isReadable() (false for unreadable files) etc..
If you don't want lookup sub-folders, just change the RecursiveDirectoryIterator in the second line from:
$rdi = new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
to:
$rdi = new \DirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS);
Hope it helps.
As #brock-b said, you could use glob to get the full list of files and file_get_contents to grab the contents:
$blacklist = array('index.php');
$files = glob('*.txt'); # could be *.* if needed
foreach ($files as $file) {
if (!in_array(basename($file), $blacklist)) {
echo file_get_contents($file);
}
}
Note: the blacklist wont be hit since you're seeking for *.txt files. Only useful when doing an *.* or *.php file search
I'm trying to write some PHP that runs through a folder grabbing each sub directory name and assigning it to a variable. Then, open a URL with that variable.
For example, D:Folder contains a number of sub folders named 1-??.
The PHP would first open www.url.com/run_batch.php?q=1 and sleep for 30 seconds, then www.url.com/run_batch.php?q=2, etc... for each sub directory in the main directory.
I'm currently in the process of trying to write this. I don't have much code yet, but thought one of you geniuses could help me speed up this process.
UPDATED
Ok, here is what I have so far, it runs without any errors, but it appears to be running all of them at once without sleeping? Not sure, the page just stays busy.
<?php
if ($handle = opendir('D:\HTTP\pic\')) {
$blacklist = array('.', '..', 'bu');
while (false !== ($file = readdir($handle))) {
if (!in_array($file, $blacklist)) {
echo "<iframe width='800' height='600' src='http://www.url.com/run_batch.php?q=" . "$file" . "'></iframe>";
sleep(100);
}
}
closedir($handle);
}
?>
When you make a sleep in PHP code, the HTML is not sent to the browser, that is why it looks busy.
You have to call flush() on each pass.
<?php
if ($handle = opendir('D:\HTTP\pic\')) {
$blacklist = array('.', '..', 'bu');
while (false !== ($file = readdir($handle))) {
if (!in_array($file, $blacklist)) {
echo "<iframe width='800' height='600' src='http://www.url.com/run_batch.php?q=" . "$file" . "'></iframe>";
//Send content to browser
flush();
sleep(100);
}
}
closedir($handle);
}
?>
I suggest you start with pseudo code; create comments for the steps. From there, look at PHP.net for help with specific tasks. When you have something workable but buggy, paste your code.
Pseudocode:
// get directory list
// loop through directories
// ...
// redirect to next page
I have the following which is fairly slow. How can I speed it up?
(it scans a directory and makes headers out of the foldernames and retrieves the pdf files from within and adds them to lists)
$directories= array_diff(scandir("../pdfArchive/subfolder", 0), array('..', '.'));
foreach ($directories as $v) {
echo "<h3>".$v."</h3>";
$current = array_diff(scandir("../pdfArchive/subfolder/".$v, 0), array('..', '.'));
echo "<ul style=\"list-style-image: url(/images/pdf.gif); margin-left: 20px;\">";
foreach ($current as $vone) {
echo "<li><a target=\"blank\" href=\"../pdfArchive/subfolder/".$vone."\">".str_replace(".pdf", "", $vone)."</a>";
echo "</li><br>";
}
echo "</ul>";
}
Don't use array_diff() to filter out current and parent directory, use something like DirectoryIterator or glob() and then test whether it's . or .. via an if statement
glob() has a flag that allows you to retrieve only directories for your loops
Profile your code to see exactly what lines/functions are executing slowly
I'm not sure how fast array_diff() is when the array is very large, isn't it faster to simply add a separate check and make sure that '.' and '..' is not the returned name?
Other than that, I can't see there being anything really wrong.
What did you test to consider the current approach slow?
Here is a snippet of code I use that I adapted from php.net. It is very basic and goes through a given directory and lists the files contained within.
// The # suppresses any errors, $dir is the directory path
if (($handle = #opendir($dir)) != FALSE) {
// Loop over directory contents
while (($file = readdir($handle)) !== FALSE) {
// We don't want the current directory (.) or parent (..)
if ($file != "." && $file != "..") {
var_dump($file);
if (!is_dir($dir . $file)) {
// $file is really a file
} else {
// $file is a directory
}
}
}
closedir($handle);
} else {
// Deal with it
}
You may adapt this further to recurse over subdirectories by using is_dir to identify folders as I have shown above.