移动端会员头像上传解决方案,基于php
问题描述
手机端会员中心头像上传是个基本的功能需求,目前手机照片像素越来越大,有的甚至超过10M,对于普通的PHP主机来说,不特殊配置根本无法上传,如何通过手机端浏览器自带的api进行上传前缩放,是解决这个问题的有效方法
浏览器接口
利用FileReader对象读取上传文件,然后通过canvas缩放,转成base64字符上传,头像的尺寸不要太大,宽度400像素足够用,这样一张超大图片压缩后才60KB左右,非常节省带宽。
思路描述
- 创建上传按钮,上传按钮做成绝对定位,透明色
- 创建图片处理临时容器,这个容器尽量不可见,绝对定位,放到可视范围以外
服务端用PHP对base64进行解码
实现代码
html容器代码
<div class="img" style="position: relative">
<input type="file" onchange="fileSelected(this);" accept="image/*" style="position: absolute;width: 100%;height: 100%;z-index: 999;opacity: 0;">
<img class="avatar" style="width: 80px;height: auto;" src="./images/img_user.png"/>
</div>
<div id="image-tmp-div" style="position:absolute;opacity: 0;width: 400px;overflow: hidden;left: -400px;">
<img src="" id="image-tmp"/>
<canvas id="canvas-tmp"/>
</div>
javascript代码
function fileSelected(obj) {
var MAX_WIDTH = 400;
var oFile = obj.files[0];
var oImage = document.getElementById('image-tmp');
// prepare HTML5 FileReader
var canvas = document.getElementById("canvas-tmp");
var oReader = new FileReader();
oReader.onload = function (e) {
oImage.src = e.target.result;
oImage.src = "data:application/octet-stream;" + e.target.result.substr(e.target.result.indexOf("base64,"));
oImage.onload = function () { // binding onload event
if (oImage.width > MAX_WIDTH) {
// 宽度等比例缩放 *=
oImage.width = MAX_WIDTH;
oImage.height *= MAX_WIDTH / oImage.width;
}
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = oImage.width;
canvas.height = oImage.height;
ctx.drawImage(oImage, 0, 0, oImage.width, oImage.height);
var picData = canvas.toDataURL("image/png");
$.ajax({
type: "POST",
url: "{:url('upload')}",
data: {"img_data": picData},
success: function (r) {
if (r.code !== 1) {
alert(r.msg);
return;
}
$('.avatar').attr("src", "{:UPLOAD_PATH}" + r.url + "?" + Math.random());
},
error: function (err) {
alert('操作失败,请联系管理员');
}
});
};
oImage.onerror = function () {
alert('没有缩略图,请返回重试');
}
};
oReader.readAsDataURL(oFile);
}
php代码
class Upload {
public function idpath($id) {
$id = abs(intval($id));
$id = sprintf("%09d", $id);
$dir1 = substr($id, 0, 3);
$dir2 = substr($id, 3, 2);
$dir3 = substr($id, 5, 2);
return $dir1 . '/' . $dir2 . '/' . $dir3 . '/';
}
public function bybase64($imgid, $dir, $base64_str) {
$dest_dir = UPLOAD_ROOT . $dir . '/' . $this->idpath($imgid);
ac('file::mkdir', $dest_dir);
list($ext, $tmp) = explode(';base64,', $base64_str);
if (empty($tmp)) {
return array('url' => '');
}
$ext = 'jpg';
$targetFile = $dest_dir . $imgid . '.' . $ext;
//用string读取
$tmp = imagecreatefromstring(base64_decode($tmp));
$w = imagesx($tmp);
$h = imagesy($tmp);
$simg = imagecreatetruecolor($w, $h);
$bg = imagecolorallocate($simg, 255, 255, 255);
imagefill($simg, 0, 0, $bg);
imagecopyresized($simg, $tmp, 0, 0, 0, 0, $w, $h, $w, $h);
imagejpeg($simg, $targetFile, 80);
imagedestroy($simg);
$ret = array('url' => substr($targetFile, strlen(UPLOAD_ROOT)));
$ret['width'] = $w;
$ret['height'] = $h;
return $ret;
}
}
// ProfileController.php控制器
public function uploadAction(Request $request) {
$img = $request->post("img_data");
if ($img) {
$data = ac('upload::bybase64', $this->user_id, "avatar", $img);
if ($data) {
$data['code'] = 1;
User::where('id', $this->user_id)->update(['avatar' => $data['url']]);
ajax_return($data);
}
} else {
$this->error("图片不能为空");
}
}
评论已关闭