| 模式 | 編碼 | 最大長度 | 適用場景 |
| Text Mode | GSM 7-bit | 160 字符 | 簡單英文/數字,諾基亞等支援 |
| PDU Mode | UCS2 (16-bit) | 70 字符 | 中文/多語言,通用性最強 |
| PDU Mode | 8-bit | 140 字節 | 二進制數據,手機通常不顯示 |
PDU 結構詳細解析
發送「你好」到 13638197275,中心號 13800571500:
完整 PDU: 0891683180501705F011000D91683136187972F5000800044F60597D
拆解:
08 - 中心號長度(含91) = (2+14)/2 = 8
91 - TON/NPI: 國際號碼格式(+號)
683180501705F0 - 中心號 8613800571500 (奇偶位交換+F補位)
11 - PDU 類型: SMS-SUBMIT
00 - TP-MR: 參考號(0)
0D - 目標號碼長度: 13位
91 - 目標號碼類型: 國際格式
683136187972F5 - 目標號碼 8613638197275 (奇偶交換+F)
00 - TP-PID: 協議標識
08 - TP-DCS: 數據編碼 UCS2(16-bit)
00 - TP-VP: 有效期(無)
04 - TP-UDL: 用戶數據長度 4字節(2字符×2)
4F60597D - 內容 "你好" UCS2-BE 編碼
PHP 完整實現代碼
9600,
'bits' => 8,
'stop' => 1,
'parity' => 0
]);
// Windows 替代: exec('mode COM1: baud=9600 data=8 stop=1 parity=n xon=on');
$smsc = "8613800571500"; // 短信中心號
$send_to = "8613638197275"; // 目標號碼
$text = "你好"; // 短信內容
// 1. 構建 PDU 地址部分
$pdu_addr = '0891' . invertNumbers($smsc);
// 2. 構建 PDU 內容部分
$pdu_text = hex2str(utf82unicode($text)); // 4F60597D
$pdu_text = sprintf("%02X", strlen($pdu_text)/2) . $pdu_text; // 04 + 內容
$pdu_phone = '11000D91' . invertNumbers($send_to) . '000800' . $pdu_text;
// 3. 計算總長度(不含地址部分)
$pdu_len = strlen($pdu_phone) / 2;
// 4. 發送 AT 命令序列
$inter = chr(13); // 回車
$ctrlz = chr(26); // Ctrl+Z 結束符
// 設置 PDU 模式
dio_write($fd, "AT+CMGF=0$inter");
// 發送長度
dio_write($fd, "AT+CMGS=$pdu_len$inter");
// 發送 PDU 數據 + 結束符
dio_write($fd, $pdu_addr . $pdu_phone . $ctrlz . $inter);
dio_close($fd);
// ===== 輔助函數 =====
function utf82unicode($str) {
return iconv("utf-8", "UCS-2BE", $str);
}
function hex2str($hexstring) {
$str = '';
for ($i = 0, $len = strlen($hexstring); $i < $len; $i++) {
$str .= sprintf("%02X", ord($hexstring[$i]));
}
return $str;
}
function invertNumbers($msisdn) {
$len = strlen($msisdn);
if ($len % 2) $msisdn .= "F"; // 奇數長度補 F
for ($i = 0; $i < $len; $i += 2) {
$t = $msisdn[$i];
$msisdn[$i] = $msisdn[$i+1];
$msisdn[$i+1] = $t;
}
return $msisdn;
}
關鍵點總結
| 環節 | 關鍵操作 | 易錯點 |
| 號碼處理 | 去+號 → 奇數補F → 奇偶位交換 → 前綴91 | 忘記補F導致長度錯誤 |
| 內容編碼 | UTF-8 → UCS-2BE → 每字節轉兩位十六進制 | 使用 UCS-2LE 導致亂碼 |
| 長度計算 | PDU 字節數(十六進制字符數/2) | 包含地址部分導致長度超標 |
| AT 命令 | CMGF=0 → CMGS=長度 → PDU數據 → Ctrl+Z | 缺少回車符、發送過快 |
現代替代方案
- **HTTP 短信網關**:阿里云/騰訊云/網易雲信等 REST API,無需硬件
- **GSM Modem Pool**:多卡池設備 + HTTP 接口,支援高併發
- **IoT 卡 + MQTT**:物聯網場景下的數據傳輸替代短信
總結
PDU 模式 UCS2 編碼是短信發送最通用、最兼容的方案。理解其位級結構有助於排查發送失敗、亂碼、長度截斷等疑難問題。現代項目優先選擇雲短信 API,降低硬件維護成本。
- 上一篇文章: PHP Redis Sort 排序功能全解析:從基礎到外部鍵權重排序
- 下一篇文章: PHP 使用 cURL 模擬登錄實戰:驗證碼人工介入與 Cookie 管理
Copyright ©
程式碼之家 All Rights Reserved