You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Slim 4应用如何从非公开uploads目录实现文件下载?

解决Slim 4中从非public目录下载文件的问题

你当前的问题在于直接将服务器本地路径传给前端,浏览器会把它当作URL路径解析,自然无法访问。而且uploads目录不在public下,Web服务器(Nginx/Apache)不会直接暴露这个目录,必须通过PHP代理请求来实现下载。

以下是具体实现步骤:

1. 创建下载路由

在路由文件中添加专门处理下载请求的路由,映射到对应的控制器:

// routes.php
use Slim\Routing\RouteCollectorProxy;

$app->group('/download', function (RouteCollectorProxy $group) {
    // 命名路由方便生成URL
    $group->get('/{filename}', \App\Controllers\DownloadController::class . ':download')->setName('download');
});

2. 编写下载控制器

创建DownloadController,负责验证文件、读取内容并返回下载响应:

// app/Controllers/DownloadController.php
namespace App\Controllers;

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Exception\HttpNotFoundException;

class DownloadController
{
    public function download(Request $request, Response $response, array $args): Response
    {
        $filename = basename($args['filename']); // 过滤文件名,防止路径遍历
        $uploadsDir = realpath(__DIR__ . '/../../uploads'); // 获取uploads目录的绝对路径
        $filePath = $uploadsDir . DIRECTORY_SEPARATOR . $filename;

        // 验证文件是否存在且位于uploads目录内
        if (!file_exists($filePath) || !is_file($filePath) || strpos(realpath($filePath), $uploadsDir) !== 0) {
            throw new HttpNotFoundException($request, "文件不存在或非法请求");
        }

        // 写入文件内容到响应体
        $response->getBody()->write(file_get_contents($filePath));

        // 设置响应头,触发浏览器下载
        return $response
            ->withHeader('Content-Type', mime_content_type($filePath))
            ->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"')
            ->withHeader('Content-Length', filesize($filePath));
    }
}

3. 生成下载URL并传递给视图

在原来的控制器中,不再传递本地路径,而是生成下载路由的URL:

// 原控制器代码
$filename = "目标文件名";
// 使用路由名称生成URL
$downloadUrl = $this->router->urlFor('download', ['filename' => $filename]);

// 传递给视图
return $this->view->render($response, '你的视图模板.twig', [
    'downloadUrl' => $downloadUrl,
    'library' => $library
]);

4. 修改视图链接

将视图中的链接替换为生成的下载URL:

<p><a href="{{ downloadUrl }}" download>{{ library.uploads }}</a></p>

注意事项

  • 安全验证:必须用basename()过滤文件名,同时验证文件路径是否在uploads目录内,防止路径遍历攻击。
  • 扩展依赖:mime_content_type()需要启用PHP的fileinfo扩展,若未启用可改用finfo类替代。
  • 性能优化:对于大文件,建议使用分段读取(如readfile()配合输出缓冲),避免占用过多内存。

内容的提问来源于stack exchange,提问作者cesarcarlos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:43:20