0

0

用PHP4和PostgreSQL构建一个电子商务应用_PHP

php中文网

php中文网

发布时间:2016-06-01 12:35:06

|

1270人浏览过

|

来源于php中文网

原创

postgresql电子商务

magento(麦进斗)
magento(麦进斗)

Magento是一套专业开源的PHP电子商务系统。Magento设计得非常灵活,具有模块化架构体系和丰富的功能。易于与第三方应用系统无缝集成。Magento开源网店系统的特点主要分以下几大类,网站管理促销和工具国际化支持SEO搜索引擎优化结账方式运输快递支付方式客户服务用户帐户目录管理目录浏览产品展示分析和报表Magento 1.6 主要包含以下新特性:•持久性购物 - 为不同的

下载

由 徐永久 发表于 2001年10月16日 09:06。   



本文通过一个简单的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:






//连接 postgres 数据库

$conn=pg_pconnect("user=tim dbname=db_example");



//看连接是否成功

if (!$conn) {

//如果失败则报告出错

echo pg_errormessage($conn);

exit;

}



//站点的头文件



function site_header ($title) {

return '



'.$title.'



';

}



// 页面结尾的 HTML 代码



function site_footer () {



return '';



}



//一个简单的查询执行函数,用来减少代码



function query($sql) {

global $conn;

return pg_exec($conn,$sql);

}



//让每一个页面自动启动session或者保存 session 状态



session_start();



?>





因此
我们的第一个版本的库已经可以用了它连接数据库提供了简单的 HTML

代码。



我们站点上每一个页面都包括




\n>



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



echo site_header('示范页面');



/*

页面逻辑处理

*/




echo site_footer();



?>



一般说来
在构建应用程序时把逻辑和实际的表示在我们这里就是HTML分开是很明智的。因此我把逻辑放到函数里面。但是PHP 使用函数调用的方法缺点是没有标准的出错处理过程如果函数内部有错的话呼叫函数的程序不能把把错误信息传递给用户。在其他的语言例如Java 里面你可以使用try/catch语句来处理。



我的解决办法是
每个函数总是返回 true 或者 false 设置一个$feedback全局变量这样的话结果就可以测试。现在有一个叫做PEAR (http://pear.php.net/) 的项目在做标准化错误处理以及数据库存取的努力,

但是到目前为止,还不能稳定运行。



下面是一个使用我的 true/false 方法调用函数的例子:






$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 '$0.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

);





这个结构给我们一个基本的购物车为了规范数据库模式我建立一个独立的表用于列出顾客的购物车里的内容。这样让顾客的购物车可以有多项物品并且可以很容易

地和库存数据库连接。



现在我们需要考虑桓鲈谙呱痰甑母髦止δ芰恕R桓鲎罨镜墓δ芫褪侨〉靡徊抗何锍担道锾砑游锲罚缓蠼嵴恕5比灰桓鍪导什僮鞯脑谙呱痰辏剐枰芏喙δ埽皲
?物品调整数量等。这些就等你自己来完成了。



我从一个简单的生成一个顾客的功能开始
所有这些其实就是在排队的顾客中取得下一个顾客的资料插入顾客表把顾客号码在PHP4 内置的session 管理中注册。



表三、建立一个新顾客




function cart_new() {



global $conn, $customer_id, $feedback;



// 启动一个事务

query("BEGIN WORK");



//查询下一个顾客号码

$res=query("SELECT nextval('seq_customer_id')");



//检查错误

if (!$res || pg_numrows($res)
$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)
$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 那么建立新顾客的记录也就泡汤接下来就是不能更新她的地址不能往购物车里添加物品对吧



现在我们看看添加物品的过程这个步骤相对比较容易在添加物品之前要先检查物品是否在数据库中。这样比较安全因为物品号码来自浏览器可能被篡改。一旦知道物品存在我们就能测试它是否已经在购物车里如果已经放入那么数量加一而不是另外插入一行否则插入一条数量为一的记录到购物车。



表四、添加物品到购物车






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)


//如果没有该物品,新插入一条

$res=query("INSERT INTO cart_items ".

"(customer_id,part_number,quantity)".

"VALUES ($customer_id,$item_id,$quantity)");



if (!$res || pg_cmdtuples($res)
$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)
$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。



表五、结账
减库存




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)
$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)
$feedback .= pg_errormessage($conn);

$feedback .= ' Error - no items in cart ';

query("END WORK");

return false;

} else {

$rows=pg_numrows($res2);



// 更新库存余额



for ($i=0; $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)
$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)
//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)
$feedback .= pg_errormessage($conn);

$feedback .= ' Error - updating customer information ';

query("ROLLBACK");

return false;

} else {

// 改变正式生效

query("COMMIT");



// 删除 session

$customer_id=0;

session_destroy();

return true;

}

}

}

}

}



?>





理论上
这是一个很复杂的交易每一步必须正确执行否则整个事务必须回滚到正确的顺序。



如果你没有使用本例的事务处理
那么万一在更新过程中失败的话麻烦就大了。可能你只是更新了库存的一部分如果访问者刷新页面的话你怎么知道那个库存需要减少呢



本文不想提供一个购物车的综合解决方案如果这样的话只要我有时间完全可以写一本书了但是本文演示了最基本的设计和运行的方法建议每一位Web 开发人员使用。更深入的讨论可以访问 PHPBuilder.com.



文中所有的代码可以从http
://www.phpbuilder.com/columns/linuxjournal200009.php3 下载。



译者注


作者 Tim Perdue (tim@perdue.net) 是 SourceForge.net 的建设者以及 PHPBuilder.com 和

Geocrawler
.com 的创立?

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

463

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

135

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

64

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

20

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

26

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

14

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

524

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

53

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Excel 教程
Excel 教程

共162课时 | 17.8万人学习

Go语言web开发--经典项目电子商城
Go语言web开发--经典项目电子商城

共23课时 | 1.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号