CodeIgniter 3.x 內建的 Cart Library 預設限制商品名稱只能包含英數字、破音符號、底線、冒號與空格,導致中文商品名無法加入購物車。本文深入分析源碼限制邏輯,提供三種解決方案並對比優劣,助你快速修復並理解底層機制。
檔案:system/libraries/Cart.php (約第 186-195 行)
<?php
// 原始驗證邏輯
if (!preg_match("/^[".$this->product_name_rules."]+$/i", $items['name'])) {
log_message('error', 'An invalid name was submitted as the product name: '.$items['name'].' The name can only contain alpha-numeric characters, dashes, underscores, colons, and spaces');
return FALSE;
}
// 預設規則定義 (約第 45 行)
public $product_name_rules = 'a-z0-9:\-\_\ '; // 只允許英數、冒號、連字符、底線、空格
核心問題:正則模式 a-z0-9:\-\_\ 不包含任何 Unicode 字元範圍,中文、日文、韓文、表情符號等均會被拒絕。
<?php
// 在 Controller 建構子或 MY_Cart 擴展中設置
$this->cart->product_name_rules = 'a-z0-9:\-\_\ \p{L}\p{N}\p{P}\p{S}';
// \p{L} 任意語言字母, \p{N} 數字, \p{P} 標點, \p{S} 符號 (含表情)
優點:一行配置解決,無需修改核心檔。
缺點:過於寬鬆,可能允許惡意字元 (如控制字元、零寬空格),需配合前端/其他層驗證。
<?php
$this->cart->product_name_rules = 'a-z0-9:\-\_\ \x{4e00}-\x{9fff}\x{3400}-\x{4dbf}\x{20000}-\x{2a6df}\x{2a700}-\x{2b73f}\x{2b740}-\x{2b81f}\x{2b820}-\x{2ceaf}\xf900-\x{faff}\x{3300}-\x{33ff}\x{fe30}-\x{fe4f}\x{f900}-\x{faff}';
// 涵蓋基本區、擴展A/B/C/D/E/F、相容字元、康熙部首等
優點:精確控制允許字元集。
缺點:正則極長難維護,漏字風險高,不支援 PHP 7.3 以下版本的 Unicode 屬性逃逸。
建立 application/libraries/MY_Cart.php 繼承核心類,重寫驗證邏輯:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Cart extends CI_Cart {
/**
* 重寫 name 驗證:允許 UTF-8 可見字元,拒絕控制字元
*/
protected function _validate_name(string $name): bool {
// 1. 長度限制 (防止異常長名稱撐爆 session/cookie)
if (mb_strlen($name, 'UTF-8') > 255) {
log_message('error', 'Cart name too long: ' . mb_strlen($name));
return false;
}
// 2. 字元白名單:字母、數字、常用標點、空格、CJK 統一表意文字
// 使用 u 修飾符啟用 UTF-8 模式
$pattern = '/^[\p{L}\p{N}\p{P}\p{Zs}\p{Sc}\p{Sk}\p{Sm}\p{So}]+$/u';
// \p{L} 字母, \p{N} 數字, \p{P} 標點, \p{Zs} 空格分隔符, \p{Sc} 貨幣符號, \p{Sk} 修飾符號, \p{Sm} 數學符號, \p{So} 其他符號
if (!preg_match($pattern, $name)) {
// 記錄被拒絕的字元 (調試用)
$invalidChars = preg_replace($pattern, '', $name);
log_message('debug', 'Cart rejected name: ' . $name . ' | invalid chars: ' . bin2hex($invalidChars));
return false;
}
// 3. 拒絕控制字元、格式化字元、代理區 (防 XSS/注入)
if (preg_match('/[\p{Cc}\p{Cf}\p{Cs}]/u', $name)) {
log_message('error', 'Cart name contains control/format/surrogate chars: ' . $name);
return false;
}
return true;
}
/** 覆寫 insert 方法調用新驗證 */
public function insert($items = []) {
// ... 複製父類 insert 邏輯,將原驗證替換為 $this->_validate_name($items['name'])
// 為簡潔起見此處省略完整複製,實際請從 CI_Cart 複製 insert() 並修改驗證行
}
}
優點:
注意:CodeIgniter 3.x 載入 Library 時會自動尋找 MY_ 前綴類,無需額外配置。
在加入購物車前,將中文名編碼為安全字串 (Base64 / JSON / URL 編碼),取出時解碼:
<?php
// 加入購物車前
$safeName = base64_encode($chineseName); // 或 json_encode($chineseName)
$this->cart->insert([
'id' => $productId,
'qty' => 1,
'price' => $price,
'name' => $safeName, // 現在只包含 A-Z a-z 0-9 + / =
'options' => ['original_name' => $chineseName] // 可選:原名存 options
]);
// 讀取購物車時
foreach ($this->cart->contents() as $item) {
$displayName = base64_decode($item['name']);
// 或從 options 取原名
echo $displayName;
}
優點:零修改框架代碼,相容所有 CI 版本。
缺點:
base64 產生 + / = 可能觸發其他驗證 (需確認 product_name_rules 包含這些)。| 維度 | 方案一: 改規則 | 方案二: MY_Cart | 方案三: 預編碼 |
|---|---|---|---|
| 實施速度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 安全性 | ⭐⭐ (需自行加強) | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 可維護性 | ⭐⭐ (分散在配置中) | ⭐⭐⭐⭐⭐ (集中封裝) | ⭐⭐⭐ (業務代碼耦合) |
| 升級相容 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 搜尋/報表友好 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐ (需解碼) |
| 推薦場景 | 快速原型、內部工具 | 正式專案、長期維護 | 極度不想動框架、臨時方案 |
<?php
// 允許:各語言文字、數字、常用標點、空格、貨幣符號、基本表情符號
// 拒絕:控制字元(Cc)、格式化字元(Cf)、代理對(Cs)、私有使用區(Co)
const CART_NAME_PATTERN = '/^
[\p{L}\p{N}\p{P}\p{Zs}\p{Sc}\p{Sk}\p{Sm}\p{So}] # 允許字元類別
+ # 至少一個
$/ux'; // u: UTF-8, x: 忽略空白註釋
// 使用範例
function isValidCartName(string $name): bool {
if (mb_strlen($name) > 200) return false;
if (!preg_match(self::CART_NAME_PATTERN, $name)) return false;
if (preg_match('/[\p{Cc}\p{Cf}\p{Cs}\p{Co}]/u', $name)) return false;
return true;
}
CI 4 的 CodeIgniter\Cart\Cart 使用 Validation 服務驗證,規則定義在 Config\Validation.php 或模型 $validationRules 中,預設規則為 alpha_numeric_punct (含基本標點)。修改方式:
<?php
// app/Config/Validation.php
public $cartItem = [
'name' => 'required|max_length[255]|utf8|regex_match[/^[\p{L}\p{N}\p{P}\p{Zs}\p{Sc}\p{Sk}\p{Sm}\p{So}]+$/u]',
];
CI 4 內建 utf8 規則已檢查有效 UTF-8 編碼,配合 regex_match 更安全簡潔。
CodeIgniter 購物車中文問題本質是舊版正則未考慮 Unicode。生產專案強烈建議採用 方案二 (MY_Cart 擴展),集中封裝驗證邏輯,兼顧安全性、可維護性與升級相容性。若專案已遷移至 CI 4,請直接調整 Validation 規則,享受現代化驗證體系帶來的便利。