【问题标题】:Create a folder if it doesn't already exist如果文件夹不存在,则创建一个文件夹
【发布时间】:2011-01-19 04:33:25
【问题描述】:

我遇到过一些使用 Bluehost 安装 WordPress 的案例,我的 WordPress 主题出现错误,因为上传文件夹 wp-content/uploads 不存在。

显然 Bluehost cPanel WordPress 安装程序不会创建此文件夹,但 HostGator 会。

所以我需要向我的主题添加代码来检查文件夹并以其他方式创建它。

【问题讨论】:

  • if (!file_exists('path/to/directory')) { mkdir('path/to/directory', 0777, true); }

标签: php wordpress directory


【解决方案1】:

使用这样的辅助函数:

function makeDir($path)
{
     $ret = mkdir($path); // use @mkdir if you want to suppress warnings/errors
     return $ret === true || is_dir($path);
}

如果目录创建成功或已经存在则返回true,如果目录无法创建则返回false

更好的替代方案是这样的(不应该给出任何警告):

function makeDir($path)
{
     return is_dir($path) || mkdir($path);
}

【讨论】:

  • 如果您删除 @ 并用正确的 is_dir 检查替换它,我的赞成票是您的 :) 检查父目录 is_writable() 是否具有防水辅助功能的奖励积分。
  • 使用 @ 来抑制错误会影响性能。最好检查一下它不像 Gumbo 那样已经存在
  • 不管错误抑制如何,对于第一个示例,我倾向于使用 -1。第二个好多了,第一个毫无意义。
  • 这很难阅读代码,只是为了将它放在 1 行。接受的答案更加清晰。
【解决方案2】:

这是一个更通用的东西,因为它出现在 Google 上。虽然细节更具体,但这个问题的标题更普遍。

/**
 * recursively create a long directory path
 */
function createPath($path) {
    if (is_dir($path)) 
        return true;
    $prev_path = substr($path, 0, strrpos($path, '/', -2) + 1 );
    $return = createPath($prev_path);
    return ($return && is_writable($prev_path)) ? mkdir($path) : false;
}

这将采用一条路径,可能包含一长串未创建的目录,并继续向上一个目录,直到它到达现有目录。然后它将尝试在该目录中创建下一个目录,并继续创建所有目录。成功则返回true。

可以通过提供停止级别来改进它,因此如果超出用户文件夹或其他内容并包含权限,它就会失败。

【讨论】:

  • @phazei 由于 $return = createPath($prev_path);
  • 谢谢@phazei :)
【解决方案3】:

登录网站也需要同样的东西。我需要创建一个包含两个变量的目录。

$directory 是我想用用户许可证号创建另一个子文件夹的主文件夹。

include_once("../include/session.php");

$lnum = $session->lnum; // Users license number from sessions
$directory = uploaded_labels; // Name of directory that folder is being created in

if (!file_exists($directory . "/" . $lnum)) {
    mkdir($directory . "/" . $lnum, 0777, true);
}

【讨论】:

    【解决方案4】:

    如果文件夹不存在则创建文件夹

    考虑问题的环境。

    • WordPress。
    • 虚拟主机服务器。
    • 假设它是 Linux,而不是运行 PHP 的 Windows。

    引用自:mkdir

    bool mkdir ( string $pathname [, int $mode = 0777 [, bool $recursive = FALSE [, 资源 $context ]]] )

    手册说唯一需要的参数是$pathname

    所以,我们可以简单地编码:

    <?php
        error_reporting(0); 
    
        if(!mkdir('wp-content/uploads')){
            // Todo
        }
    ?>
    

    解释:

    除非需要,我们不必传递任何参数或检查文件夹是否存在甚至传递模式参数;原因如下:

    • 该命令将创建具有0755 权限(共享主机文件夹的默认权限)或0777,该命令的默认权限的文件夹。
    • mode运行 PHP 的 Windows 主机上被忽略。
    • mkdir 命令已经内置了一个检查文件夹是否存在的检查器;所以我们只需要检查返回 True|False ;这不是错误;这只是一个警告,默认情况下在托管服务器上禁用警告。
    • 根据速度,如果禁用警告,则速度会更快。

    这只是研究问题的另一种方式,而不是声称有更好或最佳的解决方案。

    已在 PHP 7、生产服务器和 Linux 上进行了测试

    【讨论】:

      【解决方案5】:

      我们应该总是模块化我们的代码,我在下面写了同样的检查...

      我们首先检查目录。如果目录不存在,我们创建目录。

      $boolDirPresents = $this->CheckDir($DirectoryName);
      
      if (!$boolDirPresents) {
              $boolCreateDirectory = $this->CreateDirectory($DirectoryName);
              if ($boolCreateDirectory) {
              echo "Created successfully";
            }
        }
      
      function CheckDir($DirName) {
          if (file_exists($DirName)) {
              echo "Dir Exists<br>";
              return true;
          } else {
              echo "Dir Not Absent<br>";
              return false;
          }
      }
           
      function CreateDirectory($DirName) {
          if (mkdir($DirName, 0777)) {
              return true;
          } else {
              return false;
          }
      }
      

      【讨论】:

        【解决方案6】:

        如果您想避免 file_existsis_dir 的问题,我建议您查看 here

        我试过了,它只会在目录不存在时创建目录。它不关心是否存在具有该名称的文件。

        /* Creates the directory if it does not exist */
        $path_to_directory = 'path/to/directory';
        if (!file_exists($path_to_directory) && !is_dir($path_to_directory)) {
            mkdir($path_to_directory, 0777, true);
        }
        

        【讨论】:

          【解决方案7】:

          递归创建目录路径:

          function makedirs($dirpath, $mode=0777) {
              return is_dir($dirpath) || mkdir($dirpath, $mode, true);
          }
          

          灵感来自 Python 的 os.makedirs()

          【讨论】:

          • 以什么方式递归?不在函数调用中(它不调用自身)?工作原理是什么?为什么有效? mkdir 是否递归执行?你能在你的答案中详细说明一下吗? (但没有“编辑:”、“更新:”或类似的 - 答案应该看起来好像是今天写的。)
          • Satish Gadhave's answer中有一些解释。
          【解决方案8】:

          在 WordPress 中,还有一个非常方便的函数 wp_mkdir_p,它将递归地创建一个目录结构。

          参考来源:

          function wp_mkdir_p( $target ) {
              $wrapper = null;
          
              // Strip the protocol
              if( wp_is_stream( $target ) ) {
                  list( $wrapper, $target ) = explode( '://', $target, 2 );
              }
          
              // From php.net/mkdir user contributed notes
              $target = str_replace( '//', '/', $target );
          
              // Put the wrapper back on the target
              if( $wrapper !== null ) {
                  $target = $wrapper . '://' . $target;
              }
          
              // Safe mode fails with a trailing slash under certain PHP versions.
              $target = rtrim($target, '/'); // Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
              if ( empty($target) )
                  $target = '/';
          
              if ( file_exists( $target ) )
                  return @is_dir( $target );
          
              // We need to find the permissions of the parent folder that exists and inherit that.
              $target_parent = dirname( $target );
              while ( '.' != $target_parent && ! is_dir( $target_parent ) ) {
                  $target_parent = dirname( $target_parent );
              }
          
              // Get the permission bits.
              if ( $stat = @stat( $target_parent ) ) {
                  $dir_perms = $stat['mode'] & 0007777;
              } else {
                  $dir_perms = 0777;
              }
          
              if ( @mkdir( $target, $dir_perms, true ) ) {
          
                  // If a umask is set that modifies $dir_perms, we'll have to re-set the $dir_perms correctly with chmod()
                  if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
                      $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
                      for ( $i = 1; $i <= count( $folder_parts ); $i++ ) {
                          @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
                      }
                  }
          
                  return true;
              }
          
              return false;
          }
          

          【讨论】:

          • Re“递归创建目录结构”:这是否暗示原生PHP函数做不到?
          【解决方案9】:

          创建文件夹的更快方法:

          if (!is_dir('path/to/directory')) {
              mkdir('path/to/directory', 0777, true);
          }
          

          【讨论】:

          • 如果该路径中有一个名为“目录”的文件,则会出错。
          【解决方案10】:

          最好的方法是使用wp_mkdir_p 函数。此函数将递归创建一个具有正确权限的文件夹。

          另外,您可以跳过文件夹存在条件,因为函数返回:

          • true 目录创建时或之前存在时
          • false 如果您无法创建目录。

          例子:

          $path = 'path/to/directory';
          if ( wp_mkdir_p( $path ) ) {
              // Directory exists or was created.
          }
          

          更多:https://developer.wordpress.org/reference/functions/wp_mkdir_p/

          【讨论】:

          • 值得一提的是,如果目录已经存在,wp_mkdir_p() 也将返回 true,因此您不需要任何额外的 file_exists() 检查。此外,它会尽力设置适当的目录权限。我总是使用这个功能而不是重新发明轮子。
          【解决方案11】:

          对于您关于 WordPress 的具体问题,请使用以下代码:

          if (!is_dir(ABSPATH . 'wp-content/uploads')) wp_mkdir_p(ABSPATH . 'wp-content/uploads');
          

          函数参考:WordPress wp_mkdir_pABSPATH 是返回 WordPress 工作目录路径的常量。

          还有另一个名为 wp_upload_dir() 的 WordPress 函数。它返回上传目录路径,如果不存在则创建一个文件夹。

          $upload_path = wp_upload_dir();
          

          以下代码适用于一般的PHP

          if (!is_dir('path/to/directory')) mkdir('path/to/directory', 0777, true);
          

          函数参考:PHP is_dir()

          【讨论】:

          • 对于WordPress使用,更安全的使用方式是wp_get_upload_dir()函数。
          • @IvijanStefanStipić 你能解释一下为什么你认为我的代码不安全吗?我故意不使用 wp_get_upload_dir() 函数。所以用户可以创建他想要的任何文件夹,而不仅仅是上传文件夹。
          • 该函数返回上传文件夹的基本目录和基本网址。如果有人使用安全插件或 CDN 并想要更改它,它将中继到该功能。我开发 WP 插件大约 8 年,相信我,在生产中你需要提前考虑。您只需要添加您的自定义文件夹,如果不存在则创建。
          • 为什么它在 WordPress 中与普通 PHP 不同?是绝对必要的吗?更安全? (不是反问。)
          【解决方案12】:

          作为对当前解决方案的补充,实用功能。

          function createDir($path, $mode = 0777, $recursive = true) {
            if(file_exists($path)) return true;
            return mkdir($path, $mode, $recursive);
          }
          
          createDir('path/to/directory');
          

          如果已经存在或创建成功,则返回true。否则返回 false。

          【讨论】:

            【解决方案13】:

            你也可以试试:

            $dirpath = "path/to/dir";
            $mode = "0764";
            is_dir($dirpath) || mkdir($dirpath, $mode, true);
            

            【讨论】:

              【解决方案14】:

              试试这个,使用mkdir:

              if (!file_exists('path/to/directory')) {
                  mkdir('path/to/directory', 0777, true);
              }
              

              请注意,0777 已经是目录的默认模式,并且仍可能被当前的 umask 修改。

              【讨论】:

              • 您错过了“递归”标志 - 请参阅 Satish 的回答。
              • is_dir() 比 file_exists() 快一点
              • @YuryPliashkou 是的,也许,但如果已经有一个具有该名称的 文件,它就不起作用了。
              • 这里的问题:所以如果在 path/to 中有一个名为 'directory' 的文件,is_dir 会返回 true,但 file_exists 会返回 false?
              • file_exists — 检查文件或目录是否存在 is_file — 判断文件名是否为常规文件 is_dir — 判断文件名是否为目录
              【解决方案15】:

              这是缺少的部分。您需要在 mkdir 调用中将“递归”标志作为第三个参数(布尔值 true)传递,如下所示:

              mkdir('path/to/directory', 0755, true);
              

              【讨论】:

              • “递归”标志是布尔第三个参数true
              【解决方案16】:

              给你。

              if (!is_dir('path/to/directory')) {
                  if (!mkdir('path/to/directory', 0777, true) && !is_dir('path/to/directory')) {
                      throw new \RuntimeException(sprintf('Directory "%s" was not created', 'path/to/directory'));
                  }
              }
              

              【讨论】:

              • PHPStorm(带有 PHP 检查)给出了这个建议;-) 顺便说一句。您可以将外部 if 合并到内部: if (!is_dir(...) && !mkdir(...) && !is_dir(...)) ...
              • @aProgger 如果将它们分开时看起来会更好。很多程序员不会合并 if 语句。
              • 这是一个品味问题。我会合并它们,甚至踢牙套,得到一个衬里。但我很好奇。你会只分开第一个 !is_dir 还是最后一个?
              • 哇,在所有答案中,这是唯一一个具有有意义的错误处理的强大答案。恭喜,你赢得了我的互联网积分。
              【解决方案17】:

              你首先需要检查目录是否存在file_exists('path_to_directory')

              然后使用mkdir(path_to_directory)创建目录

              mkdir( string $pathname [, int $mode = 0777 [, bool $recursive = FALSE [, resource $context ]]] ) : bool
              

              更多关于mkdir() here

              完整代码在这里:

              $structure = './depth1/depth2/depth3/';
              if (!file_exists($structure)) {
                  mkdir($structure);
              }
              

              【讨论】:

                【解决方案18】:
                $upload = wp_upload_dir();
                $upload_dir = $upload['basedir'];
                $upload_dir = $upload_dir . '/newfolder';
                if (! is_dir($upload_dir)) {
                   mkdir( $upload_dir, 0700 );
                }
                

                【讨论】:

                  【解决方案19】:

                  这是没有错误抑制的最新解决方案:

                  if (!is_dir('path/to/directory')) {
                      mkdir('path/to/directory');
                  }
                  

                  【讨论】:

                    【解决方案20】:
                    if (!is_dir('path_directory')) {
                        @mkdir('path_directory');
                    }
                    

                    【讨论】:

                    • 通过错误抑制,无需检查目录是否存在
                    • 处理错误比抑制错误要好。如果这失败了,你永远不会知道为什么,并且必须研究它
                    • 在高并发/多线程环境中,建议抑制错误。可能会出现竞争条件,其中两个或多个线程会将 is_dir() 评估为 false 并尝试创建目录。第一个线程将能够毫无问题地创建它,但其他线程将无法创建它,因为该目录已经存在。为避免错过实际失败的目录创建,您应该在再次调用 @mkdir() 后检查目录是否存在。
                    猜你喜欢
                    • 2013-09-18
                    • 1970-01-01
                    • 2018-02-10
                    • 1970-01-01
                    • 2011-02-19
                    • 2013-01-17
                    • 1970-01-01
                    • 2017-06-28
                    相关资源
                    最近更新 更多