问题描述
过去,我制作了一个拖放式画布图像裁剪器,现在我需要在新项目中重复使用它。
回到过去我曾经打电话给 toBlob() 的日子里,使用Ajax请求发送Blob并使用可验证所有内容的文件类处理文件服务器端,但是这次我必须将其作为普通表单发布请求进行处理。
这次,我基本上是用 toDataURL 创建一个DOM字符串,然后更新输入字段的值并使用该数据服务器端,对数据进行格式化而且我必须处理字符串
这是一个简短的代码段(是较大代码库的一部分),以显示我如何创建字符串并更新输入字段
var tempCanvas = document.createElement('canvas');
var tempCtx = tempCanvas.getContext('2d');
tempCanvas.width = this.containerWidth;
tempCanvas.height = this.containerHeiht;
tempCtx.drawImage(
this.ctx.canvas,this.cutoutWidth,this.containerWidth,this.containerWidth
);
var dataurl = tempCanvas.toDataURL("image/png");
selectElems('cc-upload-blob__input','i').value = dataurl;
然后在服务器端,我像这样处理字符串
$picture = $post['cc-upload-blob'];
if (! empty($picture)) {
if (preg_match('/^data:image\/(\w+);base64,/',$picture,$type)) {
$picture = substr($picture,strpos($picture,',') + 1);
$type = strtolower($type[1]); // jpg,png,gif
if (! in_array($type,[ 'jpg','jpeg','gif','png' ])) {
throw new \Exception('invalid image type');
}
$picture = str_replace( ' ','+',$picture );
$picture = base64_decode($picture);
if ($picture === false) {
throw new \Exception('base64_decode Failed');
}
} else {
throw new \Exception('did not match data URI with image data');
}
$pictureName = 'bla.{$type}';
$picturePath = '/pictures/'.$pictureName;
if (file_put_contents($picturePath,$picture)) {
echo '<h1>Uploaded</h1>';
} else {
echo '<h1>Not Uploaded</h1>';
}
}
此演示工作正常,它上传了一个图像,PHP脚本删除了一些不必要的数据,从字符串中获取图像类型,对base64进行解码。.
我担心的是解码后的数据?我如何验证这些数据?我的意思是,这有任何安全性吗?是否可以仅对恶意代码进行编码,然后将其附加到类似于普通字符串的字符串中?然后解码的数据将是恶意的?
在将数据传递给 file_put_contents() 之前,我知道数据将使用有效的扩展名从数组中修复,但是仍然吗?有什么需要关注的吗?有没有一种方法可以像平常一样使用$ _FILES数据和PHP上传类来验证这一点?
解决方法
在类似的项目(<canvas>
-> JS .toDataURL-> Ajax-> PHP ...)中,我在后端使用此逻辑进行 validate (至少部分)上传的图片是真实的PNG
:
function checkImage1($image_string) {
$im = imagecreatefromstring($image_string);
$valid = ($im != FALSE);
imagedestroy($im);
return $valid;
}
function checkImage2($path) {
if (exif_imagetype($path) != IMAGETYPE_PNG) {
return false;
}
//
return true;
}
// $image (string) is the base64_decoded data from frontend
// $image_path (string) is where the image will be saved
$check1 = $check2 = false;
$check1 = checkImage1($image);
if ($check1) {
if ( file_put_contents($image_path,$image) ) {
$check2 = checkImage2($image_path);
if (!$check2)
unlink($image_path);
}
}
if ($check1 && $check2) { /* all good */ } else { /* bad image */}
参考:
- imagecreatefromstring
- exif_imagetype
- 对于
IMAGETYPE_PNG
以外的其他类型:Predefined constants IMAGETYPE...