首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 實現短信發送完整方案:XML 協議封裝與 CURL 通訊實戰

     編輯:PHP 相關知識

PHP 實現短信發送完整方案:XML 協議封裝與 CURL 通訊實戰

短信服務是應用系統核心基礎設施。本文提供基於 XML 協議的短信發送完整封裝類,涵蓋簽名驗證、模板管理、錯誤碼解析、異常處理等生產級要素,適配主流短信服務商(騰訊雲、阿里雲、華為雲等均採用類似協議)。

核心架構設計

class Sms {
    // 配置屬性(建議從環境變量/配置中心讀取)
    private string $userId = 'XXXXX';
    private string $password = 'XXXXXX';      // 已 MD5 加密
    private string $templateId = 'XXXXXX';
    private string $serverUri = 'XXXXXX';
    private string $port = 'XXXXXX';

    /**
     * 發送單條短信
     * @param string $message  短信內容(模板變量值)
     * @param string $mobile   接收手機號
     * @param string $signature 簽名(已在服務商備案)
     * @return bool|string     true=成功,false=網絡失敗,string=錯誤碼
     */
    public function sendOneMsg(string $message, string $mobile, string $signature = 'demo'): bool|string {
        $xmlContent = $this->createXmlContent($message, $mobile, $signature);
        $xmlResponse = $this->sendHttpRequest($xmlContent);
        
        if (!$xmlResponse) {
            return false; // 網絡層失敗:超時、DNS、連接拒絕等
        }
        
        return $this->parseResponse($xmlResponse);
    }
    
    // ... 私有方法見下文
}

XML 協議構建

private function createXmlContent(string $message, string $mobile, string $signature): string {
    $data = [
        'userId'     => $this->userId,
        'password'   => $this->password,
        'templateId' => $this->templateId,
        'phone'      => $mobile,
        'port'       => $this->port,
        'data'       => $message,
        'signature'  => $signature,
    ];
    
    $dom = new DOMDocument('1.0', 'UTF-8');
    $request = $dom->createElement('request');
    $dom->appendChild($request);
    
    foreach ($data as $key => $val) {
        $element = $dom->createElement($key);
        $request->appendChild($element);
        $text = $dom->createTextNode($val);
        $element->appendChild($text);
    }
    
    return $dom->saveXML();
}

HTTP 通訊與簽名驗證

private function sendHttpRequest(string $xmlContent): string|false {
    $timestamp = time();
    $headers = [
        'Content-Type: text/xml',
        'Content-Length: ' . strlen($xmlContent),
        'Cmd: mt',
        'TS: ' . $timestamp,
        // 簽名算法:MD5(XML內容 + 時間戳 + 密碼) 大寫
        'Authorization: ' . strtoupper(md5($xmlContent . $timestamp . $this->password)),
    ];
    
    $ch = curl_init($this->serverUri);
    curl_setopt_array($ch, [
        CURLOPT_HTTPHEADER => $headers,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => $xmlContent,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => false,
        CURLOPT_TIMEOUT => 10,        // 連接超時
        CURLOPT_CONNECTTIMEOUT => 5,  // 總超時
        CURLOPT_SSL_VERIFYPEER => false, // 生產環境建議開啟並配置 CA 憑證
    ]);
    
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    curl_close($ch);
    
    if ($errno) {
        error_log("SMS CURL Error [$errno]: $error");
        return false;
    }
    
    return $response;
}

響應解析與錯誤碼處理

private function parseResponse(string $xml): bool|string {
    $xmlObj = simplexml_load_string($xml);
    if (!$xmlObj) {
        error_log("SMS XML Parse Failed: $xml");
        return 'PARSE_ERROR';
    }
    
    $retCode = (int)($xmlObj->retCode ?? -1);
    
    // 成功碼映射(視具體服務商文檔調整)
    $successCodes = [1000, 2000, 'OK', 'SUCCESS'];
    if (in_array($retCode, $successCodes, true)) {
        return true;
    }
    
    // 記錄失敗詳情便於排查
    error_log("SMS Send Failed: Code=$retCode, Msg={$xmlObj->retMsg ?? 'Unknown'}");
    return (string)$retCode; // 返回具體錯誤碼供上層業務判斷
}

生產級增強建議

維度基礎版缺口增強方案
配置管理硬編碼敏感信息環境變量 + 配置中心 + 密鑰輪換
並發性能同步阻塞發送異步隊列 + 連接池 + 批量發送接口
可靠性無重試/降級指數退避重試、熔斷器、失敗進死信隊列人工補發
監控告警無可觀測性發送量/成功率/延遲/錯誤碼分布儀表盤 + 閾值告警
安全合規明文傳輸風險HTTPS 強制、簽名算法升級(HMAC-SHA256)、IP 白名單
模板管理模板 ID 硬編碼模板版本化、變量校驗、審核狀態同步

現代化重構:PSR-18 客端適配

use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestFactoryInterface;

class ModernSmsClient {
    public function __construct(
        private ClientInterface $httpClient,
        private RequestFactoryInterface $requestFactory,
        private string $endpoint,
        private string $appId,
        private string $appSecret
    ) {}
    
    public function send(string $mobile, string $templateId, array $params): SmsResult {
        $payload = ['mobile' => $mobile, 'template_id' => $templateId, 'params' => $params];
        $request = $this->requestFactory->createRequest('POST', $this->endpoint)
            ->withHeader('Content-Type', 'application/json')
            ->withHeader('Authorization', $this->generateSignature($payload))
            ->withBody(new \GuzzleHttp\Psr7\Stream(json_encode($payload)));
        
        $response = $this->httpClient->sendRequest($request);
        return $this->parseResult($response);
    }
}

常見錯誤碼對照表(示例)

代碼含義處理建議
1000成功記錄日誌,標記發送成功
1001認證失敗檢查 AppID/Secret、IP 白名單、簽名算法
1002模板不存在/未審核同步模板狀態,告警運營
1003手機號格式錯誤前端校驗 + 後端二次校驗,過濾無效號碼
1004余額不足觸發充值告警,降級走備用通道
1005頻率限制令牌桶限流,延遲重試
9999系統異常記錄完整請求響應,聯繫服務商技術支持

這個封裝類提供了短信發送的核心骨架。實際接入時,請仔細閱讀服務商 API 文檔,調整 XML 結構、簽名算法、字段映射、錯誤碼定義,並按上表補全生產級非功能性需求。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved