15
回答
请问php有没有可逆加密解密函数,不要base64,最好是能加密成散列
终于搞明白,存储TCO原来是这样算的>>>   

我网站的图片很多,但都是实时调用其他大型网站的,不是自己的。后台是这么一个过程:先搜集其他网站图片的原始地址,计算其md5值,生成以md5值为键名,原始地址为键值的数组,serialize后分组保存到硬盘上,自己网站图片的url中包含这个md5值。前台用户访问的时候都是先根据图片url中的md5值查找到原始地址,再用file_get_contens函数调用其他大型网站的原始地址,然后设置header("Content-type:image/jpeg"),再给用户显示出来。比如http://www.5umao.com/imgs/c-50103018-03defd4c00bc654561c9b5e4f3bc0150.jpg这张图片,"03defd4c00bc654561c9b5e4f3bc0150"是原始地址的md5值,你在访问的时候后台就是先根据这个md5值查询到原始地址,然后去抓取返回给你,图片并没有保存在自己的服务器上。

现在的问题是,整站大概有近千万张图片,而且在更新时为了保留原始图片不失效,图片数量还在持续增加,目前光serialize后的文件(保存图片的md5值和对应的原始地址)就有1G多。

现在我就想找到一个php加密解密函数,在用户访问图片的时候能根据加密后的地址实时计算出原始图片地址,这样就不需要去后台查询。要求不要像base64那样生成一长串密文,最好能像32位的md5值那样,加密后是固定位数的散列,还能解密。

请问能实现吗?谢谢各位了。或者有其他更好的处理海量图片的方法。

PHP
举报
鹏鹏鸟
发帖于4年前 15回/9K+阅
共有15个答案 最后回答: 2个月前
这样的话效率可慢了,还不如搞成独立的图片服务器,弄个加速什么的,url加密嘛,建议你存到数据库输出一个id码算了,查数据库比你这么加密解密靠谱

md5 实际上并不是一种加密算法..只是计算hash散列值..

如果要加密并且可以解密的话,固定长度是不可能的..

其实base64 也不是加密,只是编码.

其实最好的思路是 用k-v的数据库 来存储 md5之后的值和原始图片的地址
--- 共有 1 条评论 ---
鹏鹏鸟kv数据库,还没研究过,先考虑一下再说。 4年前 回复

还可以借用短网址来实现

$host = "126.am/"; //网易短网址
$url="http://www.5umao.com/imgs/c-50103018-03defd4c00bc654561c9b5e4f3bc0150.jpg";
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,"http://".$host."short.action");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$data=array('json'=>json_encode(array('urls'=>array(array("url"=>$url)))));
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
$r=curl_exec($ch);
curl_close($ch);
$r=json_decode($r,true);

$img=str_replace($host,"",$r['shortUrls'][0]['url']); //得到图片地址

//echo $img; //输出字符串 hUVOa4,该字符串可以作为图片文件名

//读取并输出图片
header("Content-type:image/jpeg");
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,"http://".$host."$img");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,true);
echo curl_exec($ch);
curl_close($ch);

上述代码就是 把 示例图片 http://www.5umao.com/imgs/c-50103018-03defd4c00bc654561c9b5e4f3bc0150.jpg

先通过短网址转换成很短的字符串.

然后通过短网址服务器跳转真实的地址并获取图片输出

--- 共有 5 条评论 ---
鹏鹏鸟回复 @酒逍遥 : 嗯,做个备用方案也可以,原图片是淘宝的商品图片,淘宝都是保留原始图片地址的,我还是建立数据库吧。 4年前 回复
酒逍遥@鹏鹏鸟 这个概率应该是比较小的.你要不放心就用你原来的方法做个备用方案.平时不用,如果网易的短网址服务关了就切换回去.不过我觉得原图片挂掉的可能性会更大 4年前 回复
鹏鹏鸟回复 @酒逍遥 : 方式是可以,但万一要是网易的短网址服务关掉了怎么办? 4年前 回复
酒逍遥回复 @鹏鹏鸟 : 不大的..本质上和你用file_get_contents 函数去读别人服务器上的图片是一样的. 就是多了个301跳转而已.跳转在curl函数内部消化掉了.性能开销不是很大. 你可以做个测试就知道了. 4年前 回复
鹏鹏鸟这样的话,每次展示图片的时候,后台还得去访问网易的服务器,性能上应该有很大的开销吧 4年前 回复

Discuz 中经典的加密解密函数,可以解决你的问题

// $string: 明文 或 密文  
// $operation:DECODE表示解密,其它表示加密  
// $key: 密匙  
// $expiry:密文有效期  
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {  
    // 动态密匙长度,相同的明文会生成不同密文就是依靠动态密匙  
    $ckey_length = 4;  
      
    // 密匙  
    $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);  
      
    // 密匙a会参与加解密  
    $keya = md5(substr($key, 0, 16));  
    // 密匙b会用来做数据完整性验证  
    $keyb = md5(substr($key, 16, 16));  
    // 密匙c用于变化生成的密文  
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';  
    // 参与运算的密匙  
    $cryptkey = $keya.md5($keya.$keyc);  
    $key_length = strlen($cryptkey);  
    // 明文,前10位用来保存时间戳,解密时验证数据有效性,10到26位用来保存$keyb(密匙b),解密时会通过这个密匙验证数据完整性  
    // 如果是解码的话,会从第$ckey_length位开始,因为密文前$ckey_length位保存 动态密匙,以保证解密正确  
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;  
    $string_length = strlen($string);  
    $result = '';  
    $box = range(0, 255);  
    $rndkey = array();  
    // 产生密匙簿  
    for($i = 0; $i <= 255; $i++) {  
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);  
    }  
    // 用固定的算法,打乱密匙簿,增加随机性,好像很复杂,实际上对并不会增加密文的强度  
    for($j = $i = 0; $i < 256; $i++) {  
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;  
        $tmp = $box[$i];  
        $box[$i] = $box[$j];  
        $box[$j] = $tmp;  
    }  
    // 核心加解密部分  
    for($a = $j = $i = 0; $i < $string_length; $i++) {  
        $a = ($a + 1) % 256;  
        $j = ($j + $box[$a]) % 256;  
        $tmp = $box[$a];  
        $box[$a] = $box[$j];  
        $box[$j] = $tmp;  
        // 从密匙簿得出密匙进行异或,再转成字符  
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));  
    }  
    if($operation == 'DECODE') {  
        // substr($result, 0, 10) == 0 验证数据有效性  
        // substr($result, 0, 10) - time() > 0 验证数据有效性  
        // substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16) 验证数据完整性  
        // 验证数据有效性,请看未加密明文的格式  
        if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {  
            return substr($result, 26);  
        } else {  
            return '';  
        }  
    } else {  
        // 把动态密匙保存在密文里,这也是为什么同样的明文,生产不同密文后能解密的原因  
        // 因为加密后的密文可能是一些特殊字符,复制过程可能会丢失,所以用base64编码  
        return $keyc.str_replace('=', '', base64_encode($result));  
    }  
}
--- 共有 4 条评论 ---
悦澜殇这个不错,可以用来做邮件验证, 3年前 回复
苏生不惑这个加密不错 4年前 回复
鹏鹏鸟可以是可以,可惜加密的字符串太长了,还有有效期。我还是建立数据库吧,把md5值映射得到url 4年前 回复
鹏鹏鸟多谢了,等会试试 4年前 回复
楼主用MD5来做键名不怕冲突吗?
--- 共有 6 条评论 ---
游侠回复 @鹏鹏鸟 : 比如redis就支持MGET,亿级的key数量应该还好。到后期由于key太多导致的性能问题也可以用多机来解决。 4年前 回复
鹏鹏鸟回复 @游侠 : 因为是采集淘宝的图片,直接用base64加密图片地址的话,一个是字符串太长,百度图片蜘蛛好像抓的不怎么好,另一个就是百度好像能识别用base64_encode方式加密的淘宝图片地址,判断你为一个作弊采集站,还是用自己的url编码安全些 4年前 回复
鹏鹏鸟回复 @游侠 : 存储可以的,主要是图片数量太大,到了后期估计有几亿张,如果存储的话,每个页面的都有50张图片要加载,连续读取数据库,会不会性能成问题? 4年前 回复
游侠回复 @鹏鹏鸟 : 2。我觉得楼主说的base64_encode挺好,不知道哪里不满足需求。 然后我对楼主业务的理解可能有偏差,楼主有兴趣可以回复下。 4年前 回复
游侠回复 @鹏鹏鸟 : 主要不太清楚楼主纠结的地方是不愿意访问存储,还是存储太大,然后为什么base64_encode也不行。 我给楼主说下我的想法: 1。使用存储的话,存储里key可以使用int自增,或者比较短的字符串等,没必要用md5那样长的;使用K/V存储能提高点性能,类似redis的那种。 4年前 回复
顶部