Symfony中带后缀的上传文件URL无法触发访问控制控制器如何解决
问题原因
你遇到的问题是Apache默认重写规则导致的:自动生成的.htaccess中存在如下规则
RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ %{ENV:BASE}/index.php [L]
规则含义是:如果用户请求的路径对应服务器上真实存在的文件,Apache直接返回该文件,不会转发请求给Symfony的前端控制器index.php。所以只要public/uploads目录下存在对应带后缀的文件,就会被Apache直接返回,完全不会进入你写的控制器逻辑。不带点的文件名不存在于目录中,所以才会走Symfony路由。
解决方案
方案一(推荐):修改上传文件存储位置
把上传的附件存到项目public目录之外,例如存到var/uploads目录下,从根源上避免Apache能直接找到文件:
- 修改上传逻辑,将文件存储路径改为
%kernel.project_dir%/var/uploads,对应每个帖子的文件存到var/uploads/{帖子ID}/路径下 - 控制器校验权限通过后,用
BinaryFileResponse返回文件内容,示例代码:
<?php namespace App\Controller; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\Routing\Annotation\Route; class checkAccessAttachmentController extends AbstractController { /** * @Route("/uploads/{post}/{file}", requirements={"file"="[0-9a-zA-Z_.]*"}) */ public function index(Post $post, string $file): BinaryFileResponse { // 你的权限校验逻辑 $filePath = $this->getParameter('kernel.project_dir').'/var/uploads/'.$post->getId().'/'.$file; return new BinaryFileResponse($filePath); } }
该方案安全性最高,不存在配置疏漏导致文件被直接下载的风险。
方案二:修改.htaccess规则
如果你一定要将文件存在public/uploads目录下,可修改重写规则,强制所有/uploads开头的请求都走Symfony控制器:
找到.htaccess中原有的重写规则:
# If the requested filename exists, simply serve it. # We only want to let Apache serve files and not directories. # Rewrite all other queries to the front controller. RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ %{ENV:BASE}/index.php [L]
修改为:
# 所有/uploads开头的请求全部走Symfony控制器,不管文件是否存在 RewriteCond %{REQUEST_URI} ^/uploads/ [OR] # 其他请求保持原有逻辑,不存在的文件才走控制器 RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ %{ENV:BASE}/index.php [L]
修改后重启Apache生效,不会影响其他静态资源(CSS、JS、图片等)的正常返回。
内容的提问来源于stack exchange,提问作者Captain Nemo
相关产品推荐
相关产品推荐

