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

PHP 將 POST 多維陣列轉換為字串的遞歸實現:日誌記錄最佳實務

     編輯:PHP 綜合知識

API 除錯、安全審計、請求快照都需要將 $_POST 多維陣列扁平化為字串。本文提供健壯的遞歸實現,支援任意深度巢狀陣列、鍵名編碼、特殊字元處理,輸出標準 application/x-www-form-urlencoded 格式,可直接寫入日誌或資料庫。

核心函式實現

<?php
/**
 * 將多維 POST 陣列轉為 URL 編碼字串
 * 
 * @param array  $data  輸入陣列 (預設 $_POST)
 * @param string $prefix 遞歸用鍵名前綴
 * @return string 格式:key1=val1&key2[sub]=val2&...
 */
function postArrayToString(array $data = [], string $prefix = ''): string {
    $parts = [];
    
    foreach ($data as $key => $value) {
        // 鍵名處理:URL 編碼,支援中文鍵名
        $encodedKey = rawurlencode($key);
        $fullKey = $prefix ? "{$prefix}[{$encodedKey}]" : $encodedKey;
        
        if (is_array($value)) {
            // 遞歸處理巢狀陣列
            $parts[] = postArrayToString($value, $fullKey);
        } elseif (is_scalar($value) || (is_object($value) && method_exists($value, '__toString'))) {
            // 標量值或可字串化物件
            $encodedValue = rawurlencode((string)$value);
            $parts[] = "{$fullKey}={$encodedValue}";
        } elseif (is_null($value)) {
            // null 值輸出為空字串
            $parts[] = "{$fullKey}=";
        } else {
            // resource 等不可序列化型別
            $parts[] = "{$fullKey}=[unserializable:" . gettype($value) . "]";
        }
    }
    
    return implode('&', $parts);
}

// 便捷封裝:直接處理 $_POST
function getPostLogString(): string {
    return postArrayToString($_POST);
}
?>

測試案例與輸出

<?php
// 模擬複雜 POST 資料
$_POST = [
    'user' => [
        'name' => '張三',
        'age'  => 25,
        'tags' => ['vip', 'beta-tester'],
        'address' => [
            'city' => '台北',
            'zip'  => '100'
        ]
    ],
    'action' => 'update_profile',
    'empty_val' => '',
    'null_val' => null,
    'files' => [  // 檔案上傳陣列結構
        'avatar' => [
            'name' => 'photo.jpg',
            'type' => 'image/jpeg',
            'size' => 102400
        ]
    ]
];

echo getPostLogString();
/*
輸出:
action=update_profile
&empty_val=
&files[avatar][name]=photo.jpg
&files[avatar][size]=102400
&files[avatar][type]=image%2Fjpeg
&null_val=
&user[address][city]=%E5%8F%B0%E5%8C%97
&user[address][zip]=100
&user[age]=25
&user[name]=%E5%BC%B5%E4%B8%89
&user[tags][0]=vip
&user[tags][1]=beta-tester
*/
?>

關鍵設計決策

決策點選擇理由
編碼函式rawurlencode()RFC 3986 標準,空格編為 %20 而非 +
巢狀格式PHP 風格 key[sub][sub]與 parse_str() 完美互逆,原生支援
排序依陣列順序 (PHP 7+ 保持插入序)確定性輸出,利於日誌比對
Null 處理輸出 key=區別於未傳遞參數,符合表單語意
型別支援標量 + __toString 物件覆蓋 99% 實際場景,resource 標記不可序列化

反向解析:字串還原陣列

$str = 'user[name]=John&user[tags][0]=vip&user[tags][1]=beta&action=login';
parse_str($str, $output);
/*
$output = [
    'user' => [
        'name' => 'John',
        'tags' => ['vip', 'beta']
    ],
    'action' => 'login'
];
*/

進階:支援 JSON 輸出 (結構化日誌)

function postToJsonString(array $data = [], int $flags = JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES): string {
    // 直接 JSON 編碼,保留結構,適合 ELK/Logstash 分析
    return json_encode($data ?: $_POST, $flags);
}

// 輸出範例:
// {"user":{"name":"張三","age":25,"tags":["vip","beta-tester"],"address":{"city":"台北","zip":"100"}},"action":"update_profile"}

日誌記錄最佳實務

// middleware 裡記錄請求
function logRequest() {
    $logData = [
        'timestamp'   => date('c'),
        'method'      => $_SERVER['REQUEST_METHOD'],
        'uri'         => $_SERVER['REQUEST_URI'],
        'ip'          => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
        'user_agent'  => $_SERVER['HTTP_USER_AGENT'] ?? '',
        'post_data'   => getPostLogString(),  // 或 postToJsonString()
        'get_data'    => http_build_query($_GET),
        'session_id'  => session_id(),
    ];
    
    // 寫入檔案/資料庫/送往 Logstash
    error_log(json_encode($logData, JSON_UNESCAPED_UNICODE) . "\n", 3, '/var/log/api_requests.log');
}

安全性考量:敏感欄位過濾

function sanitizePostForLog(array $data): array {
    $sensitiveKeys = ['password', 'passwd', 'pwd', 'secret', 'token', 'api_key', 'credit_card', 'cvv'];
    $masked = '***MASKED***';
    
    array_walk_recursive($data, function (&$value, $key) use ($sensitiveKeys, $masked) {
        if (in_array(strtolower($key), $sensitiveKeys, true)) {
            $value = $masked;
        }
    });
    
    return $data;
}

// 使用
$safePost = sanitizePostForLog($_POST);
$logStr = postArrayToString($safePost);

遞歸扁平化 + URL 編碼是將 POST 資料序列化為字串的標準做法,配合敏感欄位遮罩與結構化 JSON 選項,能滿足從除錯到合規審計的多樣化日誌需求。

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