Delete folder and files in PHP - php

I have a question about the little code snippet below.
At the moment I use the first code snippet and it runs perfectly.
But wouldn't the second code be a better way to delete the folder and files in it?
My variable $target is everytime a path to the folder hwo needs to delete.
function deleteFilesAndDirectory($target)
{
if(is_dir($target))
{
$files = glob($target . '*', GLOB_MARK);
foreach($files as $file)
{
deleteFilesAndDirectory($file);
}
rmdir($target);
}
elseif(is_file($target))
{
unlink($target);
}
}
Why this code shouldn't be used?
function deleteFilesAndDirectory($target)
{
$files = glob($target . '*', GLOB_MARK);
foreach($files as $file)
{
unlink($file);
}
rmdir($target);
}

The second will work fine, so long as the directory to be deleted does not contain any subdirectories. To clean out subdirectories, a recursive function is the best way, which is why in the first code sample the function deleteFilesAndDirectory() calls itself.

Related

Loop through series of folders and check how old the folder

I am making a Cron that will delete a folder older than 15days. I already made a function to delete the folder and it's content, what I don't have is to loop inside a folder then check each folder's age then if that is 15days old or above I will executue my delete function.
I want to loop inside public/uploads
in my uploads directory I store folders with content ex.
public/
uploads/
Test/
Test2/
I want to check how old those folder then delete it by calling
function Delete($path)
{
if (is_dir($path) === true)
{
$files = array_diff(scandir($path), array('.', '..'));
foreach ($files as $file)
{
Delete(realpath($path) . '/' . $file);
}
return rmdir($path);
}
else if (is_file($path) === true)
{
return unlink($path);
}
return false;
}
How do I do that? Thanks
The function you are looking for is filemtime(). This lets you determine the last modified date of a file (or directory). That in combination with the various directory functions will allow you to loop through them and check their dates.
This is something mocked up off the top of my head to give you a rough idea of how you may go about this:
$dir = '/path/to/my/folders';
$folders = scandir($dir);
foreach ($folders as $folder) {
$lastModified = filemtime($folder);
// Do a date comparison here and call your delete if necessary
}

PHP List Directories Recursively Issue

I'm trying to list all PHP files in a specified directory and for it to recursively check all sub-directories until it finds no more, there could be numerous levels.
The function I have below works fine with the exception that it only recurses down one level.
I've spent hours trying to see where I'm going wrong, I'm calling the scanFiles() when it finds a new directory but this only seems to work one level down and stop, any help greatly appreciated.
Updated:
function scanFiles($pParentDirectory)
{
$vFileArray = scandir($pParentDirectory);
$vDirectories = array();
foreach ($vFileArray as $vKey => $vValue)
{
if (!in_array($vValue, array('.', '..')) && (strpos($vValue, '.php') || is_dir($vValue)))
{
if (!is_dir($vValue))
$vDirectories[] = $vValue;
else
{
$vDirectory = $vValue;
$vSubFiles = scanFiles($vDirectory);
foreach ($vSubFiles as $vKey => $vValue)
$vDirectories[] = $vDirectory.DIRECTORY_SEPARATOR.$vValue;
}
}
}
return $vDirectories;
}
You can do this easily like this:
// helper function
function getFiles(&$files, $dir) {
$items = glob($dir . "/*");
foreach ($items as $item) {
if (is_dir($item)) {
getFiles($files, $item);
} else {
if (end(explode('.', $item)) == 'php') {
$files[] = basename($item);
}
}
}
}
// usage
$files = array();
getFiles($files, "myDir");
// debug
var_dump($files);
myDir looks like this: has php files in all dirs
Output:
P.S. if you want the function to return the full path to the found .php files, remove the basename() from this line:
$files[] = basename($item);
This will then produce result like this:
hope this helps.
This is because $vDirectory is just a folder name, so scanDir looks in the current folder for it, not the sub folder.
What you want to do is to pass in the path to the folder, not just the name. This should be as simple as changing your recursive call to scanFiles($pParentDirectory . DIRECTORY_SEPARATOR . $vDirectory)
Your main problem is functions like scanDir or isDir need the full file path to work.
If you pass the full file path to them, it should work correctly.

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);
}
}
?>

Foreach glob to include files in a subdirectory

I'm trying to learn how to include all the files in a directory using glob(), however I can't seem to get it to work. This is the code I have now:
foreach (glob("addons/*.php") as $filename) {
include $filename;
}
However a single file include seems to work just fine:
include "addons/hello.php";
This is what my file structure looks like:
Theme
-addons
--hello.php
-index.php
-options.php
So I'm not sure where the problem is. The code is inside a (theme) subdirectory itself, if that makes a difference at all. Thanks.
Use this for testing:
foreach (glob("addons/*.php", GLOB_NOCHECK) as $filename) {
PRINT $filename . "\n";
}
Should the directory not exist relatively to the current, then it will show addons/*.php as output.
This recursive function should do the trick:
function recursiveGlob($dir, $ext) {
$globFiles = glob("$dir/*.$ext");
$globDirs = glob("$dir/*", GLOB_ONLYDIR);
foreach ($globDirs as $dir) {
recursiveGlob($dir, $ext);
}
foreach ($globFiles as $file) {
include $file;
}
}
Usage: recursiveGlob('C:\Some\Dir', 'php');
If you want it to do other things to the individual file, just replace the include $file part.
Include is going to be using the search path which (while it typically includes the current working directory) isn't limited to that... using glob() with a relative directory path will always be relative to the current working directory. Before you enter your loop... ensure that your current working directory is where you think it is using echo getcwd()... you may find you're not in the Theme subdirectory after all; but that the Theme subdirectory is in the search path.
Make sure that path to file is absolute (from root of your server).
In my case this example works without problems:
$dir = getcwd();//can be replaced with your local path
foreach (glob("{$dir}/addons/*.php") as $filename) {
if(file_exists($filename))
{
//file exists, we can include it
include $filename;
}
else
{
echo 'File ' . $filename . ' not found<br />';
}
};

Is there a way to put this PHP into an array and simplify it?

The following code loads all .php files found in the specified folder (defined separately). Is there a way to put this into an array to simplify the code?
Only a couple of variables change but essentially the code repeats several times.
// The General Files
$the_general = opendir(FRAMEWORK_GENERAL);
while (($the_general_files = readdir($the_general)) !== false) {
if(strpos($the_general_files,'.php')) {
include_once(FRAMEWORK_GENERAL . $the_general_files);
}
}
closedir($the_general);
// The Plugin Files
$the_plugins = opendir(FRAMEWORK_PLUGINS);
while (($the_plugins_files = readdir($the_plugins)) !== false) {
if(strpos($the_plugins_files,'.php')) {
include_once(FRAMEWORK_PLUGINS . $the_plugins_files);
}
}
closedir($the_plugins);
There are several more sections which call different folders.
Any help is greatly appreciated.
Cheers,
James
I nicer way to do this would to use glob(). And make it into a function.
function includeAllInDirectory($directory)
{
if (!is_dir($directory)) {
return false;
}
// Make sure to add a trailing slash
$directory = rtrim($directory, '/\\') . '/';
foreach (glob("{$directory}*.php") as $filename) {
require_once($directory . $filename);
}
return true;
}
This is fairly simple. See arrays and foreach.
$dirs = array(FRAMEWORK_GENERAL, FRAMEWORK_PLUGINS, );
foreach ($dirs as $dir) {
$d = opendir($dir);
while (($file = readdir($d)) !== false) {
if(strpos($file,'.php')) {
include_once($dir . $file);
}
}
closedir($d);
}
A better idea might be lazy loading via __autoload or spl_autoload_register, including all the .php files in a directory might seem like a good idea now, but not when your codebase gets bigger.
Your code should be layed out in an easy to understand heirarchy, rather than putting them all in one directory so they can be included easily. Also, if you dont need all of the code in the files in every request you are wasting resources.
Check http://php.net/manual/en/language.oop5.autoload.php for an easy example.
This can be done pretty tightly:
$dirs = array(FRAMEWORK_GENERAL, FRAMEWORK_PLUGINS);
foreach($dirs as $dir) {
if (!is_dir($dir)) { continue; }
foreach (glob("$dir/*.php") as $filename) {
include($filename);
}
}
Put that in a function where $dirs comes in as a param and use freely.

Categories