新浪微博接口发布图片到微博(10007、20007)等各种错误

这两天研究了一下新浪微博登录和新浪微博的同步接口,发送文字或者带图片的信息到新浪微博需要用POST方式提交过去,于是想到了用php的curl扩展模拟post提交,按官方文档顺利获取到Access Token,尝试一下发送文字信息到微博:

function post_contents($url,$data=”){
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_POST, true); //设置为post提交
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_POSTFIELDS, $data); //提交数据
curl_setopt ($ch, CURLOPT_TIMEOUT, 1000);
curl_setopt($ch, CURLINFO_HEADER_OUT, TRUE );
$file_contents = curl_exec($ch);
curl_close($ch);
return $file_contents;
}

$url-为https://api.weibo.com/2/statuses/update.json
$data此时为一个数组
结果页面出现数据类型错误,经过研究,原来是$data 造成的,

$data为用“&”拼接的字符串时可以正常发送(可用http_build_query函数),此时的编码方式为“application/x-www-form-urlencoded”;

若为数组时,则报类型错误,此时的编码方式为“multipart/form-data”;

ok,到此,发布文字信息算是解决了!

接下来,准备再发布一条带图片的信息,同样用上面的函数,只是更换了$url和多设置了pic参数,按照官方文档,此时的pic需要是二进制数据,于是想到用file_get_contents(),结果出人意料,还是不行!纠结了很长一段时间,干脆直接下sdk来研究,果然用sdk是能顺利的发布图片信息到微博,sdk底层代码也是用的curl实现的,这就奇怪了,为什么sdk中用就可以,自己写就不行?

通过研究,找到了sdk中的build_http_query_multi()函数,原来提交的参数是通过这个函数拼接成字符串的,自己模仿写了一个,结果还是不行!报数据类型错误。

再通过多方资料查找,原来在post的时候需要设置header中的数据类型,于是在上面的函数中加入了:

$headers[] = “Content-Type: multipart/form-data” ;
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers );

再试,依然不行!

再次研究了sdk,发现发现sdk中在设置header的时候加上了 boundary,翻译得知是边界,原来拼接参数的时候要设置各个参数之间的边界,于是照搬sdk的代码:
$headers[] = “Content-Type: multipart/form-data; boundary=” . self::$boundary;

curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers );

 

public static function build_http_query_multi($params) {
if (!$params) return ”;
self::$boundary = $boundary = uniqid(‘——————‘);
$MPboundary = ‘–‘.$boundary;
$endMPboundary = $MPboundary. ‘–‘;
$multipartbody = ”;

foreach ($params as $parameter => $value) {

if( in_array($parameter, array(‘pic’, ‘image’))) {
$url = $value;
$content = file_get_contents( $url );
$array = explode( ‘?’, basename( $url ) );
$filename = $array[0];

$multipartbody .= $MPboundary . “\r\n”;
$multipartbody .= ‘Content-Disposition: form-data; name=”‘ . $parameter . ‘”; filename=”‘ . $filename . ‘”‘. “\r\n”;
$multipartbody .= “Content-Type: image/unknown\r\n\r\n”;
$multipartbody .= $content. “\r\n”;
} else {
$multipartbody .= $MPboundary . “\r\n”;
$multipartbody .= ‘content-disposition: form-data; name=”‘ . $parameter . “\”\r\n\r\n”;
$multipartbody .= $value.”\r\n”;
}

}

$multipartbody .= $endMPboundary;
return $multipartbody;
}

ok,终于发布上去了!

再这个过程中发现还有一种方法可以发布上去,curl的时候不用添加header代码,pic参数要写成本地的绝对路径(不能使用http开头的路径),并在前面加上“@”,但这种方式有局限性,如果图片放在另外一台服务器上就无法上传了,因此弃用。