图片输出的几种方式及加解密

         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 也不能正常访问。

        参考:

                图片加密,在实际项目中的应用 

                openssl_encrypt decrypt实现加密解密

                php使用openssl_encrypt和openssl_decrypt进行AES加密解密

                php如何openssl_encrypt加密解密

                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;
    }
}

        

 

 

 

 

 

 

冷暖自知一抹茶ck
请先登录后发表评论
  • 最新评论
  • 总共0条评论