正文
我们在网站上时常会涉及到图片的上传,所以最好能有个实例:
<?php
// 接受数据
$req_pic = $_FILES['input_pic'];
// 保存目录
$uploadDir = 'pic'.DIRECTORY_SEPARATOR.date("Ymd").DIRECTORY_SEPARATOR;
$dir_db = DIRECTORY_SEPARATOR.'Uploads'.DIRECTORY_SEPARATOR.$uploadDir;
$dir = '.'.$dir_db;
// 生成日期文件夹
file_exists($dir) || (mkdir($dir,0777,true) && chmod($dir,0777));
// 生成文件名
$fileName = time().uniqid().'.'.pathinfo($req_pic["name"])['extension'];
// 移动到目的文件夹下
move_uploaded_file($req_pic["tmp_name"], $dir.$fileName);
// 完整保存地址及文件名
$req_pic_file = $dir_db.$fileName;
// 存入数据库前赋值
$data['pic'] = $req_pic_file;
我们打印一下$req_pic,看一下有什么内容:
如果我们上传的是docx文件呢:
我们可以看出name是上传时的文件名,type是文件类型,tmp_name是上传后临时保存的目录,error是错误数,size是文件大小。
我们最后把临时文件转移到目标文件夹下就算是上传成功了。
在这里我们要分清相对路径和绝对路劲。
Base64
Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。
Base64要求把每三个8Bit的字节转换为四个6Bit的字节(38 = 46 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节, 也就是说,转换后的字符串理论上将要比原来的长1/3。
关于这个编码的规则:
- 把3个字节变成4个字节。
- 每76个字符加一个换行符。
- 最后的结束符也要处理。
RFC2045转换表,The Base64 Alphabet:
看个例子:
转换前 10101101,10111010,01110110
转换后 00101011, 00011011 ,00101001 ,00110110
十进制 43 27 41 54
对应码表中的值 r b p 2
所以上面的24位编码,编码后的Base64值为 rbp2
解码同理,把 rbq2 的二进制位连接上再重组得到三个8位值,得出原码。
上传图片或文件
我们可以读取一个文件的内容,然后用 base_encode()
编码,传送后,接收端使用 base_decode()
解码,再写入文件。
理论上 Base64 只有文件内容,为了区分是什么类型文件,我们要在 Base64文件内容 前加一个文件类型描述。
base64_encode(string $string): string
base64_decode(string $string, bool $strict = false): string|false
如,发送端:
<?php
$content = file_get_contents('a.png');
$base64_str = base64_encode($content);
// 加一个文件类型标识符
$base64_png = 'data:image/png;base64,' .$base64_str;
// $base64_png 为发送到的字符串
接收端:
<?php
// $img 为接收到的字符串
// 判断图片后缀,并还原图片base64内容
if(!(strpos($img, 'data:image/png;base64,') === false)){
$base64_str = str_replace('data:image/png;base64,', '', $img);
$ext = '.png';
}
$content = base64_decode($base64_str);
// 本地保存
file_put_contents(time() .$ext, $content);
上传多张图
下面加一个很有意思的上传功能,一次可以上传多张图:
<load href="/Public/js/jquery.min.js"/>
<load href="/Public/js/layermobile/layer.js"/>
<div class="upfile">
<input type="file" name="input_pic" onchange="imgPreview(this)">
<img src="/Public/images/shop/file-style.png">
</div>
<div class="bottom" id="submit">
<a>确认发布</a>
</div>
<script type="text/javascript">
// 上传图片
function imgPreview(fileDom)
{
//判断是否支持FileReader
if (window.FileReader) {
var reader = new FileReader();
} else {
layer.open({
content: '您的设备不支持图片预览功能,如需该功能请升级您的设备!'
,style: 'background-color:#2248ab; color:#ecfcff; border:none;font-size:1.2rem;border-radius:0.5rem;' //自定风格
,time: 2
});
return false;
}
//获取文件
var file = fileDom.files[0];
var imageType = /^image\//;
//是否是图片
if (!imageType.test(file.type)) {
layer.open({
content: '请选择图片'
,style: 'background-color:#2248ab; color:#ecfcff; border:none;font-size:1.2rem;border-radius:0.5rem;' //自定风格
,time: 2
});
return false;
}
if(file.size > 500000){ //图片限制大小
layer.open({
content: '图片文件太大'
,style: 'background-color:#2248ab; color:#ecfcff; border:none;font-size:1.2rem;border-radius:0.5rem;' //自定风格
,time: 2
});
return false;
}
//读取完成
reader.onload = function(e) {
//获取图片dom
// var img = document.getElementByIdx_x_x_x("preview");
//图片路径设置为读取的图片
// img.src = e.target.result;
var str = "php <wbr>上传图片的处理" style='width: 150px;'/>";
var input =''">';
$("#input_img").find('input').remove();
$("#img_container").find('img').remove();
$("#src_images").before(str);
$("#input_img").append(input);
};
reader.readAsDataURL(file);
}
// 提交检查
$("#submit").click( function ()
{
var input_pic = {};
var pic_num = 0;
$("input[name='images[]']").each(function(index, el) {
input_pic[index] =$(el).val();
pic_num++;
});
if ( pic_num == 0 ) {
layer.open({
content: '商品图片不能为空'
,style: 'background-color:#2248ab; color:#ecfcff; border:none;font-size:1.2rem;border-radius:0.5rem;' //自定风格
,time: 2
});
return false;
}
var postdata = {};
postdata['input_pic'] = input_pic;
$.ajax({
url: "{:U('Product/creatProduct')}",
type: 'POST',
dataType: 'json',
data: postdata,
success:function(data){
if ( data.status == 1 ) {
layer.open({
content: data.info
,style: 'background-color:#2248ab; color:#ecfcff; border:none;font-size:1.2rem;border-radius:0.5rem;' //自定风格
,time: 2
});
if ( data.url != '' ) {
setTimeout(function(){
window.location.href = data.url;
},2000)
}
} else {
layer.open({
content: data.info
,style: 'background-color:#2248ab; color:#ecfcff; border:none;font-size:1.2rem;border-radius:0.5rem;' //自定风格
,time: 2
});
if ( data.url != '' ) {
setTimeout(function(){
window.location.href = data.url;
},2000)
}
}
}
})
});
</script>
后台php页:
<?php
public function creatProduct ()
{
// 商品图片
$req_pic = $_POST['input_pic'];
foreach ( $req_pic as $key => $img )
{
// 判断后缀名
$ext = '';
if( !(strpos($img, 'data:image/jpeg;base64,') === false)){
$img = str_replace('data:image/jpeg;base64,', '', $img);
$ext = '.jpg';
}
if(!(strpos($img, 'data:image/jpg;base64,') === false)){
$img = str_replace('data:image/jpg;base64,', '', $img);
$ext = '.jpg';
}
if(!(strpos($img, 'data:image/png;base64,') === false)){
$img = str_replace('data:image/png;base64,', '', $img);
$ext = '.png';
}
// 生成文件名
$name = time().uniqid();
$filename = "/Uploads/shop_product/" . date('Ymd') . "/" . $name . $ext;
$img_arr[] = $filename;
// 文件写入
put(APP_PATH.'../www'.$filename, base64_decode($img));
}
$data['prod_pic'] = $img_arr[0];
}
function put ( $filename, $content, $type = '' )
{
$dir = dirname($filename);
if ( !is_dir($dir) ) {
mkdir($dir,0777,true);
}
if ( false === file_put_contents($filename,$content) ) {
// 写入错误日志文件
}
}
图片压缩
有时用户上传的图片很大,如15M,会导致页面加载速度变慢,我们需要对用户上传的图片进行压缩。如:
<?php
function compress($image_src, $image_dist, $dist_width = 320, $dist_height = 240, $quality = 70, $filename = "")
{
$imagecreate_list = [
1 => function ($path) {
return imagecreatefromgif($path);
},
2 => function ($path) {
return imagecreatefromjpeg($path);
},
3 => function ($path) {
return imagecreatefrompng($path);
},
// 4 => function($path) {return imagecreatefromswf($path);},
// 5 => function($path) {return imagecreatefrompsd($path);},
6 => function ($path) {
return imagecreatefrombmp($path);
},
// 7 => function($path) {return imagecreatefromtiff($path);},
// 8 => function($path) {return imagecreatefromtiff($path);},
9 => function ($path) {
return imagecreatefromjpeg($path);
},
10 => function ($path) {
return imagecreatefromjpeg($path);
},
11 => function ($path) {
return imagecreatefromjpeg($path);
},
12 => function ($path) {
return imagecreatefromjpeg($path);
},
// 13 => function($path) {return imagecreatefromswc($path);},
// 14 => function($path) {return imagecreatefromiff($path);},
15 => function ($path) {
return imagecreatefromwbmp($path);
},
16 => function ($path) {
return imagecreatefromxbm($path);
},
// 17 => function($path) {return imagecreatefromico($path);},
18 => function ($path) {
return imagecreatefromwebp($path);
},
];
// 后缀名
$file_extension = null;
if (!empty($filename) && strrpos($filename, '.') !== false) {
$file_extension = substr($filename, strrpos($filename, '.') + 1);
}
try {
list($src_width, $src_height, $stype) = getimagesize($image_src);
if ($dist_width && ($src_width < $src_height)) {
$dist_width = ($dist_height / $src_height) * $src_width;
} else {
$dist_height = ($dist_width / $src_width) * $src_height;
}
$image_resource = imagecreatetruecolor($dist_width, $dist_height);
$src_image = $imagecreate_list[$stype]($image_src);
imagecopyresampled($image_resource, $src_image, 0, 0, 0, 0, $dist_width, $dist_height, $src_width, $src_height);
if (strtolower($file_extension) == 'jpg' || strtolower($file_extension ) == 'jpeg') {
imagejpeg($image_resource, $image_dist, $quality);
} else {
imagepng($image_resource, $image_dist, intval(($quality - 10) / 10));
}
imagedestroy($image_resource);
imagedestroy($src_image);
return true;
} catch (\Exception $e) {
throw new UploadException($e->getMessage());
return false;
}
}
参考资料
百度百科 base64 https://baike.baidu.com/item/base64
PHP 手册 函数参考 其它基本扩展 URL URL 函数 base64_decode https://www.php.net/manual/zh/function.base64-decode.php