basename() 函数返回路径中的文件名部分。它接受一个文件路径字符串,并返回该路径的文件名部分(包括扩展名,除非指定了后缀参数)。
basename() 函数通常用于从完整路径中提取文件名,或者在文件上传、文件处理等场景中获取干净的文件名。
basename(string $path, string $suffix = ""): string
| 参数 | 描述 |
|---|---|
| path |
必需。一个文件路径字符串。 可以是绝对路径或相对路径。Windows 和 Unix/Linux 路径都支持。 |
| suffix |
可选。如果文件名以此后缀结尾,该后缀也会被去掉。 常用于去除文件扩展名。注意:如果后缀与文件名末尾不匹配,则不会去除任何内容。 |
| 返回值 | 描述 |
|---|---|
| string | 返回路径中的文件名部分。如果指定了 suffix 参数且文件名以此后缀结尾,则去除此外缀后返回。 |
<?php
// 基本用法
echo "1. " . basename("/etc/passwd") . "<br>"; // 输出: passwd
echo "2. " . basename("/etc/") . "<br>"; // 输出: etc
echo "3. " . basename(".") . "<br>"; // 输出: .
echo "4. " . basename("C:\\test\\test.txt") . "<br>"; // 输出: test.txt
echo "5. " . basename("/usr/local/lib/libc.so.6") . "<br>"; // 输出: libc.so.6
echo "6. " . basename("filename.txt") . "<br>"; // 输出: filename.txt
echo "7. " . basename("/var/www/html/index.php") . "<br>"; // 输出: index.php
// 使用 suffix 参数去除扩展名
echo "<br>使用 suffix 参数:<br>";
echo "8. " . basename("/var/www/html/index.php", ".php") . "<br>"; // 输出: index
echo "9. " . basename("/path/to/document.pdf", ".pdf") . "<br>"; // 输出: document
echo "10. " . basename("/path/to/archive.tar.gz", ".tar.gz") . "<br>"; // 输出: archive
echo "11. " . basename("file.txt", ".pdf") . "<br>"; // 输出: file.txt (后缀不匹配)
?>
<?php
// 演示 suffix 参数的各种用法
$testCases = [
['path' => '/var/www/html/index.php', 'suffix' => '.php'],
['path' => '/var/www/html/index.php', 'suffix' => '.html'],
['path' => '/path/to/document.pdf', 'suffix' => '.pdf'],
['path' => '/path/to/README', 'suffix' => '.txt'],
['path' => 'C:\\Windows\\explorer.exe', 'suffix' => '.exe'],
['path' => 'image.jpg', 'suffix' => '.jpg'],
['path' => 'archive.tar.gz', 'suffix' => '.gz'],
['path' => 'archive.tar.gz', 'suffix' => '.tar.gz'],
['path' => 'config.ini.bak', 'suffix' => '.bak'],
['path' => '/path/to/file.with.multiple.dots.txt', 'suffix' => '.txt'],
];
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>路径</th><th>后缀</th><th>basename() 结果</th><th>说明</th></tr></thead>";
echo "<tbody>";
foreach ($testCases as $case) {
$result = basename($case['path'], $case['suffix']);
$fullName = basename($case['path']);
// 判断后缀是否匹配
$suffixMatches = substr($fullName, -strlen($case['suffix'])) === $case['suffix'];
$explanation = $suffixMatches ? '后缀匹配,已去除' : '后缀不匹配,未去除';
echo "<tr>";
echo "<td>" . htmlspecialchars($case['path']) . "</td>";
echo "<td>" . htmlspecialchars($case['suffix']) . "</td>";
echo "<td>" . htmlspecialchars($result) . "</td>";
echo "<td>$explanation</td>";
echo "</tr>";
}
echo "</tbody></table>";
// 实际应用:安全地获取不带扩展名的文件名
function getFileNameWithoutExtension($path) {
$filename = basename($path);
$extension = pathinfo($path, PATHINFO_EXTENSION);
if ($extension) {
// 使用 basename 去除扩展名
return basename($path, '.' . $extension);
}
return $filename;
}
echo "<br>安全获取不带扩展名的文件名:<br>";
echo "getFileNameWithoutExtension('/var/www/html/index.php'): " .
getFileNameWithoutExtension('/var/www/html/index.php') . "<br>";
echo "getFileNameWithoutExtension('/path/to/document'): " .
getFileNameWithoutExtension('/path/to/document') . "<br>";
?>
<?php
// 演示 basename() 与 dirname() 和 pathinfo() 的配合
$path = "/var/www/html/project/src/controller/UserController.php";
echo "完整路径: $path<br><br>";
// 使用 basename() 和 dirname()
echo "使用 basename(): " . basename($path) . "<br>";
echo "使用 dirname(): " . dirname($path) . "<br><br>";
// 使用 basename() 去除扩展名
echo "不带扩展名的文件名: " . basename($path, '.php') . "<br>";
echo "不带 'Controller.php' 的文件名: " . basename($path, 'Controller.php') . "<br><br>";
// 使用 pathinfo()
$info = pathinfo($path);
echo "使用 pathinfo():<br>";
echo "- 目录名: " . $info['dirname'] . "<br>";
echo "- 文件名: " . $info['basename'] . "<br>";
echo "- 扩展名: " . $info['extension'] . "<br>";
echo "- 文件名(无扩展名): " . $info['filename'] . "<br><br>";
// 比较 basename() 和 pathinfo()['basename']
echo "比较:<br>";
echo "basename(\$path): " . basename($path) . "<br>";
echo "pathinfo(\$path, PATHINFO_BASENAME): " . pathinfo($path, PATHINFO_BASENAME) . "<br>";
echo "结果相同: " . (basename($path) === pathinfo($path, PATHINFO_BASENAME) ? '是' : '否') . "<br><br>";
// 实际应用:处理上传的文件
function processUploadedFile($uploadedPath) {
// 获取原始文件名
$originalName = basename($uploadedPath);
// 生成安全的文件名
$safeName = preg_replace('/[^a-zA-Z0-9._-]/', '_', $originalName);
// 获取不带扩展名的文件名
$nameWithoutExt = pathinfo($safeName, PATHINFO_FILENAME);
// 获取扩展名
$extension = pathinfo($safeName, PATHINFO_EXTENSION);
// 生成新文件名(例如添加时间戳)
$newName = $nameWithoutExt . '_' . time() . ($extension ? '.' . $extension : '');
return [
'original' => $originalName,
'safe' => $safeName,
'without_extension' => $nameWithoutExt,
'extension' => $extension,
'new_name' => $newName
];
}
// 测试上传文件处理
$uploadedFile = "/tmp/uploads/用户文件-测试 (1).pdf";
echo "处理上传文件: $uploadedFile<br>";
$result = processUploadedFile($uploadedFile);
echo "原始文件名: " . $result['original'] . "<br>";
echo "安全文件名: " . $result['safe'] . "<br>";
echo "不带扩展名: " . $result['without_extension'] . "<br>";
echo "扩展名: " . $result['extension'] . "<br>";
echo "新文件名: " . $result['new_name'] . "<br>";
?>
<?php
/**
* 跨平台的 basename 处理
*/
function crossPlatformBasename($path, $suffix = '') {
// 标准化路径分隔符为 Unix 风格(basename 能处理)
$normalizedPath = str_replace('\\', '/', $path);
// 使用 basename
$result = basename($normalizedPath, $suffix);
return $result;
}
// 测试不同操作系统的路径格式
$testPaths = [
'/var/www/html/index.php', // Unix 风格
'C:\\xampp\\htdocs\\project\\index.php', // Windows 风格
'relative/path/to/file.txt', // Unix 相对路径
'..\\..\\documents\\report.pdf', // Windows 相对路径
'file.txt', // 只有文件名
'.', // 当前目录
'..', // 父目录
'/', // Unix 根目录
'C:\\', // Windows 根目录
'C:', // Windows 驱动器(无分隔符)
'//server/share/file.txt', // UNC 路径
];
echo "<h4>跨平台 basename 测试</h4>";
echo "<table class='table table-bordered'>";
echo "<thead><tr><th>原始路径</th><th>basename() 结果</th><th>去除 .php 后缀</th></tr></thead>";
echo "<tbody>";
foreach ($testPaths as $path) {
$basename = crossPlatformBasename($path);
$basenameWithoutExt = crossPlatformBasename($path, '.php');
echo "<tr>";
echo "<td>" . htmlspecialchars($path) . "</td>";
echo "<td>" . htmlspecialchars($basename) . "</td>";
echo "<td>" . htmlspecialchars($basenameWithoutExt) . "</td>";
echo "</tr>";
}
echo "</tbody></table>";
// 实际应用:获取文件的 MIME 类型
function getFileInfo($path) {
$info = [];
// 获取文件名和扩展名
$filename = basename($path);
$extension = pathinfo($path, PATHINFO_EXTENSION);
// 常见 MIME 类型映射
$mimeTypes = [
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls' => 'application/vnd.ms-excel',
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'txt' => 'text/plain',
'html' => 'text/html',
'php' => 'application/x-httpd-php',
'css' => 'text/css',
'js' => 'application/javascript',
];
$info['filename'] = $filename;
$info['extension'] = $extension;
$info['mime_type'] = isset($mimeTypes[strtolower($extension)]) ?
$mimeTypes[strtolower($extension)] : 'application/octet-stream';
$info['name_without_ext'] = basename($path, '.' . $extension);
return $info;
}
echo "<br><h4>文件信息提取示例</h4>";
$files = ['/var/www/html/index.php', 'C:\\Users\\Document\\report.pdf', 'image.jpg'];
foreach ($files as $file) {
$fileInfo = getFileInfo($file);
echo "文件: $file<br>";
echo "文件名: " . $fileInfo['filename'] . "<br>";
echo "扩展名: " . $fileInfo['extension'] . "<br>";
echo "MIME 类型: " . $fileInfo['mime_type'] . "<br>";
echo "不带扩展名的文件名: " . $fileInfo['name_without_ext'] . "<br><br>";
}
?>
<?php
/**
* 安全处理用户提供的文件路径
*/
class SafeFilenameHandler {
/**
* 从路径中安全地提取文件名
*/
public static function getSafeBasename($path, $options = []) {
$defaults = [
'remove_extension' => false,
'allowed_extensions' => [], // 空数组表示允许所有
'max_length' => 255,
'sanitize' => true,
];
$options = array_merge($defaults, $options);
// 获取原始文件名
$filename = basename($path);
// 安全过滤
if ($options['sanitize']) {
$filename = self::sanitizeFilename($filename);
}
// 检查扩展名
$extension = pathinfo($filename, PATHINFO_EXTENSION);
if (!empty($options['allowed_extensions']) && $extension) {
if (!in_array(strtolower($extension), array_map('strtolower', $options['allowed_extensions']))) {
throw new InvalidArgumentException("文件扩展名 '$extension' 不被允许");
}
}
// 去除扩展名(如果需要)
if ($options['remove_extension'] && $extension) {
$filename = basename($filename, '.' . $extension);
}
// 限制长度
if (strlen($filename) > $options['max_length']) {
$filename = substr($filename, 0, $options['max_length']);
if ($extension && !$options['remove_extension']) {
// 确保保留扩展名
$filename = rtrim($filename, '.') . '.' . $extension;
}
}
return $filename;
}
/**
* 清理文件名,移除潜在危险字符
*/
private static function sanitizeFilename($filename) {
// 移除空字符和目录遍历序列
$filename = str_replace(["\0", '../', '..\\'], '', $filename);
// 移除控制字符
$filename = preg_replace('/[\x00-\x1F\x7F]/', '', $filename);
// 替换空格和特殊字符
$filename = preg_replace('/[\/\\\\:\*\?"<>\|]/', '_', $filename);
// 限制连续的下划线
$filename = preg_replace('/_+/', '_', $filename);
// 移除开头和结尾的下划线
$filename = trim($filename, '_');
// 如果文件名变为空,使用默认名
if (empty($filename)) {
$filename = 'file_' . uniqid();
}
return $filename;
}
/**
* 生成安全的下载文件名
*/
public static function getDownloadFilename($path, $userFilename = null) {
if ($userFilename) {
// 从用户提供的文件名中提取基本名
$filename = self::getSafeBasename($userFilename, [
'sanitize' => true,
'max_length' => 100
]);
} else {
// 从路径中提取
$filename = self::getSafeBasename($path, [
'sanitize' => true,
'max_length' => 100
]);
}
return $filename;
}
}
// 使用示例
echo "<h4>安全文件名处理示例</h4>";
$testFiles = [
'/var/www/html/../../../etc/passwd',
'C:\\Windows\\System32\\cmd.exe',
'正常文件.pdf',
'文件 名称 with 空格.txt',
'file<script>alert("xss")</script>.php',
'very_long_filename_that_exceeds_maximum_length_restrictions_and_needs_to_be_truncated.pdf',
];
foreach ($testFiles as $file) {
try {
$safeName = SafeFilenameHandler::getSafeBasename($file, [
'allowed_extensions' => ['pdf', 'txt', 'jpg', 'png'],
'max_length' => 50
]);
echo "原始: " . htmlspecialchars($file) . "<br>";
echo "安全: " . htmlspecialchars($safeName) . "<br><br>";
} catch (Exception $e) {
echo "错误处理 " . htmlspecialchars($file) . ": " . $e->getMessage() . "<br><br>";
}
}
// 下载文件名示例
echo "<h4>下载文件名示例</h4>";
$serverFile = '/var/www/uploads/季度报告2023Q4.pdf';
$userProvidedName = '我的报告<script>.pdf';
echo "服务器文件: $serverFile<br>";
echo "用户提供的文件名: " . htmlspecialchars($userProvidedName) . "<br>";
echo "安全的下载文件名: " .
htmlspecialchars(SafeFilenameHandler::getDownloadFilename($serverFile, $userProvidedName)) . "<br>";
?>
<?php
/**
* 批量处理文件路径的工具类
*/
class BatchFileProcessor {
/**
* 批量提取文件名
*/
public static function extractFilenames(array $paths, $removeExtensions = false) {
$results = [];
foreach ($paths as $index => $path) {
if ($removeExtensions) {
$extension = pathinfo($path, PATHINFO_EXTENSION);
if ($extension) {
$results[$index] = basename($path, '.' . $extension);
} else {
$results[$index] = basename($path);
}
} else {
$results[$index] = basename($path);
}
}
return $results;
}
/**
* 按扩展名分组文件名
*/
public static function groupByExtension(array $paths) {
$groups = [];
foreach ($paths as $path) {
$filename = basename($path);
$extension = pathinfo($path, PATHINFO_EXTENSION);
if (empty($extension)) {
$extension = '无扩展名';
}
if (!isset($groups[$extension])) {
$groups[$extension] = [];
}
$groups[$extension][] = $filename;
}
// 按扩展名排序
ksort($groups);
return $groups;
}
/**
* 重命名文件,保持目录结构
*/
public static function renameFiles(array $fileMap, $callback) {
$results = [];
foreach ($fileMap as $oldPath => $newFilename) {
$dir = dirname($oldPath);
$extension = pathinfo($oldPath, PATHINFO_EXTENSION);
// 应用回调函数生成新文件名
$processedName = $callback(basename($oldPath, '.' . $extension));
// 添加扩展名(如果存在)
if ($extension) {
$newFilename = $processedName . '.' . $extension;
} else {
$newFilename = $processedName;
}
$newPath = $dir . '/' . $newFilename;
$results[$oldPath] = $newPath;
}
return $results;
}
}
// 使用示例
echo "<h4>批量文件处理示例</h4>";
$files = [
'/var/www/html/index.php',
'/var/www/html/style.css',
'/var/www/html/script.js',
'/var/www/html/images/logo.png',
'/var/www/html/images/banner.jpg',
'/var/www/html/documents/report.pdf',
'/var/www/html/README',
'C:\\Users\\Documents\\presentation.ppt',
];
echo "<h5>1. 提取所有文件名</h5>";
$filenames = BatchFileProcessor::extractFilenames($files);
foreach ($filenames as $index => $name) {
echo ($index + 1) . ". " . htmlspecialchars($name) . "<br>";
}
echo "<h5>2. 提取不带扩展名的文件名</h5>";
$namesWithoutExt = BatchFileProcessor::extractFilenames($files, true);
foreach ($namesWithoutExt as $index => $name) {
echo ($index + 1) . ". " . htmlspecialchars($name) . "<br>";
}
echo "<h5>3. 按扩展名分组</h5>";
$grouped = BatchFileProcessor::groupByExtension($files);
foreach ($grouped as $extension => $fileList) {
echo "扩展名: $extension (" . count($fileList) . " 个文件)<br>";
foreach ($fileList as $filename) {
echo " - " . htmlspecialchars($filename) . "<br>";
}
echo "<br>";
}
echo "<h5>4. 批量重命名示例</h5>";
$fileMap = [
'/var/www/html/document1.pdf' => 'doc1',
'/var/www/html/document2.pdf' => 'doc2',
'/var/www/html/image1.jpg' => 'img1',
];
$renameCallback = function($oldName) {
// 示例:添加前缀和时间戳
return 'renamed_' . $oldName . '_' . date('Ymd');
};
$renamed = BatchFileProcessor::renameFiles($fileMap, $renameCallback);
foreach ($renamed as $oldPath => $newPath) {
echo "原路径: " . htmlspecialchars($oldPath) . "<br>";
echo "新路径: " . htmlspecialchars($newPath) . "<br><br>";
}
?>
| 特性 | basename() | pathinfo() |
|---|---|---|
| 返回类型 | 字符串(文件名) | 数组(包含多个路径信息) |
| 功能范围 | 仅获取文件名 | 获取目录名、文件名、扩展名等 |
| 去除后缀 | 支持(通过第二个参数) | 不支持(但可以获取无扩展名的文件名) |
| 性能 | 较高(只做一件事) | 较低(需要解析多个部分) |
| 使用场景 | 仅需要文件名时 | 需要多个路径信息时 |
| 易用性 | 简单直接 | 需要处理数组 |
| 错误 | 原因 | 解决方法 |
|---|---|---|
| 预期获取文件名却得到目录名 | 路径以分隔符结尾,如 "/path/to/dir/" | 使用 rtrim($path, '/\\') 清理路径结尾 |
| suffix 参数没有生效 | 后缀与文件名结尾不匹配(大小写敏感) | 确保后缀完全匹配,或使用 pathinfo() 获取扩展名 |
| 处理 UNC 路径问题 | Windows UNC 路径如 "\\server\share\file" | 先标准化路径分隔符,或使用专门处理 UNC 路径的函数 |
| 多字节字符问题 | 文件名包含非 ASCII 字符 | 使用 mb_* 函数或多字节安全的字符串函数 |
| 安全问题 | 用户输入可能包含目录遍历序列 | 结合使用 realpath() 或自定义安全过滤函数 |