PHP DirectoryIterator and .DS_Store File - php

I have a local XAMP install on my Mac. I have this code:
foreach (new DirectoryIterator('test') as $fileInfo) {
if ($fileInfo->isDot() && $fileInfo->getBasename() !== '.DS_Store') {
continue;
}
$xmlFile = "test/" . $fileInfo->getFilename() . "/content.xml";
if (file_exists($xmlFile)) {
$xml = simplexml_load_file($xmlFile);
foreach ($xml->infos as $infos) {
echo "<li><a href='#tab_3' data-toggle='tab'>$infos->bezeichnung</a></li>";
}
}
}
The problem is that I get an error that says that the file .DS_Store cannot be opened. I thought my code filtered out the .DS_Store directory. It's clear that this file cannot be opened. It is a mac specific folder.

Your filter is saying "if it is a dot file and it is not .DS_Store, skip it" which is the opposite of what I believe you want. Try this:
if ($fileInfo->isDot() || $fileInfo->getBasename() === '.DS_Store') {
continue;
}
Which says "if it is a dot file (. or ..) or it is .DS_Store, skip it."

.DS_Store is a file, not a folder.
Your code is inappropriately assuming that anything returned by the directory iterator will be a folder and looking for a content.xml file inside it; this fails for regular files. .DS_Store happens to be a file, but the same issue would arise with any other file which happened to be in this directory.
Use the isdir method of DirectoryIterator to check whether the current item is a directory before trying to open files within it. Once you do this, you won't need a special case for .DS_Store.

Related

Delete folder and all inside contents function returns "directory not empty"

Below is my attempt to delete a folder and all its content. A folder may contain zip files and folders with files.
public function deleteFolder($dir){
if(file_exists($dir)){
$it = new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS);
$files = new \RecursiveIteratorIterator($it,
\RecursiveIteratorIterator::CHILD_FIRST);
foreach($files as $file) {
if ($file->isDir()){
rmdir($file->getRealPath());
} else {
unlink($file->getRealPath());
}
}
rmdir($dir);
}
}
but it returns the following error:
rmdir(C:\Juliver\UIUX\pd-loader\loader/temp/utso-pulgada-pd-loader-5066a7e0298a):
Directory not empty in C:\Juliver\UIUX\pd-loader\loader\Patcher.php on line 95
line 95 points to rmdir($dir); line
If I check the folder utso-pulgada-pd-loader-5066a7e0298a, I see that it's already empty but it throws me the above error.
$dirname = 'C:/Users/Admin/Desktop/test';
array_map('unlink', glob("$dirname/*.*"));
rmdir($dirname);
try this, this remove all the file present in the folder, and that folder too
Directory may contain other directories so you have to use a recursive function.
function removeDir($path) {
$files = glob("$path/*");
foreach ($files as $file) {
if (is_dir($file)) {
removeDir($file);
} else {
unlink($file);
}
}
rmdir($path);
}
Now is enough to call removeDir("/my/nice/path");
If you see the directory already empty, try to check for hidden files and be sure that you have the right permissions.
I suspect you have already checked its not a file permissions issue. As your code works for me but not you, it makes me wonder if it is a to do with PHP file stat or Real Path caching.
Unlinking a file should clear stat cache for individual file automatically. However PHP bugs have previously been known to cause this issue with rmdir.
Try doing a clearstatcache after the rmdir statement in your foreach block.
Previously I've used glob (mentioned in other answers) so I've no idea how RecursiveDirectoryIterator works re file handles; as a long shot try destroying these objects ( unset($files); unset($it) ) before your final rmdir.

FTP Delete All Folders in Target Directory

What i am trying to do is to delete all files in my target servers folder, the folder all the files are in is: "/public_html/" this directory contains all the target files, i don't want to delete this folder as it must remain the intact, just everything inside.
function ftpDelete($conn, $directory) {
echo "<pre><b>FTP Files on Server:</b>\n";
$filelist = ftp_nlist($conn, $directory);
foreach($filelist as $file) {
// Do not show "." or ".."
if ($file != "." && $file != "..") {
ftp_delete($conn, $directory);
echo $file . "\n";
}
}
echo "</pre>";
}
// Run delete functions ...
ftpDelete($conn, "/public_html/");
// Files out that is still on the server ...
FTP Folders on Server:
/public_html/vendor
/public_html/stats
/public_html/icon
/public_html/images
This code so far will delete all files that is the "public_html" directory, but not any folders, i know from reading the folders need to be empty first, i'm not sure the best way to handle these folders, i didn't see a command that would delete the target folders and it's contents, any help would be appreciated.
You need to append the filename after the directory:
ftp_delete($conn, "$directory/$file");

PHP is_dir defective

Strange behaviour, exentially:
(the name of the folder depends on the date - the purpose is a hit counter of the website, broken down by day)
if (!is_dir($folder)) { // first access in the day
mkdir($folder);
}
Well: on the server in internet all works well.
But when i try in local, with the server simulator of Easy PHP, happens that:
(a) The first time, no problem. The folder doesn't exists and it is created.
(b) subsequently, for example to a page refresh, the program flow again goes in the IF (!!!) generating the error (at line of mkdir) of kind: "Warning: mkdir(): No such file or directory in [...]".
All parent part of the directory $folder exists.
Thanks
.
Try using a recursive directory creation function:
function mkdir_r($dirName, $rights = 0777)
{
$dirs = explode(DIRECTORY_SEPARATOR , $dirName);
$dir = '';
if (strpos($dirs[count($dirs) - 1], '.')) {
array_pop($dirs);
}
foreach ($dirs as $part) {
$dir .= $part . DIRECTORY_SEPARATOR ;
if (!is_dir($dir) && strlen($dir) > 0) {
mkdir($dir, $rights);
}
}
}
This way all directories up to the directry you wanted to create are created if they don't exist.
mkdir doesn't work recursively unfortunately.
If anyone faces the issue; Use the native clearstatcache() function after you delete the file.
I'm quoting the interesting part of the original documentation
You should also note that PHP doesn't cache information about non-existent files. So, if you call file_exists() on a file that doesn't exist, it will return false until you create the file. If you create the file, it will return true even if you then delete the file. However unlink() clears the cache automatically.
For further information here is the documentation page: https://www.php.net/manual/en/function.clearstatcache.php

PHP Iterating through and removing directory issues

I've built a system whereby users can start a project and upload files to this project. When they create the project, I create a directory specifically for that project and all uploads fill this directory. However, I have implemented a system that allows the user to remove this project if they wish, deleting all the files within the directory and then the directory itself.
Locally (on MAMP), this worked a charm; on a live server however, it doesn't. For the directory removal I used a stock piece of code from a tutorial website (posted below) and as I said, works fine on a local webserver.
$name = $_POST['projectName'];
rrmdir("../../project/$name");
function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($dir."/".$object) == "dir") rrmdir($dir."/".$object); else unlink($dir."/".$object);
}
}
reset($objects);
rmdir($dir);
echo "Directory Removed";
}
Be very careful with this:
$name = $_POST['projectName'];
rrmdir("../../project/$name");
That's like an SQL injection for your server's file system, imagine if someone types this in to their browser: http://www.yoursite.com/this-script.php?projectName=../../../../var/www You'll probably want to look at escapeshellarg() to help close this gaping security hole and realpath() to convert the relative path in to an absolute one. If the target dir isn't empty then rmdir won't work, you need to remove all of the subdirs and files first before rmdir will work.
Try this one instead:
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator('/path/to/project/directory'),
RecursiveIteratorIterator::CHILD_FIRST);
foreach($iterator as $fileObject) {
if($fileObject->isFile()) {
echo 'Removing File: ', $fileObject->getRealpath(), PHP_EOL;
// unlink($fileObject->getRealpath());
} elseif($fileObject->isDir()) {
echo 'Removing Dir: ', $fileObject->getRealpath(), PHP_EOL;
// rmdir($fileObject->getRealpath());
}
}
Uncomment the rmdir and unlink lines to actually perform the removals.
Noticing your use of relative paths please see if this comment helps:
http://php.net/manual/en/function.unlink.php#85938

PHP: moving directories with contents?

I'm having an array $bundle that stores filenames and directory names.
I'm running through the array with a foreach loop and I want to move them inside of another directory. I'm using the rename method therefore and it works pretty fine with JUST FILES.
However directories with other files in there don't respond to the rename() method.
$folder = 'files';
foreach ($bundle as $value) {
$ext = pathinfo($value, PATHINFO_EXTENSION);
if ($ext != "") { //if $value has no suffix it's a fil
rename(PATH . '/' .$value, $folder . '/' . $value);
}
if ($ext == "") { // it's a folder/directory
//rename doesn't work for directories with contents
//what method should i use here???
}
}
I know the pathinfo() method is not the best way to find out if it's a directory or not, however for my little project it's fine. I just need to know how I can move any directory with all it's contents into the "files" folder.
Thank you for your help.
You will have to get all the filenames in that directory using glob or scandir. Then you would have to loop through them with the rename and move them.
Your other option, if you host allows it, is to use shell_exec and do the mv for linux or copy / xcopy for windows command and move them that way. If you choose the exec route, make sure to secure the input etc to prevent any bad stuff from happening.

Categories