我正在尝试打开名称中包含拉丁字符的图片(113_Atlético Madrid
)。
我通过使用PHP函数rawurlencode()
对其名称进行编码来保存它,所以现在它的新名称是113_Atl%C3%A9tico%20Madrid
。但是,当我尝试通过此URL打开它时,例如 mysite.com/images/113_Atl%C3%A9tico%20Madrid.png ,我收到404错误。
我如何解决这个问题?
PHP代码:
if(isset($_FILES['Team'])){
$avatar = $_FILES['Team'];
$model->avatar = "{$id}_".rawurlencode($model->name).".png";
if(!is_file(getcwd()."/images/avatars/competitions/{$model->avatar}")){
move_uploaded_file($avatar['tmp_name']['avatar'], getcwd()."/images/avatars/teams/{$model->avatar}");
}
}
答案 0 :(得分:1)
如果您不需要保留文件的名称(通常有充分的理由不这样做),那么最好简单地重命名。当前时间戳是一个合理的选择。
if(isset($_FILES['Team'])){
$avatar = $_FILES['Team'];
$date = new DateTime();
$model->avatar = "{$id}_".$date->format('Y-m-d-H-i-sP').".png";
if(!is_file(getcwd()."/images/avatars/competitions/{$model->avatar}")){
move_uploaded_file($avatar['tmp_name']['avatar'], getcwd()."/images/avatars/teams/{$model->avatar}");
}
}
毕竟,文件 在上传之前被调用的内容应该不那么重要,更重要的是,如果两个用户有一张名为“me.png”的图片,那么冲突。
如果您对编码文件名的想法感兴趣,那么我只能指出其他答案:
答案 1 :(得分:1)
% - 编码用于网址。文件名不是URL。您使用以下表单:
http://example.org/images/113_Atl%C3%A9tico%20Madrid.png
URL中的,Web服务器会将其解码为文件名,如:
/var/www/example-site/data/images/113_Atlético Madrid.png
当您准备文件名以进入网址时,您应该使用rawurlencode()
,但不应使用它来准备光盘存储的文件名。
此处还有一个问题,即在光盘上存储非ASCII文件名是跨平台不可靠的。特别是如果你在Windows服务器上运行,像move_uploaded_file()
这样的PHP文件API很可能会使用你不想要的编码,最后你可能会得到像113_Atlético Madrid.png
这样的文件名。
对此并不一定是一个简单的解决方法,但您可以使用任何形式的编码,甚至是%-encoding。因此,如果您坚持使用当前的rawurlencode()
来制作文件名:
/var/www/example-site/data/images/113_Atl%C3%A9tico%20Madrid.png
没关系,但你必须使用double - rawurlencode
来生成匹配的网址:
http://example.org/images/113_Atl%25C3%25A9tico%2520Madrid.png
但无论如何,将潜在用户提供的任意字符串作为文件名的一部分包含在内是非常危险的。您可能对目录遍历攻击持开放态,其中名称包含类似/../../
的字符串,以访问目标目录之外的文件系统。 (对于通常使用弱权限部署的PHP应用程序,这些攻击通常会升级为执行任意代码攻击。)根据@MatthewBrown的建议(+1),使用完全合成的名称要好得多。
(注意这仍然不是允许用户文件上传的安全性问题的结束,事实证明这是一个非常难以实现的功能。内容嗅探和插件仍然存在问题,可以允许图像文件被重新解释为其他类型的文件,导致跨站点脚本问题。为了防止这种情况的所有可能性,最好只从单独的主机名提供用户提供的文件,以便针对该主机的XSS不能得到你针对主站点的XSS。)