Using scandir() to find folders in a directory (PHP) - php

I am using this peice of code:
$target = 'extracted/' . $name[0];
$scan = scandir($target);
To scan the directory of a folder which is used for zip uploads. I want to be able to find all the folders inside my $target folder so I can delete them and their contents, leaving only the files in the $target directory.
Once I have returned the contents of the folder, I don't know how to differentiate between the folders and the files to be able to delete the folders.
Also, I have been told that the rmdir() function can't delete folders which have content inside them, is there any way around this?
Thanks, Ben.

To determine whether or not you have a folder or file use the functions is_dir() and is_file()
For example:
$path = 'extracted/' . $name[0];
$results = scandir($path);
foreach ($results as $result) {
if ($result === '.' or $result === '..') continue;
if (is_dir($path . '/' . $result)) {
//code to use if directory
}
}

Better to use DirectoryIterator
$path = 'extracted'; // '.' for current
foreach (new DirectoryIterator($path) as $file) {
if ($file->isDot()) continue;
if ($file->isDir()) {
print $file->getFilename() . '<br />';
}
}

First off, rmdir() cannot delete a folder with contents. If safe mode is disabled you can use the following.
exec("rm -rf folder/");
Also look at is_dir()/is_file() or even better the PHP SPL.

$directories = scandir('images');
foreach($directories as $directory){
if($directory=='.' or $directory=='..' ){
echo 'dot';
}else{
if(is_dir($directory)){
echo $directory .'<br />';
}
}
}
a simpler and perhaps faster version

scandir will scan the entire directory, you can manually filter.
but if you are lazy like I am, then use glob
$scan = glob($target."/*",GLOB_ONLYDIR);
and it will output an array of all your directories of your target.

To get all the files in all the sub, sub folders
function myfunction($dir){
foreach ($dir as $dirname => $file) {
if(is_dir($file) && $file != '.' && $file != '..' ) {
// echo $file;
$newDir = scandir($file);
myfunction($newDir);
}elseif($file !='.' && $file != '..'){
echo "<br>File name is ---";
echo $file;
}
} // end foreach
} //function ends
$dirpass = scandir($mypath3); // set directory
echo myfunction($dirpass); // pass directory
We will get the result like below (plz ignore file names )
File name is ----->index.PHP
File name is -----> 100000045 Invoices Sales Magento Admin.png
File name is -----> 100000142 Orders Sales Magento Admin(1).png
File name is -----> 100000142 Orders Sales Magento Admin.png
File name is ----->hrc-siberian-tiger-2-jpg_21253111.jpg
File name is ----->images (3rd copy).jpeg
File name is ----->images (4th copy).jpeg
File name is ----->images (5th copy).jpeg
File name is ----->images (another copy).jpeg
File name is ----->images (copy).jpeg
File name is ----->images.jpeg
File name is ----->JPEG_example_JPG_RIP_100.jpg
File name is ----->preload
File name is ----->Stonehenge (3rd copy).jpg
File name is ----->Stonehenge (4th copy).jpg
File name is ----->Stonehenge (5th copy).jpg
File name is ----->Stonehenge (another copy).jpg
File name is ----->Stonehenge (copy).jpg
File name is ----->Stonehenge.jpg

You also wanted to remove items if they were inside that directory. rmdir does not allow you to remove directories containing files. But there is a simple sollution.
array_map('unlink', glob($target.'/*/*'));
array_map('rmdir',glob($target."/*",GLOB_ONLYDIR));
First it will unlink all the files in all sub-directories.
Secondly it will remove all directories, because they contain no files.
If you got sub-sub-directories, then you should add another 2 lines like this:
array_map('unlink', glob($target.'/*/*/*')); //remove sub-sub-files
array_map('rmdir',glob($target."/*/*",GLOB_ONLYDIR)); //remove sub-sub-directories
array_map('unlink', glob($target.'/*/*')); //remove sub-files
array_map('rmdir',glob($target."/*",GLOB_ONLYDIR)); //remove sub-directories

The quick and dirty way:
$folders = glob("<path>/*", GLOB_ONLYDIR);
A more versatile and object-oriented solution, inspired by earlier answers using DirectoryIterator but slightly more concise and general purpose:
$path = '<path>';
$folders = [];
foreach (new \DirectoryIterator($path) as $file)
{
if (!$file->isDot() && $file->isDir())
{
$folders[] = $file;
}
}

here is one function i used mostly to parse archives and directories
function scan_full_dir($dir,$child=false){
$dir_content_list = scandir($dir);
foreach($dir_content_list as $value)
{
if($value === '.' || $value === '..') {continue;}
// check if we have file
if(is_file($dir.'/'.$value)) {
echo '<br> File Name --> '.$value;
continue;
}
// check if we have directory
if (is_dir($dir.'/'.$value)) {
if(!$child){
echo '<br> parent --> '.$value;
}else{
echo '<br> child of '.$child.' --> '.$value;
}
scan_full_dir($dir.'/'.$value,$value);
}
}
}
output sample
parent --> fonts
File Name --> standard
parent --> steps
child of steps --> pcb
File Name --> .attrlist.sum
File Name --> .profile.sum
File Name --> .stephdr.sum
File Name --> attrlist
child of pcb --> netlists
child of netlists --> cadnet
File Name --> .netlist.sum
File Name --> netlist
File Name --> profile
File Name --> stephdr
// to scan dir
scan_full_dir('path/of/myfolder');
// to scan archive without opening it , supported formats : gz, zip, tar and bz files.
scan_full_dir('phar://uploads/youarchive.zip);

Related

How to display latest 4 images from mounted network folder in php?

I have used symlinks to fetch mounted network folder in the specified path "/var/www/Access/images".As the beginner tried certain piece of code but it is displaying broken image.I think there is issue in path format,but unable to figure out.Please any one suggest.
`<?php
// Open the directory
$dir = opendir('/var/www/Access/images');
// Initialize an array to store the file names and last modified times
$files = array();
// Read the contents of the directory
while (($file = readdir($dir)) !== false) {
// Exclude the current and parent directories
if ($file == '.' || $file == '..') continue;
// Check if the file is a directory
if (is_dir("/var/www/Access/images/'$file")) continue;
// Get the last modified time for the file
$lastModified = filemtime("/var/www/html/Access/images/'$file");
// Add the file name and last modified time to the array
$files[$file] = $lastModified;
}
// Close the directory
closedir($dir);
// Sort the array by last modified time
asort($files);
$files=array_reverse($files);
// Initialize a counter
$count = 0;
// Iterate through the sorted array
foreach ($files as $file => $lastModified) {
// Display the image
echo "<img src='/var/www/Access/images/'$file'>";
// Increment the counter
$count++;
// Stop displaying images after the fourth one
if ($count == 2) break;
}
?>`
``
browser can not recognize path except the root of web server.
for example if /var/www/project/ is your source containg index.php that web server load it , browser can read data only in this directory and subdirectory such /var/www/project/access/images/img.png
to set src attribute of <img> you can accomplish this using:
absoulte path : https://example.com/access/images/img.png
relative path : access/images/img.png
I hope this works

PHP FILES Recursive backup of directories, deleting main directory

Function:
function scandir_recursive($dir) {
$items = scandir($dir);
foreach($items as $item) {
if ($item == '.' || $item == '..') {
continue;
}
$file = $dir . '/' . $item;
echo "$file<br />";
if (is_dir($file)) {
scandir_recursive($file);
}
}
}
scandir_recursive($path);
Output:
EEAOC/EN/1001/data
EEAOC/EN/1001/data/New Text Document.txt
EEAOC/EN/1001/data/troll.txt
EEAOC/EN/1002/data
EEAOC/EN/1002/data/New Text Document.txt
EEAOC/EN/1002/data/troll.txt
EEAOC/EN/1003/data
EEAOC/EN/1003/data/New Text Document.txt
EEAOC/EN/1003/data/troll.txt
EEAOC/EN/1004/data
EEAOC/EN/1004/data/New Text Document.txt
EEAOC/EN/1004/data/troll.txt
Is it possible to delete those empty directories and keep files?
such deleting EEAOC/EN/1001/data &EEAOC/EN/1002/data& EEAOC/EN/1003/data &EEAOC/EN/1004/data
I want to keep remaining how?
As shown from your function-output, the directories are not empty.
I suppose that the data is of low value and just needs to be backed up. I assume you are running Linux from your choice of a slash rather than a backslash. Naturally directories incur links or inodes, with metadata, which in linux can be checked via
df -hi
The Inode-Ids of files can be shown via the -i flag of ls
ls -i filename
ls -iltr
ls -ltri `echo $HOME`
Inodes take up space, and introduce overhead in file-system operations. So much to the motivation to remove the directories.
PHP's rmdir function to remove directories requires that The directory must be empty, and the relevant permissions must permit this. It is also non-recursive.
Approach 1: flatten filenames and move the files to a backup directory, then remove the empty directories
Approach 2: incrementally archive and remove the directories
#Approach 1
Your choice should depend on how easy and frequent your file access occurs.
function scandir_recursive($dir) {
$items = scandir($dir);
foreach($items as $item) {
if ($item == '.' || $item == '..') {
continue;
}
$file = $dir . '/' . $item;
$fnameflat = $dir . '_' . $item;
echo "$file<br />\n";
if (is_dir($file)) {
scandir_recursive($file);
}
if(is_file($file)){
rename($file, '~/backup/'.$fnameflat);
}
}
}
scandir_recursive($path);
Afterwards use this function by SeniorDev, to unlink files and directories, or run
`exec("rmdir -rf $path")`
This is not recommended.
#Approach 2
Archive the directory using exec("tar -cvzf backup".date().".tar.gz $path"); or using php.
Then remove the directory aferwards, as described in #1.

PHP to post links to sub directories & php to display images

I'm very basic when it comes to PHP.
With my website, I have a directory called "uploads"
Within "uploads" I have 3 folders "Example1" "Example2" and "Example3"
Within each of the folders, they contain images.
I need to know how to use php to create a navigation for every sub directory.
So that if I add a new folder "Example4" it will give a navigation like:
Select what section you're looking for:
Example1 | Example2 | Example3
and if I later add new folders add them to the navigation.
EX:
Example1 | Example2 | Example3 | Example4 | Example5
Then once they click the link to go into the folder, have a code that displays all the images in that folder.
So far I have:
<?php
$files = glob("uploads/*.*");
for ($i=0; $i<count($files); $i++)
{
$num = $files[$i];
echo '<img src="/'.$num.'">'."<p>";
}
?>
but it will only display the images in the upload directory, not the images in Example1 and so on.
How on earth would I go about doing this? I'm doing it for a school project and have two weeks to complete it, but I am so lost. I only have knowledge with CSS, HTML, and the only PHP I know is php includes, so any help would be appreciated.
Since it seems that you are familiar with globs a bit, here is an example using the "glob" function. You can see a basic working example of what you are looking for here:
http://newwebinnovations.com/glob-images/
Here is how I have the example set up:
There are two PHP files, one is index.php and the other is list-images.php.
There is also a folder for images two subfolders that have images inside of them.
index.php is the file that finds the folders in the images folder and places them in a list with links list-images.php which will display the images inside of the folder:
$path = 'images';
$folders = glob($path.'/*');
echo '<ul>';
foreach ($folders as $folder) {
echo '<li>'.$folder.'</li>';
}
echo '</ul>';
The links created above have a dynamic variable created that will pass in the link to the list-images.php page.
Here is the list-images.php code:
if (isset($_GET['folder'])) {
$folder = $_GET['folder'];
}
$singleImages = array();
foreach (glob($folder . '/*.{jpg,jpeg,png,gif}', GLOB_BRACE) as $image) {
$imageElements = array();
$imageElements['source'] = $image;
$singleImages[$image] = $imageElements;
}
echo '<ul>';
foreach ($singleImages as $image) {
echo '<li><img src="'.$image['source'].'" width="400" height="auto"></li>';
}
echo '</ul>';
The links created here will link you to the individual images.
To get files of every specific folder ,pass it throw a get variable that contains folder's name,an then scan this folder an show images ,url should be like this :
listImages.php?folderName=example1
To have menu like what you want :
<?php
$path = 'uploads/' ;
$results = scandir($path);
for ($i=0;$i<count($results);$i++ ) {
$result=$results[$i];
if ($result === '.' or $result === '..') continue;
if (is_dir($path . '/' . $result)) {
echo "<a href='imgs.php?folderName=$result'>$result</a> ";
}
if($i!=count($results)-1) echo '|'; //to avoid showing | in the last element
}
?>
And here is PHP page listImages that scan images of a specific folder :
<?php
if (isset($_GET['folderName'])) $folder=$_GET['folderName'];
$path = 'uploads/'.$folder.'/' ;
$images = glob($path . '*.{jpg,jpeg,png,gif}', GLOB_BRACE);
foreach ($images as $image) {
echo "<img src='$image' />";
}
?>
First of all, do read more PHP manual, for directory related: opendir, for files related: fopen
The following code is basically re-arranging the example code provided in opendir. What it does:
A scan_directory function to simply check if directory path is valid and is a directory, then proceed to do a recursive call if there's a child directory else just print out the file name.
The first if/else condition is just to ensure the base directory is valid.
I'll added ul and li to make it slightly more presentable.
$base_dir = 'upload';
if (is_dir($base_dir))
scan_directory($base_dir);
else
echo 'Invalid base directory. Please check your setting.';
// recursive function to check all dir
function scan_directory($path) {
if (is_dir($path)) {
if ($dir_handle = opendir($path)) {
echo '<ul>';
while (($file = readdir($dir_handle)) !== false) {
if ($file != '.' && $file != '..') {
if (is_dir($path . '/' . $file)) {
echo '<li>';
echo $file;
scan_directory($path . '/' . $file);
echo '</li>';
}
else
echo "<li>{$file}</li>";
}
}
echo '</ul>';
}
}
}
create image as subdirectory name with image name and save it in database
example:
subdirectory name: example2
image name: image.jpg
store image name in db as "example2/image.jpg"

ZipArchives stores absolute paths

Can I zip files using relative paths?
For example:
$zip->addFile('c:/wamp/www/foo/file.txt');
the ZIP should have a directory structure like:
foo
-> file.txt
and not:
wamp
-> www
-> foo
-> file.txt
like it is by default...
ps: my full code is here (I'm using ZipArchive to compress contents of a directory into a zip file)
See the addFile() function definition, you can override the archive filename:
$zip->addFile('/path/to/index.txt', 'newname.txt');
If you are trying to recursively add all subfolders and files of a folder, you can try the code below (I modified this code/note in the php manual).
class Zipper extends ZipArchive {
public function addDir($path, $parent_dir = '') {
if($parent_dir != ''){
$this->addEmptyDir($parent_dir);
$parent_dir .= '/';
print '<br>adding dir ' . $parent_dir . '<br>';
}
$nodes = glob($path . '/*');
foreach ($nodes as $node) {
if (is_dir($node)) {
$this->addDir($node, $parent_dir.basename($node));
}
else if (is_file($node)) {
$this->addFile($node, $parent_dir.basename($node));
print 'adding file '.$parent_dir.basename($node) . '<br>';
}
}
}
} // class Zipper
So basically what this does is it does not include the directories (absolute path) before the actual directory/folder that you want zipped but instead only starts from the actual folder (relative path) you want zipped.
Here is a modified version of Paolo's script in order to also include dot files like .htaccess, and it should also be a bit faster since I replaced glob by opendir as adviced here.
<?php
$password = 'set_a_password'; // password to avoid listing your files to anybody
if (strcmp(md5($_GET['password']), md5($password))) die();
// Make sure the script can handle large folders/files
ini_set('max_execution_time', 600);
ini_set('memory_limit','1024M');
//path to directory to scan
if (!empty($_GET['path'])) {
$fullpath = realpath($_GET['path']); // append path if set in GET
} else { // else by default, current directory
$fullpath = realpath(dirname(__FILE__)); // current directory where the script resides
}
$directory = basename($fullpath); // parent directry name (not fullpath)
$zipfilepath = $fullpath.'/'.$directory.'_'.date('Y-m-d_His').'.zip';
$zip = new Zipper();
if ($zip->open($zipfilepath, ZipArchive::CREATE)!==TRUE) {
exit("cannot open/create zip <$zipfilepath>\n");
}
$past = time();
$zip->addDir($fullpath);
$zip->close();
print("<br /><hr />All done! Zipfile saved into ".$zipfilepath);
print('<br />Done in '.(time() - $past).' seconds.');
class Zipper extends ZipArchive {
// Thank's to Paolo for this great snippet: http://stackoverflow.com/a/17440780/1121352
// Modified by LRQ3000
public function addDir($path, $parent_dir = '') {
if($parent_dir != '' and $parent_dir != '.' and $parent_dir != './') {
$this->addEmptyDir($parent_dir);
$parent_dir .= '/';
print '<br />--> ' . $parent_dir . '<br />';
}
$dir = opendir($path);
if (empty($dir)) return; // skip if no files in folder
while(($node = readdir($dir)) !== false) {
if ( $node == '.' or $node == '..' ) continue; // avoid these special directories, but not .htaccess (except with GLOB which anyway do not show dot files)
$nodepath = $parent_dir.basename($node); // with opendir
if (is_dir($nodepath)) {
$this->addDir($nodepath, $parent_dir.basename($node));
} elseif (is_file($nodepath)) {
$this->addFile($nodepath, $parent_dir.basename($node));
print $parent_dir.basename($node).'<br />';
}
}
}
} // class Zipper
?>
This is a standalone script, just copy/paste it into a .php file (eg: zipall.php) and open it in your browser (eg: zipall.php?password=set_a_password , if you don't set the correct password, the page will stay blank for security). You must use a FTP account to retrieve the zip file afterwards, this is also a security measure.

PHP - Deleting folder/files only if there are no more in there

$value can = a folder structure to the language file. Example: languages/english.php
$value can also = the files name. Example: english.php
So I need to get the current folder that $value is in and delete the folder ONLY if there are no other files/folders within that directory (after deleting the actual file as I am doing already, ofcourse).
foreach($module['languages'] as $lang => $langFile)
{
foreach ($langFile as $type => $value)
{
#unlink($module_path . '/' . $value);
// Now I need to delete the folder ONLY if there are no other directories inside the folder where it is currently at.
// And ONLY if there are NO OTHER files within that folder also.
}
}
How can I do this?? And wondering if this can be done without using a while loop, since a while loop within a foreach loop could take some time, and need this to be as quick as possible.
And just FYI, the $module_path should never be deleted. So if $value = english.php, it should never delete the $module_path. Ofcourse, there will always be another file in there, so checking for this is not necessary, but won't hurt either way.
Thanks guys :)
EDIT
Ok, now I'm using this code here and it is NOT working, it is not removing the folders or the files, and I don't get any errors either... so not sure what the problem is here:
foreach($module['languages'] as $lang => $langFile)
{
foreach ($langFile as $type => $value)
{
if (#unlink($module_path . '/' . $value))
#rmdir(dirname($module_path . '/' . $value));
}
}
NEVERMIND, this works a CHARM!!! Cheers Everyone!!
The easyest way is try to use rmdir. This don't delete folder if it is not empty
rmdir($module_path);
also you can check is folder empty by
if(count(glob($module_path.'*'))<3)//delete
2 for . and ..
UPD: as I reviewed maybe you should replace $module_path by dirname($module_path.'.'.$value);
Since the directory you care about might be part of the $value, you need to use dirname to figure out what the parent directory is, you can't just assume that it's $module_path.
$file_path = $module_path . '/' . $value;
if (#unlink($file_path)) {
#rmdir(dirname($file_path));
}
if (is_file($value)) {
unlink($value);
} else if (is_dir($value)) {
if (count(scandir($value)) == 2) }
unlink($value)
}
}
http://php.net/manual/en/function.is-dir.php
http://www.php.net/manual/en/function.scandir.php
The code below will take a path, check if it is a file (i.e. not a directory). If it is a file, it will extract the directory name, then delete the file, then iterate over the dir and count the files in it, if the files are zero it'll delete the dir.
Code is as an example and should work, however privileges and environment setup may result in it not working.
<?php
if(!is_dir ( string $filename )){ //if it is a file
$fileDir = dirname ( $filename );
if ($handle = opendir($fileDir)) {
echo "Directory handle: $handle\n";
echo "Files:\n";
$numFiles=0;
//delete the file
unlink($myFile);
//Loop the dir and count the file in it
while (false !== ($file = readdir($handle))) {
$numFiles = $numFiles + 1;
}
if($numFiles == 0) {
//delete the dir
rmdir($fileDir);
}
closedir($handle);
}
}
?>

Categories