|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
不断巩固,摸透大部分PHP常用函数,并可理解OOP,MYSQL优化,以及模板电子商务 本文经由过程一个复杂的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全局变量,如许的话,了局就能够测试。如今有一个叫做PEAR (http://pear.php.net/) 的项目在做尺度化毛病处置和数据库存取的勉力,
然而到今朝为止,还不克不及不乱运转。
上面是一个利用我的 true/false 办法挪用函数的例子:
<?php
$result=function_call_name();
if (!$result) {
//显示毛病
echo $feedback;
} else {
//没有毛病,持续
}
?>
好了,如今让咱们入手下手想一想购物车吧! 咱们需求一些根基的数据布局存储购物车的数据。例如,咱们需求一个库存数据库列出物品名字,部件号码,价钱和数目,同时,咱们
还需求纪录顾客购置的物品......太庞杂了,就写这些吧。
表2、购物车数据布局
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
);
这个布局给咱们一个根基的购物车,为了标准数据库形式,我创立一个自力的表,用于列出顾客的购物车里的内容。如许,让顾客的购物车可以有多项物品,而且可以很轻易
地和库存数据库毗连。
如今咱们需求思索桓鲈谙呱痰甑母髦止δ芰恕R桓鲎罨镜墓δ芫褪侨〉靡徊抗何锍担道锾砑游锲罚缓蠼嵴恕5比灰桓鍪导什僮鞯脑谙呱痰辏剐枰芏喙δ埽皲?物品,调剂数目等。这些就等你本人来完成了。
我从一个复杂的生成一个顾客的功效入手下手,一切这些其实就是在列队的顾客中获得下一个顾客的材料,拔出顾客表,把顾客号码在PHP4 内置的session 办理中注册。
表3、创立一个新顾客
<?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 ,那末,创立新顾客的纪录也就泡汤,接上去就是不克不及更新她的地址,不克不及往购物车里添加物品,对吧?
如今,咱们看看添加物品的进程,这个步调绝对对照轻易,在添加物品之前,要先反省物品是不是在数据库中。如许对照平安,由于物品号码来自阅读器,能够被改动。一旦晓得物品存在,咱们就可以测试它是不是已在购物车里,假如已放入,那末数目加一,而不是别的拔出一行,不然,拔出一条数目为一的纪录到购物车。
表4、添加物品到购物车
<?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。
表5、结账,减库存
<?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;
}
}
}
}
}
?>
学习了六个多月PHP了,还是个新手,在这里受到了很多人的帮助,谢谢你们! |
|