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