PHP:删除目录和内容-最安全、最可靠的方法

PHP:删除目录和内容-最安全、最可靠的方法,php,Php,在一个项目中,我能够创建目录和文件以及编辑这些文件。但现在我添加了一个删除功能来删除目录和其中的所有内容。我做了一些研究,发现2009年的堆栈溢出答案有两种选择。我很好奇哪一个更好,两个的安全性是否有任何更新(只是确保我使用的是安全的方法)。下面是答案的复制和粘贴 此函数允许您删除任何文件夹(只要它是可写的)及其文件和子目录 function Delete($path) { if (is_dir($path) === true) { $files = array

在一个项目中,我能够创建目录和文件以及编辑这些文件。但现在我添加了一个删除功能来删除目录和其中的所有内容。我做了一些研究,发现2009年的堆栈溢出答案有两种选择。我很好奇哪一个更好,两个的安全性是否有任何更新(只是确保我使用的是安全的方法)。下面是答案的复制和粘贴

此函数允许您删除任何文件夹(只要它是可写的)及其文件和子目录

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;
}
或者使用RecursiveDirectoryIterator不使用递归:

function Delete($path)
{
    if (is_dir($path) === true)
    {
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::CHILD_FIRST);

        foreach ($files as $file)
        {
            if (in_array($file->getBasename(), array('.', '..')) !== true)
            {
                if ($file->isDir() === true)
                {
                    rmdir($file->getPathName());
                }

                else if (($file->isFile() === true) || ($file->isLink() === true))
                {
                    unlink($file->getPathname());
                }
            }
        }

        return rmdir($path);
    }

    else if ((is_file($path) === true) || (is_link($path) === true))
    {
        return unlink($path);
    }

    return false;
    } 

您还可以使用底层操作系统命令执行此操作:

if(is_dir($path)) {
    $path_escaped = escapeshellcmd(realpath($path));
    $output = shell_exec('rm -fR ' . $path_escaped);
}
应该注意的是,您肯定希望能够验证所提供的“$path”值(如果输入来自不受信任的源)是否属于您希望允许此类功能的任何目录或目录集

例如,您可以执行以下操作:

$allowable_delete_dirs = array(
    '/var/www/some_dir/',
    '/var/www/some_other_dir/'
);

if(is_dir($path)) {
    $real_path = realpath($path);
    $result_array = array_filter($allowable_delete_dirs, function($value) use ($real_path) {
        return (str_pos($real_path, $value) === 0 && $real_path !== $value);
    }
    if (count($result_array) > 0) {
        // the path provided matches one or more of the allowable directories
        $output = shell_exec('rm -fR ' . escapeshellcmd($real_path));
    }
}

使用此方法删除任何目录或文件,即使该目录有子目录:

<?php

function list_files_dirs($dir) {
    if (!is_dir($dir))
        return ('Directory ' . $dir . ' doesn\'t exists.');
    $files = scandir($dir);
    unset($files[array_search('.', $files)]);
    unset($files[array_search('..', $files)]);
    return $files;
}

function delete_files($dir) {
    if (substr($dir, -1) == '/')
        $dir = substr($dir, 0, strlen($dir) - 1);
    if (!is_dir($dir) && !file_exists($dir))
        return $dir . ' doesn\'t exists.';

    function rmdir_recursive($dir, $instance) {
        foreach (list_files_dirs($dir) as $file) {
            if (is_dir("$dir/$file"))
                rmdir_recursive($dir . "/" . $file, $instance);
            else
                unlink($dir . "/" . $file);
        }
        rmdir($dir);
    }

    rmdir_recursive($dir, $this);
    return true;
}
echo delete_files("directory/or/file");
?>


我不明白您所说的安全是什么意思。如果您不知道自己在做什么,这两种方法都会造成损害。例如代码中的漏洞或已知的不安全方法。我知道有些东西由于已知的漏洞而不推荐,我只是想确保这些东西不包含任何漏洞。^那么你要问的是代码审查?如果是的话,那么这可能是OTI知道代码是在2009年发布的,自2009年以来已经发生了很大的变化,所以我只想确保它是一个安全的代码,使用哪种方法更好。上面有两种不同的方法。我的意思是,如果有比这些更好的方法,那么我也愿意接受这些方法。@kdjernigan你可能应该了解每个脚本都在做什么,这样在你询问哪个是安全的之前,你就知道它们之间的区别了。在PHP手册中查找函数。那么如果
$path
恰好是
/
?@cryptic怎么办ツ 很有可能,除非以root用户身份运行,否则PHP将无法执行。严肃地说,也许有人想限制可以以这种方式删除的目录的范围,但这在最初问题的示例中也没有涉及。对我来说,这可以通过确保将要使用的路径位于已知的目录结构中来实现。我将为答案添加注释。@kdjernigan我更新了答案,以举例说明如何将删除限制为某些目录层次结构。注意:此示例不允许您删除实际指定的目录,而是删除那些目录下的目录。@kdjernigan但该用户拥有的任何文件夹都可以被PHP删除。Mike Brant的回答创建了一个白名单来防止出现这种情况,但除非您这样做或硬编码路径,否则永远不要运行这种功能,因为您可能会删除整个webroot。@kdjernigan这应该没问题,除非有某种原因,
$\u SERVER['DOCUMENT\u ROOT']
您的代码中的值可能被篡改。这是否很难修改以将函数限制到特定目录?例如,它只能删除
$\u服务器['DOCUMENT\u ROOT']./directory/'
文件夹中的文件/文件夹。只需在start中放置
如果
并检查目录是否不允许,然后
死亡('not allowed')