在PHP项目开发中,文件上传功能完成后,动态生成可访问的文件URL是提升用户体验的重要环节。静态硬编码URL会因为服务器环境、部署路径的变化出现失效问题,因此需要根据当前运行环境动态拼接地址。
文件上传基础流程
首先我们需要完成基础的文件上传逻辑,将用户上传的文件保存到服务器指定目录,后续再基于保存的路径生成访问URL。基础上传代码如下:
<?php
// 检查是否有文件上传
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upload_file'])) {
$uploadDir = __DIR__ . '/uploads/'; // 服务器上的文件保存目录
// 如果目录不存在则创建
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
$fileName = basename($_FILES['upload_file']['name']);
$targetPath = $uploadDir . $fileName;
// 移动上传的文件到目标目录
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $targetPath)) {
echo "文件上传成功,保存路径:" . $targetPath;
} else {
echo "文件上传失败";
}
}
?>
动态生成可访问URL的核心逻辑
要生成可访问的URL,需要结合几个关键信息:请求协议(http或https)、当前访问的域名、服务器根目录对应的URL路径、文件相对于根目录的存储路径。
步骤1:获取请求协议
通过$_SERVER['HTTPS']判断当前请求是否使用HTTPS协议:
<?php // 判断请求协议 $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://'; ?>
步骤2:获取当前域名
使用$_SERVER['HTTP_HOST']获取当前访问的域名,包含端口信息:
<?php $domain = $_SERVER['HTTP_HOST']; ?>
步骤3:计算文件相对根目录的路径
我们需要将文件的绝对保存路径转换为相对于网站根目录的相对路径,这里需要用到$_SERVER['DOCUMENT_ROOT']获取服务器配置的根目录:
<?php
// 网站根目录的绝对路径
$documentRoot = $_SERVER['DOCUMENT_ROOT'];
// 文件保存的绝对路径
$fileAbsolutePath = $targetPath; // 前面上传成功后的$targetPath
// 替换路径分隔符为统一格式,避免Windows和Linux的差异
$fileAbsolutePath = str_replace('\', '/', $fileAbsolutePath);
$documentRoot = str_replace('\', '/', $documentRoot);
// 计算相对根目录的路径
$relativePath = str_replace($documentRoot, '', $fileAbsolutePath);
// 确保相对路径以/开头
if (strpos($relativePath, '/') !== 0) {
$relativePath = '/' . $relativePath;
}
?>
步骤4:拼接完整可访问URL
将前面获取的协议、域名、相对路径拼接起来,就得到了动态的文件访问URL:
<?php $fileUrl = $protocol . $domain . $relativePath; echo "文件可访问URL:" . $fileUrl; ?>
完整示例整合
将上传和URL生成逻辑整合后的完整代码如下:
<?php
$fileUrl = '';
$uploadMsg = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upload_file'])) {
$uploadDir = __DIR__ . '/uploads/';
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
// 处理文件名,避免特殊字符问题
$originalName = basename($_FILES['upload_file']['name']);
$safeName = preg_replace('/[^w.-]/u', '_', $originalName);
$targetPath = $uploadDir . $safeName;
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $targetPath)) {
$uploadMsg = "文件上传成功";
// 生成动态URL
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
$domain = $_SERVER['HTTP_HOST'];
$documentRoot = str_replace('\', '/', $_SERVER['DOCUMENT_ROOT']);
$fileAbsolutePath = str_replace('\', '/', $targetPath);
$relativePath = str_replace($documentRoot, '', $fileAbsolutePath);
if (strpos($relativePath, '/') !== 0) {
$relativePath = '/' . $relativePath;
}
$fileUrl = $protocol . $domain . $relativePath;
} else {
$uploadMsg = "文件上传失败";
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PHP文件上传</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<input type="file" name="upload_file">
<button type="submit">上传</button>
</form>
<?php if ($uploadMsg): ?>
<p><?php echo $uploadMsg; ?></p>
<?php endif; ?>
<?php if ($fileUrl): ?>
<p>文件可访问URL:<?php echo htmlspecialchars($fileUrl); ?></p>
<?php endif; ?>
</body>
</html>
注意事项
- 如果服务器配置了虚拟目录或者URL重写规则,需要根据实际规则调整相对路径的计算逻辑。
- 文件名如果包含中文或特殊字符,建议进行URL编码后再拼接,避免URL无法识别:
urlencode($relativePath)。 - 生产环境中需要添加文件类型、大小校验,避免上传恶意文件。
- 如果上传目录不在网站根目录下,需要通过配置服务器(如Nginx的alias、Apache的Alias)将目录映射到URL路径,再基于映射规则生成URL。