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

PHP escapeshellarg 中文被過濾問題解決:setlocale 設定正確 Locale 環境

     編輯:PHP 綜合知識

問題現象

相同代碼,瀏覽器訪問 (PHP-FPM/Apache) 與 CLI (`php script.php`) 執行結果不一致:`escapeshellarg()` 在 Web 環境下會過濾掉中文字元,導致傳遞給 Shell 指令的參數遺失中文。

測試代碼

<?php
$str = "測試中文參數";
$cmd = 'echo ' . escapeshellarg($str) . ' | cat';
echo "Web 環境輸出: ";
echo shell_exec($cmd);

echo "\nCLI 環境請執行: php " . __FILE__;
?>

根因分析

`escapeshellarg()` 依賴當前 Locale 環境 (LC_CTYPE) 判斷合法字元。Web 環境 (Apache/Nginx + PHP-FPM) 繼承的 Locale 通常為 `C` 或 `POSIX` (僅 ASCII),而 CLI 環境繼承使用者 Shell 的 Locale (如 `zh_TW.UTF-8`),導致同一函式行為差異。

解決方案

<?php
// 在腳本最開頭設定正確 Locale
setlocale(LC_CTYPE, "zh_TW.UTF-8", "en_US.UTF-8", "UTF-8");

// 驗證設定生效
echo "Current LC_CTYPE: " . setlocale(LC_CTYPE, 0) . "\n";

$str = "測試中文參數";
echo escapeshellarg($str); // 現在正確保留中文
?>

環境別設定指南

環境設定位置推薦值
PHP-FPM腳本開頭 / `php.ini` / `php-fpm.conf` `env[LC_CTYPE]`zh_TW.UTF-8 / en_US.UTF-8
Apache mod_php`/etc/apache2/envvars` 或 `httpd.conf` `SetEnv`export LC_CTYPE=zh_TW.UTF-8
Nginx + PHP-FPM`/etc/php/7.x/fpm/pool.d/www.conf` `env[LC_CTYPE]`env[LC_CTYPE] = zh_TW.UTF-8
CLIShell 設定檔 `.bashrc` `/etc/locale.conf`LANG=zh_TW.UTF-8
Docker`Dockerfile` `ENV LC_CTYPE=zh_TW.UTF-8`ENV LC_CTYPE=zh_TW.UTF-8

驗證 Locale 設定

# 檢查系統支援的 Locale
locale -a | grep -i utf

# 檢查當前進程 Locale
php -r 'echo setlocale(LC_CTYPE, 0);'

# 測試 escapeshellarg
php -r 'echo escapeshellarg("測試");'

進階:跨平台相容寫法

<?php
function safe_escapeshellarg($arg) {
    // 1. 嘗試設定 UTF-8 Locale
    $locales = ['zh_TW.UTF-8', 'zh_CN.UTF-8', 'en_US.UTF-8', 'C.UTF-8', 'UTF-8'];
    $original = setlocale(LC_CTYPE, 0);
    foreach ($locales as $loc) {
        if (setlocale(LC_CTYPE, $loc) !== false) break;
    }
    
    // 2. 執行 escapeshellarg
    $result = escapeshellarg($arg);
    
    // 3. 恢復原 Locale
    setlocale(LC_CTYPE, $original);
    
    return $result;
}

// 使用
$cmd = 'mycmd ' . safe_escapeshellarg($userInput);
?>

替代方案:完全繞過 Shell

<?php
// 使用 proc_open 直接傳遞參數陣列,無需 escapeshellarg
$proc = proc_open(
    ['mycmd', $arg1, $arg2], // 指令陣列,不經 Shell 解析
    [
        0 => ['pipe', 'r'],  // stdin
        1 => ['pipe', 'w'],  // stdout
        2 => ['pipe', 'w'],  // stderr
    ],
    $pipes
);

$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) fclose($pipe);
$returnCode = proc_close($proc);
?>

優點:完全避免 Shell 注入、編碼、逸出問題;缺點:無法使用 Shell 內建指令/管道/重導向。

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