在PHP中组合目录和文件名(相当于.Net中的Path.Combine)

时间:2009-06-26 16:04:36

标签: php

这应该是一个简单的问题,但我不记得相关的API。使用术语“combine directory name php”在Google上搜索不会产生任何结果。所以我想通过提出这个问题,我自己和编程社区都在做服务。

如何组合目录和文件名以在PHP中形成完整的文件路径?假设目录名称为“D:\setup program”,文件名为“mj.txt”。该方法应该在Windows“D:\setup program\mj.txt”上返回给我。当然,该方法应该在Linux或其他操作系统中返回正确的文件路径。

.Net中的相关功能是Path.Combine,但在PHP中,我记不起来了,尽管我以前一定见过它。

7 个答案:

答案 0 :(得分:34)

$filepath = $path . DIRECTORY_SEPARATOR . $file;

虽然在较新版本的PHP中,斜杠的方式无关紧要,但总是使用正斜杠也没关系。

您可以使用realpath()获取正确的绝对路径,这也会删除诸如额外不必要的斜杠之类的内容并解析../之类的引用。如果路径无效,它将返回false。

答案 1 :(得分:9)

我认为最干净,最灵活的方法是使用join函数和DIRECTORY_SEPARATOR常量:

$fullPath = join(DIRECTORY_SEPARATOR, array($directoryPath, $fileName));

答案 2 :(得分:1)

所有给出的答案都不会占用$directoryPath中的空值,也不会处理重复的斜杠。虽然PHP确实具有很高的容错能力,但是第一点可能是致命的,如果您编写的是干净的代码,第二点也不应忽略。

因此正确的解决方案是:

function PathCombine($one, $other, $normalize = true) {

    # normalize
    if($normalize) {
        $one = str_replace('/', DIRECTORY_SEPARATOR, $one);
        $one = str_replace('\\', DIRECTORY_SEPARATOR, $one);
        $other = str_replace('/', DIRECTORY_SEPARATOR, $other);
        $other = str_replace('\\', DIRECTORY_SEPARATOR, $other);
    }

    # remove leading/trailing dir separators
    if(!empty($one) && substr($one, -1)==DIRECTORY_SEPARATOR) $one = substr($one, 0, -1);
    if(!empty($other) && substr($other, 0, 1)==DIRECTORY_SEPARATOR) $other = substr($other, 1);

    # return combined path
    if(empty($one)) {
        return $other;
    } elseif(empty($other)) {
        return $one;
    } else {
        return $one.DIRECTORY_SEPARATOR.$other;
    }

}

唯一的限制是第二个参数不能是绝对路径。

答案 3 :(得分:0)

这并不是您想要的,但是它应该得到一系列路径零件,然后使用DIRECTORY_SEPARATOR联接零件,然后使用DIRECTORY_SEPARATOR拆分联接零件并删除空的路径零件。它应该返回由DIRECTORY_SEPARATOR连接的其余路径部分。

 function path_combine($paths) {
  for ($i = 0; $i < count($paths); ++$i) {
    $paths[$i] = trim($paths[$i]);
  }

  $dirty_paths = explode(DIRECTORY_SEPARATOR, join(DIRECTORY_SEPARATOR, $paths));
  for ($i = 0; $i < count($dirty_paths); ++$i) {
    $dirty_paths[$i] = trim($dirty_paths[$i]);
  }

  $unslashed_paths = array();

  for ($i = 0; $i < count($dirty_paths); ++$i) {
    $path = $dirty_paths[$i];
    if (strlen($path) == 0) continue;
    array_push($unslashed_paths, $path);
  }

  $first_not_empty_index = 0;
  while(strlen($paths[$first_not_empty_index]) == 0) {
    ++$first_not_empty_index;
  }
  $starts_with_slash = $paths[$first_not_empty_index][0] == DIRECTORY_SEPARATOR;

  return $starts_with_slash
    ? DIRECTORY_SEPARATOR . join(DIRECTORY_SEPARATOR, $unslashed_paths)
    : join(DIRECTORY_SEPARATOR, $unslashed_paths);
}

用法示例:

$test = path_combine([' ', '/cosecheamo', 'pizze', '///// 4formaggi', 'GORGONZOLA']);
echo $test;

将输出:

/cosecheamo/pizze/4formaggi/GORGONZOLA

答案 4 :(得分:0)

尝试此功能。我使用此功能来满足自己的需求。

如果要检查路径,必须将$ isReal设置为true

  public static function path($base, $com = null, $isReal = false)
  {
    if(substr($base, -1)!=DIRECTORY_SEPARATOR) $base.=DIRECTORY_SEPARATOR;
    if($com) $base.=$com;
    $base = preg_replace('/(\/+|\\\\+)/', DIRECTORY_SEPARATOR, $base);
    while(preg_match('/(\/[\w\s_-]+\/\.\.)/', $base)){
      $base = preg_replace('/(\/[\w\s_-]+\/\.\.)/', "", $base);
      if(preg_match('/\/\.\.\//', $base))
        throw new \Exception("Error directory don't have parent folder!", 1);
    }
    if($isReal){
      $base = realpath($base);
      if(is_dir($base)) $base .= DIRECTORY_SEPARATOR;
    }
    return $base;
  }

示例输出:

var_dump(Combine::path("www///system", "Combine/../"));
// string(11) "www/system/"

var_dump(Combine::path("System", "Combine/../", true));
// string(40) "/home/snow/Desktop/localhost/www/System/"

var_dump(Combine::path("System", "Combine", true));
// string(48) "/home/snow/Desktop/localhost/www/System/Combine/"

var_dump(Combine::path("System", "Combine/notPath", true)); // if you try to create a path that does not exist
// bool(false)

var_dump(Combine::path("System", "Combine/class.Combine.php", true)); // you can also select a file
//string(65) "/home/snow/Desktop/localhost/www/System/Combine/class.Combine.php"

var_dump(Combine::path("/home/testuser\\badPath///////repair"));
// string(30) "/home/testuser/badPath/repair/"

答案 5 :(得分:0)

10年后,但这也许会帮助下一个。 这是我所做的使其与PHP 7.4+兼容的事情。

它与Path.Combine一样工作,除了字符串开头的\或/不会排除以前的参数。

class Path
{
    public static function combine (): string
    {
        $paths = func_get_args();
        $paths = array_map(fn($path) => str_replace(["\\", "/"], DIRECTORY_SEPARATOR, $path), $paths);
        $paths = array_map(fn($path) => self::trimPath($path), $paths);
        return implode(DIRECTORY_SEPARATOR, $paths);
    }

    private static function trimPath(string $path): string
    {
        $path = trim($path);
        $start = $path[0] === DIRECTORY_SEPARATOR ? 1 : 0;
        $end = $path[strlen($path) - 1] === DIRECTORY_SEPARATOR ? -1 : strlen($path);
        return substr($path, $start, $end);
    }
}

Path::combine("C:\Program Files", "/Repository", "sub-repository/folder/", "file.txt");
//return "C:\Program Files\Repository\sub-repository\folder\file.txt"

Path::combine("C:\Program Files", "/Repository/", "\\sub-repository\\folder\\", "sub-folder", "file.txt");
//return "C:\Program Files\Repository\sub-repository\folder\sub-folder\file.txt"

Path::combine("C:\file.txt");
//return "C:\file.txt"

Path::combine();
//return ""

答案 6 :(得分:-1)

你可以将它与php常量DIRECTORY_SEPARATOR连接起来,或者只使用正斜杠。 Windows可能不介意= D