本文目錄 :上傳圖文素材的圖片上傳其他素材關鍵的http表單請求代碼小結參考文檔前言:我在實現微信公眾平臺上傳素材的時候遇到了許多問題,但最終還是成功實現這一功能,特此在這里做一下總結和記錄。文中遇到諸如 ...
本文目錄 :
上傳圖文素材的圖片
上傳其他素材
關鍵的http表單請求代碼
小結
參考文檔
前言:
我在實現微信公眾平臺上傳素材的時候遇到了許多問題,但最終還是成功實現這一功能,特此在這里做一下總結和記錄。
文中遇到諸如 getAccessToken() 等關鍵函數卻沒有找到實現時,可參考前面的這兩篇文章:
1、微信開發之獲取用戶詳細列表
2、微信開發之向用戶群發文本消息
1、 上傳圖文素材的圖片
首先選一個簡單的接口來做說明例子,這個上傳素材的接口在所有上傳素材的接口中是參數最簡單的,而且還單獨享用一個URL, 作為入門例子再合適不過了。
注意,本文主要側重點是代碼層面的實現,而不是微信官方一大堆規則的講解,如果你有需要此方面的介紹,下面已給出官方鏈接不謝。
官方文檔:
新增永久素材
官方給的這個接口,除了需要慣例的 access_token ,還需要一個文件的參數,一般而言,只需要一個文件路徑,其他文件參數通過這個路徑獲取解析則可,做成一個黑匣子,簡單易用。
我知道,有人就是專門找下邊的 Requests::request() 的實現的,可在這就沒看到實現,別急,下面就有。
public function uploadNewsImage($path)
{
$access_token = $this->getAccessToken();
if (!$access_token) {
return false;
}
$path = realpath($path);
$post = ['media '=> '@'.$path];
$url ="https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token={$access_token}";
$return = $this->requestAndCheck($url, 'POST', $post);
if ($return === false) {
return false;
}
return $return;
}
/**
* 專門用來檢查微信接口返回值的。
* 是的,這個接口比上一兩篇文章的接口更加好用。東西一般做多,就知道要抽象了,如果還沒有那水平的話。
*/
public function requestAndCheck($url, $method = 'GET', $fields = [])
{
$return = Requests::request($url, $method, $fields);
if ($return === false) {
$this->setError("request出錯! " . Requests::$error);
return false;
}
$wxdata = json_decode($return, true);
if (isset($wxdata['errcode']) && $wxdata['errcode'] != 0) {
$this->setError("微信錯誤代碼:{$wxdata['errcode']};<br>錯誤信息:{$wxdata['errmsg']}<br>請求鏈接:$url");
return false;
}
if (strtoupper($method) === 'GET' && empty($wxdata)) {
$this->setError("微信http請求返回為空!<br>請求鏈接:$url");
return false;
}
return $wxdata;
}
2、 上傳其他素材 懂得上面的流程,其他的上傳素材的接口,無非就是加多個 GET 和 POST 參數,主流程沒變。 其他相關接口列舉如下: 1、新增永久圖文素材:https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN 2、新增其他類型永久素材:https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE 3、新增臨時素材:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
功能的約束和細節還望參考官方文檔: 1、新增永久素材 2、新增臨時素材
3、 關鍵的http表單請求代碼 先上代碼:(這里邊已經簡化很多附加功能,比如可以改變header之類的功能,該代碼主要參考一些開源的項目)
public static function request($url, $method = 'GET', $fields = [])
{
self::$ch = curl_init();
curl_setopt(self::$ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt(self::$ch, CURLOPT_CONNECTTIMEOUT, 10);
$method = strtoupper($method);
if ($method == 'GET' && !empty($fields)) {
$url = $url . (strpos($url,"?")===false ? "?" : "&") . http_build_query($fields);
}
curl_setopt(self::$ch, CURLOPT_URL, $url);
if ($method != 'GET') {
curl_setopt(self::$ch, CURLOPT_POST, true);
if (!empty($fields)) {
if (is_array($fields)) {
/* 支持文件上傳 */
if (class_exists('\CURLFile')) {
curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, true);
foreach ($fields as $key => $value) {
if (is_string($value) && strpos($value, '@') === 0) {
$fields[$key] = new CURLFile(realpath(ltrim($value, '@')),
'image/jpg', basename(ltrim($value, '@')));
}
}
} elseif (defined('CURLOPT_SAFE_UPLOAD')) {
curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, false);
}
}
curl_setopt(self::$ch, CURLOPT_POSTFIELDS, $fields);
}
}
/* 關閉https驗證 */
if ("https" == substr($url, 0, 5)) {
curl_setopt(self::$ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt(self::$ch, CURLOPT_SSL_VERIFYHOST, false);
}
self::$content = curl_exec(self::$ch);
curl_close(self::$ch);
return self::$content;
}
重點分析:
/* 支持文件上傳 */
if (class_exists('\CURLFile')) {
curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, true);
foreach ($fields as $key => $value) {
if (is_string($value) && strpos($value, '@') === 0) {
$fields[$key] = new CURLFile(realpath(ltrim($value, '@')));
}
}
} elseif (defined('CURLOPT_SAFE_UPLOAD')) {
curl_setopt(self::$ch, CURLOPT_SAFE_UPLOAD, false);
}
這里面有個PHP版本的坑,5.4版本只支持用 @ 來進行上傳文件,5.5是個過渡版本,支持 @ 和 CURLFile 兩種方式上傳文件,而到了5.6,就只支持 CURLFile 了。所以需要用兼容模式來適應不同版本。
關于為什么不用php版本號來判斷呢?你用版本號誰知道你是要來判斷啥呢?難道加個注釋?
而常量 CURLOPT_SAFE_UPLOAD 是用來開啟是否支持 @ 的,當然,5.6版本設置了也沒有。
還有,要上傳file的時候,一定要用數組給 curl_setopt(self::fields); 傳值,而不能用 http_build_query() ,一個的http請求頭中的 content-type 是 multipart/form-date ,另一個是 application/x-www-form-urlencoded 。file用二進制編碼進行傳輸,而普通的post數據是文本傳輸。
上面的相關知識還請詳看 參考文檔。
小結:
如果你已有上傳文件的接口,其實這個功能不算啥,按照官方文檔進行 post url 即可。如果沒有,或者沒有實現文件上傳功能,就要對 curl 研究一下了,還要踩一下php版本的坑。。。不過對 curl 掌握就更加全面而牢固了,這難道不是我們的目的?
主要參考文檔:
1、微信公眾號開發文檔
2、Multipart/form-data POST文件上傳詳解
3、PHP的CURLOPT_POSTFIELDS參數使用數組和字符串的區別
4、The CURLFile class
5、考慮 PHP 5.0~5.6 各版本兼容性的 cURL 文件上傳
-end-