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

PHP 接收 HTTP POST 提交的 XML 資料並解析實作

     編輯:PHP 綜合知識

當第三方系統或前端透過 HTTP POST 直接送出 XML 內容(Content-Type: text/xml 或 application/xml)時,PHP $_POST 無法自動解析,需從原始輸入流讀取並解析。

核心步驟

  1. 讀取原始 POST 資料:file_get_contents('php://input')(推薦)或 $GLOBALS['HTTP_RAW_POST_DATA'](PHP 5.6+ 棄用、7.0+ 移除)
  2. 解析 XML:simplexml_load_string()(簡單結構)或 DOMDocument(複雜、需命名空間、XPath)
  3. 錯誤處理:關閉 libxml 錯誤報告,自行捕獲

完整實作範例

<?php
declare(strict_types=1);

// 僅允許 POST
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('Method Not Allowed');
}

// 1. 讀取原始 XML
$rawXml = file_get_contents('php://input');
if (empty($rawXml)) {
    http_response_code(400);
    exit('Empty XML body');
}

// 2. 解析(關閉 libxml 內部錯誤,改由程式碼處理)
libxml_use_internal_errors(true);
$xml = simplexml_load_string($rawXml);
$errors = libxml_get_errors();
libxml_clear_errors();

if ($xml === false) {
    $msg = 'XML 解析失敗: ' . implode('; ', array_map(fn($e) => $e->message, $errors));
    error_log($msg);
    http_response_code(400);
    exit($msg);
}

// 3. 取得資料(範例結構對應原文)
$namespace = ''; // 若有命名空間需註冊:$xml->registerXPathNamespace('ns', 'uri');
$iata = (string)($xml->Agency->Iata ?? '');
$agent = (string)($xml->Agency->Agent ?? '');
$password = (string)($xml->Agency->Password ?? '');
$brand = (string)($xml->Agency->Brand ?? '');

$adults = [];
foreach ($xml->Passengers->Adult ?? [] as $adult) {
    $adults[] = [
        'id' => (string)($adult['ID'] ?? ''),
        'age' => (string)($adult['AGE'] ?? ''),
    ];
}

$destCode = (string)($xml->HotelAvailReq1->DestCode ?? '');
$hotelCode = (string)($xml->HotelAvailReq1->HotelCode ?? '');
$checkIn = (string)($xml->HotelAvailReq1->CheckInDate ?? '');
$checkOut = (string)($xml->HotelAvailReq1->CheckOutDate ?? '');
$useField = (string)($xml->HotelAvailReq1->UseField ?? '');

// 4. 業務邏輯處理...
// $result = processBooking($iata, $agent, $adults, $destCode, $hotelCode, $checkIn, $checkOut);

// 5. 回應 XML
header('Content-Type: text/xml; charset=utf-8');
echo <<

進階:使用 DOMDocument(支援命名空間、XPath、大檔案)

$dom = new DOMDocument();
$dom->loadXML($rawXml, LIBXML_NOERROR | LIBXML_NOWARNING);
$xpath = new DOMXPath($dom);

// 註冊命名空間(若 XML 含 xmlns)
// $xpath->registerNamespace('ns', 'https://example.com/ns');

$iata = $xpath->evaluate('string(//Agency/Iata)');
$adultNodes = $xpath->query('//Passengers/Adult');
foreach ($adultNodes as $node) {
    $id = $node->getAttribute('ID');
    $age = $node->getAttribute('AGE');
    // ...
}

cURL 發送 XML 測試(客戶端視角)

<?php
$xmlData = '<AATAvailReq1><Agency><Iata>1234567890</Iata>...</AATAvailReq1>';

$ch = curl_init('https://your-api.example.com/endpoint');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $xmlData,
    CURLOPT_HTTPHEADER => [
        'Content-Type: text/xml; charset=utf-8',
        'Content-Length: ' . strlen($xmlData),
    ],
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => true, // 生產環境必須驗證
    CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "HTTP $httpCode\n$response";

常見坑與對策

問題原因解決
$_POST 為空PHP 只解析 application/x-www-form-urlencoded 或 multipart/form-data用 php://input
大檔案記憶體爆炸simplexml_load_string 全載入記憶體用 XMLReader 流式解析或分塊處理
命名空間無法查詢SimpleXML 預設不處理命名空間用 DOMDocument + registerXPathNamespace
編碼亂碼XML 宣告 encoding 與實際不符強制 mb_convert_encoding($rawXml, 'UTF-8', 'auto')
外部實體注入 (XXE)解析器預設載入外部 DTD/實體libxml_disable_entity_loader(true) (PHP 8.0+ 預設關閉)

安全建議

  • 驗證 Content-Type 標頭確為 text/xml 或 application/xml
  • 限制請求體大小:nginx client_max_body_size、php.ini post_max_size
  • 使用 XML Schema (XSD) 驗證結構合法性
  • 敏感欄位(密碼、Token)勿在日誌輸出完整 XML
  • 採用數位簽章或 HMAC 驗證資料完整性與來源

掌握 php://input + simplexml_load_string/DOMDocument 組合,即可輕鬆處理各類 XML API 整合場景(旅館預訂、支付回調、物流追蹤、電子發票等)。

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