Web 應用安全的第一道防線是輸入過濾與輸出轉義。本文整理一套實用的 PHP 安全工具類 S,涵蓋 HTML 轉義、SQL 轉義、目錄遍歷防禦、變數檢查等核心功能,並說明每個方法的適用場景與注意事項,助你快速建立安全基線。
<?php
final class S {
// 禁止實例化
private function __construct() {}
/**
* HTML 輸出轉義:僅轉義單雙引號,保留 HTML 標籤結構
* 適用場景:輸出到 HTML 屬性值、JavaScript 字串、已信任的富文本
*/
public static function htmlEscape(string $param): string {
return trim(htmlspecialchars($param, ENT_QUOTES, 'UTF-8'));
}
/**
* 完整 HTML 實體化:轉義所有特殊字元,防止 XSS
* 適用場景:輸出到 HTML 內容區、用戶生成內容
*/
public static function htmlEntities(string $param): string {
return htmlspecialchars($param, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
/**
* 判斷是否為非空陣列
*/
public static function isArray($params): bool {
return is_array($params) && count($params) > 0;
}
/**
* 檢查值是否存在於陣列(自動轉型字串比較)
*/
public static function inArray($param, $params): bool {
return in_array((string)$param, (array)$params, true); // 嚴格模式
}
/**
* SQL 轉義:支援字串、數字、陣列遞迴
* 注意:現代專案請優先使用 PDO 預處理語句,此函數僅用於舊代碼維護
*/
public static function sqlEscape($var, bool $strip = true, bool $isArray = false) {
if (is_array($var)) {
if (!$isArray) return "''";
foreach ($var as $key => $value) {
$var[$key] = trim(self::sqlEscape($value, $strip));
}
return $var;
} elseif (is_numeric($var)) {
return "'" . $var . "'";
} else {
$var = $strip ? stripslashes($var) : $var;
return "'" . addslashes($var) . "'";
}
}
/**
* 獲取並過濾 $_SERVER 變數:移除常見 XSS 向量字元
*/
public static function getServer($keys) {
$server = [];
$array = (array) $keys;
foreach ($array as $key) {
$server[$key] = null;
if (isset($_SERVER[$key])) {
$server[$key] = str_replace(
['<', '>', '"', "'", '%3C', '%3E', '%22', '%27', '%3c', '%3e'],
'',
$_SERVER[$key]
);
}
}
return is_array($keys) ? $server : $server[$keys];
}
/**
* 遞迴對陣列值執行 addslashes(舊專案相容)
*/
public static function slashes(array &$array): void {
foreach ($array as $key => $value) {
if (is_array($value)) {
self::slashes($array[$key]);
} else {
$array[$key] = addslashes($value);
}
}
}
/**
* 目錄路徑清理:防止目錄遍歷攻擊
* 移除危險字元、合併多重斜線、去除尾部斜線
*/
public static function escapeDir(string $dir): string {
$dir = str_replace(["'", '#', '=', '`', '$', '%', '&', ';'], '', $dir);
$dir = preg_replace('/\/+/', '/', $dir); // 合併多重斜線
return rtrim($dir, '/');
}
/**
* 通用變數轉義:依類型分派處理
* @param mixed $mixed
* @param bool $isint 強制轉整數
* @param bool $istrim 是否修剪字串
*/
public static function escapeChar($mixed, bool $isint = false, bool $istrim = false) {
if (is_array($mixed)) {
foreach ($mixed as $key => $value) {
$mixed[$key] = self::escapeChar($value, $isint, $istrim);
}
} elseif ($isint) {
$mixed = (int) $mixed;
} elseif (!is_numeric($mixed)) {
if ($istrim) $mixed = trim($mixed);
if ($mixed !== '') {
$mixed = self::escapeStr($mixed);
}
}
return $mixed;
}
/**
* 字串深度清理:移除控制字元、修正實體、統一空白
*/
public static function escapeStr(string $string): string {
// 移除空位元組、CR、NULL
$string = str_replace(["\0", "\r", "%00"], '', $string);
// 移除不可見控制字元(保留換行、Tab)
$string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F]/', '', $string);
// 修正未編碼的 & 實體
$string = preg_replace('/&(?!(#[0-9]+|[a-z]+);)/is', '&', $string);
// 統一實體編碼
$string = str_replace(['%3C', '<'], '<', $string);
$string = str_replace(['%3E', '>'], '>', $string);
$string = str_replace(['"', "'", "\t", ' '], ['"', ''', ' ', ' '], $string);
return $string;
}
/**
* 變數安全檢查:後台/前台差異策略
* 前台:移除路徑遍歷、腳本標籤前綴
* 後台:檢測 iframe/meta/script 注入,觸發攔截
*/
public static function checkVar(&$var): void {
if (is_array($var)) {
foreach ($var as $key => $value) {
self::checkVar($var[$key]);
}
} elseif (defined('P_W') && P_W !== 'admincp') {
// 前台:基本清理
$var = str_replace(['..', ')', '<', '='], ['..', ')', '<', '='], $var); // 此處原碼似有誤,建議改為實際過濾
} elseif (defined('P_W') && P_W === 'admincp') {
// 後台:嚴格檢測危險標籤
$lower = strtolower($var);
if (strpos($lower, '
| 方法 | 用途 | 適用場景 | 備註 |
|---|---|---|---|
| htmlEscape | HTML 屬性/JS 字串轉義 | 輸出到 value="...", onclick='...' | 不轉義 < >,保留標籤 |
| htmlEntities | 完整 HTML 實體化 | 用戶評論、文章內容輸出 | 最常用的 XSS 防禦 |
| sqlEscape | SQL 字串轉義 | 舊專案拼接 SQL 字串 | 新專案請用 PDO prepare() |
| escapeDir | 路徑清理 | 文件上傳、模板載入、include 路徑 | 防止 ../ 目錄遍歷 |
| escapeChar | 通用入口轉義 | 控制器接收 $_GET/$_POST 統一處理 | 可整合至 Request 物件 |
| checkVar | 全域變數掃描 | 框架入口統一檢查 | 後台嚴格模式可攔截 XSS 載荷 |
sqlEscape 僅作舊碼過渡。Content-Security-Policy,限制腳本來源、禁止內聯腳本,縱使有 XSS 也無法執行。filter_var()、Respect\Validation、Symfony Validator 定義嚴格規則,拒絕不符合預期的資料進入系統。Content-Disposition: attachment。X-Frame-Options: DENY、X-Content-Type-Options: nosniff、Referrer-Policy: strict-origin-when-cross-origin、Permissions-Policy 等。S 類封裝為 SecurityHelper,註冊為服務容器單例。Request 物件建構時,自動對所有輸入執行 escapeChar(可配置白名單欄位跳過)。htmlEntities,僅在標記為 raw/safe 的變數使用 htmlEscape。這套工具類雖屬「手動防禦」時代產物,但其設計思路——分類處理、上下文感知、遞迴清理——仍具參考價值。現代專案建議以「框架內建防護 + CSP + 參數化查詢」為主,工具類作為補充與舊碼遷移橋樑。