PHP cURL 是後端調用第三方 HTTP API 的利器。微信開發中,獲取 access_token(GET)、發送客服消息/模板消息(POST)均需通過 cURL 實現。本文提供兩個封裝良好、可直接用於生產的函數示例,涵蓋 HTTPS 處理、JSON 編解碼、錯誤處理等關鍵細節。
access_token 是調用所有微信高級接口的憑證,有效期 7200 秒。建議緩存到 Redis/文件/數據庫,避免頻繁請求觸發限流。
/**
* 獲取微信 access_token
* @return string|false access_token 或 false(失敗)
*/
function getAccessToken() {
$appId = 'YOUR_APPID';
$appSecret = 'YOUR_APPSECRET';
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appId}&secret={$appSecret}";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 生產環境建議配置 CA 憑證路徑
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 10); // 連接超時 10 秒
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // DNS/連接建立超時 5 秒
$response = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
curl_close($ch);
if ($errno) {
error_log("cURL Error [{$errno}]: {$error} - URL: {$url}");
return false;
}
$data = json_decode($response, true);
if (isset($data['errcode'])) {
error_log("WeChat API Error: {$data['errcode']} - {$data['errmsg']}");
return false;
}
return $data['access_token'] ?? false;
}
客服消息接口要求 JSON 格式 POST,支持文本、圖片、語音、視頻、圖文、菜單等類型。下面以發送「天氣圖文消息」為例。
/**
* 發送客服圖文消息
* @param string $openid 用戶 OpenID
* @param string $access_token 有效憑證
* @return array|false 微信返回結果或 false
*/
function sendNewsMessage($openid, $access_token) {
$url = "https://api.weixin.qq.com/cgi-bin/message/custom/send?access_token={$access_token}";
$postData = [
'touser' => $openid,
'msgtype' => 'news',
'news' => [
'articles' => [[
'title' => '今日天氣預報',
'description' => '晴轉多雲 18~25°C,紫外線強,建議攜帶雨具防曬。',
'url' => 'https://www.weather.com.cn/weather/101010100.shtml',
'picurl' => 'https://example.com/assets/weather_sunny.jpg',
]],
],
];
$jsonData = json_encode($postData, JSON_UNESCAPED_UNICODE); // 中文不轉義
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonData);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json; charset=utf-8',
'Content-Length: ' . strlen($jsonData),
]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
curl_close($ch);
if ($errno) {
error_log("cURL Error [{$errno}]: {$error}");
return false;
}
return json_decode($response, true);
}
實際項目中建議封裝一個 HttpClient 類,統一處理:
CURLOPT_CAINFO)class HttpClient {
private $ch;
private $defaultOptions = [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_TIMEOUT => 15,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => true, // 生產環境 true
CURLOPT_CAINFO => '/path/to/cacert.pem', // CA 憑證路徑
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3,
CURLOPT_ENCODING => 'gzip,deflate', // 支持壓縮
];
public function __construct() {
$this->ch = curl_init();
curl_setopt_array($this->ch, $this->defaultOptions);
}
public function get(string $url, array $headers = []): ?array { /* ... */ }
public function post(string $url, $data, array $headers = []): ?array { /* ... */ }
public function __destruct() { curl_close($this->ch); }
}
| 問題 | 原因 | 解決 |
|---|---|---|
| cURL error 60: SSL certificate problem | 未配置 CA 憑證或證書過期 | 設置 CURLOPT_CAINFO 指向有效 cacert.pem,或臨時關閉驗證(僅測試) |
| 返回 errcode 40001: invalid credential | access_token 過期/錯誤/被刷新 | 緩存 token 並提前刷新,失敗時重試獲取 |
| POST 參數格式錯誤 | 未設置 Content-Type: application/json | 手動添加 HTTPHEADER,或使用 CURLFile 上傳文件 |
| 中文亂碼 | json_encode 默認轉義 Unicode | 使用 JSON_UNESCAPED_UNICODE 參數 |
更多實戰技巧:PHP cURL 用法總結、PHP 微信開發技巧匯總、PHP 網絡編程技巧總結 等專題。