• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    用PHP4和PostgreSQL構建一個電子商務應用

    發布: 2007-7-14 19:53 | 作者: 佚名    | 來源: 網絡轉載     | 查看: 9次 | 進入軟件測試論壇討論

    領測軟件測試網


    本文通過一個簡單的web 應用,演示了 PHP 和 PostgresSQL 在電子商務中的應用。

    不久以前,如果要架構一個嚴肅的Web應用的話,意味著購買價格不菲的Cold Fusion 許可,以及一個商業的數據庫服務程序像Sybase 加上Sun 服務器。幸運的是,這樣的日子一去不復返了。隨著日漸成熟的免費數據庫市場以及Apache 使用者的大量增長,一些替代產品已經具有相當,甚至超過了這些專有軟件的能力。

    比較好的開放源碼軟件的一種是 PHP,一個很像Perl 的腳本語言,以及PostgreSQL,一個很強大的面向對象的數據庫。如果把兩者結合起來的話,你可以設計從簡單的留言簿到一個巨大的基于Web 的財務軟件。PHP 提供大腦而Postgres 提供發達的肌肉。

    下面介紹一個很基本的 PHP 購物車和庫存應用,充分利用 Postgres 的事務功能。源碼推淥柿峽梢源?PHPBuilder.com 下載。

    首先要提到的是應用程序的結構,在我的PHP Web 應用中,我總是首先設置一個綜合庫,網站的每一個頁面都會用到它,取名叫common.php 存放在include 目錄。

    這個庫會處理日常任務,例如數據庫連接,用戶鑒別,站點的頭部/尾部文件等。把這些函數放在一個地方,我們的應用看上去很干凈,容易維護。

    表一:示范的庫代碼

    common.php:
    <?php

    //連接 postgres 數據庫
    $conn=pg_pconnect("user=tim dbname=db_example");

    //看連接是否成功
    if (!$conn) {
    //如果失敗則報告出錯
    echo pg_errormessage($conn);
    exit;
    }

    //站點的頭文件

    function site_header ($title) {
    return '<HTML>
    <HEAD>
    <TITLE>'.$title.'</TITLE>
    </HEAD>
    <BODY>';
    }

    // 頁面結尾的 HTML 代碼

    function site_footer () {

    return '</BODY></HTML>';

    }

    //一個簡單的查詢執行函數,用來減少代碼

    function query($sql) {
    global $conn;
    return pg_exec($conn,$sql);
    }

    //讓每一個頁面自動啟動session或者保存 session 狀態

    session_start();

    ?>

    因此,我們的第一個版本的庫已經可以用了,它連接數據庫,提供了簡單的 HTML
    代碼。

    我們站點上每一個頁面都包括:

    <?php<n>

    require ($DOCUMENT_ROOT.'/include/common.php');

    echo site_header('示范頁面');

    /*
    頁面邏輯處理
    */

    echo site_footer();

    ?>

    一般說來,在構建應用程序時,把邏輯和實際的表示(在我們這里就是HTML)分開是很明智的。因此,我把邏輯放到函數里面。但是PHP 使用函數調用的方法,缺點是沒有標準的出錯處理過程,如果函數內部有錯的話,呼叫函數的程序不能把把錯誤信息傳遞給用戶。在其他的語言,例如Java 里面,你可以使用try/catch語句來處理。

    我的解決辦法是,每個函數總是返回 true 或者 false ,設置一個$feedback全局變量,這樣的話,結果就可以測試,F在有一個叫做PEAR (http://pear.php.net/) 的項目在做標準化錯誤處理以及數據庫存取的努力,
    但是到目前為止,還不能穩定運行。

    下面是一個使用我的 true/false 方法調用函數的例子:

    <?php

    $result=function_call_name();

    if (!$result) {
    //顯示錯誤
    echo $feedback;
    } else {
    //沒有錯誤,繼續
    }

    ?>

    好了,現在讓我們開始想想購物車吧! 我們需要一些基本的數據結構存儲購物車的數據。例如,我們需要一個庫存數據庫列出物品名字,部件號碼,價格以及數量,同時,我們
    還需要記錄顧客購買的物品......太復雜了,就寫這些吧。

    表二、購物車數據結構

    Cart.sql:

    # 建立一個順序表用來產生顧客號碼。
    # 每個id 之間用隨意的一個數字分開,以防別人猜測購物車號碼。
    create sequence seq_customer_id increment 26 start 1;

    create table customers (
    customer_id int not null default 0 primary key,
    name text,
    address text,
    credit_card text,
    total_order MONEY DEFAULT '{CONTENT}.00'
    );

    create table cart_items (
    cart_item serial,
    customer_id int,
    part_number int,
    quantity int
    );

    create index idx_cart_customer on cart_items(customer_id);

    create table item_inventory (
    part_number serial,
    name text,
    price float,
    inventory int
    );

    這個結構給我們一個基本的購物車,為了規范數據庫模式,我建立一個獨立的表,用于列出顧客的購物車里的內容。這樣,讓顧客的購物車可以有多項物品,并且可以很容易
    地和庫存數據庫連接。

    現在我們需要考慮桓鱸諳呱痰甑母髦止δ芰。一各c罨鏡墓δ芫褪僑〉靡徊抗何锍擔道鍰砑游鍥罰緩蠼嵴。当然一个蕦操醉d腦諳呱痰輳剮枰芏喙δ,习棷?物品,調整數量等。這些就等你自己來完成了。

    我從一個簡單的生成一個顧客的功能開始,所有這些其實就是在排隊的顧客中取得下一個顧客的資料,插入顧客表,把顧客號碼在PHP4 內置的session 管理中注冊。

    表三、建立一個新顧客
    <?php

    function cart_new() {

    global $conn, $customer_id, $feedback;

    // 啟動一個事務
    query("BEGIN WORK");

    //查詢下一個顧客號碼
    $res=query("SELECT nextval('seq_customer_id')");

    //檢查錯誤
    if (!$res || pg_numrows($res)<1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error - Database didn't return next value ';
    query("ROLLBACK");
    return false;
    } else {
    $customer_id=pg_result($res,0,0);

    // 登記到 session
    session_register('customer_id');

    // 插入新顧客
    $res=query("INSERT INTO customers (customer_id)
    VALUES ('$customer_id')");

    //檢查錯誤
    if (!$res || pg_cmdtuples($res)<1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error - couldn't insert new customer row ';
    query("ROLLBACK");
    return false;
    } else {
    //commit this transaction
    query("COMMIT");
    return true;
    }
    }
    }

    ?>

    這段代碼比較長,雖然我不是很喜歡,但是它演示了怎樣正確開始和結束Postgres 的事務以及怎樣檢查查詢語句的錯誤。我要在所有的代碼用到同樣的錯誤監測程序,我想,你也應該如此。

    需要計劃好如果查詢出錯的處理辦法,你是直接終止程序呢?還是重新運行查詢語句,抑或繼續執行,就當什么也沒有發生?仔細考慮每種選擇的結果。例如,如果不能得到下一個顧客的customer_id ,那么,建立新顧客的記錄也就泡湯,接下來就是不能更新她的地址,不能往購物車里添加物品,對吧?

    現在,我們看看添加物品的過程,這個步驟相對比較容易,在添加物品之前,要先檢查物品是否在數據庫中。這樣比較安全,因為物品號碼來自瀏覽器,可能被篡改。一旦知道物品存在,我們就能測試它是否已經在購物車里,如果已經放入,那么數量加一,而不是另外插入一行,否則,插入一條數量為一的記錄到購物車。

    表四、添加物品到購物車
    <?php

    function cart_add_item($item_id,$quantity=1) {
    global $customer_id, $feedback, $conn;

    $res=query("SELECT * FROM item_inventory WHERE part_number='$item_id'");

    if (!$res || pg_numrows($res)<1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error-item not found ';
    return false;
    } else {
    // 檢查物品是否放入購物車,如果是,增加數量
    // 開始事務
    query("BEGIN WORK");

    $res=query("SELECT * FROM cart_items ".
    "WHERE part_number='$item_id' AND customer_id='$customer_id' FOR UPDATE");

    if (!$res || pg_numrows($res)<1) {

    //如果沒有該物品,新插入一條
    $res=query("INSERT INTO cart_items ".
    "(customer_id,part_number,quantity)".
    "VALUES ($customer_id,$item_id,$quantity)");

    if (!$res || pg_cmdtuples($res) < 1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error-couldn't insert into cart ';
    //盡管沒有東西被改變,但是最好還是回滾事務
    query("ROLLBACK");
    return false;
    } else {
    query("COMMIT");
    return true;
    }
    } else {
    //購物車中已經存在該物品
    $res=query("UPDATE cart_items SET quantity = quantity + $quantity ".
    "WHERE part_number='$item_id' AND
    customer_id='$customer_id'");
    if (!$res || pg_cmdtuples($res) < 1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error-couldn't increment quantity in cart ';
    query("ROLLBACK");
    return false;
    } else {
    // 提交改變,正式更新數據庫。
    query("COMMIT");
    return true;
    }
    }
    }
    }

    ?>

    現在我們能建立新顧客,并且他們添加物品了。我們現在需要結賬,并減掉庫存。這一部分是最復雜的,充分利用了Postgres 的事務功能和先進鎖機制。

    我們用Postgres 的 SELECT...FOR UPDATE 語法作為開始,這個語句能有效地對當前選擇的行加鎖使你能在一個事務里更新并提交改變。

    通過在一個事務里使用這個語句,你可以保證數據的一致性。在其他的一些數據庫,例如MySQL ,就不能鎖定指定的數據行,而得到不正確的數據以及沒用的庫存統計。

    這個語句也能利用子查詢,另外一個數據庫的標準特性。子查詢可以讓你很省事地把兩個查詢結合在一起,

    鎖定行以后,我們需要按照購物車的物品減少對應的庫存量。為簡便起見,我們對庫存不夠不報告錯誤,并把庫存變為負數。你可以自己寫一個管理頁面,查看負數庫存的物品,并去訂購。

    最后,我們更新顧客表中的信用卡,購買信息,合計購買金額,撤掉這個顧客的session。

    表五、結賬,減庫存
    <?php

    function cart_checkout($credit_card,$address,$name) {
    global $conn, $customer_id, $feedback;

    // 事務開始
    query("BEGIN WORK");

    // 鎖住庫存表的對應行,用一個簡單的子查詢來處理。

    $sql="SELECT * FROM item_inventory ".
    "WHERE part_number ".
    "IN (SELECT part_number FROM cart_items ".
    "WHERE customer_id='$customer_id') ".
    "FOR UPDATE";
    $res=query($sql);

    if (!$res || pg_numrows($res)<1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error - no items locked ';
    query("END WORK");
    return false;
    } else {

    // 庫存的某幾行已被鎖定,從購物車取得物品以及數量。
    $sql="SELECT part_number,quantity ".
    "FROM cart_items ".
    "WHERE
    customer_id='$customer_id' ".
    "ORDER BY part_number DESC";
    $res2=query($sql);

    if (!$res2 || pg_numrows($res2)<1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error - no items in cart ';
    query("END WORK");
    return false;
    } else {
    $rows=pg_numrows($res2);

    // 更新庫存余額

    for ($i=0; $i < $rows; $i++) {
    // 讀取購物車數據
    $quantity=pg_result($res2,$i,'quantity');
    $item_id=pg_result($res2,$i,'part_number');

    $res3=query("UPDATE item_inventory".
    "SET inventory =inventory-$quantity ".
    "WHERE part_number='$item_id'");

    if (!$res3 || pg_cmdtuples($res3) < 1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error - updating inventory failed ';
    query("ROLLBACK");
    return false;
    }
    }
    // 庫存更新結束,得到這個訂單的合計金額并更新顧客記錄
    $res=query("SELECT sum(cart_items.quantity*item_inventory.price) ".
    "FROM cart_items,item_inventory ".
    "WHERE cart_items.customer_id='$customer_id' ".
    "AND cart_items.part_number=item_inventory.part_number");

    if (!$res || pg_numrows($res) < 1) {
    //couldn't get order total
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error - couldn't get order total ';
    query("ROLLBACK");
    return false;
    } else {
    // 更新顧客表
    $total=pg_result($res,0,0);
    $res=query("UPDATE customers ".
    "SET address='$address',name='$name',".
    "total_order='$total',credit_card='$credit_card'".
    "WHERE customer_id='$customer_id'");

    if (!$res || pg_cmdtuples($res) < 1) {
    $feedback .= pg_errormessage($conn);
    $feedback .= ' Error - updating customer information ';
    query("ROLLBACK");
    return false;
    } else {
    // 改變正式生效
    query("COMMIT");

    // 刪除 session
    $customer_id=0;
    session_destroy();
    return true;
    }
    }
    }
    }
    }

    ?>

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>