Where does "." (dot) come from when using PHP ´scandir´ - php

I'm a bit confused.
I'm building a PHP function to loop out images in a specified dir.
PHP
$dir = "bilder/".$objekt[0]['objekt_nr']."/thumbnail/";
$thumbnails = scandir($dir);
print_r($thumbnails);
foreach ($thumbnails as $value) {
echo "<img src='".$dir.$value. "'>";
}
array
(
[0] => .
[1] => ..
[2] => bjornc.jpg
[3] => test_bild3.jpg
)
HTML
<img src='bilder/22159/thumbnail/.'>
<img src='bilder/22159/thumbnail/..'>
<img src='bilder/22159/thumbnail/bjornc.jpg'>
<img src='bilder/22159/thumbnail/test_bild3.jpg'>
How can i get rid of theese dots?
I guess it´s the directorie dots..
UPDATE
The most easy way was found in php.net manual
$thumbnails = array_diff(scandir($dir), array('..', '.'));

The dot directory is the current directory. Dot-dot is the parent directory.
If you want to create a list of files in a directory you should really skip those two, or really any directory starting with a leading dot (on POSIX systems like Linux and OSX those are supposed to be hidden directories).
You can do that by simply check if the first character in the file name is a dot, and if it is just skip it (i.e. you continue the loop).

You can skip it by using in_array as
foreach ($thumbnails as $value) {
if (!in_array($value, array(".", ".."))) {
echo "<img src='" . $dir . $value . "'>";
}
}

You can also use this
foreach ($thumbnails as $value) {
if ( $value !='.' && $value !='..')
{
echo "<img src='".$dir.$value. "'>";
}
}

If you are looking for a specific file type, such as images, you are better off using glob.
It allows you to pass a pattern of extensions.
This way you can be sure you fetch only the files you are looking for.
Example for multiple file types, .jpg and .png
$dir = "bilder/".$objekt[0]['objekt_nr']."/thumbnail/";
$files = glob("*.{jpg,png}", GLOB_BRACE);
print_r($files);
GLOB_BRACE - Expands {a,b,c} to match 'a', 'b', or 'c'
Example for a single file type, .jpg
$dir = "bilder/".$objekt[0]['objekt_nr']."/thumbnail/";
$files = glob("*.jpg");
print_r($files);

they are directory and parent directory, they can be removed with following code:
<?php
$dir = "downloads/";
if (is_dir($dir)){
if ($dir_handler = opendir($dir)){
while (($file = readdir($dir_handler)) !== false){
if ($file!="."&&$file!="..") {
//your code
}
}
closedir($dir_handler);
}
}
?>

#joachim Pileborg answer is correct, By the way you can also use glob()
$thumbnails = glob("$dir/*.jpg");
foreach ($thumbnails as $value) {
echo "<img src='$value'/>";
}

Related

PHP Create Image Gallery From Directory And Subdirectories

I'm trying to make an image gallery that scans a main directory and creates a separate album for each subdirectory.
My structure is similar to this:
-Gallery
--Subdir 1
---Image 1
---Image 2
--Subdir 2
---Image 1
---Image 2
The idea is that each album is going to be made of a div with a class of web-gallery. Then there will be a header for the album title made from the subdirectories name. After that a list is generated of each image. This is going to be a one page gallery. If possible I would like to have a variable that sets how many albums are listed that way if I have 30 subdirectories my page doesn't get too crowded.
So far I've written this but it doesn't work. I'm not getting any errors or logs though it just doesn't work.
$dirs = glob('img/gallery_temp/*', GLOB_ONLYDIR);
foreach($dirs as $val) {
echo '<div class="web-gallery">';
echo "<h3><span>»</span> ".basename($val). "</h3>";
echo '<ul class="web-gallery-list">';
$files = glob($val.'*.{jpg,png,gif}', GLOB_BRACE);
foreach($files as $file) {
echo "<li><a href='".$file."'><img src='" . $file . "' alt='description'></a></li> \r\n";
}
echo "</ul>";
echo "</div>";
}
Simply add a / before *.{jpg,png,gif} like this:
$files = glob($val.'/*.{jpg,png,gif}', GLOB_BRACE);
This is because $val doesn't have a final / for the directory.
You might consider using "readdir" instead of glob. Glob is to find pathnames matching a pattern, see here: http://php.net/manual/en/function.glob.php and is known to be a bit problematic.
Readdir, if your directory is entirely images might be easier to use: http://php.net/manual/en/function.readdir.php
Couple this with is_dir() http://php.net/manual/en/function.is-dir.php to resolve your directories vs files. Here is a snippet
<?php
if ($handle = opendir('/galleries')) {
while (false !== ($entry = readdir($handle))) {
// this is a subdirectory
if (is_dir($entry)) {
}
// this is a file
else {
echo $entry;
}
}
closedir($handle);
}
?>
If you make it a recursive function you could actually have it traverse a number of subdirectories creating galleries within galleries.
I also found this fantastic little snippet that is very elegant on another stack question: Get Images In Directory and Subdirectory With Glob
$rdi = new RecursiveDirectoryIterator("uploads/prevImgs/");
$it = new RecursiveIteratorIterator($rdi);
foreach($it as $oneThing)
if (is_file($oneThing))
echo '<img src="'.$oneThing.'" /><br />';
Using SPL Library (PHP >= 5)
Better solution in your case
is to use SPL library (the most cross-platform)
$directory = new RecursiveDirectoryIterator("./img/gallery_temp", FilesystemIterator::SKIP_DOTS);
// Flatten the recursive iterator, folders come before their files
$it = new RecursiveIteratorIterator($directory, RecursiveIteratorIterator::SELF_FIRST);
foreach($it as $fileinfo)
{
if($fileinfo->isDir())
{
// prevPath used to separate each directory listing and closing the bracket UL list
$prevPath = $it->getSubPath().DIRECTORY_SEPARATOR.$fileinfo->getFilename();
echo sprintf
(
"<div class='web-gallery'>
<h3><span>></span> %s</h3>
<ul>".PHP_EOL,
$fileinfo->getFilename()
);
}
if($fileinfo->isFile())
{
echo sprintf("<li><a href=''><img src='%s/%s' alt='description'></a></li>".PHP_EOL, $it->getSubPath(), $fileinfo->getFilename());
if($prevPath != $it->getSubPath())
echo("</ul>");
}
}
Note:
For more informations : SPL Documentation
DIRECTORY_SEPARATOR is a cross-platform constant, will use the
correct directory separator of the OS where are executed the code
FilesystemIterator::SKIP_DOTS, avoid to fetch the '.' and '..' dir
link level.
you can limit the depth of scanning with $it->setMaxDepth(5);

php - listing folders and files in a directory

hi there i am using the following function to list all the files and folders in a directory.
<?php
function listFolderFiles($dir){
$ffs = scandir($dir);
foreach($ffs as $ff){
echo $ff . "<br/>";
}
}
?>
but the problem seems to be i'm getting all the folders in the directory alright but i'm also getting a . and a ... something like the one below.
.
..
direc
img
music
New Text Document.txt
and i am using the following function like: listFolderFiles('MyFolder');
what i want to do is get all the folders and files but not the . and the .., what have i done wrong and how can i get what i want. thanks!
Easy way to get rid of the dots that scandir() picks up in Linux environments:
<?php
$ffs = array_diff(scandir($dir), array('..', '.'));
?>
You can use glob quite easily, which puts the filenames into an array:
print_r(glob("*.*"));
example:
// directory name
$directory = "/";
// get in directory
$files = glob($directory . "*");
$d = 0; // init dir array count
$f = 0; // init file array count
// directories and files
foreach($files as $file) {
if(is_dir($file)) {
array($l['directory'][$d] = $file);
$d++;
} else {
array($l['file'][$f] = $file);
$f++;
}
}
print_r($l);
NOTE: scandir will also pick up hidden files such as .htaccess, etc. That is why the glob method should be considered instead, unless of course you want to show them.
This should do it!
<?php
function listFolderFiles($dir){
$ffs = scandir($dir);
foreach($ffs as &$ff){
if ($ff != '.' && $ff != '..') {
echo $ff . "<br/>";
}
}
}
?>

Exclude hidden files from scandir

I am using the following code to get a list of images in a directory:
$files = scandir($imagepath);
but $files also includes hidden files. How can I exclude them?
On Unix, you can use preg_grep to filter out filenames that start with a dot:
$files = preg_grep('/^([^.])/', scandir($imagepath));
I tend to use DirectoryIterator for things like this which provides a simple method for ignoring dot files:
$path = '/your/path';
foreach (new DirectoryIterator($path) as $fileInfo) {
if($fileInfo->isDot()) continue;
$file = $path.$fileInfo->getFilename();
}
$files = array_diff(scandir($imagepath), array('..', '.'));
or
$files = array_slice(scandir($imagepath), 2);
might be faster than
$files = preg_grep('/^([^.])/', scandir($imagepath));
function nothidden($path) {
$files = scandir($path);
foreach($files as $file) {
if ($file[0] != '.') $nothidden[] = $file;
return $nothidden;
}
}
Simply use this function
$files = nothidden($imagepath);
I encountered a comment from php.net, specifically for Windows systems: http://php.net/manual/en/function.filetype.php#87161
Quoting here for archive purposes:
I use the CLI version of PHP on Windows Vista. Here's how to determine if a file is marked "hidden" by NTFS:
function is_hidden_file($fn) {
$attr = trim(exec('FOR %A IN ("'.$fn.'") DO #ECHO %~aA'));
if($attr[3] === 'h')
return true;
return false;
}
Changing if($attr[3] === 'h') to if($attr[4] === 's') will check for system files.
This should work on any Windows OS that provides DOS shell commands.
I reckon because you are trying to 'filter' out the hidden files, it makes more sense and looks best to do this...
$items = array_filter(scandir($directory), function ($item) {
return 0 !== strpos($item, '.');
});
I'd also not call the variable $files as it implies that it only contains files, but you could in fact get directories as well...in some instances :)
use preg_grep to exclude files name with special characters for e.g.
$dir = "images/";
$files = preg_grep('/^([^.])/', scandir($dir));
http://php.net/manual/en/function.preg-grep.php
Assuming the hidden files start with a . you can do something like this when outputting:
foreach($files as $file) {
if(strpos($file, '.') !== (int) 0) {
echo $file;
}
}
Now you check for every item if there is no . as the first character, and if not it echos you like you would do.
Use the following code if you like to reset the array index too and set the order:
$path = "the/path";
$files = array_values(
preg_grep(
'/^([^.])/',
scandir($path, SCANDIR_SORT_ASCENDING)
));
One line:
$path = "daten/kundenimporte/";
$files = array_values(preg_grep('/^([^.])/', scandir($path, SCANDIR_SORT_ASCENDING)));
scandir() is a built-in function, which by default select hidden file as well,
if your directory has only . & .. hidden files then try selecting files
$files = array_diff(scandir("path/of/dir"),array(".","..")) //can add other hidden file if don't want to consider
I am still leaving the checkmark for seengee's solution and I would have posted a comment below for a slight correction to his solution.
His solution masks the directories(. and ..) but does not mask hidden files like .htaccess
A minor tweak solves the problem:
foreach(new DirectoryIterator($curDir) as $fileInfo) {
//Check for something like .htaccess in addition to . and ..
$fileName = $fileInfo->getFileName();
if(strlen(strstr($fileName, '.', true)) < 1) continue;
echo "<h3>" . $fileName . "</h3>";
}

auto display filename in a directory and auto fill it as value

I want something (final) like this :
<?php
//named as config.php
$fn[0]["long"] = "file name"; $fn[0]["short"] = "file-name.txt";
$fn[1]["long"] = "file name 1"; $fn[1]["short"] = "file-name_1.txt";
?>
What that I want to?:
1. $fn[0], $fn[1], etc.., as auto increasing
2. "file-name.txt", "file-name_1.txt", etc.., as file name from a directory, i want it auto insert.
3. "file name", "file name 1", etc.., is auto split from "file-name.txt", "file-name_1.txt", etc..,
and config.php above needed in another file e.g.
<? //named as form.php
include "config.php";
for($tint = 0;isset($text_index[$tint]);$tint++)
{
if($allok === TRUE && $tint === $index) echo("<option VALUE=\"" . $text_index[$tint]["short"] . "\" SELECTED>" . $text_index[$tint]["long"] . "</option>\n");
else echo("<option VALUE=\"" . $text_index[$tint]["short"] . "\">" . $text_index[$tint]["long"] . "</option>\n");
} ?>
so i try to search and put php code and hope it can handling at all :
e.g.
<?php
$path = ".";
$dh = opendir($path);
//$i=0;
$i= 1;
while (($file = readdir($dh)) !== false) {
if($file != "." && $file != "..") {
echo "\$fn[$i]['short'] = '$file'; $fn[$i]['long'] = '$file(splited)';<br />"; // Test
$i++;
}
}
closedir($dh);
?>
but i'm wrong, the output is not similar to what i want, e.g.
$fn[0]['short'] = 'file-name.txt'; ['long'] = 'file-name.txt'; //<--not splitted
$fn[1]['short'] = 'file-name_1.txt'; ['long'] = 'file-name_1.txt'; //<--not splitted
because i am little known with php so i don't know how to improve code more, there are any good tips of you guys could help me, Please
New answer after OP edited his question
From your edited question, I understand you want to dynamically populate a SelectBox element on an HTML webpage with the files found in a certain directory for option value. The values are supposed to be split by dash, underscore and number to provide the option name, e.g.
Directory with Files > SelectBox Options
filename1.txt > value: filename1.txt, text: Filename 1
file_name2.txt > value: filename1.txt, text: File Name 2
file-name3.txt > value: filename1.txt, text: File Name 3
Based from the code I gave in my other answer, you could achieve this with the DirectoryIterator like this:
$config = array();
$dir = new DirectoryIterator('.');
foreach($dir as $item) {
if($item->isFile()) {
$fileName = $item->getFilename();
// turn dashes and underscores to spaces
$longFileName = str_replace(array('-', '_'), ' ', $fileName);
// prefix numbers with space
$longFileName = preg_replace('/(\d+)/', ' $1', $fileName);
// add to array
$config[] = array('short' => $filename,
'long' => $longFilename);
}
}
However, since filenames in a directory are unique, you could also use this as an array:
$config[$filename] => $longFilename;
when building the config array. The short filename will form the key of the array then and then you can build your selectbox like this:
foreach($config as $short => $long)
{
printf( '<option value="%s">%s</option>' , $short, $long);
}
Alternatively, use the Iterator to just create an array of filenames and do the conversion to long file names when creating the Selectbox options, e.g. in the foreach loop above. In fact, you could build the entire SelectBox right from the iterator instead of building the array first, e.g.
$dir = new DirectoryIterator('.');
foreach($dir as $item) {
if($item->isFile()) {
$fileName = $item->getFilename();
$longFileName = str_replace(array('-', '_'), ' ', $fileName);
$longFileName = preg_replace('/(\d+)/', ' $1', $fileName);
printf( '<option value="%s">%s</option>' , $fileName, $longFileName);
}
}
Hope that's what your're looking for. I strongly suggest having a look at the chapter titled Language Reference in the PHP Manual if you got no or very little experience with PHP so far. There is also a free online book at http://www.tuxradar.com/practicalphp
Use this as the if condition to avoid the '..' from appearing in the result.
if($file != "." && $file != "..")
Change
if($file != "." ) {
to
if($file != "." and $file !== "..") {
and you get the behaviour you want.
If you read all the files from a linux environment you always get . and .. as files, which represent the current directory (.) and the parent directory (..). In your code you only ignore '.', while you also want to ignore '..'.
Edit:
If you want to print out what you wrote change the code in the inner loop to this:
if($file != "." ) {
echo "\$fn[\$i]['long'] = '$file'<br />"; // Test
$i++;
}
If you want to fill an array called $fn:
if($file != "." ) {
$fn[]['long'] = $file;
}
(You can remove the $i, because php auto increments arrays). Make sure you initialize $fn before the while loop:
$fn = array();
Have a look at the following functions:
glob — Find pathnames matching a pattern
scandir — List files and directories inside the specified path
DirectoryIterator — provides a simple interface for viewing the contents of filesystem directories
So, with the DirectoryIterator you simply would do:
$dir = new DirectoryIterator('.');
foreach($dir as $item) {
if($item->isFile()) {
echo $file;
}
}
Notice how every $item in $dir is an SplFileInfo instance and provides access to a number of useful other functions, e.g. isFile().
Doing a recursive directory traversal is equally easy. Just use a RecursiveDirectoryIterator with a RecursiveIteratorIterator and do:
$dir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator('.'));
foreach($dir as $item) {
echo $file;
}
NOTE I am afraid I do not understand what the following line from your question is supposed to mean:
echo "$fn[$i]['long'] = '$file'<br />"; // Test
But with the functions and example code given above, you should be able to do everything you ever wanted to do with files inside directories.
I've had the same thing happen. I've just used array_shift() to trim off the top of the array
check out the documentation. http://ca.php.net/manual/en/function.array-shift.php

PHP (folder) File Listing in Alphabetical Order?

I'm not sure how simple this would be, but I'm using a script which displays the files from a specific folder, however I'd like them to be displayed in alphabetical order, would it be hard to do this? Here's the code I'm using:
if ($handle = opendir($mainframe->getCfg( 'absolute_path' ) ."/images/store/")) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if (($file != "index.html")&&($file != "index.php")&&($file != "Thumbs.db")) {
$strExt = end(explode(".", $file));
if ($strExt == 'jpg') {
$Link = 'index.php?option=com_shop&task=deleteFile&file[]='.$file;
$thelist .= '<tr class="row0"><td nowrap="nowrap">'.$file.'</td>'."\n";
$thelist .= '<td align="center" class="order"><img src="/administrator/images/publish_x.png" width="16" height="16" alt="delete"></td></tr>'."\n";
}
}
}
}
closedir($handle);
}
echo $thelist;
:)
Instead of using readdir you could simply use scandir (documentation) which sorts alphabetically by default.
The return value of scandir is an array instead of a string, so your code would have to be adjusted slightly, to iterate over the array instead of checking for the final null return value. Also, scandir takes a string with the directory path instead of a file handle as input, the new version would look something like this:
foreach(scandir($mainframe->getCfg( 'absolute_path' ) ."/images/store/") as $file) {
// rest of the loop could remain unchanged
}
That code looks pretty messy. You can separate the directory traversing logic with the presentation. A much more concise version (in my opinion):
<?php
// Head of page
$it = new DirectoryIterator($mainframe->getCfg('absolute_path') . '/images/store/'));
foreach ($it as $file) {
if (preg_match('#\.jpe?g$#', $file->getFilename()))
$files[] = $file->getFilename();
}
sort($files);
// Further down
foreach ($files as $file)
// display links to delete file.
?>
You don't even need to worry about opening or closing the handle, and since you're checking the filename with a regular expression, you don't need any of the explode or conditional checks.
I like Glob
It makes directory reading a snap as it returns an array that's easily sortable:
<?php
$files = glob("*.txt");
sort($files);
foreach ($files as $filename) {
echo "$filename size " . filesize($filename) . "\n";
}
?>
If you're using Joomla1.5 you should be using the defined constant JPATH_BASE instead of
$mainframe->getCfg( 'absolute_path' )
If this is a Joomla extension that you will distribute, don't use scandir() as it is PHP5 only.
The best thing to do is to use the Joomla API. It has a classes for directory and file access that is layered to do this over different networks and protocols. So the file system can be over FTP for example, and the classes can be extended for any network/protocol.
jimport( 'joomla.filesystem.folder' );
$files = JFolder::files(JPATH_BASE."/images/store/");
sort($files);
foreach($files as $file) {
// do your filtering and other task
}
You can also pass a regular expression as the second parameter to JFolder::files() that filters the files you receive.
You also don't want to use URL literals like /administrator/ since they can be changed.
use the JURI methods like:
JURI::base();
If you want to make sure of the Joomla CSS classes in the tables, for:
'<tr class="row0">'
use:
'<tr class="row'.($i&1).'">'
where $i is the number of iterations. This gives you a sequence of alternating 0s and 1s.
if we have PHP built in functions, always use it, they are faster.
use glob instead of traversing folders, if it fits for your needs.
$folder_names = array();
$folder_names = glob( '*', GLOB_ONLYDIR + GLOB_MARK + GLOB_NOSORT );
returs everything in the current directory, use chdir() before calling it
remove the GLOB_ONLYDIR to include files too ( . would be only files )
GLOB_MARK is for adding a slash to folders names
Remove GLOB_NOSORT not to sort the array

Categories