wordpress优化经历(六)——wordpress图片防盗链

背景

由于我写博客的习惯是先在本地把博客写好,然后图片什么的先放在本地,之后将博客在CSDN上进行markdown排版,并且将图片上传图加进去,在CSDN上先完成博客文章的发布;最后就直接将CSDN上的排版好的文章进行复制粘贴进自己的个人博客网站上,这样做的好处就是文章不用重新排版了,然后里面的图片资源也上传到了CSDN的服务器上,之后自己网站引用图片也是使用了CSDN的图片资源。但是最近出现了一个问题,CSDN上的图片全部失效了,原因是图片被防盗链处理,请求全部被跨域访问了,导致我个人网站的所有使用过CSDN排版的博客图片全部链接失效了,这导致我很头疼,这篇文章就记录一下这次图片被防盗链事故的处理经过。

wordpress优化经历(六)——wordpress图片防盗链-左眼会陪右眼哭の博客

解决方法

WordPress很多插件或者代码都可以实现在编辑文章中自动将外链图片下载到本地,但是我试了几个效果都不是很好。 最后选择了一个比较笨一点的方法,但是效果贼好。

  1. 将下面代码加到当前主题函数模板 functions.php 中:
代码语言:javascript
复制
function ecp_save_post($post_id, $post) {
  global $wpdb;
  if($post->post_status == 'publish') {
    $p   = '/<img.*[\s]src=[\"|\'](.*)[\"|\'].*>/iU';
    $num = preg_match_all($p, $post->post_content, $matches);
    if ($num) {
      $wp_upload_dir = wp_upload_dir();
      set_time_limit(0);
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_HEADER, false);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
      curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
      curl_setopt($ch, CURLOPT_MAXREDIRS,20);
      curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
  $ecp_options = $_SERVER[&#39;HTTP_HOST&#39;];
  foreach ($matches[1] as $src) {
    if (isset($src) &amp;&amp; strpos($src, $ecp_options) === false) {
      $file_info = wp_check_filetype(basename($src), null);
      if ($file_info[&#39;ext&#39;] == false) {
        date_default_timezone_set(&#39;PRC&#39;);
        $file_name = date(&#39;YmdHis-&#39;).dechex(mt_rand(100000, 999999)).&#39;.tmp&#39;;
      } else {
        $file_name = dechex(mt_rand(100000, 999999)) . &#39;-&#39; . basename($src);
      }
      curl_setopt($ch, CURLOPT_URL, $src);
      $file_path = $wp_upload_dir[&#39;path&#39;] . &#39;/&#39; . $file_name;
      $img = fopen($file_path, &#39;wb&#39;);
      curl_setopt($ch, CURLOPT_FILE, $img);
      $img_data  = curl_exec($ch);
      fclose($img);

      if (file_exists($file_path) &amp;&amp; filesize($file_path) &gt; 0) {
        $t   = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
        $arr = explode(&#39;/&#39;, $t);
        if (pathinfo($file_path, PATHINFO_EXTENSION) == &#39;tmp&#39;) {
          $file_path = ecp_handle_ext($file_path, $arr[1], $wp_upload_dir[&#39;path&#39;], $file_name, &#39;tmp&#39;);
        } elseif (pathinfo($file_path, PATHINFO_EXTENSION) == &#39;webp&#39;) {
          $file_path = ecp_handle_ext($file_path, $arr[1], $wp_upload_dir[&#39;path&#39;], $file_name, &#39;webp&#39;);
        }
        $post-&gt;post_content  = str_replace($src, $wp_upload_dir[&#39;url&#39;] . &#39;/&#39; . basename($file_path), $post-&gt;post_content);
        $attachment = ecp_get_attachment_post(basename($file_path), $wp_upload_dir[&#39;url&#39;] . &#39;/&#39; . basename($file_path));
        $attach_id = wp_insert_attachment($attachment, ltrim($wp_upload_dir[&#39;subdir&#39;] . &#39;/&#39; . basename($file_path), &#39;/&#39;), 0);
        $attach_data = wp_generate_attachment_metadata($attach_id, $file_path);
        $ss = wp_update_attachment_metadata($attach_id, $attach_data);
      }
    }
  }
  curl_close($ch);
  $wpdb-&gt;update( $wpdb-&gt;posts, array(&#39;post_content&#39; =&gt; $post-&gt;post_content), array(&#39;ID&#39; =&gt; $post-&gt;ID));
}

}
}

function ecp_handle_ext(file, type, file_dir, file_name, $ext) {
switch ($ext) {
case 'tmp':
if (rename(file, str_replace(&#39;tmp&#39;, type, $file))) {
if ('webp' == $type) {
return ecp_image_convert('webp', 'jpeg', file_dir . &#39;/&#39; . str_replace(&#39;tmp&#39;, type, $file_name));
}
return file_dir . &#39;/&#39; . str_replace(&#39;tmp&#39;, type, $file_name);
}
case 'webp':
if ('webp' == $type) {
return ecp_image_convert('webp', 'jpeg', $file);
} else {
if (rename(file, str_replace(&#39;webp&#39;, type, $file))) {
return file_dir . &#39;/&#39; . str_replace(&#39;webp&#39;, type, $file_name);
}
}
default:
return $file;
}
}

function ecp_image_convert(from=&#39;webp&#39;, to='jpeg', $image) {
im = imagecreatefromwebp(image);
if (imagejpeg(im, str_replace(&#39;webp&#39;, &#39;jpeg&#39;, image), 100)) {
try {
unlink($image);
} catch (Exception $e) {
error_msg = sprintf(&#39;Error removing local file %s: %s&#39;, image,
$e->getMessage());
error_log($error_msg);
}
}
imagedestroy($im);

return str_replace('webp', 'jpeg', $image);
}

function ecp_get_attachment_post(filename, url) {
file_info = wp_check_filetype(filename, null);
return array(
'guid' => $url,
'post_type' => 'attachement',
'post_mime_type' => $file_info['type'],
'post_title' => preg_replace('/.[^.]+/&#39;, &#39;&#39;, filename),
'post_content' => '',
'post_status' => 'inherit'
);
}
add_action('save_post', 'ecp_save_post', 120, 2);

  1. 编辑更新文章

单篇操作
之后,编辑文章只需要点击更新按钮,就可以将文章中的外链图片下载到本地并替换链接。

不过逐个编辑文章不仅繁琐而且工作量不小,这里教大家一个小技巧,可以批量下载文章中的外链图片。

批量操作
该插件的代码不仅可以在正常的编辑页面点击更新按钮触发下载功能,而且可以在后台所有文章列表页面中触发下载图片功能,原理明白了,操作就简单了。

进入WP后台,文章→所有文章,进入文章管理页面,勾选“标题”全选当前页面的所有文章,并选择“编辑”,并点击“应用”按钮。
切记,不要更改批量编辑中的任何设置,只需单击 “更新”即可。

wordpress优化经历(六)——wordpress图片防盗链-左眼会陪右眼哭の博客

这个过程将触发检查所有选定的文章,并自动下载外链图片!

  1. 完成上面操作后就可以将步骤1中加入functions.php 的代码给注释掉了

推荐写文章资源处理的几个方法

由于程序员一般写博客文章啥的一般都是使用markdown,所以用对工具可以提高效率 也是为了避免防盗链,真的太可恶了

方案一(推荐)

我目前写文章打算使用自己的服务器部署的云电脑kodbox,用这个的好处是:

  1. 资源全部在云服务器上,不用担心同步问题
  2. kodbox里面有很多好用的小工具,文章编写也很方便,可以极大的提高效率
  3. 然后就是资源存储问题,由于自己服务器上的kodbox,所以不会出现防盗链的情况,然后写文章时上传图片也很方便,可以将图片复制粘贴直接上传,上传时会自动在该文章的目录下新建一个images目录,所有的资源都放在那里
wordpress优化经历(六)——wordpress图片防盗链-左眼会陪右眼哭の博客
  1. 最后这些资源是虽然是相对路径引用的,但是可以根据自己的需求将路径更改为直连访问(该死的CSDN肯定不给直链)

方案二

如果是在本地写博客的话,首选肯定是Typora,但是Typora在资源处理上也挺麻烦的。但是可以自定义图片上传服务,目前好像只能使用PicGo当作资源服务器中端进行上传服务器,所以要上传到自己云服务器保证资源不会被防盗链就得自己另外部署一个PicGo图床项目,由于我已经使用了图床chevereto,就不想再折腾了。

wordpress优化经历(六)——wordpress图片防盗链-左眼会陪右眼哭の博客

具体可以自己折腾或者参考:https://www.bilibili.com/read/cv13781176/

java开发中也可以使用Servlet进行设置防盗链 参考我之前的博客:https://qkongtao.cn/?p=389#h2-2