hi I'm writing a script to loop through the current directory and list all sub directories
all is working fine but i can't get it to exclude folders starting with an _
<?php
$dir = __dir__;
// Open a known directory, and proceed to read its contents
if (is_dir($dir)) {
if ($dh = opendir($dir)) {
echo("<ul>");
while (($file = readdir($dh)) !== false) {
if ($file == '.' || $file == '..' || $file == '^[_]*$' ) continue;
if (is_dir($file)) {
echo "<li> <a href='$file'>$file</a></li>";
}
}
closedir($dh);
}
}
?>
you can use substr[docs] like :
|| substr($file, 0, 1) === '_'
No need for a regex, use $file[0] == '_' or substr($file, 0, 1) == '_'
If you do want a regex, you need to use preg_match() to check: preg_match('/^_/', $file)
Or, if you would like to use regexp, you should use regex functions, like preg_match: preg_match('/^_/', $file); but as said by ThiefMaster, in this case a $file[0] == '_' suffices.
A more elegant solution is to use SPL. The GlobIterator can help you out. Each item is an instance of SplFileInfo.
<?php
$dir = __DIR__ . '/[^_]*';
$iterator = new GlobIterator($dir, FilesystemIterator::SKIP_DOTS);
if (0 < $iterator->count()) {
echo "<ul>\n";
foreach ($iterator as $item) {
if ($item->isDir()) {
echo sprintf("<li>%s</li>\n", $item);
}
}
echo "</ul>\n";
}
Related
Having some issues regarding the scandir() function in PHP.
When trying to echo a list of files in the current directory, it echoes . and .. as directories. I've attempted to filter these out like so:
<?php
$dir = "pages";
if ($d = scandir($dir)) {
foreach ($d as $value) {
echo("<script>console.log(\"$value\")</script>");
if ($value !== '.' || $value !== '..') {
echo("<p>$value</p>");
} else {
echo("");
}
}
}
I feel like it's something obvious that I'm missing.
Has anyone got any ideas?
-R
As per documentation, scandir() returns an array of files and directories from the target directory. So you could use array_diff, which in the end would return an array containing all the entries from the first array that are not present in the second array:
array_diff(scandir($directory), ['..', '.']);
Or if you're too lazy for that, you could actually array_shift the first two elements:
$dir = "pages";
if($d = scandir($dir)) {
array_shift($d);
array_shift($d);
...
}
I like doing this:
$dir = "pages";
if($d = scandir($dir)) {
foreach($d as $file){
if(substr($file,0,1) == '.') continue;
echo "$file\n";
}
}
This way it skips all $file starting with . such as .htaccess etc.
But I have a lot of stuff like this in my projects:
.
..
.buildpath
.git
.gitignore
.htaccess
.project
.settings
I would use is_file(). It will also avoid directories.
$dir = "pages";
if ($d = scandir($dir)) {
foreach ($d as $value) {
echo("<script>console.log(\"$value\")</script>");
if (is_file($value)) {
echo("<p>$value</p>");
} else {
echo("");
}
}
}
Just continue your loop when your find . or ..
Simply add this in first line of foreach block:
if($value == '.' || $value == '..') continue;
# your rest of codes
OR
if(in_array($value, array(".",".."))) continue;
# your rest of codes
in your code:
if ($value !== '.' || $value !== '..') {
when $value equals "." then it certainly doesn't equal ".." at the same time, so one side of the "||" will be true for ".", the other for ".." and the overall result will be true.
you need either:
if ($value !== '.' && $value !== '..') {
or
if ($value == '.' || $value == '..') continue;
I use this php code to retrieve the files stored in a directory .
if ($handle = opendir('FolderPath')) {
while (false !== ($entry = readdir($handle))) {
if ($entry != "." && $entry != "..") {
echo "$entry\n <br />" ;
}
}
closedir($handle);
}
This Directory only holds PHP files , how would i be able to remove the extension from the echoed results? example: ( index.php would become index )
The easiest way to do this is by using the glob function:
foreach (glob('path/to/files/*.php') as $fileName) {
//extension .php is guaranteed here
echo substr($fileName, 0, -4), PHP_EOL;
}
The advantages of glob here is that you can do away with those pesky readdir and opendir calls. The only slight "disatvantage" is that the value of $fileName will contain the path, too. However, that's an easy fix (just add one line):
foreach (glob('path/to/files/*.php') as $fullName) {
$fileName = explode('/', $fullName);
echo substr(
end($fileName),//the last value in the array is the file name
0, -4),
PHP_EOL;
}
This should work for you:
echo basename($entry, ".php") . "\n <br />" ;
A quick way to do this is
<?php
if ($handle = opendir('FolderPath')) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
$info = pathinfo($file);
$file_name = basename($file,'.'.$info['extension']);
echo $file_name;
}
}
closedir($handle);
?>
$files = glob('path/to/files/*.*');
foreach($files as $file) {
if (! is_dir($file)) {
$file = pathinfo($file);
echo "<br/>".$file['filename'];
}
}
Use pathinfo()
$entry = substr($entry, 0, strlen($entry) - 4);
Note that this is a simple and quick solution which works perfect if you are 100% sure that your extension is in the form of *.xxx. However if you need a more flexible and safer solution regarding possible different extension lenghts, than this solution is not recommended.
Elegant solution would be to use $suffix attribute of DirectoryIterator::getBasename() method. When provided, $suffix will be removed on each call. For known extension, you can use:
foreach (new DirectoryIterator('/full/dir/path') as $file) {
if ($file->isFile()) {
print $file->getBasename('.php') . "\n";
}
}
or this, as an universal solution:
foreach (new DirectoryIterator('/full/dir/path') as $file) {
if ($file->isFile()) {
print $file->getBasename($file->getExtension() ? '.' . $file->getExtension() : null) . "\n";
}
}
PHP docs: http://php.net/manual/en/directoryiterator.getbasename.php
I have a bit of PHP used to pulled a list of files from my image directory - it's used in a form to select where an uploaded image will be saved. Below is the code:
$files = array_map("htmlspecialchars", scandir("../images"));
foreach ($files as $file) {
$filelist .= sprintf('<option value="%s">%s</option>' . PHP_EOL, $file, $file );
}
It works fine but shows all files and folders in 'images', does someone know a way to modify this code so that it only shows folder names found in the 'images' folder, not any other files.
Thanks
The easiest and quickest will be glob with GLOB_ONLYDIR flag:
foreach(glob('../images/*', GLOB_ONLYDIR) as $dir) {
$dirname = basename($dir);
}
Function is_dir() is the solution :
foreach ($files as $file) {
if(is_dir($file) and $file != "." && $file != "..") $filelist .= sprintf('<option value="%s">%s</option>' . PHP_EOL, $file, $file );
}
The is_dir() function requires an absolute path to the item that it is checking.
$base_dir = get_home_path() . '/downloads';
//get_home_path() is a wordpress function
$sub_dirs = array();
$dir_to_check = scandir($dir);
foreach ($dir_to_check as $item){
if ($item != '..' && $item != '.' && is_dir($base_dir . "/" . $item)){
array_push($sub_dirs, $item);
}
}
You could just use your array_map function combined with glob
$folders = array_map(function($dir) {
return basename($dir);
}, glob('../images/*', GLOB_ONLYDIR));
Yes, I copied a part of it of dev-null-dweller, but I find my solution a bit more re-useable.
I try this
<?php
$dir = "../";
$a = array_map("htmlspecialchars", scandir($dir));
$no = 0; foreach ($a as $file) {
if ( strpos($file, ".") == null && $file !== "." && $file !== ".." ) {
$filelist[$no] = $file; $no ++;
}
}
print_r($filelist);
?>
How to count the number of files in a directory using PHP?
Please answer for the following things:
1. Recursive Search: The directory (which is being searched) might be having several other directories and files.
2. Non-Recursive Search: All the directories should be ignored which are inside the directory that is being searched. Only files to be considered.
I am having the following code, but looking for a better solution.
<?php
$files = array();
$dir = opendir('./items/2/l');
while(($file = readdir($dir)) !== false)
{
if($file !== '.' && $file !== '..' && !is_dir($file))
{
$files[] = $file;
}
}
closedir($dir);
//sort($files);
$nooffiles = count($files);
?>
Recursive:
$it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));
$count = 0;
while($it->next()) $count++;
Most of the mentioned ways for "Non-Recursive Search" work, though it can be shortened using PHP's glob filesystem function.
It basically finds pathnames matching a pattern and thus can be used as:
$count = 0;
foreach (glob('path\to\dir\*.*') as $file) {
$count++;
}
The asterisk before the dot denotes the filename, and the one after denotes the file extension. Thus, its use can further be extended to counting files with specific filenames, specific extensions or both.
non-recrusive:
$dir = opendir('dir/');
$i = 0;
while (false !== ($file = readdir($dir))){
if (!in_array($file, array('.', '..') and !is_dir($file)) $i++;
}
echo "There were $i files";
recrusive:
function crawl($dir){
$dir = opendir($dir);
$i = 0;
while (false !== ($file = readdir($dir)){
if (is_dir($file) and !in_array($file, array('.', '..'))){
$i += crawl($file);
}else{
$i++;
}
}
return $i;
}
$i = crawl('dir/');
echo "There were $i files";
Might be useful for you:
http://www.php.net/manual/en/class.dir.php
http://www.php.net/manual/en/function.is-file.php
But, i think, there is no other good solutions.
Rather than posting code for you, I would provide the outline of what you should do as you seem to have the basic code already.
Place your code in a function. Have two parameters ($path, $recursive = FALSE) and within your code, separate the is_dir() and if that's true and the recursive flag is true, then pass the new path (path to the current file) back to the function (self reference).
Hope this helps you learn, rather than copy paste :-)
Something like this might work:
(might need to add some checks for '/' for the $dir.$file concatenation)
$files = array();
$dir = './items/2/l';
countFiles($dir, $files); // Recursive
countFiles($dir, $files, false); // Not recursive;
var_dump(count($files));
function countFiles($directory, &$fileArray, $recursive = true){
$currDir = opendir($directory);
while(($file = readdir($dir)) !== false)
{
if(is_dir($file) && $recursive){
countFiles($directory.$fileArray, $saveArray);
}
else if($file !== '.' && $file !== '..' && !is_dir($file))
{
$fileArray[] = $file;
}
}
}
Recursive:
function count_files($path) {
// (Ensure that the path contains an ending slash)
$file_count = 0;
$dir_handle = opendir($path);
if (!$dir_handle) return -1;
while ($file = readdir($dir_handle)) {
if ($file == '.' || $file == '..') continue;
if (is_dir($path . $file)){
$file_count += count_files($path . $file . DIRECTORY_SEPARATOR);
}
else {
$file_count++; // increase file count
}
}
closedir($dir_handle);
return $file_count;
}
Non-Recursive:
$directory = ".. path/";
if (glob($directory . "*.") != false)
{
$filecount = count(glob($directory . "*."));
echo $filecount;
}
else
{
echo 0;
}
Courtesy of Russell Dias
You can use the SPL DirectoryIterator to do this in a non-recursive (or with a recursive iterator in a recursive) fashion:
iterator_count(new DirectoryIterator($directory));
It's good to note that this will not just count regular files, but also directories, dot files and symbolic links. For regular files only, you can use:
$directory = new DirectoryIterator($directory);
$count = 0;
foreach($directory as $file ){ $count += ($file->isFile()) ? 1 : 0;}
PHP 5.4.0 also offers:
iterator_count(new CallbackFilterIterator($directory, function($current) { return $current->isFile(); }));
$dir = opendir('dir/');
$i = 0;
while (false !== ($file = readdir($dir))){
if (!in_array($file, array('.', '..' ))and (!is_dir($file)))
$i++;
}
echo "There were $i files";
I created a script that list the directories in the current directory
<?php
$dir = getcwd();
if($handle = opendir($dir)){
while($file = readdir($handle)){
if(is_dir($file)){
echo "$file<br />";
}
}
?>
but the problem is, I am seeing this ".." and "." right above the directory listings, when someone clicks it, they get redirected one level up the directories.. can someone tell me how to remove those ".." and "." ?
If you use opendir/readdir/closedir functions, you have to check manually:
<?php
if ($handle = opendir($dir)) {
while ($file = readdir($handle)) {
if ($file === '.' || $file === '..' || !is_dir($file)) continue;
echo "$file<br />";
}
}
?>
If you want to use DirectoryIterator, there is isDot() method:
<?php
$iterator = new DirectoryIterator($dir);
foreach ($iterator as $fileInfo) {
if ($fileInfo->isDot() || !$fileInfo->isDir()) continue;
$file = $fileinfo->getFilename();
echo "$file<br />";
}
?>
Note: I think that continue can simplify this kind of loops by reducing indentation level.
Or use glob:
foreach(glob('/path/*.*') as $file) {
printf('%s<br/>', $file, $file);
}
If your files don't follow the filename dot extension pattern, use
array_filter(glob('/path/*'), 'is_file')
to get an array of (non-hidden) filenames only.
Skips all hidden and "dot directories":
while($file = readdir($handle)){
if (substr($file, 0, 1) == '.') {
continue;
}
Skips dot directories:
while($file = readdir($handle)){
if ($file == '.' || $file == '..') {
continue;
}
<?php
if($handle = opendir($dir)){
while($file = readdir($handle)){
if(is_dir($file) && $file !== '.' && $file !== '..'){
echo "$file<br />";
}
}
}
?>