php生成临时文件链接需服务端签名+时效校验,用hash_hmac生成url参数,download.php校验签名与时间;大文件须交由nginx/apache通过x-accel-redirect或x-sendfile输出,避免php超时和内存溢出。

PHP生成临时文件访问链接的核心思路
PHP本身不提供“云盘式”的共享链接功能,所有链接必须由你控制生命周期、权限和路径。真正的临时链接 = 服务端生成带签名/时效的URL + 前端或API返回给用户 + 后端路由校验后输出文件。直接把文件路径暴露(如 /uploads/report.pdf)等于放弃控制权。
用时间戳+哈希签名实现简单安全的临时链接
这是最轻量、无需数据库、适合中小流量场景的做法:把文件名、过期时间、密钥拼接后哈希,作为URL参数校验依据。
- 生成链接时:
$expires = time() + 3600;(1小时后过期) - 签名计算:
$signature = hash_hmac('sha256', "$filename|$expires", $_ENV['SECRET_KEY']); - 最终链接形如:
/download.php?file=report.pdf&expires=1718923456&sig=a1b2c3... -
download.php必须在响应前校验:time() 且 <code>$signature === hash_hmac(...),否则返回 403 - 注意:不要在URL中暴露真实路径,
download.php内部用readfile()或fpassthru()输出,且需设置Content-Disposition: attachment或inline头
避免用 symlink() 或公开目录直出
有人试过用 symlink() 指向临时目录再给链接,这非常危险:Web服务器若未禁用符号链接解析(如Nginx默认允许),攻击者可能遍历到敏感路径;Apache的 FollowSymLinks 开启时同理。更糟的是,如果临时目录在Web根下(如 /var/www/html/tmp/),哪怕加了随机名,搜索引擎或扫描器也可能撞库抓取。
- 绝对不要把上传文件存到可被直接HTTP访问的目录
- 临时目录应设在Web根之外,例如
/var/tmp/php_uploads/ - 如果非要用“伪静态”链接(如
/share/abc123),必须通过路由(如ApacheRewriteRule或 PHP-FPM 的 front controller)统一落到校验逻辑,不能靠文件系统映射
大文件或高并发场景要绕开PHP内存和超时限制
用 readfile() 输出大文件(>50MB)容易触发 max_execution_time 或内存溢出;Nginx/Apache 代理还可能截断响应。正确做法是交由Web服务器处理:
立即学习“PHP免费学习笔记(深入)”;
- Nginx:用
X-Accel-Redirect头,例如:header('X-Accel-Redirect: /internal/tmp/report.pdf');,并在Nginx配置中定义location /internal/ { internal; alias /var/tmp/php_uploads/; } - Apache:用
X-Sendfile(需启用模块),原理类似 - 此时PHP只做鉴权,不读文件内容,彻底规避超时和内存问题
- 注意:
X-Accel-Redirect路径是Nginx内部别名,不是真实文件系统路径,别写成/var/tmp/...
临时链接的“临时性”不在前端跳转速度,而在服务端是否每次请求都重新校验签名与时间——哪怕链接被转发,过期即失效,这才是关键。很多人漏掉对 $_GET['sig'] 的严格等值比对(用 hash_equals() 防时序攻击),或者把密钥硬编码在脚本里,这些细节一旦松动,整个机制就形同虚设。











