pathinfo() 函数返回文件路径的信息。它可以以数组形式返回路径的多个组成部分,也可以单独返回指定的部分。
pathinfo() 函数非常有用,特别是当需要同时获取文件路径的目录名、文件名、扩展名等信息时,它比单独使用 dirname()、basename() 等函数更高效。
pathinfo(string $path, int $flags = PATHINFO_ALL): mixed
| 参数 | 描述 |
|---|---|
| path |
必需。一个文件路径字符串。 可以是绝对路径或相对路径。Windows 和 Unix/Linux 路径都支持。 |
| flags |
可选。指定要返回的信息。可以是以下常量之一:
|
| 返回值 | 描述 |
|---|---|
| array | 当 flags 为 PATHINFO_ALL 或未指定时,返回包含所有信息的关联数组 |
| string | 当 flags 为其他值时,返回指定的字符串部分 |
<?php
// 基本用法:返回所有信息
$path = "/var/www/html/project/index.php";
$info = pathinfo($path);
echo "完整路径: $path<br><br>";
echo "pathinfo() 返回的数组:<br>";
print_r($info);
echo "<br><br>";
// 访问数组元素
echo "目录名: " . $info['dirname'] . "<br>";
echo "文件名: " . $info['basename'] . "<br>";
echo "扩展名: " . $info['extension'] . "<br>";
echo "文件名(无扩展名): " . $info['filename'] . "<br><br>";
// 其他路径示例
$paths = [
"/home/user/docs/report.pdf",
"C:\\Windows\\System32\\cmd.exe",
"相对路径/file.txt",
"file",
".",
"..",
"/",
"C:\\"
];
foreach ($paths as $p) {
echo "路径: " . htmlspecialchars($p) . "<br>";
print_r(pathinfo($p));
echo "<br><br>";
}
?>
<?php
// 演示 flags 参数的使用
$path = "/var/www/html/project/src/controller/UserController.php";
echo "完整路径: $path<br><br>";
// 获取特定部分
echo "PATHINFO_DIRNAME: " . pathinfo($path, PATHINFO_DIRNAME) . "<br>";
echo "PATHINFO_BASENAME: " . pathinfo($path, PATHINFO_BASENAME) . "<br>";
echo "PATHINFO_EXTENSION: " . pathinfo($path, PATHINFO_EXTENSION) . "<br>";
echo "PATHINFO_FILENAME: " . pathinfo($path, PATHINFO_FILENAME) . "<br><br>";
// 使用常量对应的数值(了解即可)
echo "使用数值常量:<br>";
echo "1 (PATHINFO_DIRNAME): " . pathinfo($path, 1) . "<br>";
echo "2 (PATHINFO_BASENAME): " . pathinfo($path, 2) . "<br>";
echo "4 (PATHINFO_EXTENSION): " . pathinfo($path, 4) . "<br>";
echo "8 (PATHINFO_FILENAME): " . pathinfo($path, 8) . "<br><br>";
// 组合使用(通过位或运算)
echo "组合使用(目录名和扩展名):<br>";
$combined = PATHINFO_DIRNAME | PATHINFO_EXTENSION;
$result = pathinfo($path, $combined);
echo "结果: ";
print_r($result);
echo "<br><br>";
// 实际应用:根据需求获取信息
function getFileInfo($path, $infoType = 'all') {
switch ($infoType) {
case 'dirname':
return pathinfo($path, PATHINFO_DIRNAME);
case 'basename':
return pathinfo($path, PATHINFO_BASENAME);
case 'extension':
return pathinfo($path, PATHINFO_EXTENSION);
case 'filename':
return pathinfo($path, PATHINFO_FILENAME);
default:
return pathinfo($path);
}
}
echo "使用封装函数:<br>";
echo "目录名: " . getFileInfo($path, 'dirname') . "<br>";
echo "扩展名: " . getFileInfo($path, 'extension') . "<br>";
?>
<?php
/**
* 演示 pathinfo() 处理各种文件类型
*/
function analyzeFile($path) {
$info = pathinfo($path);
echo "分析文件: " . htmlspecialchars($path) . "<br>";
echo "目录名: " . (isset($info['dirname']) ? $info['dirname'] : 'N/A') . "<br>";
echo "文件名: " . (isset($info['basename']) ? $info['basename'] : 'N/A') . "<br>";
echo "扩展名: " . (isset($info['extension']) ? $info['extension'] : '无扩展名') . "<br>";
echo "文件名(无扩展名): " . (isset($info['filename']) ? $info['filename'] : 'N/A') . "<br><br>";
}
// 测试各种文件类型
$testFiles = [
// 常见扩展名
'/var/www/html/index.php',
'/home/user/document.pdf',
'/tmp/image.jpg',
'/usr/bin/python3',
// 点号在文件名中
'/path/to/version.2.0.1.tar.gz',
'/backup/file.2023-01-01.bak',
// 无扩展名
'/etc/hosts',
'/usr/bin/bash',
'README',
// 隐藏文件
'/home/user/.bashrc',
'/home/user/.gitignore',
// 多扩展名
'/archive/file.tar.gz',
'/archive/file.phar.gz',
// 特殊字符
'/path/to/file with spaces.txt',
'/path/to/file-with-dashes_and_underscores.pdf',
// 相对路径
'./config/settings.ini',
'../logs/error.log',
];
foreach ($testFiles as $file) {
analyzeFile($file);
}
// 特殊处理:对于隐藏文件(以点开头的文件)
function getRealFilename($path) {
$info = pathinfo($path);
$basename = $info['basename'];
// 如果是隐藏文件(以.开头),则整个basename都是文件名
if (strpos($basename, '.') === 0) {
return [
'filename' => $basename,
'extension' => '',
'is_hidden' => true
];
}
return [
'filename' => isset($info['filename']) ? $info['filename'] : $basename,
'extension' => isset($info['extension']) ? $info['extension'] : '',
'is_hidden' => false
];
}
echo "<h4>隐藏文件处理示例</h4>";
$hiddenFiles = ['.bashrc', '.gitignore', '.env.example', 'normal.txt'];
foreach ($hiddenFiles as $file) {
$result = getRealFilename($file);
echo "文件: $file - 文件名: {$result['filename']}, 扩展名: {$result['extension']}, 隐藏: " .
($result['is_hidden'] ? '是' : '否') . "<br>";
}
?>
<?php
// 比较 pathinfo()、dirname() 和 basename()
$path = "/var/www/html/project/index.php";
echo "完整路径: $path<br><br>";
echo "<h4>使用 pathinfo()</h4>";
$info = pathinfo($path);
echo "目录名: " . $info['dirname'] . "<br>";
echo "文件名: " . $info['basename'] . "<br>";
echo "扩展名: " . $info['extension'] . "<br>";
echo "文件名(无扩展名): " . $info['filename'] . "<br><br>";
echo "<h4>使用 dirname() 和 basename()</h4>";
echo "目录名: " . dirname($path) . "<br>";
echo "文件名: " . basename($path) . "<br>";
echo "文件名(无扩展名): " . basename($path, '.php') . "<br><br>";
// 性能比较
function comparePerformance($path, $iterations = 10000) {
$start1 = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$info = pathinfo($path);
$dirname = $info['dirname'];
$basename = $info['basename'];
$extension = $info['extension'];
$filename = $info['filename'];
}
$time1 = microtime(true) - $start1;
$start2 = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$dirname = dirname($path);
$basename = basename($path);
$extension = pathinfo($path, PATHINFO_EXTENSION);
$filename = basename($path, '.' . pathinfo($path, PATHINFO_EXTENSION));
}
$time2 = microtime(true) - $start2;
return [
'pathinfo' => $time1,
'separate' => $time2,
'difference' => $time2 - $time1,
'percentage' => ($time1 / $time2) * 100
];
}
echo "<h4>性能比较(10000次迭代)</h4>";
$performance = comparePerformance($path, 10000);
echo "pathinfo(): " . round($performance['pathinfo'] * 1000, 3) . " 毫秒<br>";
echo "分开调用: " . round($performance['separate'] * 1000, 3) . " 毫秒<br>";
echo "差异: " . round($performance['difference'] * 1000, 3) . " 毫秒<br>";
echo "pathinfo() 效率: " . round($performance['percentage'], 2) . "%<br><br>";
// 实际建议
echo "<h4>使用建议</h4>";
echo "1. 当需要获取多个路径信息时,使用 pathinfo() 更高效<br>";
echo "2. 当只需要一个信息(如目录名)时,使用 dirname() 可能更直接<br>";
echo "3. pathinfo() 返回的数组便于一次获取所有信息,代码更简洁<br>";
?>
<?php
/**
* 文件上传处理类
*/
class FileUploadHandler {
/**
* 处理上传的文件信息
*/
public static function processUpload($uploadedFile) {
// 获取文件信息
$fileInfo = pathinfo($uploadedFile['name']);
// 构建安全文件名
$safeFilename = self::generateSafeFilename($fileInfo);
// 验证文件类型
$allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx'];
if (!in_array(strtolower($fileInfo['extension']), $allowedExtensions)) {
throw new Exception("文件类型不允许");
}
// 验证文件大小(最大5MB)
$maxSize = 5 * 1024 * 1024; // 5MB
if ($uploadedFile['size'] > $maxSize) {
throw new Exception("文件太大,最大允许5MB");
}
return [
'original_name' => $uploadedFile['name'],
'safe_name' => $safeFilename,
'extension' => $fileInfo['extension'],
'size' => $uploadedFile['size'],
'mime_type' => $uploadedFile['type'],
'temp_path' => $uploadedFile['tmp_name']
];
}
/**
* 生成安全的文件名
*/
private static function generateSafeFilename($fileInfo) {
// 清理文件名(移除特殊字符)
$cleanName = preg_replace('/[^a-zA-Z0-9._-]/', '_', $fileInfo['filename']);
// 限制长度
$maxLength = 100;
if (strlen($cleanName) > $maxLength) {
$cleanName = substr($cleanName, 0, $maxLength);
}
// 添加时间戳防止重名
$timestamp = time();
$random = rand(1000, 9999);
// 重建完整文件名
$safeName = $cleanName . '_' . $timestamp . '_' . $random;
if (!empty($fileInfo['extension'])) {
$safeName .= '.' . $fileInfo['extension'];
}
return $safeName;
}
/**
* 保存上传的文件
*/
public static function saveUpload($uploadInfo, $targetDir) {
// 确保目标目录存在
if (!is_dir($targetDir)) {
mkdir($targetDir, 0755, true);
}
// 构建完整目标路径
$targetPath = $targetDir . '/' . $uploadInfo['safe_name'];
// 移动文件
if (move_uploaded_file($uploadInfo['temp_path'], $targetPath)) {
return $targetPath;
} else {
throw new Exception("文件保存失败");
}
}
/**
* 获取文件类型信息
*/
public static function getFileTypeInfo($path) {
$info = pathinfo($path);
// 常见文件类型映射
$typeMap = [
'image' => ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'],
'document' => ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rtf'],
'archive' => ['zip', 'rar', 'tar', 'gz', '7z'],
'code' => ['php', 'js', 'css', 'html', 'htm', 'json', 'xml', 'py', 'java'],
'video' => ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv'],
'audio' => ['mp3', 'wav', 'ogg', 'm4a', 'flac']
];
$extension = strtolower($info['extension'] ?? '');
$fileType = 'other';
foreach ($typeMap as $type => $extensions) {
if (in_array($extension, $extensions)) {
$fileType = $type;
break;
}
}
return [
'filename' => $info['filename'] ?? '',
'extension' => $extension,
'type' => $fileType,
'full_path' => $path
];
}
}
// 使用示例
echo "<h4>文件上传处理示例</h4>";
// 模拟上传的文件(实际环境中来自 $_FILES 数组)
$uploadedFile = [
'name' => '用户文件-测试 (1).pdf',
'type' => 'application/pdf',
'size' => 204800, // 200KB
'tmp_name' => '/tmp/php1234.tmp',
'error' => 0
];
try {
// 处理上传
$fileInfo = FileUploadHandler::processUpload($uploadedFile);
echo "原始文件名: " . $fileInfo['original_name'] . "<br>";
echo "安全文件名: " . $fileInfo['safe_name'] . "<br>";
echo "文件扩展名: " . $fileInfo['extension'] . "<br>";
echo "文件大小: " . round($fileInfo['size'] / 1024, 2) . " KB<br>";
echo "MIME 类型: " . $fileInfo['mime_type'] . "<br><br>";
// 保存文件
$targetDir = '/var/www/uploads';
$savedPath = FileUploadHandler::saveUpload($fileInfo, $targetDir);
echo "文件保存到: $savedPath<br><br>";
// 获取文件类型信息
$typeInfo = FileUploadHandler::getFileTypeInfo($savedPath);
echo "文件类型分析:<br>";
echo "文件名: " . $typeInfo['filename'] . "<br>";
echo "扩展名: " . $typeInfo['extension'] . "<br>";
echo "文件类型: " . $typeInfo['type'] . "<br>";
} catch (Exception $e) {
echo "错误: " . $e->getMessage() . "<br>";
}
// 批量处理示例
echo "<br><h4>批量文件类型分析</h4>";
$files = [
'/var/www/html/image.jpg',
'/var/www/html/document.pdf',
'/var/www/html/script.js',
'/var/www/html/archive.zip',
'/var/www/html/video.mp4',
'/var/www/html/readme.txt'
];
foreach ($files as $file) {
$info = FileUploadHandler::getFileTypeInfo($file);
$basename = basename($file);
echo "$basename - 类型: {$info['type']}, 扩展名: {$info['extension']}<br>";
}
?>
<?php
/**
* 高级路径处理工具类
*/
class PathUtils {
/**
* 获取路径的所有可能信息
*/
public static function getCompletePathInfo($path) {
$info = pathinfo($path);
// 确保所有键都存在
$defaults = [
'dirname' => '.',
'basename' => basename($path),
'extension' => '',
'filename' => ''
];
$info = array_merge($defaults, $info);
// 如果没有 filename 但 basename 存在
if (empty($info['filename']) && !empty($info['basename'])) {
if (!empty($info['extension'])) {
$info['filename'] = substr($info['basename'], 0, -strlen($info['extension']) - 1);
} else {
$info['filename'] = $info['basename'];
}
}
// 添加额外信息
$info['absolute'] = realpath($path) ?: $path;
$info['exists'] = file_exists($path);
$info['is_dir'] = is_dir($path);
$info['is_file'] = is_file($path);
$info['size'] = $info['exists'] && $info['is_file'] ? filesize($path) : 0;
$info['modified'] = $info['exists'] ? filemtime($path) : 0;
return $info;
}
/**
* 安全地更改文件扩展名
*/
public static function changeExtension($path, $newExtension) {
$info = pathinfo($path);
// 如果原路径没有扩展名
if (empty($info['extension'])) {
if (!empty($newExtension)) {
return $info['dirname'] . '/' . $info['filename'] . '.' . ltrim($newExtension, '.');
}
return $path;
}
// 如果有扩展名,替换它
if (!empty($newExtension)) {
return $info['dirname'] . '/' . $info['filename'] . '.' . ltrim($newExtension, '.');
} else {
// 移除扩展名
return $info['dirname'] . '/' . $info['filename'];
}
}
/**
* 比较两个路径是否指向同一个文件(规范化比较)
*/
public static function comparePaths($path1, $path2) {
$real1 = realpath($path1) ?: $path1;
$real2 = realpath($path2) ?: $path2;
// 规范化路径分隔符
$normalized1 = str_replace('\\', '/', $real1);
$normalized2 = str_replace('\\', '/', $real2);
return rtrim($normalized1, '/') === rtrim($normalized2, '/');
}
/**
* 获取文件的相对路径
*/
public static function getRelativePath($from, $to) {
$from = str_replace('\\', '/', realpath($from) ?: $from);
$to = str_replace('\\', '/', realpath($to) ?: $to);
$fromParts = explode('/', trim($from, '/'));
$toParts = explode('/', trim($to, '/'));
// 移除相同的部分
while (count($fromParts) && count($toParts) && $fromParts[0] === $toParts[0]) {
array_shift($fromParts);
array_shift($toParts);
}
// 构建相对路径
$relativePath = str_repeat('../', count($fromParts)) . implode('/', $toParts);
return $relativePath ?: '.';
}
/**
* 批量处理路径信息
*/
public static function batchProcess(array $paths, callable $processor) {
$results = [];
foreach ($paths as $index => $path) {
$info = pathinfo($path);
$results[$index] = $processor($info, $path);
}
return $results;
}
}
// 使用示例
echo "<h4>高级路径处理示例</h4>";
$testPath = "/var/www/html/project/src/controllers/UserController.php";
// 1. 获取完整路径信息
echo "<h5>1. 完整路径信息</h5>";
$completeInfo = PathUtils::getCompletePathInfo($testPath);
foreach ($completeInfo as $key => $value) {
if (is_bool($value)) {
$value = $value ? 'true' : 'false';
}
echo "$key: " . htmlspecialchars($value) . "<br>";
}
// 2. 更改扩展名
echo "<h5>2. 更改扩展名</h5>";
echo "原路径: $testPath<br>";
echo "改为 .html: " . PathUtils::changeExtension($testPath, 'html') . "<br>";
echo "改为 .class.php: " . PathUtils::changeExtension($testPath, 'class.php') . "<br>";
echo "移除扩展名: " . PathUtils::changeExtension($testPath, '') . "<br><br>";
// 3. 比较路径
echo "<h5>3. 路径比较</h5>";
$path1 = "/var/www/html/index.php";
$path2 = "/var/www/./html/index.php";
$path3 = "/var/www/html/../html/index.php";
$path4 = "/var/www/html/other.php";
echo "比较 $path1 和 $path2: " .
(PathUtils::comparePaths($path1, $path2) ? '相同' : '不同') . "<br>";
echo "比较 $path1 和 $path3: " .
(PathUtils::comparePaths($path1, $path3) ? '相同' : '不同') . "<br>";
echo "比较 $path1 和 $path4: " .
(PathUtils::comparePaths($path1, $path4) ? '相同' : '不同') . "<br><br>";
// 4. 获取相对路径
echo "<h5>4. 相对路径计算</h5>";
$from = "/var/www/html";
$to = "/var/www/html/css/style.css";
echo "从 $from 到 $to 的相对路径: " . PathUtils::getRelativePath($from, $to) . "<br>";
$from = "/var/www/html/css";
$to = "/var/www/html/js/script.js";
echo "从 $from 到 $to 的相对路径: " . PathUtils::getRelativePath($from, $to) . "<br><br>";
// 5. 批量处理
echo "<h5>5. 批量处理</h5>";
$paths = [
'/var/www/html/index.php',
'/var/www/html/style.css',
'/var/www/html/script.js',
'/var/www/html/.htaccess'
];
$processor = function($info, $path) {
return [
'name' => $info['filename'],
'ext' => $info['extension'] ?? '',
'type' => in_array($info['extension'] ?? '', ['php', 'js', 'css']) ? 'code' : 'other'
];
};
$batchResults = PathUtils::batchProcess($paths, $processor);
foreach ($batchResults as $index => $result) {
$path = $paths[$index];
echo "路径: " . basename($path) . " - 名称: {$result['name']}, 扩展名: {$result['ext']}, 类型: {$result['type']}<br>";
}
?>
| 键名 | 描述 | 示例 |
|---|---|---|
| dirname | 文件所在的目录路径 | /var/www/html |
| basename | 文件名(包含扩展名) | index.php |
| extension | 文件扩展名(如果有) | php |
| filename | 文件名(不包含扩展名) | index |
. 开头的文件),extension 为空,filename 包含整个文件名extension 键不存在或为空字符串basename 是目录名,extension 不存在basename 可能是空字符串PATHINFO_FILENAME 常量从 PHP 5.2.0 开始可用extensionrealpath() 规范化路径SplFileInfo 类| 错误 | 原因 | 解决方法 |
|---|---|---|
| 未定义的数组键 'extension' | 文件没有扩展名,但代码直接访问 $info['extension'] |
使用 isset($info['extension']) 检查或使用 null 合并运算符 |
| 隐藏文件扩展名处理错误 | 隐藏文件如 .env 的 filename 是 .env 而不是空 |
专门处理以点开头的文件 |
| 路径中的多个点号 | 如 file.tar.gz 只会识别 .gz 为扩展名 |
根据需求自定义扩展名解析逻辑 |
| 目录路径的处理 | 对目录路径使用 pathinfo() 可能返回意外结果 | 先用 is_dir() 检查路径类型 |
| Windows 路径问题 | Windows 路径中的反斜杠可能导致解析错误 | 先用 str_replace('\\', '/', $path) 标准化路径 |