資深 PHP 開發者累積的實戰技巧,往往能大幅提升開發效率與程式碼品質。本文精選 10 大高頻實用技巧,涵蓋表單處理、安全防護、超全域變數、Header 操作、字串處理與時間取得,並標註常見錯誤與現代最佳實務。
<!-- HTML: name 以 [] 結尾,PHP 自動接收為陣列 -->
<input type="checkbox" name="ids[]" value="1">
<input type="checkbox" name="ids[]" value="2">
<input type="checkbox" name="ids[]" value="3">
<?php
// PHP 接收:$_POST['ids'] 為陣列 [1, 2, 3]
$ids = $_POST['ids'] ?? [];
// 安全建構 SQL IN 子句 (數值型)
if (!empty($ids)) {
$placeholders = implode(',', array_fill(0, count($ids), '?')); // ?,?,?
$sql = "SELECT * FROM users WHERE id IN ($placeholders)";
$stmt = $pdo->prepare($sql);
$stmt->execute($ids); // 直接綁定陣列值
}
// 字串型欄位需加引號 (已由預處理自動處理,無需手動拼接)
// 錯誤示範:手動拼接字串極易導致 SQL 注入
// $expr = "'" . implode("','", $ids) . "'"; // 危險!
?>
<?php
// 方法一:檢查請求方法 (推薦)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 處理表單
}
// 方法二:檢查特定按鈕 (舊式寫法,不推薦)
if (isset($_POST['submit_btn'])) { ... }
// 方法三:隱藏欄位標記 (多表單頁面適用)
if (isset($_POST['form_action']) && $_POST['form_action'] === 'user_register') { ... }
?>
<?php
$str = "中文測試"; // 6 個位元組 (UTF-8 每中文 3 bytes)
echo strlen($str); // 6 (位元組數)
echo mb_strlen($str); // 4 (字元數,需 mbstring 擴充)
echo mb_strlen($str, 'UTF-8'); // 明確指定編碼
// 截取中文字串
echo mb_substr($str, 0, 2); // "中文" (正確)
echo substr($str, 0, 6); // "中文" (碰巧正確,但不可靠)
?>
<?php
// 基本重導向
header("Location: https://example.com/thanks.php");
exit; // 關鍵!防止後續程式繼續執行
// 回到上一頁 (HTTP_REFERER 可被偽造,謹慎使用)
$referer = $_SERVER['HTTP_REFERER'] ?? '/';
header("Location: $referer");
exit;
// 安全重導向:驗證目標網域
$allowedHosts = ['example.com', 'api.example.com'];
$url = $_POST['redirect_url'] ?? '/';
$parsed = parse_url($url);
if ($parsed && in_array($parsed['host'] ?? '', $allowedHosts)) {
header("Location: $url");
} else {
header("Location: /");
}
exit;
<?php
$a = 10;
$b = 20;
function sumGlobal(): void {
// 直接存取全域變數 (不需 global 關鍵字)
$GLOBALS['result'] = $GLOBALS['a'] + $GLOBALS['b'];
}
sumGlobal();
echo $result; // 30
// 注意:$GLOBALS 是超全域陣列,在函數內可直接讀寫全域符號表
// 但濫用會降低程式碼可讀性,建議改用參數傳遞、依賴注入
?>
<?php
// 明確指定來源 (安全、可讀、效能佳)
$id = $_GET['id'] ?? 0; // URL 參數 ?id=123
$name = $_POST['name'] ?? ''; // POST 表單
// $_REQUEST = $_GET + $_POST + $_COOKIE (順序由 variables_order 決定)
// 缺點:來源不明確、同名鍵值覆蓋行為不可預期、安全性較低
// 建議:棄用 $_REQUEST,明確使用 $_GET/$_POST
?>
<?php
function getClientIp(): string {
$headers = [
'HTTP_CLIENT_IP', // 標準代理頭
'HTTP_X_FORWARDED_FOR', // 常見代理頭 (可能包含多個 IP,逗號分隔)
'HTTP_X_FORWARDED', // 較少見
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED',
'REMOTE_ADDR' // 直接連線 (最後備援)
];
foreach ($headers as $header) {
if (!empty($_SERVER[$header])) {
// X-Forwarded-For 可能為 "client, proxy1, proxy2",取第一個
$ips = explode(',', $_SERVER[$header]);
$ip = trim($ips[0]);
// 驗證 IP 格式 (IPv4/IPv6)
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return $ip;
}
}
}
return '0.0.0.0'; // 未知
}
// 使用
$ip = getClientIp();
echo "Client IP: $ip";
?>
<?php
// 常用格式字元
// Y: 4位年 y: 2位年 m: 月(01-12) n: 月(1-12)
// d: 日(01-31) j: 日(1-31) H: 24時(00-23) h: 12時(01-12)
// i: 分(00-59) s: 秒(00-59) l: 星期全名 D: 星期縮寫
echo date('Y-m-d H:i:s'); // 2024-01-15 14:30:00
echo date('Y/m/d'); // 2024/01/15
echo date('Y年m月d日 l'); // 2024年01月15日 Monday
echo date('H:i'); // 14:30
// 時間戳記
$ts = time(); // 秒級
$ms = microtime(true); // 微秒級
// DateTime 物件 (推薦,支援時區、運算)
$dt = new DateTime('now', new DateTimeZone('Asia/Taipei'));
echo $dt->format('c'); // ISO 8601: 2024-01-15T14:30:00+08:00
echo $dt->format('U'); // Unix timestamp
?>
| 錯誤寫法 | 風險 | 正確做法 |
|---|---|---|
$sql = "SELECT * FROM users WHERE id = $_GET[id]"; | SQL 注入 | PDO 預處理 $stmt->execute([$_GET['id']]) |
echo $_GET['msg']; | XSS 跨站腳本 | echo htmlspecialchars($_GET['msg'], ENT_QUOTES, 'UTF-8'); |
include $_GET['page'] . '.php'; | LFI/RCE 任意檔案包含 | 白名單驗證 in_array($_GET['page'], $allowed) |
setcookie('auth', $token); | 缺少 HttpOnly、Secure、SameSite | setcookie('auth', $token, ['httponly'=>true, 'secure'=>true, 'samesite'=>'Lax']) |
session_start(); 無參數 | Session 劫持、固定攻擊 | session_start(['cookie_httponly'=>true, 'cookie_secure'=>true, 'use_strict_mode'=>true]) |
password = md5($pass); | 雜湊過弱、無鹽值 | password_hash($pass, PASSWORD_DEFAULT) / password_verify() |
<?php
// 開發環境專用
function dd(mixed ...$vars): never {
foreach ($vars as $var) {
echo '<pre>';
var_dump($var);
echo '</pre>';
}
die;
}
// 使用
dd($_POST, $_SESSION, $userObject);
// 簡易日誌
function logDebug(string $msg, mixed $context = null): void {
$line = date('Y-m-d H:i:s') . " $msg";
if ($context !== null) $line .= ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
error_log($line . PHP_EOL, 3, __DIR__ . '/logs/debug.log');
}
logDebug('User login', ['id' => $userId, 'ip' => getClientIp()]);
?>
這 10 大技巧涵蓋 PHP 開發最高頻的痛點:表單陣列處理、安全重導向、多位元組字串、IP 偵測、日期格式化與關鍵安全修正。內化這些模式,並養成「輸出必逃逸、查詢必預處理、Cookie 必 HttpOnly、Session 嚴格模式」的肌肉記憶,即能寫出既高效又安全的 PHP 程式碼。