1、fpassthru()输出图片
fpassthru() 函数从打开文件的当前位置开始读取所有数据,直到文件末尾(EOF),并向输出缓冲写结果。
1. 新建image.php
<?php $picPath = '1.jpg'; $mimeType = getMimeType($picPath); $fp = fopen($picPath, 'rb'); header('Content-Type: ' . $mimeType); header("Content-Length: " . filesize($picPath)); fpassthru($fp); exit; function getMimeType($pathORdata, $isData = false) { if (!$isData && !file_exists($pathORdata)) { return false; } if (!class_exists("finfo")) { return false; } $finfo = new finfo(FILEINFO_MIME_TYPE, null); if ($isData) { $mime_type = $finfo->buffer($pathORdata); } else { $mime_type = $finfo->file($pathORdata); } if (!$mime_type) { return false; } return $mime_type; }
2、新建image.html
<img src="image.php" alt="" style="height: 200px;">
2、输出二进制图片
<?php //输出二进制图片 ob_clean(); //清除缓冲区,防止出现“图像因其本身有错无法显示'的问题 //图片路径 $file_name = "./1.jpg"; //获取图片的mime类型 $mime_type = mime_content_type($file_name); //显示图片 echo "<img width='250px' height='250px' src='data:".$mime_type.";base64,".base64_encode(file_get_contents($file_name))."'>";
浏览器访问,输出图片。
3、php将图片进行base64加密、再base64解密还原图片
1、新建 base64.php
$data是一段经过base64编码的图片
<?php $file_name = "./1.jpg"; $data = base64_encode(file_get_contents($file_name)); $img = base64_decode($data); echo $img;
2. 引用图片的方法:
<img src="base64.php">
php实现对图片对称加解密(适用身份证加密等场景)
对用户上传的敏感图片数据,进行加密处理,即时访问 url 也不能正常访问。
参考:
php使用openssl_encrypt和openssl_decrypt进行AES加密解密
php mcrypt 加密图片,PHP mcrypt启用、加密以及解密过程详解
1. 新建 upload.php
<?php /** * 用户上传图片 * 1. 生成唯一文件名,并把临时图片写入到安全目录 * 2. 把文件名及 iv(初始化向量) 保存记录到 表table1 * 3. 数据库 table2 记录生成的url访问地址 * 4. 步骤2可以分离出去,作为图片系统的整体使用 */ header('content-type:text/html;charset=utf-8'); $tempPic = "1.jpg"; //临时上传文件 $picPath = "1649437632.jpg"; //生成新的图片 $picName = '1649437632'; //生成新的图片的文件名 //使用salt 和 文件名生成唯一 iv(初始化向量) $salt = "encrypt"; $iv = base64_encode(crypt($picName, $salt)); $picData = file_get_contents($tempPic); $result = encrypt($picData, $iv); if(!$result){ exit('error 100'); } //把加密后的图片数据写入新的文件 $picPath if(!file_put_contents("./upload/".$picPath, $result)){ exit('文件写入失败'); } //生成加密后图片的访问地址 http://localhost/base64/upload/1649437632.jpg $picUrl = "http://localhost/base64/upload/".$picPath; //1.连接 $link=mysqli_connect('localhost','root','','test') or die('Connect Error:'.mysqli_connect_errno().":".mysqli_connect_error()); //2.设置编码方式 mysqli_set_charset($link,'UTF8'); ####保存到table1####### //3.执行SQL查询 $sql="INSERT table1(`pic`,`iv`) VALUES('$picName', '$iv');"; $res=mysqli_query($link, $sql); if(!$res){ echo 'ERROR:'; echo mysqli_errno($link).':'.mysqli_error($link); } echo 'AFFECTED ROWS:'.mysqli_affected_rows($link)."<br/>"; ####保存到table2######## $sql="INSERT table2(`url`) VALUES('$picUrl');"; $res=mysqli_query($link, $sql); if(!$res){ echo 'ERROR:'; echo mysqli_errno($link).':'.mysqli_error($link); } echo 'AUTO_INCREMENT:'.mysqli_insert_id($link)."<br/>"; echo 'AFFECTED ROWS:'.mysqli_affected_rows($link); //4.关闭连接 mysqli_close($link); exit("操作成功"); /** * 加密 */ function encrypt($data, $iv) { if ($data== null || empty($data)) { return $data; } $result= base64_encode(@openssl_encrypt( $data, "aes-256-cbc", 'aa11bb22cc33dd44ee55ff66gg77hh88ii990', 0, $iv)); return $result; }
2. 列表循环展示生成的加密图片。
新建test.html
<a href="showPic.php?url=http://localhost/base64/upload/1649437632.jpg" target="_blank"> <img src="showPic.php?url=http://localhost/base64/upload/1649437632.jpg" width="250px" height="250px"> </a>
3.解密图片,二进制输出并展示图片信息
新建 showPic.php
<?php /* * 解密显示前端访问的url,二进制输出图片 * 1. 校验当前查看用户是否拥有权限,没有权限的人显示一张error.jpg的图片 * 2. 根据图片文件名 获取对应的 iv(初始化向量) * 3. 根据url返回url的实际路径地址 * 此url已加密,所以直接访问是访问不到的, * 4. 判断文件是否存在 * 5. 解密图片 */ // $url = $_REQUEST['url'] ?? "http://localhost/base64/upload/1649437632.jpg"; // 获取图片的文件名和物理路径 $filenamePath = './upload/1649437632.jpg'; $picname = '1649437632';//图片文件名 $mysqli=new mysqli('localhost','root','','test'); if($mysqli->errno){ var_dump(2222);die; ouputError(); //die('Connect Error'.$mysqli->error); } $mysqli->set_charset('UTF8'); $picname = $mysqli->escape_string($picname); $sql="SELECT * FROM table1 WHERE pic='{$picname}'"; $mysqli_result=$mysqli->query($sql); if(!$mysqli_result || $num = $mysqli_result->num_rows<0) { var_dump(3333);die; ouputError(); } $row= $mysqli_result->fetch_assoc(); $mysqli_result->close(); $mysqli->close(); $iv = $row['iv']; $picData = file_get_contents($filenamePath); $decrypted = decode($picData, $iv); $mimeType = getMimeType($decrypted, true); header('Content-Type: ' . $mimeType); echo $decrypted; exit; function ouputError($picPath="D:/wamp/www/base64/error.jpg") { $mimeType = mime_content_type($picPath); header('Content-Type: ' . $mimeType); $fp = fopen($picPath, 'rb'); fpassthru($fp); exit; } /** * 解密 */ function decode($data, $iv) { if ($data== null || empty($data)) { return $data; } $result= @openssl_decrypt(base64_decode($data), "aes-256-cbc", 'aa11bb22cc33dd44ee55ff66gg77hh88ii990', 0, $iv); return $result; } function getMimeType($pathORdata, $isData = false) { if (!$isData && !file_exists($pathORdata)) { return false; } if (!class_exists("finfo")) { return false; } $finfo = new finfo(FILEINFO_MIME_TYPE, null); if ($isData) { $mime_type = $finfo->buffer($pathORdata); } else { $mime_type = $finfo->file($pathORdata); } if (!$mime_type) { return false; } return $mime_type; }
1)、浏览器访问 http://localhost/base64/upload.php ,上传图片
2)、浏览器访问 http://localhost/base64/test.html ,展示加密图片信息。
php实现对图片对称加解密
// 可以将人员身份证图片通过修改字节加密,并且可将身份证信息也写入图片中。 class Encrypt { /** * 图片对称加密 * * @param [string] $filePath 图片路径 * @return void */ public function enc($filePath) { // 文档中建议:为移植性考虑,强烈建议在用 fopen() 打开文件时总是使用 'b' 标记。 $fileId = fopen($filePath, 'rb+'); // 取出文件大小的字节数 (29124) $fileSize = fileSize($filePath); // 读取文件,返回所读取的字符串 (读出来的为二进制序列) $img = fread($fileId, $fileSize); // 使用“无符号字符”,从二进制字符串对数据进行解包 // (pack、unpack用法)https://segmentfault.com/a/1190000008305573 $imgUnpack = unpack('C*', $img); // $fileSize 长度的一维数组 [ 1=>255, 2=>216, 3=>255, ……, 29124=>217 ] // 关闭一个已打开的文件指针 fclose($fileId); $tempArr = []; // 自定义加密规则 for ($i = 1; $i <= $fileSize; $i++) { $value = 0; if ($i % 3 == 0) { $value = 2; } elseif ($i % 5 == 0) { $value = 4; } elseif ($i % 7 == 0) { $value = 6; } $byte = $imgUnpack[$i]; // 图片原始字节 $byte = $byte + $value; // 经过加密规则之后的字节 // 打包成二进制字符串 $tempArr[] = pack('C*', $byte); } $img = implode('', $tempArr); // 将解包之后的一维数组装换成字符串 file_put_contents($filePath, $img); // 重写图片 } /** * 图片对称解密 * * @param [string] $filePath 图片路径 * @return void */ public function dec($filePath) { $fileId = fopen($filePath, 'rb+'); $fileSize = filesize($filePath); $img = fread($fileId, $fileSize); $imgUnpack = unpack('C*', $img); fclose($fileId); $tempArr = []; // 开始解密 for ($i = 1; $i <= $fileSize; $i++) { $value = 0; if ($i % 3 == 0) { $value = 2; } elseif ($i % 5 == 0) { $value = 4; } elseif ($i % 7 == 0) { $value = 6; } $byte = $imgUnpack[$i]; $byte = $byte - $value; $tempArr[] = pack('C*', $byte); } $img = implode('', $tempArr); file_put_contents($filePath, $img); } /** * 图片追加信息 * * @param [string] $filePath 图片路径 * @param [array] $cardmsg 需要添加的信息数组 * @param [array] $separate 分隔数组(类似于做一个加密分隔 key) * @return void */ public function encmsg($filePath, $cardmsg, $separate) { // 文档中建议:为移植性考虑,强烈建议在用 fopen() 打开文件时总是使用 'b' 标记。 $fileId = fopen($filePath, 'rb+'); // 取出文件大小的字节数 (29124) $fileSize = fileSize($filePath); // 读取文件,返回所读取的字符串 (读出来的为二进制序列) $img = fread($fileId, $fileSize); // 使用“无符号字符”,从二进制字符串对数据进行解包 // (pack、unpack用法)https://segmentfault.com/a/1190000008305573 $imgUnpack = unpack('C*', $img); // $fileSize 长度的一维数组 [ 1=>255, 2=>216, 3=>255, ……, 29124=>217 ] // 关闭一个已打开的文件指针 fclose($fileId); // 处理身份信息 $cardmsgJson = json_encode($cardmsg, JSON_UNESCAPED_UNICODE); $cardmsgUnpack = unpack('C*', $cardmsgJson); // 合并图片字节、自定义分隔数组(类似手动加 key 值)、身份信息字节 $mergeArr = array_merge($imgUnpack, $separate, $cardmsgUnpack); $pack = []; foreach ($mergeArr as $k => $v) { $pack[] = pack('C*', $v); } $packStr = join('', $pack); file_put_contents($filePath, $packStr); // 重写图片 } /** * 获取追加进图片的信息 * * @param [string] $filePath 图片路径 * @param [array] $separate 定义的分隔数组(分隔 key) * @return [string] 追加进的图片信息 */ public function decmsg ($filePath, $separate) { // 文档中建议:为移植性考虑,强烈建议在用 fopen() 打开文件时总是使用 'b' 标记。 $fileId = fopen($filePath, 'rb+'); // 取出文件大小的字节数 (29192) $fileSize = fileSize($filePath); // 读取文件,返回所读取的字符串 (读出来的为二进制序列) $img = fread($fileId, $fileSize); // 使用“无符号字符”,从二进制字符串对数据进行解包 $imgUnpack = unpack('C*', $img); // $fileSize 长度的一维数组 [ 1=>255, 2=>216, 3=>255, ……, 29192=>217 ] // 关闭一个已打开的文件指针 fclose($fileId); $imgUnpackStr = join(',',$imgUnpack); // 将一维数组转换为字符串 $separateStr = implode(',', $separate); // 将一维数组转换为字符串 $imgAndCardmsgArr = explode($separateStr, $imgUnpackStr); // 以自定义分隔符分隔出图片字节和身份信息字节 $cardmsgArr = explode(',', $imgAndCardmsgArr[1]); // 取出身份信息字节 unset($cardmsgArr[0]); // 去除身份信息字节首位空白 (字符串转数组时所留) $cardmsg = ''; foreach ($cardmsgArr as $k => $v) { $cardmsg .= pack('C*', $v); // 打包成二进制文件字符串 } return json_decode($cardmsg, true); } } $encrypt = new Encrypt(); $path = 'D:\software\wamp64\www\image\1.jpg'; $separate = [255, 0, 255, 0, 255, 0, 255, 206, 210, 202, 199, 183, 214, 184, 244]; // 15字节 $cardmsg = ['name' => '张三', 'gender' => '男', 'idcard' => 12345678910]; // 53字节 var_dump($encrypt->decmsg($path, $separate));
PHP实现支持加盐的图片加密解密
一个简单的图片加解密函数,使用命令行模式(cli)运行
<?php $notice = <<<A 为了稳定性,必须在客户端跑 格式 :php path=D:/xxx/uuu type=en is_copy=1 salt=xxx 参数使用空格分开 path -- 路径 必须写 type -- en加密, de为解密 必须写 is_copy -- 1为复制,0为转移, 不写默认为转移 salt -- 加密钥匙 加密用什么,解密就用什么 不写默认为salt A; //如果不是客户端 if(PHP_SAPI != 'cli') {echo $notice;die;} //获取参数 $arr = parse_parameter($argv); //如果路径没设置 if(!isset($arr['path']) || !isset($arr['type'])) {echo $notice;die;} //如果is_dir没设置 if(!isset($arr['is_copy'])) {$arr['is_copy'] = '';} //如果salt没设置 if(!isset($arr['salt'])) {$arr['salt'] = '';} //type为en就加密 if($arr['type'] == "en") img_enconde($arr['path'], $arr['is_copy'], $arr['salt']); //type为de就解密 if($arr['type'] == "de") img_deconde($arr['path'], $arr['is_copy'], $arr['salt']); function parse_parameter($argv) { $arr = array(); //获取参数 for($len=count($argv)-1; $len--; ) { list($key, $val) = explode('=', $argv[$len]); $arr[$key] = $val; } return $arr; } //图片加密函数 //路径文件夹 //是否为复制(默认不复制) //盐(默认为salt) function img_enconde($path, $is_copy = 0, $salt = 'salt') { $time1 = microtime(1); $handle = opendir($path); if(!$salt) $salt = 'salt'; if($handle) { echo "路径:" . $path . "\r\n\r\n"; //在指定文件夹下创建临时文件夹 $temp_dir = $path . '\\' . 'temp'; @mkdir($temp_dir, 0777, 1); while ($file = readdir($handle)) { $time2 = microtime(1); //构造当前文件绝对地址 $dir_path = $path . '\\' . $file; //获取文件后缀 $suffix = strrchr($file, '.'); //图片后缀 $fix = array('.jpg', '.gif', '.bmp', '.png', '.jpeg', '.JPG', '.GIF', '.BMP', '.PNG', 'JPEG'); if(is_file($dir_path) && in_array($suffix, $fix)) { //打开当前文件 $fh = fopen($dir_path, 'r'); //打开文件为流 $stream = fread($fh, filesize($dir_path)); //输出 file_put_contents($temp_dir . '\\' . uniqid('',1), $file . '!' . $salt . '@' . $stream); //关闭句柄 fclose($fh); //是否为复制 //1为复制,0为删除(默认) if(!$is_copy) { echo "加密并删除 : " . $dir_path . "\r\n"; @unlink($dir_path); } else { echo "加密 : " . $dir_path . "\r\n"; } $time3 = microtime(1); echo "此图用时 ", ($time3 - $time2), " S\r\n", "已经用时 ", ($time3 - $time1), " S\r\n\r\n"; } } echo "加密完成\r\n"; } else { echo "path invalid "; return false; } } //图片解密函数 //路径文件夹 //是否为复制(默认不复制) //盐(默认为salt)加密写什么,这里就写什么 function img_deconde($path, $is_copy = 0, $salt = '') { $time1 = microtime(1); $handle = opendir($path); if($handle) { echo "路径:" . $path . "\r\n\r\n"; if(!$salt) $salt = 'salt'; //在指定文件夹下创建临时文件夹 $temp_dir = $path . '\\' . 'temp'; @mkdir($temp_dir, 0777, 1); //核心正则 $reg = "#^(.+?[jpgifbmne]{3,4})!(" . $salt . ")@#im"; $res = array(); $count = 0; while ($file = readdir($handle)) { $time2 = microtime(1); //构造当前文件绝对地址 $file_path = $path . '\\' . $file; if(is_file($file_path)) { //文件句柄 $hf = fopen($file_path, 'r'); //返回流 $stream = fread($hf, filesize($file_path)); fclose($hf); //匹配加的密码 if(preg_match_all($reg, $stream, $res)) { $count++; //清空盐 $stream = str_replace($res[0][0], '', $stream); //输出文件 file_put_contents($temp_dir . '\\' . $res[1][0], $stream); //是否为复制 //1为复制,0为删除(默认) if(!$is_copy) { echo "成功解密删除 : " . $temp_dir . '\\' . $res[1][0] . "\r\n"; @unlink($file_path); } else { echo "解密 : " . $temp_dir . '\\' . $res[1][0] . "\r\n"; } } $time3 = microtime(1); echo "此图用时 ", ($time3 - $time2), " S\r\n", "已经用时 ", ($time3 - $time1), " S\r\n\r\n"; } } if(!$count) { echo "没有有效的加密文件\r\n"; return false; } echo "解密完成\r\n"; } else { echo "path invalid "; return false; } }
本文为崔凯原创文章,转载无需和我联系,但请注明来自冷暖自知一抹茶ckhttp://www.cksite.cn