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

PHP 實用開發技巧速查:核心功能與常見陷阱

     編輯:PHP 相關知識

資深 PHP 開發者累積的實戰技巧,往往能大幅提升開發效率與程式碼品質。本文精選 10 大高頻實用技巧,涵蓋表單處理、安全防護、超全域變數、Header 操作、字串處理與時間取得,並標註常見錯誤與現代最佳實務。

1. 批次處理 Checkbox 陣列

<!-- 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) . "'"; // 危險!
?>

2. 判斷表單是否送出

<?php
// 方法一:檢查請求方法 (推薦)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 處理表單
}

// 方法二:檢查特定按鈕 (舊式寫法,不推薦)
if (isset($_POST['submit_btn'])) { ... }

// 方法三:隱藏欄位標記 (多表單頁面適用)
if (isset($_POST['form_action']) && $_POST['form_action'] === 'user_register') { ... }
?>

3. 字串長度計算:strlen vs mb_strlen

<?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);    // "中文" (碰巧正確,但不可靠)
?>

4. HTTP 重導向與安全防護

<?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;

5. 超全域變數 $GLOBALS 實戰用法

<?php
$a = 10;
$b = 20;

function sumGlobal(): void {
    // 直接存取全域變數 (不需 global 關鍵字)
    $GLOBALS['result'] = $GLOBALS['a'] + $GLOBALS['b'];
}

sumGlobal();
echo $result; // 30

// 注意:$GLOBALS 是超全域陣列,在函數內可直接讀寫全域符號表
// 但濫用會降低程式碼可讀性,建議改用參數傳遞、依賴注入
?>

6. 表單取值:$_GET / $_POST / $_REQUEST

<?php
// 明確指定來源 (安全、可讀、效能佳)
$id = $_GET['id'] ?? 0;      // URL 參數 ?id=123
$name = $_POST['name'] ?? ''; // POST 表單

// $_REQUEST = $_GET + $_POST + $_COOKIE (順序由 variables_order 決定)
// 缺點:來源不明確、同名鍵值覆蓋行為不可預期、安全性較低
// 建議:棄用 $_REQUEST,明確使用 $_GET/$_POST
?>

7. 取得客戶端真實 IP (含代理偵測)

<?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";
?>

8. 日期時間格式化速查

<?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
?>

9. 常見安全陷阱與修正

錯誤寫法風險正確做法
$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、SameSitesetcookie('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()

10. 除錯輸出技巧

<?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 程式碼。

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