用php代码破解新浪图片防盗链的问题(wordpress专用)

解决微博图床防盗链无非有下面几种:
1、在标签里添加:

<meta name="referrer" content="no-referrer" />

这段代码简单易上手,直接在wordpress的主题文件找到header.php,在中间加入上述代码,全站的图片立马恢复本来面目。但是,缺点很明显:从你网站引导到其他网站的流量不显示来路,对于挂广告的站点来说,风险极大,容易被联盟封号。而且不利于分析网站的营销能力。所以,只能做个备选项了。

2、用nginx做反代。这个方法相对复杂,但是却最可靠,需要的小伙伴可以参考下面的代码自己部署:

<?php

/**
 * 1.增加对gif的支持
 * 2.对源图片的显示
 * 3.非常强悍,哪怕url有跳转,也能正常显示最终的图片
 * 4.gif不支持水印,其他格式没问题
 * 5.支持https了
 * 6.对有错的、不存在的图片,进行友好的提示
 */

 class ImgBridge{
    private $water='';
    private $imgUrl=''; 
    private $referer='';
    private $ua='MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1';
    private $imgCode='';
    private $imgHeader='';
    private $imgBody='';
    private $imgType='';

    public function __construct($config=array()){
        foreach($config as $key=>$value){
            $this->$key=$value;
        }
    }
    
    public function getImg($imgUrl){
        $this->imgUrl=$imgUrl;
        /** 处理url */
        if(substr($this->imgUrl,0,7)!=='http://' && substr($this->imgUrl,0,8)!=='https://'){
            $this->imgUrl='http://'.$this->imgUrl;
        }
        /** 解析url中的host */
        $url_array=parse_url($this->imgUrl);
        /** 设置referer */
        $this->referer=$this->referer==""?'http://'.$url_array['host']:$this->referer;
        /**开始获取 */
        $this->urlOpen();
        $this->imgBody;
        /**处理错误 */
        if($this->imgCode!=200){
            $this->error(1);
            exit();
        }
        
        /**获取图片格式 */
        preg_match("/Content-Type: image\/(.+?)\n/sim",$this->imgHeader,$result);
        /**看看是不是图片 */
        if(!isset($result[1])){
            $this->error(2);
            exit();
        }else{
            $this->imgType=$result[1];
        }
        /** 输出内容 */
        $this->out();        
    }
    private function out(){
        /** gif 不处理,直接出图 */
        if($this->imgType=='gif'){
            header("Content-Type: image/gif");
            echo $this->imgBody;
            exit();
        }
        header("Content-Type: image/png");
        /** 其他类型的,加水印 */
        $im=imagecreatefromstring($this->imgBody);
        $white = imagecolorallocate($im, 255, 255, 255);
        /*加上水印*/
        if($this->water){
            imagettftext($im, 12, 0, 20, 20, $white, "/fonts/hwxh.ttf", $this->water);            
        }
        imagepng($im);
        
    }
    private function error($err){
        header("Content-Type: image/jpeg");
        $im=imagecreatefromstring(file_get_contents('./default.jpg'));
        imagejpeg($im);
    }

    private function urlOpen()
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->imgUrl);
        curl_setopt($ch, CURLOPT_USERAGENT, $this->ua);
        curl_setopt ($ch,CURLOPT_REFERER,$this->referer);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        /**跳转也要 */
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        /**  支持https */
        $opt[CURLOPT_SSL_VERIFYHOST] = 2;
        $opt[CURLOPT_SSL_VERIFYPEER] = FALSE;
        curl_setopt_array($ch, $opt);
        $response = curl_exec($ch);
        $this->imgCode=curl_getinfo($ch, CURLINFO_HTTP_CODE) ;
        if ($this->imgCode == '200') {
            $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
            $this->imgHeader = substr($response, 0, $headerSize);
            $this->imgBody = substr($response, $headerSize);
            return ;
        }
        curl_close($ch);
    }

 }

 $img=new ImgBridge(array('water'=>''));
 $img->getImg(strstr($_SERVER["QUERY_STRING"], "http"));

代码命名为img-reverse-proxy.php
那么直接可以访问
http://你的域名/img-reverse-proxy.php?url=防盗链图片地址

不过这样做有个缺陷就是所有的图片跑的都是你自己服务器的带宽(等于是你在给远程图片做CDN加速),虽然图片不在本地,不占磁盘空间,但是配置比较低的小鸡带宽可能吃不消。

3、修改微博图床生成的图片的服务器地址。比如,新浪几个常用的:wx1.sinaimg.cn,wx2.sinaimg.com,ws2.sinaimg.cn等,直接修改为:tva1.sinaimg.cn。这个方法现在还可以正常使用。但不知道能挺多久。

4、这其实是第1种方法的变种。将“no-referrer”标签直接添加到文章中微博图片的img标签里。具体代码如下:

/** Auto-Generate referrerpolicy="no-referrer" to images **/
/** 解决新浪微博图床防盗链**/
function image_referrerpolicy_tag($content){
    global $post;preg_match_all('/<img(.*?)sinaimg(.*?)\/>/', $content, $images);
    if(!is_null($images)) {foreach($images[1] as $index => $value)
    {
        $new_img = str_replace('<img', '<img referrerpolicy="no-referrer"', $images[0][$index]);
        $content = str_replace($images[0][$index], $new_img, $content);}}
    return $content;
}
add_filter('the_content', 'image_referrerpolicy_tag', 99999);

这段代码的作用是:正则查找文章中有出现*.sinaimg.cn的图片,将【img】替换成【img referrerpolicy=”no-referrer”】。而如果不是微博图床的图片,则不需要替换。这样就堪称完美了。

文章前台查看源代码,会出现如下:

这样做还是有一定的缺陷:那就是部分老旧的浏览器,不支持这个referrerpolicy标签。不过受影响应该不是不大。算是我认为目前最完美的方法了。至于为什么不换其他图床,一方面是要钱,一方面是微博图床的打开速度确实给力!

补充一点:上述代码只是解决了前台新浪图床的图片显示的问题,如果在后台编辑器里面你也希望显示新浪图片的话,你还需要在functions.php里添加如下代码:

// 添加referrer标签
//add_action('wp_head', 'zm_admin_referrer');// 前端显示新浪图片(这一句可加可不加,加上后跟上面的第4点代码有冲突,二选一吧)
add_action('admin_head', 'zm_admin_referrer');// 后台也显示新浪图片
add_action('login_head', 'zm_admin_referrer');// 登录注册页面也显示新浪图片
function zm_admin_referrer(){
	echo'<meta name="referrer" content="no-referrer" />';
}

有的主题在文章详情页添加了相关文章(related articals)的推荐,如果新浪图片不显示的话,还可以直接到主题文件夹的下single.php里找到该图片调用的地方,在img标签里加上 referrerpolicy=”no-referrer”即可。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注