下面是关于图片表的结构:
表名 字段名 类型 允许空 默认值 字段说明
Picture Id int 主键
PictureBinary varbinary √ 图片数据
MimeType nvarchar 图片类型
SeoFilename nvarchar √
IsNew bit
UpdatedOnUtc datetime 创建时间
要将图片的二进制流数据写入数据库,需将二进制数据转换为 16 进制字符(bin2hex函数可以做到)。同样,我们从数据库取出的数据,也是16进制字符,所以要将它还原为2进制数据的形式(hex2bin 函数可以做到。),才能写入文件成功。
下面就直接贴代码了:
将数据库中的数据,转换为图片的方法
/*根据图片id (id可能为如下的数组)获取图片信息,包括图片的二进制流和图片类型等 待将 二进制 处理为图片
array(3) {
[0] => string(4) "1166"
[1] => string(4) "1167"
[2] => string(4) "1168"
参数: 图片的id 数组形式
返回:所有图片的 名称
}*/
function getPic(array $arr){
// 会存在不同的管理员登陆后台 重复生成图片问题
for($i=0; $i<count($arr); $i++){
$where['Id']=$arr[$i];
$pic=M('Picture')-> where($where) -> find();
// 文件的后缀名
$az = explode('image/',$pic['mimetype']);
// var_dump($az);
if($az[1] == 'jpeg'){
$az[1] = 'jpg';
}
// var_dump($where['Id']);
// 因为 轮播图处 目前需要更新 需要重新生成 id 相同的图片的 信息 故 先关闭检查 功能
$fid = "fk_".$arr[$i];
//checkPic($arr[$i]);
if(checkPic($arr[$i])){
// 图片生成过 将图片名称 返回
$picInfo[$arr[$i]]=$_SESSION[$fid];
}else{
// 没有生成过图片 调用生成图片的函数
// $pic['picturebinary'] 图片的16进制数据
$filename = getPicFile($pic['picturebinary'],$az[1]);
// 让图片 id 与 图片名称一一对应
$picInfo[$arr[$i]]=$filename;
// $_SESSION 存储的值 不能是数字
$_SESSION[$fid ] = $filename;
//将新的图片id和名称也存储再 S 缓存中 保存一周 60*60*24*7=604800
// $picinfoa[$fid] = $filename;
// S('picinfo', $picinfoa);
}
}
return $picInfo;
}
// 检查图片是否被生成过
function checkPic($pid){
$fid = "fk_".$pid;
// $cache = S('picinfo');
// $arr[$i]====图片id 避免重复生成图片, 将已 生成的图片 id 及 图片名称 存入session 传过来 图片 id 时,与 session 中存在的 图片 id 进行比对
foreach ($_SESSION as $key => $value) {
if($fid == $key){
// 图片已经生成过
return true;
}
}
//图片没有生成过
return false;
}
/*
参数:$im_data 从数据库中读出来的 16 进制的 字符串
返回:图片名称
*/
function getPicFile($im_data,$hz)
{
// 生成的图片保存路径
$filepath = './Public/img/';
// var_dump($hz);
// 随机生成文件名
do{
$filename = date('YmdHis',time()).rand(1000000,9999999).'.'.$hz;
}while(file_exists($filepath.$filename));
// var_dump($filename);
// 打开图片文件 b 代表 二进制形式
$newFile = fopen($filepath.$filename,"wb");
// 使用 hex2bin 将 16进制的字符串转换为 二进制的字符串
$image_data = hex2bin ($im_data);
// 将二进制字符串写到图片文件中
fwrite($newFile, $image_data);
fclose($newFile); //关闭文件
return $filename;
}
上传图片,将图片转为二进制数据流,并 再次转为 16 进制字符,写入sql server数据库( 此处只能写原生语句)
// 上传图片处理
public function upload()
{
// 获取到图片id ,将图片 id 和 href 存入到 轮播图表
//var_dump($_FILES);
//var_dump($_POST);
//die;
include './Application/Admin/Conf/fileupload.php';
$pp = 'slide';
// var_dump($pdo);
if($_FILES[$pp]['error'] == 0){
// 图片表 的必须数据
$data['UpdatedOnUtc'] = date('Y-m-d H:i:s',time());
// 调用上传方法
$binary = self::upload_file($pp);
switch ($binary) {
case 0:
return $this -> error('没有文件被上传',U('Admin/Site/index'));
break;
case 1:
return $this -> error('对不起,您上传的图片类型不符合规则',U('Admin/Site/index'));
break;
case 2:
return $this -> error('对不起,您上传的图片大小不符合规则',U('Admin/Site/index'));
break;
case 3:
return $this -> error('对不起,文件读取失败',U('Admin/Site/index'));
default:
$data['picdata'] = $binary;
break;
}
//var_dump($data);
// die;
// 有文件上传
if(!$_POST['pid']){
// pid 不存在,则说明是 全新上传 insert 操作 需要向 图片表 轮播图表 插入新的数据
$sql = "insert into Picture(PictureBinary,MimeType,UpdatedOnUtc,IsNew,IsTransient) values({$data['picdata']['PictureBinary']}, '{$data['picdata']['MimeType']}', '{$data['UpdatedOnUtc']}', 1, 1)";
$row = $pdo -> exec($sql);
if($row){
$pid = $pdo -> lastInsertId();
// 将图片的 id 插入到 轮播图表 solid picid href
$slid = M('slide');
$data['PicId'] = $pid;
$data['Href'] = I('post.slide-href');
$slid -> create($data);
$res = $slid -> add();
if(!$res){
return $this -> error('图片上传错误',U('Admin/Site/index'));
}
return $this -> success('轮播图上传成功',U('Admin/Site/index'));
}
}else{
// 如果 pid 存在 则说明是更新 图片 只需要更新图片的 二进制流数据, 以及 轮播图表里面的 href
$sql2 = "insert into Picture(PictureBinary,MimeType,UpdatedOnUtc,IsNew,IsTransient) values({$data['picdata']['PictureBinary']}, '{$data['picdata']['MimeType']}', '{$data['UpdatedOnUtc']}', 1, 1)";
// echo $sql2;
$row = $pdo -> exec($sql2);
if(!$row){
// 更新失败
return $this -> error('对不起,轮播图更新失败',U('Admin/Site/index'));
}
$pid = $pdo -> lastInsertId();
$sql1 = "update slide set href='{$_POST['slide-href']}',picid='{$pid}' where id={$_POST['sid']}";
$r2 = $pdo -> exec($sql1);
// var_dump($r2);
// die;
if(!$r2){
return $this -> error('对不起,轮播图链接更新失败',U('Admin/Site/index'));
}
return $this -> success('轮播图更新成功',U('Admin/Site/index'));
}
}else{
// 没有文件上传 也有可能是只更新链接 轮播图表
if($_POST['slide-href']){
$sql = "update slide set href='{$_POST['slide-href']}' where id={$_POST['sid']}";
$row = $pdo -> exec($sql);
if($row){
//如果受影响行数存在 ,则说明更新成功
return $this -> success('更新链接成功',U('Admin/Site/index'));
}else{
return $this -> error('更新失败',U('Admin/Site/index'));
}
}
return $this -> error('没有文件被上传',U('Admin/Site/index'));
}
}
// 上传图片的判断
private function upload_file($pp)
{
if($_FILES[$pp]['error'] == 0){
// 有文件上传
// 允许文件上传的类型
$allowmime = ['image/bmp','image/gif','image/jpeg','image/png'];
if(!in_array($_FILES['slide']['type'], $allowmime)){
// return $this -> error('对不起,您上传的图片不符合规则',U('Admin/Site/index'));
return 1;
}
// 允许上传的文件大小 1MB 1048576
if($_FILES['slide']['size'] > 1048576){
// return $this -> error('对不起,您上传的图片不符合规则',U('Admin/Site/index'));
return 2;
}
//图片类型 大小 都符合要求后 将临时文件夹中的上传图片 转为 二进制数据流
$data['MimeType'] = $_FILES[$pp]['type'];
// 以二进制流的方式打开一个文件
$fp = fopen($_FILES[$pp]['tmp_name'], 'r');
if(!$fp){
// return $this -> error('对不起,读取文件失败!',U('Admin/Site/index'));
return 3;
}
$data['PictureBinary'] = '0x'.bin2hex(stream_get_contents($fp));
//关闭文件
fclose($fp);
return $data;
}else{
// 没有文件被上传
return 0;
}
}
这个问题最重要的是,插入二进制数据时,不能使用 单引号或者双引号将二进制数据括起来。否则,数据库会将它当成长字符串来处理,从而报错(不能将 narchar(max)隐式转换为varbinary(max))
这是自己项目的小记录,也希望能帮助到有需要的人。O(∩_∩)O~
2 个解决方案
#1
大牛们,有更好的方法,也请不吝赐教,让我们学习
#1
大牛们,有更好的方法,也请不吝赐教,让我们学习