wordpress文章带图片同步到新浪微博

1392117921664

今天终于能把个人博客上的文章及文中图片一起同步到新浪微博了,在此发文纪念一下,并带图同步到我的微博测试。并且与大家一起分享一下经验,想必也有很多朋友在同步到微博的时候,遇到了传图的问题。

此前我都是使用多说评论框的接口同步到微博的,但为了能拥有自己的微博来源小尾巴,就自己开发一个。

首先你当然得有微博开放平台的帐号,并申请通过了网站应用审核。其次就是调用API接口了。

新浪微博有个高级接口,能发布一条微博并指定上传图片的url,这个接口由于需要申请使用,比较麻烦,还不如自己用另一个接口来实现锻炼一下自己。这里我使用的是https://upload.api.weibo.com/2/statuses/upload.json 这个接口(详情见这

必选 类型及范围 说明
source false string 采用OAuth授权方式不需要此参数,其他授权方式为必填参数,数值为应用的AppKey。
access_token false string 采用OAuth授权方式为必填参数,其他授权方式不需要此参数,OAuth授权后获得。
status true string 要发布的微博文本内容,必须做URLencode,内容不超过140个汉字。
visible false int 微博的可见性,0:所有人能看,1:仅自己可见,2:密友可见,3:指定分组可见,默认为0。
list_id false string 微博的保护投递指定分组ID,只有当visible参数为3时生效且必选。
pic true binary 要上传的图片,仅支持JPEG、GIF、PNG格式,图片大小小于5M。
lat false float 纬度,有效范围:-90.0到+90.0,+表示北纬,默认为0.0。
long false float 经度,有效范围:-180.0到+180.0,+表示东经,默认为0.0。
annotations false string 元数据,主要是为了方便第三方应用记录一些适合于自己使用的信息,每条微博可以包含一个或者多个元数据,必须以json字串的形式提交,字串长度不超过512个字符,具体内容可以自定。
rip false string 开发者上报的操作用户真实IP,形如:211.156.0.1。

文档规定的参数有以上这些,我只用到了source、status和pic三个参数就行了,当然你可以获得access_token来代替source(本文使用source讲解)。

上传图片等流媒体文件需要使用multipart/form-data编码方式,这和我们平常使用的表单上传文件类似。提交时会向服务器端发出这样的数据(如下代码,已经去除部分不相关的头信息)。

POST / HTTP/1.1
Content-Type:application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: weibo.com
Content-Length: 21
Connection: Keep-Alive
Cache-Control: no-cache

txt1=hello&txt2=world

对于普通的HTML Form POST请求,它会在头信息里使用Content-Length注明内容长度。头信息每行一条,空行之后便是Body,即“内容”(entity)。它的Content-Type是application/x-www-form-urlencoded,这意味着消息内容会经过URL编码,就像在GET请 求时URL里的QueryString那样。txt1=hello&txt2=world

最早的HTTP POST是不支持文件上传的,给编程开发带来很多问题。但是在1995年,ietf出台了rfc1867,也就是《RFC 1867 -Form-based File Upload in HTML》,用以支持文件上传。所以Content-Type的类型扩充了multipart/form-data用以支持向服务器发送二进制数据。因此发送post请求时候,表单

属性enctype共有二个值可选,这个属性管理的是表单的MIME编码:
①application/x-www-form-urlencoded(默认值)
②multipart/form-data
其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype=”application/x- www-form-urlencoded”.
通过form表单提交文件操作如下:

<form method="post"action="http://w.sohu.com/t2/upload.do" enctype=”multipart/form-data”>

<inputtype="text" name="desc">

<inputtype="file" name="pic">

</form>

浏览器会发送以下数据:

POST /t2/upload.do HTTP/1.1
User-Agent: SOHUWapRebot
Accept-Language: zh-cn,zh;q=0.5
Accept-Charset: GBK,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Content-Length: 60408
Content-Type:multipart/form-data; boundary=ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Host: weibo.com

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="desc"
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC
Content-Disposition: form-data;name="pic"; filename="photo.jpg"
Content-Type: application/octet-stream
Content-Transfer-Encoding: binary

[图片二进制数据]
--ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC--

先分析一下上面的内容,然后我们来根据这内容来构造发送的数据。

第7行指定发送编码是multipart/form-data,并且指定boundary值为“ZnGpDtePMx0KrHh_G0X99Yef9r8JZsRJSXC”,这个值可以随机产生,不难理解,boundary就是来分隔数据的。并且每段分隔时boundary值前面需要加“--”,最后结尾处在boundary值的前后加"--"(看上面代码最后一行)。

每段boundary之内,先是数据描述,再是数据的主体。

QQ截图20140818215404

 

现在放上我构造的代码,自己琢磨一下就明白了:

function post_to_sina_weibo($post_ID) {
  if( wp_is_post_revision($post_ID) ) return;
    $get_post_info = get_post($post_ID);
    //发布的文章内容,带所有标签格式
    $get_post_centent = get_post($post_ID)->post_content; 
    //用正则表达式抠图
    preg_match_all('/<img.*?(?: |\\t|\\r|\\n)?src=[\'"]?(.+?)[\'"]?(?:(?: |\\t|\\r|\\n)+.*?)?>/sim', $get_post_centent, $strResult, PREG_PATTERN_ORDER);  
   if(count($strResult[1]) > 0)
        $imgUrl = $strResult[1][0];//获得第一张图url地址
   else
        $imgUrl = null;

    //去掉文章内的html编码的空格、换行、tab等符号
    $get_post_centent = str_replace("\t", " ", str_replace("\n", " ", str_replace("&nbsp;", " ", $get_post_centent)));
    //获取文章标题
    $get_post_title = get_post($post_ID)->post_title;
    if ( $get_post_info->post_status == 'publish' && $_POST['original_post_status'] != 'publish' ) {
    //使用wordpress内置request请求类,在wp_includes/wp_http.php里
    $request = new WP_Http;
    //微博文字,格式为“【文章标题】文章摘要132字,全文地址:XXXX”
    $status = '【' . strip_tags( $get_post_title ) . '】 ' . mb_strimwidth(strip_tags( apply_filters('the_content', $get_post_centent)),0, 132,'...') . ' 全文地址:' . get_permalink($post_ID) ;
    //如果没图片则请求这个api
    $api_url = 'https://api.weibo.com/2/statuses/update.json';
    //body内容,source参数为你的appkey,详情见wordpress的WP_http类
    $body = array( 'status' => $status, 'source'=>'706960568');
    //请将xxxxxxxxx替换成你的,xxxxxxxxxx为“用户名:密码”的base64编码
    $headers = array( 'Authorization' => 'Basic ' . 'xxxxxxxxxxxxxxxx' );
    //重要步骤,如果文章有图片则构造发送数据包
    if($imgUrl!==null)
    {
    	$body['pic'] = $imgUrl;
    	uksort($body, 'strcmp');
        $str_b=uniqid('------------------');
        $str_m='--'.$str_b;
        $str_e=$str_m. '--';
        $tmpbody='';
        //对参数遍历,进行构造内容,仔细阅读,你会发现和上面讲的类似
        foreach($body as $k=>$v){
            if($k=='pic'){
                $img_c=file_get_contents($imgUrl);
                $url_a=explode('?', basename($imgUrl));
                $img_n=$url_a[0];
                $tmpbody.=$str_m."\r\n";
                $tmpbody.='Content-Disposition: form-data; name="'.$k.'"; filename="'.$img_n.'"'."\r\n";
                $tmpbody.="Content-Type: image/unknown\r\n\r\n";
                $tmpbody.=$img_c."\r\n";
            }else{
                $tmpbody.=$str_m."\r\n";
                $tmpbody.='Content-Disposition: form-data; name="'.$k."\"\r\n\r\n";
                $tmpbody.=$v."\r\n";
            }
        }
        $tmpbody.=$str_e;
        $body = $tmpbody;
        //图片处理结束,使用uploade API
    	$api_url = 'https://upload.api.weibo.com/2/statuses/upload.json';
        //设置Content-Type编码为multipart/form-data
    	$headers['Content-Type'] = 'multipart/form-data; boundary='.$str_b;
    }
    //请求接口发送数据,详见wordpress自带的WP_http类
    $result = $request->post( $api_url , array( 'body' => $body, 'headers' => $headers ) );
}

//最后将这个函数挂到pulish_post钩子上,发表文章后就会触发这个函数
add_action('publish_post', 'post_to_sina_weibo', 0);

 

这段代码理论上来说你可以拿去直接用了,只需按注释上说的修改几个参数为自己的就行了。

这也是我研究琢磨出来的,有任何疑问可以一起探讨。

标签: none

已有 9 条评论

  1. 代码小白看不懂呢,唉╯▂╰

    1. 那我也没办法了

      1. 是用户名:密码,这种格式么?

        1. 是的,那个冒号是英文状态下的

  2. 博主写个插件吧!那我们这些小白就有福了

  3. 你好 functions.php里加入这段代码后 网站打开空白了 请问是什么原因

  4. 你好 加入这段断码后 网站打不开 提示500错误 请问是什么原因

    1. 这可能需要你自己排查代码错误了,本身这段代码的逻辑只是在发布文章后执行的,如果你只是在打开网站时出现500错误,那么检查一下是否代码写错了导致编译不通过等其他问题

      1. 请问这段代码 是放到 function.php 里吗

添加新评论