對接第三方短信閘道(如卓望),協議為 HTTP POST + XML 報文,需簽名驗證。本類封裝 XML 組裝、簽名計算、cURL 發送、響應解析。
class SmsSender {
private $userId;
private $password; // 已為 MD5 小寫
private $templateId;
private $serverUri;
private $port;
public function __construct(array $config) {
$this->userId = $config['userId'];
$this->password = $config['password'];
$this->templateId = $config['templateId'];
$this->serverUri = $config['serverUri'];
$this->port = $config['port'];
}
/**
* 發送單條短信
* @param string $message 內容(模板變數已替換)
* @param string $mobile 手機號
* @param string $signature 簽名
* @return bool|string true=成功, false=網路失敗, 其他=錯誤碼
*/
public function sendOne(string $message, string $mobile, string $signature = 'demo') {
$xml = $this->buildXml($message, $mobile, $signature);
$resp = $this->postXml($xml);
if ($resp === false) return false; // 網路錯誤
$xmlObj = simplexml_load_string($resp);
if (!$xmlObj) return 'PARSE_ERROR';
return ($xmlObj->retCode == 1000) ? true : (string)$xmlObj->retCode;
}
/** 組裝 XML 報文 */
private function buildXml(string $msg, string $mobile, string $sig): string {
$data = [
'userId' => $this->userId,
'password' => $this->password,
'templateId' => $this->templateId,
'phone' => $mobile,
'port' => $this->port,
'data' => $msg,
'signature' => $sig,
];
$dom = new DOMDocument('1.0', 'UTF-8');
$req = $dom->createElement('request');
$dom->appendChild($req);
foreach ($data as $k => $v) {
$el = $dom->createElement($k);
$req->appendChild($el);
$el->appendChild($dom->createTextNode($v));
}
return $dom->saveXML();
}
/** 發送 HTTP POST XML */
private function postXml(string $xml): ?string {
$now = time();
$headers = [
'Content-Type: text/xml',
'Content-Length: ' . strlen($xml),
'Cmd: mt',
'TS: ' . $now,
'Authorization: ' . strtoupper(md5($xml . $now . $this->password)),
];
$ch = curl_init($this->serverUri);
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $xml,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_TIMEOUT => 10,
]);
$resp = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
if ($err) error_log("SMS cURL error: $err");
return $resp ?: null;
}
}
$sender = new SmsSender([
'userId' => 'YOUR_UID',
'password' => 'MD5_PASSWORD_LOWERCASE',
'templateId' => 'TPL_12345',
'serverUri' => 'https://sms.api.provider/gateway',
'port' => '8888',
]);
$result = $sender->sendOne('您的驗證碼是 123456', '13800138000', 'MyApp');
if ($result === true) {
echo "發送成功";
} elseif ($result === false) {
echo "網路異常,請重試";
} else {
echo "閘道返回錯誤碼:$result";
}
MD5(XML_BODY + TIMESTAMP + PASSWORD) 大寫,確保報文未被竄改。XML 協議雖顯老舊,但金融、電信領域仍廣泛使用。封裝可復用類別,統一異常處理與日誌,能大幅降低對接維護成本。