CodeIgniter 內置 Cart 庫在驗證商品名稱時,默認正則僅允許 ASCII 字符,導致中文商品名添加失敗。本文定位源碼位置,提供最小侵入性修復方案,並說明正則修改原則。
$this->load->library('cart');
$this->cart->insert([
'id' => 'sku_001',
'name' => '中文商品名', // 包含中文
'price' => 99,
'qty' => 1
]);
// 返回 false,日誌記錄:An invalid name was submitted as the product name...
文件:system/libraries/Cart.php (CI 3.x) 約第 186-190 行:
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;
}
默認配置 $this->product_name_rules = ':\w\d\s\-\_'; (或類似),正則字符類不包含中文 Unicode 範圍。
在控制器或 MY_Cart 擴展類中重置 product_name_rules:
<?php
class MY_Cart extends CI_Cart {
public function __construct() {
parent::__construct();
// 允許:字母、數字、中文、下劃線、連字符、冒號、空格、括號、常見標點
$this->product_name_rules = 'a-zA-Z0-9\u4e00-\u9fa5\s\-\_\:\.\,\(\)\(\)';
}
}
// 控制器中正常載入 $this->load->library('cart'); 會自動加載 MY_Cart
?>
[] 內轉義特殊字符,\u4e00-\u9fa5 需 PHP 開啟 u 修飾符支持(CI 內部 preg_match 已加 i,需確認是否加 u,建議改用 [\x{4e00}-\x{9fa5}] 並顯式加 u 修飾符,或直接擴展 preg_match 調用)。// system/libraries/Cart.php 第 186 行附近
// 原:"/^[".$this->product_name_rules."]+$/i"
// 改:支持中文的正則 (需 u 修飾符)
if ( ! preg_match("/^[\w\d\s\-\_\:\.\,\x{4e00}-\x{9fa5}]+$/iu", $items['name'])) {
// ...
}
// 控制器插入前
$name = $this->input->post('name');
$safe_name = urlencode($name); // 或 base64_encode
$this->cart->insert(['name' => $safe_name, ...]);
// 讀取時 urldecode/base64_decode
// 缺點:增加編解碼開銷、數據庫存儲不直觀、搜索/報表受影響
正則修改原則與最佳實踐
- 白名單原則:明確列出允許的字符集合,而非嘗試過濾危險字符。
- 最小權限:僅允許業務真正需要的字符(如商品名通常不需要
<>"' 等)。
- Unicode 範圍:中文基本區
\u4e00-\u9fa5、擴展區 \u3400-\u4dbf、標點 \u3000-\u303f。建議使用 [\p{Han}\p{L}\p{N}\s\-\_\:\.\,\(\)\(\)] (需 u 修飾符) 覆蓋所有漢字、字母、數字。
- 測試用例:覆蓋純中文、中英混合、含特殊標點、極長名稱、XSS 嘗試 (
<script>) 等。
驗證修復
$this->load->library('cart');
$test_cases = [
'純中文商品',
'English Product',
'中英混合 Product 123',
'特殊符號:、。,()',
'<script>alert(1)</script>', // 應被攔截或轉義
];
foreach ($test_cases as $name) {
$result = $this->cart->insert(['id'=>uniqid(), 'name'=>$name, 'price'=>10, 'qty'=>1]);
echo $name . ' => ' . ($result ? '成功' : '失敗') . "\n";
}
採用 方案一 (MY_Cart 擴展) + Unicode 白名單正則,即可徹底解決中文商品名問題,且保持代碼可維護性與安全性。