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

PHP 仿 CodeIgniter 購物車類完整實作

     編輯:PHP 綜合知識

參考 CodeIgniter 經典購物車庫,實現一個輕量、Session 持久化、支援選項 (options) 的購物車類。功能涵蓋:加入/更新/刪除商品、統計總金額/總種類/總數量、單項小計、清空購物車、資料驗證與錯誤日誌。

Cart 類核心代碼

class Cart {
    private $productIdRules = 'a-z0-9_\-.';
    private $productNameRules = 'a-z0-9_\-.:';
    private $debug = true;
    private $_cart = [];

    public function __construct() {
        session_start();
        if (isset($_SESSION['cart_contents'])) {
            $this->_cart = $_SESSION['cart_contents'];
        } else {
            $this->_cart = ['cart_total' => 0, 'total_items' => 0];
        }
    }

    /** 加入商品 (支援單筆或批量陣列) */
    public function insert($items) {
        if (!is_array($items) || empty($items)) return false;
        $saved = false;
        $items = isset($items['id']) ? [$items] : $items; // 統一為二維
        foreach ($items as $item) {
            if ($this->_insert($item)) $saved = true;
        }
        if ($saved) { $this->_save(); return true; }
        return false;
    }

    /** 更新數量 (依 rowid) */
    public function update($items) {
        if (!is_array($items) || empty($items)) return false;
        $saved = false;
        $items = isset($items['rowid']) ? [$items] : $items;
        foreach ($items as $item) {
            if ($this->_update($item)) $saved = true;
        }
        if ($saved) { $this->_save(); return true; }
        return false;
    }

    /** 取得購物車內容 */
    public function contents() { return $this->_cart; }
    public function total() { return $this->_cart['cart_total']; }
    public function totalItems() { return $this->_cart['total_items']; }

    /** 清空購物車 */
    public function destroy() {
        $this->_cart = ['cart_total' => 0, 'total_items' => 0];
        unset($_SESSION['cart_contents']);
    }

    // --- 私有方法 ---
    private function _insert($item) {
        // 驗證必要欄位
        foreach (['id','qty','price','name'] as $f) {
            if (!isset($item[$f])) return $this->_log("缺少欄位: $f");
        }
        // 數量清理
        $item['qty'] = (int)preg_replace('/[^0-9]/', '', $item['qty']);
        if ($item['qty'] <= 0) return $this->_log("數量無效");
        // ID/名稱格式驗證
        if (!preg_match("/^[$this->productIdRules]+$/i", $item['id'])) return $this->_log("ID格式錯誤");
        if (!preg_match("/^[$this->productNameRules]+$/i", $item['name'])) return $this->_log("名稱格式錯誤");
        // 價格清理
        $item['price'] = (float)preg_replace('/[^0-9.]/', '', $item['price']);
        if ($item['price'] < 0) return $this->_log("價格無效");

        // 生成 rowid (含 options 區分)
        $rowid = isset($item['options']) && $item['options']
            ? md5($item['id'] . serialize($item['options']))
            : md5($item['id']);

        unset($this->_cart[$rowid]);
        $this->_cart[$rowid] = ['rowid' => $rowid] + $item;
        return true;
    }

    private function _update($item) {
        if (!isset($item['rowid'], $item['qty']) || !isset($this->_cart[$item['rowid']])) return false;
        $item['qty'] = (int)preg_replace('/[^0-9]/', '', $item['qty']);
        if (!is_numeric($item['qty'])) return false;
        if ($this->_cart[$item['rowid']]['qty'] == $item['qty']) return false; // 無變化

        if ($item['qty'] <= 0) {
            unset($this->_cart[$item['rowid']]);
        } else {
            $this->_cart[$item['rowid']]['qty'] = $item['qty'];
        }
        return true;
    }

    private function _save() {
        unset($this->_cart['total_items'], $this->_cart['cart_total']);
        $total = 0;
        foreach ($this->_cart as $key => $val) {
            if (!is_array($val) || !isset($val['price'], $val['qty'])) continue;
            $subtotal = $val['price'] * $val['qty'];
            $this->_cart[$key]['subtotal'] = $subtotal;
            $total += $subtotal;
        }
        $this->_cart['total_items'] = count($this->_cart);
        $this->_cart['cart_total'] = $total;
        if (count($this->_cart) <= 2) { // 只有統計欄位
            unset($_SESSION['cart_contents']);
        } else {
            $_SESSION['cart_contents'] = $this->_cart;
        }
    }

    private function _log($msg) {
        if ($this->debug) file_put_contents('cart_error.log', date('Y-m-d H:i:s')." $msg\n", FILE_APPEND);
        return false;
    }
}

使用範例

session_start();
require 'Cart.php';

$cart = new Cart();

// 加入商品
$cart->insert([
    ['id' => 'SKU001', 'qty' => 2, 'price' => 199.00, 'name' => 'Wireless Mouse', 'options' => ['color' => 'black']],
    ['id' => 'SKU002', 'qty' => 1, 'price' => 899.00, 'name' => 'Mechanical Keyboard'],
]);

// 更新數量 (需先取得 rowid)
$items = $cart->contents();
foreach ($items as $rowid => $item) {
    if ($item['id'] === 'SKU001') {
        $cart->update(['rowid' => $rowid, 'qty' => 3]);
        break;
    }
}

// 顯示購物車
echo "總金額: {$cart->total()} 元\n";
echo "商品種類: {$cart->totalItems()}\n";
foreach ($cart->contents() as $rowid => $item) {
    if (!is_array($item) || !isset($item['price'])) continue;
    echo "- {$item['name']} x{$item['qty']} = {$item['subtotal']} 元\n";
}

// 清空
// $cart->destroy();

擴充建議

  • 優惠碼/折扣:在 _save() 計算總價前套用折扣邏輯。
  • 庫存檢查:insert/update 時呼叫庫存服務驗證。
  • 資料庫持久化:登入用戶可將購物車同步至 DB,Session 只作臨時快取。
  • 前端整合:輸出 JSON 供 Vue/React 直接渲染。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved