PHP Conference Japan 2024

realpath

(PHP 4、PHP 5、PHP 7、PHP 8)

realpath返回规范化的绝对路径名

描述

realpath(string $path): string|false

realpath() 函数会扩展所有符号链接,并解析输入路径 path 中对 /.//../ 以及多余的 / 字符的引用,返回规范化的绝对路径名。

参数

path

要检查的路径。

注意:

虽然必须提供路径,但该值可以是空字符串。在这种情况下,该值将被解释为当前目录。

返回值

成功时返回规范化的绝对路径名。结果路径将不包含符号链接、/.//../ 组件。末尾的定界符(例如 \/)也会被移除。

失败时,例如文件不存在,realpath() 将返回 false

注意:

运行脚本必须对层次结构中的所有目录都具有可执行权限,否则 realpath() 将返回 false

注意:

对于不区分大小写的文件系统,realpath() 可能会也可能不会规范化字符大小写。

注意:

realpath() 函数不适用于 Phar 存档内的文件,因为此类路径是虚拟路径,而不是真实路径。

注意:

在 Windows 上,连接点和目录的符号链接只会被扩展一级.

注意: 由于 PHP 的整数类型是有符号的,并且许多平台使用 32 位整数,因此某些文件系统函数可能会对大于 2GB 的文件返回意外结果。

示例

示例 #1 realpath() 示例

<?php
chdir
('/var/www/');
echo
realpath('./../../etc/passwd') . PHP_EOL;

echo
realpath('/tmp/') . PHP_EOL;
?>

以上示例将输出

/etc/passwd
/tmp

示例 #2 Windows 上的 realpath()

在 Windows 上,realpath() 会将 Unix 风格的路径更改为 Windows 风格。

<?php
echo realpath('/windows/system32'), PHP_EOL;

echo
realpath('C:\Program Files\\'), PHP_EOL;
?>

以上示例将输出

C:\WINDOWS\System32
C:\Program Files

参见

添加注释

用户贡献的注释 17 条注释

Sven Arduwie
16 年前
因为 realpath() 无法处理不存在的文件,
所以我编写了一个可以处理这种情况的函数。
它将(连续出现的)/ 和 \\ 替换为
DIRECTORY_SEPARATOR 中的内容,并可以正确处理 /. 和 /.. 。
get_absolute_path() 返回的路径在位置 0(字符串开头)或
位置 -1(结尾)处不包含(反)斜杠

<?php
function get_absolute_path($path) {
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = array();
foreach (
$parts as $part) {
if (
'.' == $part) continue;
if (
'..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
return
implode(DIRECTORY_SEPARATOR, $absolutes);
}
?>

测试
<?php
var_dump
(get_absolute_path('this/is/../a/./test/.///is'));
?>
返回:string(14) "this/a/test/is"

如您所见,它也产生了 Yoda 式的说话方式。:)
runeimp at gmail dot com
11 年前
需要一种方法来规范化可以处理超出初始文件夹引用的 .. 引用的虚拟路径。 所以我创建了以下内容。
<?php

function normalizePath($path)
{
$parts = array();// 用于从有效部分构建新路径的数组
$path = str_replace('\\', '/', $path);// 将反斜杠替换为正斜杠
$path = preg_replace('/\/+/', '/', $path);// 将多个斜杠合并为一个斜杠
$segments = explode('/', $path);// 收路径段
$test = '';// 初始化测试变量
foreach($segments as $segment)
{
if(
$segment != '.')
{
$test = array_pop($parts);
if(
is_null($test))
$parts[] = $segment;
else if(
$segment == '..')
{
if(
$test == '..')
$parts[] = $test;

if(
$test == '..' || $test == '')
$parts[] = $segment;
}
else
{
$parts[] = $test;
$parts[] = $segment;
}
}
}
return
implode('/', $parts);
}
?>

会将 /path/to/test/.././..//..///..///../one/two/../three/filename
转换为 ../../one/three/filename
moreau dot marc dot web at gmail dot com
5 年前
<?php

命名空间 MockingMagician\Organic\Helper;

Path
{
/**
* 这里有一个方法可以处理 Sven Arduwie 的建议 https://php.net/manual/en/function.realpath.php#84012
* 以及 runeimp at gmail dot com 的建议 https://php.net/manual/en/function.realpath.php#112367
* @param string $path
* @return string
*/
public static function getAbsolute(string $path): string
{
// 根据操作系统清理路径
$path = mb_ereg_replace('\\\\|/', DIRECTORY_SEPARATOR, $path, 'msr');
// 检查路径是否以分隔符开头 (UNIX)
$startWithSeparator = $path[0] === DIRECTORY_SEPARATOR;
// 检查是否以驱动器盘符开头
preg_match('/^[a-z]:/', $path, $matches);
$startWithLetterDir = isset($matches[0]) ? $matches[0] : false;
// 获取并过滤空的子路径
$subPaths = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'mb_strlen');

$absolutes = [];
foreach (
$subPaths as $subPath) {
if (
'.' === $subPath) {
continue;
}
// 如果 $startWithSeparator 为 false
// 且 $startWithLetterDir 为真
// 且 (absolutes 为空或所有先前值均为 ..)
// 保存绝对路径,因为这是一个相对路径,我们无法处理它,只需忘记我们想要向上导航
if ('..' === $subPath
&& !$startWithSeparator
&& !$startWithLetterDir
&& empty(array_filter($absolutes, function ($value) { return !('..' === $value); }))
) {
$absolutes[] = $subPath;
continue;
}
if (
'..' === $subPath) {
array_pop($absolutes);
continue;
}
$absolutes[] = $subPath;
}

return
((
$startWithSeparator ? DIRECTORY_SEPARATOR : $startWithLetterDir) ?
$startWithLetterDir.DIRECTORY_SEPARATOR : ''
).implode(DIRECTORY_SEPARATOR, $absolutes);
}

/**
* 示例
*
* echo Path::getAbsolute('/one/two/../two/./three/../../two'); => /one/two
* echo Path::getAbsolute('../one/two/../two/./three/../../two'); => ../one/two
* echo Path::getAbsolute('../.././../one/two/../two/./three/../../two'); => ../../../one/two
* echo Path::getAbsolute('../././../one/two/../two/./three/../../two'); => ../../one/two
* echo Path::getAbsolute('/../one/two/../two/./three/../../two'); => /one/two
* echo Path::getAbsolute('/../../one/two/../two/./three/../../two'); => /one/two
* echo Path::getAbsolute('c:\.\..\one\two\..\two\.\three\..\..\two'); => c:/one/two
*
*/
}
David Beck
18 年前
这是一个规范化包含相对路径的 URL 的函数。在从远程页面提取链接时遇到了这个问题。

<?php

函数 canonicalize($address)
{
$address = explode('/', $address);
$keys = array_keys($address, '..');

foreach(
$keys AS $keypos => $key)
{
array_splice($address, $key - ($keypos * 2 + 1), 2);
}

$address = implode('/', $address);
$address = str_replace('./', '', $address);
}

$url = 'http://www.example.com/something/../else';
echo
canonicalize($url); //http://www.example.com/else

?>
plamen at dragiyski dot org
5 年前
realpath() 只是一个系统/库调用,用于调用操作系统实际支持的 realpath() 函数。它不适用于字符串形式的路径,还会解析符号链接。即使给出绝对路径,结果路径也可能与输入路径大相径庭。本注释中没有函数能够解决这个问题。

realpath 手册页上的建议是查找现有的父目录。这里有一个例子
<?php
function resolvePath($path) {
if(
DIRECTORY_SEPARATOR !== '/') {
$path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
}
$search = explode('/', $path);
$search = array_filter($search, function($part) {
return
$part !== '.';
});
$append = array();
$match = false;
while(
count($search) > 0) {
$match = realpath(implode('/', $search));
if(
$match !== false) {
break;
}
array_unshift($append, array_pop($search));
};
if(
$match === false) {
$match = getcwd();
}
if(
count($append) > 0) {
$match .= DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $append);
}
return
$match;
}
?>

即使对于不存在的相对路径,该函数也会返回绝对路径。即使路径不存在,也应该存在某个目录可以获取其真实路径。如果该目录不在相对路径内(即使当前工作目录不存在),`getcwd()` 将会返回绝对路径,因此总会返回某个绝对路径(尽管在这种情况下,PHP 进程可能存在严重问题)。
匿名用户
12 年前
注意:如果您使用此函数来检查文件是否存在,则文件的路径将被缓存,即使文件被删除,该函数也会返回 true(请改用 `file_exists`)。
pulstar at ig dot com dot br
19 年前
有时您可能需要引用网站中文件的绝对路径而不是相对路径,但 `realpath()` 函数返回的是相对于服务器文件系统的路径,而不是相对于网站根目录的路径。

例如,`realpath()` 可能会返回如下内容:

/home/yoursite/public_html/dir1/file.ext

您不能在 HTML 文档中使用此路径,因为 Web 服务器将找不到该文件。为此,您可以使用以下代码:

<?php

function htmlpath($relative_path) {
$realpath=realpath($relative_path);
$htmlpath=str_replace($_SERVER['DOCUMENT_ROOT'],'',$realpath);
return
$htmlpath;
}

echo
'<img src="',htmlpath('../../relative/path/to/file.ext'),'" border=1>';

?>

它将返回如下内容:

<img src="/dir1/relative/path/to/file.ext" border=1>
Jrg Wagner
14 年前
请注意,此函数并非总是会去除尾部斜杠!

LINUX(使用 PHP 5.2.11 测试)
---
realpath('.')
:字符串 = "/myhttpdfolder"
realpath('./')
:字符串 = "/myhttpdfolder"
realpath('fileadmin')
:字符串 = "/myhttpdfolder/fileadmin"
realpath('fileadmin/')
:字符串 = "/myhttpdfolder/fileadmin"

WINDOWS(使用 PHP 5.2.5 测试)
---
realpath('.')
:字符串 = "C:\\myhttpdfolder"
realpath('./')
:字符串 = "C:\\myhttpdfolder\\"
realpath('fileadmin')
:字符串 = "C:\\myhttpdfolder\\fileadmin"
realpath('fileadmin/')
:字符串 = "C:\\myhttpdfolder\\fileadmin\\"
https://stackoverflow.com/users/1397947/
7 年前
应该明确指出 `realpath` 不会执行波浪号扩展。
Vincent Par
9 年前
小心像这样的相对符号链接(Ubuntu 上的 ext4 文件系统):

vincent@vincent:~/Bureau/dirscan$ readlink sandbox/roulant/voiture/cabriolet/ln-loop-relative
../..

在这种情况下,`realpath` 可能会返回 false

<?php
var_dump
(realpath('sandbox/roulant/voiture/cabriolet/ln-loop-relative'));
// => string(44) "/home/vincent/Bureau/dirscan/sandbox/roulant"
var_dump(realpath('sandbox/roulant/voiture/cabriolet/ln-loop-relative/moto'));
// => bool(false)
?>

但是您可以通过清除 `realpath` 缓存来解决此问题,如下所示:

<?php
var_dump
(realpath('sandbox/roulant/voiture/cabriolet/ln-loop-relative'));
clearstatcache(true);
var_dump(realpath('sandbox/roulant/voiture/cabriolet/ln-loop-relative/moto'));
// => string(49) "/home/vincent/Bureau/dirscan/sandbox/roulant/moto"
?>
imagiro
13 年前
这是一个小巧便捷的方法,用于计算从 `$from` 到 `$to` 的相对路径。注意:当 `$from` 和 `$to` 位于不同的驱动器上时,此方法在 Windows 上不起作用。

<?php
function relativePath($from, $to, $ps = DIRECTORY_SEPARATOR)
{
$arFrom = explode($ps, rtrim($from, $ps));
$arTo = explode($ps, rtrim($to, $ps));
while(
count($arFrom) && count($arTo) && ($arFrom[0] == $arTo[0]))
{
array_shift($arFrom);
array_shift($arTo);
}
return
str_pad("", count($arFrom) * 3, '..'.$ps).implode($ps, $arTo);
}
?>
eion at robbmob dot com
8 年前
需要注意的是,`realpath()` 函数无法处理隐藏的 Windows UNC 路径,例如 \\servername\share$\folder\blah.txt,但其他 PHP 文件函数可以正常访问该文件。
Lars Scheithauer <l dot scheithauer at gmx dot de>
19 年前
此函数也可用于测试安全漏洞。您可以禁止脚本访问特定目录下的文件,以防止 "../../../etc/shadow" 等类似攻击。

<?php

// 出于安全考虑,声明基本目录
// 请勿附加“/”后缀!
$basedir = '/var/www/cgi-bin/scriptfolder';

// 将输入的路径与基本目录进行比较
$path_parts = pathinfo($_REQUEST['file_to_get']);
if (
realpath($path_parts['dirname']) != $basedir) {
/* 对破解尝试采取适当的措施*/
die ('coding good - h4x1ng bad!');
}

?>

现在,URL "script.php?file_to_get=../../../etc/shadow" 将导致错误。
php at keith tyler dot com
13 年前
请注意,在 Windows 下,以斜杠开头的路径将在本地驱动器上解析,并且*不一定*是 C:\。

例如

M:\>php -r "print realpath('/AUTOEXEC.BAT');"
[不打印任何内容,因为没有 M:\AUTOEXEC.BAT]

但是

M:\>C
C:\>php -r "print realpath('/AUTOEXEC.BAT');"
C:\AUTOEXEC.BAT

相同的脚本,根据当前驱动器的不同,响应也不同。

我倾向于认为此函数*应该*使用 %SystemDrive% 的值作为“斜杠根”基准。
Leonard Challis
11 年前
使用 realpath(和类似函数)时,请记住 PHP 会考虑 open_basedir 限制。因此,如果您执行以下操作:

<?php
// httpdocs 文件夹中的 test.php
$path = realpath(dirname(__FILE__) . '/../application');
?>

如果您的 open_basedir 设置为 httpdocs 文件夹和 tmp,则将返回 false。您必须将其设置为上一级(或关闭)才能使其工作。
belisoful at icloud dot com
1 年前
Sven Arduwie 的答案未经测试,并且不能复制 realpath 的行为,但这是一个接近的解决方案。

这已经过单元测试,尽可能接近 realpath,但路径不必实际存在于系统中。

这需要相对路径并根据实际当前工作目录正确实现它们,但一切都可以是虚拟的。例如,“../someVirtualDir/./virtualFile.jpg”

<?php

public static function virtualpath($path): string
{
$path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
$len = strlen($path);
$relative = strpos($path, DIRECTORY_SEPARATOR);
if (!
$len || ($len > 0 && $path[0] == '.') || $relative !== 0) {
$path = getcwd() . DIRECTORY_SEPARATOR . $path;
}
$parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
$absolutes = [];
foreach (
$parts as $part) {
if (
'.' == $part) {
continue;
}
if (
'..' == $part) {
array_pop($absolutes);
} else {
$absolutes[] = $part;
}
}
return
DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $absolutes);
}

?>
Enzo dot Barbaguelatta at alma dot cl
2 年前
请注意,realpath 返回 false 的原因之一可能是路径不存在,或者权限问题,甚至操作系统的安全模块(例如 SELinux)阻止您检查路径。

如果您像我一样,在检查 realpath 为什么返回 false 时不太顺利,请先检查以下几点。
To Top