我查看了有关使用 PHP 安全上传图像的 StackOverflow 问题的一些答案。我已将以下脚本与解释器放在一起,并想知道这是否缺少任何内容。我唯一/主要担心的是我似乎找不到太多关于从图像本身中去除有害代码的信息,尽管这部分包含在代码中。
几个 SO 答案涉及GD
图像功能,但它们并没有真正提供任何好的代码示例案例,而且因为我是 php 新手,我似乎不太了解如何使用它(就创建而言图像的新版本)。
注意:此代码中的这些图像进入“/images”目录,但在实时站点上,它们将进入名为“images”的子域,该子域位于公共文件夹之外,仅提供静态文件(无 PHP、Perl 等)。将short_open_tag
在 php.ini 文件中关闭。
file
使用名称为“profile-image”的输入类型选择文件。
下面的代码被分成了它的组成部分——第一部分是 if/isset 语句,它检查一个名为 'submit-profile-image' 的提交按钮是否被点击,并且文件已经被上传到内存中的['tmp_name']
key$_FILES
超全球:
if(isset($_POST['submit-profile-image'])) {
$allowed = ['jpeg', 'jpg', 'png'];
if($_FILES['profile-image']['error'] === 0 ) {
// THE DIFFERENT CHECKS IN THE MAIN CODE BELOW GO HERE
} else {
$error[] = "Image failed to load please try again";
}
}
以下代码都包含在上面显示的第二个 if 语句中 - 我已将其分解以显示它的含义:
设置临时上传文件的变量名和文件输入名
$profileImageName = $_FILES['profile-image']['name'];
$temp = $_FILES['profile-image']['tmp_name'];
分解字符串以拆分文件名和文件扩展名
$ext = explode('.', $profileImageName);
$ext = strtolower(end($ext));
完全重命名文件,只保留原始文件的文件扩展名:
$file = uniqid('', true) . time() . '.' . $ext;
消毒字符串以提高安全性(可能不需要)
$file = filter_var($file, FILTER_SANITIZE_STRING);
$file = strtolower($file);
检查文件扩展名是否匹配允许的文件扩展名数组:
if (!in_array($ext, $allowed)) {
$error[] = "File type must be in the jpg / jpeg or png format";
}
getImageSize()
使用比标准 $_FILES 超全局中的 'type' 键更可靠的函数检查 MIME 类型:
$getImageSizeMime = getImageSize($temp);
if(isset($getImageSizeMime['mime']) == false) {
$error[] = "Not a recognised MIME type";
} else {
$getImageSizeMime = $getImageSizeMime['mime'];
}
确保 MIME 类型与文件扩展名匹配:
if (in_array($ext, $allowed) != $getImageSizeMime) {
$error[] = "Mime type must be of the jpg / jpeg or png format";
}
检查图像文件本身的内容:
$cleanUpload = file_get_contents($temp) ;
php
如果文件内容包含or则禁止script
:
if(preg_match('/(<\?php\s)/', $cleanUpload)) {
$error[] = "Image data cannot contain php script tags";
}
if(preg_match('/script/', $cleanUpload)) {
$error[] = "Image data cannot contain javascript tags";
}
清理 HTML 标记的文件内容
$cleanUpload = filter_var($cleanUpload, FILTER_SANITIZE_STRING);
如果不存在上述错误,则移动上传的文件
if (!isset($error)) {
if(in_array($ext, $allowed)) {
move_uploaded_file($temp, 'images/' . $file);
}
}
对于遗漏的任何安全问题或对图像文件本身的任何额外检查的任何输入将不胜感激 - 特别是关于如何复制图像以仅在可能/必要时使用 GD 库保留图像数据?StackOverflow 上的一些答案非常陈旧,并且似乎包含了也不是最新的方法(我在这个问题中避免了)。
看看是否有任何 PHP 方法可以检查图像文件本身并删除潜在的危险代码,这将是非常好的。