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
Related
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.
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.
When i am using scandir function i get different results on linux and windows.
Windows i see only folder name
Linux it does the job under
I run a check if WordPress files has been changed ?
function find_all_files($dir, $deep)
{
if(strpos($dir,"wp-content") == false){
$root = scandir($dir);
foreach($root as $value)
{
if($value === '.' || $value === '..') {continue;}
if(is_file("$dir/$value")) {
$tmpFile = "$dir/$value";
if(5000000>#filesize($tmpFile)){
$result[]="$tmpFile";
}
continue;
}
$tmp = "$dir/$value";
if(strpos($tmp,"wp-content") == false){
if($deep == true){
foreach(#$this->find_all_files("$dir/$value",true) as $value)
{
$tmpFile = $value;
if(5000000>#filesize($tmpFile)){
$result[]="$tmpFile";
}
}
}
}
}
//var_dump($result);
return $result;
}
}
I had a similar issue and it all came down to:
1) if you mean "running on windows" OS you need to include, and start from the drive directory (where server is installed) in $dir to scan.
2) Windows might be picky about separators, compare your $dir with Wordpress ABSPATH and try to use PHP constant DIRECTORY_SEPARATOR instead of your own '/' separators.
3) And I asume you working with paths, not urls (http://localhost/wordpress/...plugin/dir/). This is working for me on Windows 7, running Uniserver (LAMP):
$rootfolder = 'startfolder';
$dir = plugin_dir_path(dirname( __FILE__ )).DIRECTORY_SEPARATOR.$rootfolder;
$files = array_slice(scandir($dir), 2);
However, you need to cut down the path end begin in the install dir with ABSPATH or something. But I recommend to test where your filescript is, like plugins folder, to not consume a huge stall on errors while working with this kind of stuff.
Hint!
The PHP docs about scandir has a lot off contributed functions about reading, retriving, scanning functions and issues. Take a look at: http://php.net/manual/en/function.scandir.php
Important!
Do not start messing with windows folder access, and if you do, take a RAW copy of whole www directory first, otherwise exported Worpdress installs could get messy on a Apache server live.
Remember, did you manage to install a new plugin from the Wordpress
admin, you propably dont have a folder access issue.
Hop this helps!
Im trying to, once a button is clicked, delete a directory with any files and additional directories within that however I am encountering a problem.
The error I receive is -
PHP Fatal error: Uncaught exception 'UnexpectedValueException' with
message
'RecursiveDirectoryIterator::__construct(http://...#alink.co.uk/):
failed to open dir: not implemented' in
And here is the section of code this relates to -
$dir = 'http://www.thisismylink.co.uk/userfolder/' . $row['email'] . "/";
$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);
Now currently the structure is -
User Email ($dir)
pictures
picture.png
videos
video.mp4
What I want to do is delete everything inside the 'User Email' directory as well as the 'User Directory' itself aswell
Seems like you're using the full URL as you top directory. Shouldn't it be:
$dir = 'userfolder/' . $row['email'] . "/"; //Relative to your script
$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);
This is really a rather dangerous way to handle the issue; I'm not trying to circumvent your actual question, however please consider keeping a database full of "directories" and who they are associated to. When you remove a user, set a flag in the db to "toBeRemoved" or something of the like.
Then every so often, have a cron / scheduled task come through and query a list of directories to remove, then delete the database entry / mark it updated.
The problem is that no matter how secure you believe it to be, a script can be exploited, or produce unpredictable results from web/user based input.
In the event these errors are permission based, using the above mentality would allow this to be done at the "root" user level without fear of system files being deleted at the hand of your code being mangled by a bad user (or well intended user hitting the wrong combination of events).
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.