php程序设计代码教程(4)
时间:2008-09-08 来源:shell-wgy
以下就是 Apache 伺服器上的使用者身份确认的设定。
AuthType Basic
AuthName MyMember
AuthUserFile /usr/local/MyMember.txt
Options Includes ExecCGI
require valid-user
在这个例子中,当使用者在看 MyMember 目录下所有的档案,包括图片档案及其它各式档案时,都需要使用者的帐号密码确认。而使用者的帐号及密码档都存在于 /usr/local/MyMember.txt 之中。
这个帐号密码档 /usr/local/MyMember.txt 的样子可能如下例。其中冒号前的字串是使用者帐号,冒号之后的字串是经过不可还原加密的密码,编码一般都是使用传统的 DES 编码,密码的头二个字是类似种子的字元 (salt),本例中都是 3P。每行代表一位使用者。当然 Webmaster 要自行控制重覆帐号的情形。比较特殊是在 Win32 系统上架 Apache 的情形,冒号后的密码不可加密,因为 Win32 没有提供这方面的编码 API,因此使用者密码以明码的方式存在。
john1234:3PWudBlJMiwro
queenwan:3PFNVLNPN9W0M
noname00:3PEsXaJx5pk7E
wilson49:3PjoWb0EnaG22
rootboot:3PIt0snI6.84E
sun_moon:3PvymMeNOc.x.
nobody38:3PbskPKwV94hw
在 Apache 1.3.6 版上,可以用 ~apache/bin/htpasswd 来产生单笔的帐号及密码,但对于需要大笔资料的商业站台,可能就需要自行写程式来处理了。UNIX 上需要呼叫 crypt() 来处理编码。 在一切都设定好了之后,连线时就会在浏览器出现查核密码的视窗,如上图就是 SEEDNet 的 MySEED 网站的使用者查核机制。在输入了帐号及密码后,浏览器会将它用 BASE64 编码后,传到伺服器端。当然 BASE64 只是编码不是加密,因此在网路上这种传输的安全性仍然不高,还是有可能被中间的刽客截下,再将 BASE64 还原,这也是整个使用者认证中最美中不足的地方,或许日后支援摘要认证 (Digest) 及使用 MD5 编码后,可以解决这种问题。之后每一页仍然需要帐号及密码,只不过浏览器会帮你主动送出,不用再输入帐号密码了。这方面浏览器会保留到被关闭为止,下次重执行浏览器仍需输入第一次。在使用者数量少时,使用上述的方法轻松又省事。但是在使用者有数万人,甚至数十万人时,会发生整个伺服器的效率都被搜寻帐号密码下拖垮,可能读取一页需要数十秒到数分钟。这种情形再使用伺服器提供的密码查核机制就不太明智了。在 Netscape Enterprise Server 上可能就可以使用 NSAPI 来开发自己的查核方式,在 IIS 上也可以用 ISAPI 过滤器开发。写 C/C++ 程式呼叫 NSAPI/ISAPI 总是很累,在 PHP 上有了另外的选择,这也是本节的主题。PHP 的 HTTP 相关函式库提供了 header() 的函式。许多 Web 伺服器与客户端的互动,都可以使用这个函式来变戏法。例如在某个 PHP 页面最开始处,也就是第一行或第二行,加入以下的程式,可以将使用者重导到作者的网页。
header("Location: http://wilson.gs");
exit;
?>
当然,在上述程式之后的 HTML 文字或者是 PHP 程式都永远不会出现在使用者端了。同样的道理,我们就用 header() 来变使用者认证的把戏。可以在 PHP 的最开头送出字串到使用者端,就会在使用者端出现下图的视窗。
Header("WWW-Authenticate: Basic realm=\"Member\"");
Header("HTTP/1.0 401 Unauthorized");
?>
在程式中字串 realm=\"Member\" 中的 Member 字样出现在图中,当然若使用中文字取代,浏览器端也会出现中文字,如上面的 MySEED 图。若 Web 站台使用者还有其它语文,如英文或日文,送出中文的 realm 字串似乎就比较不合适。无论如何,这都要视站台的性质及使用者定位而决定。
当然这还是很粗糙,因为除了送出视窗后,就没有下文了,帐号输入正确也好,输入错误也罢,都不会有任何的结果。我们需要再更进阶的程式来处理。在后端的使用认证上,考虑使用资料库作为储存帐号及密码的后端,在这种架构可以容纳许多的使用者,管它一万个使用者还是十万个使用者。若您的站已有数十万个使用者帐号,那么恭喜您,您的站算是世界级的大站了。MySQL 是个不错的选择,许多站台,甚至是商业化的站台都用它来做后端的资料库。当然您要架真正的商业站台,钱不是问题的话,那可以使用口碑最广的 Oracle 资料库系列。要在 PHP 中使用任何资料库,都要先将资料库的伺服器端及客户端设定好,之后才编译 PHP 及 Apache 系统。准备好 MySQL 及 PHP 之后,先在 MySQL 中加入新的资料库,本例是加入 mymember,用别的名字当然也可以。MySQL 要加入资料库 (Database) 很容易,只要在 MySQL 存放 Database 的地方 mkdir 就可以了。例如在 UNIX Shell 下打hahaha:/usr/local/mysql/data# mkdir mymember在建立了资料库之后,尚需要建立资料表格 (Table) 方能使用。设定的表格如下,可以将它储在 /tmp/memberauth.sql 中CREATE TABLE MemberAuth (
Serial mediumint(9) NOT NULL auto_increment,
Username char(8) NOT NULL,
Password char(8) NOT NULL,
Enable char(1) DEFAULT '0' NOT NULL,
PRIMARY KEY (Serial)
);
档案 memberauth.sql 先看看 memberauth.sql 的这些栏位。Serial 是个自动增加的整数栏位,每输入一笔资料,就会自动加一,这当然不能是空的栏位,于是就用 NOT NULL 了。第二个栏位是 Username,代表使用者的帐号,为了统一以及适应各系统起见,设定成八个字,当然这个栏位也不能是空的。Password 是第三个栏位,为使用者的密码。第四个栏位 Enable 做为帐号是否有效的旗标,设计上 0 表示无用,1 表可用,日后还可加入其它值做不同的用途。设计好了资料表之后,就要将资料表加入资料库了。由于常要使用 MySQL 资料库,可以到 http://www.phpwizard.net/phpMyAdmin 下载 phpMyAdmin,使用浏览器操作及管理 MySQL,轻松又方便。若使用这套 phpMyAdmin 可以在它的使用者介面上输入 memberauth.sql 加入 MySQL 中。或者也可以在 UNIX Shell 下输入下式,也是有同样的效果。
mysql mymember
在准备好了之后,就可以输入使用者帐号及密码在 memberauth 资料表中了。当然还是使用 phpMyAdmin 方便,用 mysql 程式就要一笔笔的 INSERT 了。接着进入了设计函式的阶段了。
//---------------------------
// 使用者认证函式 auth.inc
// Author: Wilson Peng
// Copyright (C) 1999
//---------------------------
$error401 = "/home/phpdocs/error/401.php";
if ($PHP_AUTH_PW=="") {
Header("WWW-Authenticate: Basic realm=\"超金卡会员\"");
Header("HTTP/1.0 401 Unauthorized");
include($error401);
exit;
} else
{
$db_id = mysql_pconnect("localhost", "myid", "mypw");
$result = mysql_db_query("mymember","select password, enable from MemberAuth where username='$PHP_AUTH_USER'");
$row = mysql_fetch_array($result);
$MemberPasswd = $row[0];
$MemberEnable = $row[1];
if ($MemberEnable==0) {
echo "您的帐号被停用了";
exit;
}
if ($PHP_AUTH_PW!=$MemberPasswd) {
Header("WWW-Authenticate: Basic realm=\"超金卡会员\"");
Header("HTTP/1.0 401 Unauthorized");
include($error401);
exit;
}
}
?>
Copyright (C) 1999, Wilson Peng
要使用这个 auth.inc,要在每个 PHP 的第一行加入
。在加入本程式的 PHP 档案都会检查帐号密码,图片等就不会检查,比起使用 Web 伺服器功能的某目录下全都检查,PHP 显得有弹性多了。
$error401 = "/home/phpdocs/error/401.php";
这行表示在使用者按下取消,或检查失败时,要显示给使用者看的档案。
if ($PHP_AUTH_PW=="") {
Header("WWW-Authenticate: Basic realm=\"超金卡会员\"");
Header("HTTP/1.0 401 Unauthorized");
include($error401);
exit;
} else {
到 else 之前,若没有传入密码,则送出输入密码的视窗。其中的 $PHP_AUTH_USER、$PHP_AUTH_PW 是 PHP 中特殊的变数,分别代表使用者确认的帐号及密码。上面的程式也是利用这二个变数来处理使用者认证。
$db_id = mysql_pconnect("localhost", "myid", "mypw");
$result = mysql_db_query("mymember","select password, enable from MemberAuth where username='$PHP_AUTH_USER'");
$row = mysql_fetch_array($result);
$MemberPasswd = $row[0];
$MemberEnable = $row[1];
若使用者有输入帐号及密码,则向资料库查询。同时查核该使用者是否仍可使用
if ($MemberEnable==0) {
echo "您的帐号被停用了";
exit;
}
上四行程式为帐号被停用的情形。
if ($PHP_AUTH_PW!=$MemberPasswd) {
Header("WWW-Authenticate: Basic realm=\"超金卡会员\"");
Header("HTTP/1.0 401 Unauthorized");
include($error401);
exit;
}
密码错误则再次向使用者要求输入帐号及密码。
在实际使用时,可以视需要加入的网页再加入 auth.inc 这个档案,就不用连看张图形也要查一次密码,降低伺服器和使用者二端的资源。当然,和 MySQL 的连系上,可以使用 mysql_pconnect() 一直和 MySQL 伺服器连线。或是使用 mysql_connect() 每次重新连线,用这个函式要记得早点使用 mysql_close() 将资料库关闭。下面的程式 auth1.inc 是另一版本的认证程式,就是开启连线后马上关闭,释放资源的例子。
//---------------------------
// 使用者认证函式-1 auth1.inc
// Author: Wilson Peng
// Copyright (C) 1999
//---------------------------
$error401 = "/home/phpdocs/error/401.php";
if ($PHP_AUTH_PW=="") {
Header("WWW-Authenticate: Basic realm=\"超金卡会员\"");
Header("HTTP/1.0 401 Unauthorized");
include($error401);
exit;
} else {
$db_id = mysql_connect("localhost", "myid", "mypw");
$result = mysql_db_query("mymember","select password, enable from MemberAuth where username='$PHP_AUTH_USER'");
$row = mysql_fetch_array($result);
$MemberPasswd = $row[0];
$MemberEnable = $row[1];
mysql_close($db_id);
if ($MemberEnable==0) {
echo "您的帐号被停用了";
exit;
}
if ($PHP_AUTH_PW!=$MemberPasswd) {
Header("WWW-Authenticate: Basic realm=\"超金卡会员\"");
Header("HTTP/1.0 401 Unauthorized");
include($error401);
exit;
}
}
?>
Copyright (C) 1999, Wilson Peng
在实际应用时,可以在资料库中加入更多功能,如使用者分组 (CUG) 的功能;或是加入时间栏位,可做到期检查。其中的变化,端赖设计者的巧思了。
聊天室 聊天室,是 Web 站上打发无聊人士的秘密武器。同时,站长或其它人员也可以在这儿杀时间。甚至发生一段轰轰烈烈的网路恋情呢,就算没有,起码可以增加打字的速度。聊天室,其实就是多人共同使用的 CGI 程式。程式将每个人输入的字串,依系统接收完成的时间整理过后,再送给各个使用者。而 Web 聊天室和 BBS 的聊天室不同的地方是 BBS 聊天室可以每收到一句话,就马上分送给每位在聊天室的网路使用者;Web 由于 CGI 程式不能像 BBS 的 telnet 一直连线,Web CGI 必须以最快的速度将资讯送出,然后结束连线。会形成这种情形,就是因为 Web 聊天室还是使用 HTTP 传输协定,在 HTTP 实作的版本,无论是 0.9、1.0 或是 1.1 版都不能长期占据网路连线的 Port。为了解决资料无法马上传输的问题,及更新讯息的问题,Netscape 在 3.0 版浏览器之后使用了新的技术,而 Internet Explorer 也实作了这些 Netscape 研发出来的技术。Netscape 将它分成 Server Push 及 Client Pull 二种技术。Server Push 由 Web 伺服器将资料以多重 MIME 编码,送给使用者端,目前较少网站使用这种方式;而 Client Pull 则利用了 HTML 的 meta 标签,并利用 http-equiv="Refresh" 的属性,表示资料要重新载入,至于载入时间,则利用 content 属性来达成。 标签通常都放在 .. 的区段中,以便让浏览器可以仅早准备更新使用者端的网页。下面为 meta 和 PHP 合用的例子,设定为每十五秒重新载入一次">如果不用 Server Push 或是 Client Pull 来做聊天室,是否有其它的方法,让 Web 的浏览器能聊天呢?答案是肯定的。可以使用 Java 或是 ActiveX (限 IE4、5) 来做甚至自行开发专属的 Browser Plug-in 程式 (如奇摩的聊天室),不过这就和 PHP 没有关系了,不是我们要的重点除此之外,由于定期更新所有网友的留言,为了怕写了一半因为 refresh 而被清掉尚未写好的字串,因此将聊天室以 frame 的页框技术来做是有必要的。下例就是聊天室的主程式。
聊天室
本聊天室需使用页框,您的浏览器无法使用
程式中以 frame 带出二支 PHP 程式,建议将它们放在同一目录之中,例如 /chatroom,以便日后维护。另外,为了 list.php 及 post.php 可以使用相同的变数,下例将共通的变路路径放在 env.inc 中,可以将它放在 /chatroom 或是 Web 伺服器 (如 Apache) 的 PHP include 设定路径中。
// 档名: env.inc
$tempdir="/tmp/";
$chatfile="/tmp/abc";
?>
聊天室的后端可以设计的很简单,单纯的使用档案来做,也可以弄个资料库,将聊天的内容丢入,若是真的很在意系统效率,或许可以考虑使用 UNIX 的行程通讯 IPC 了。本节即将使用者留言的内容放入档案中,在这儿的例子大部份都使用 UNIX/Linux 的外部指令。若系统无该指令 (或称程式),请自行安装相关程式。实际上将资料丢入档案中会比使用资料库还快,若还很在乎速度,可以在 UNIX 机器中装上 RAM Disk,再将档案的存取路径都设在该 RAM Disk 上,保证存取速度能满足严苛的要求。在有些以高速度搜寻引擎为号召的网站,甚至将整个资料库资料都放到 RAM Disk 中,马上让系统速度提高十倍百倍,而且 RAM 的价格和其它解决方案相比的话还算很便宜。若使用 Windows NT,那就没办法了,看微软什么时候提供,或者用 Third Party 的产品了。有些使用者可能对 UNIX 还不是很熟,在这儿先简介会用到的指令:\
touch: 建立新档案,或修改旧档的最后更新日期。
echo 加上二个大于符号: 将字串显示转向到指定的地方。
tail: 显示档案最后数行的资料,内定值为十行,可使用减号加数字,修改欲显示的行数
下面为送出及处理留言字串的程式,程式用到 env.inc 的档案。
// 档名: post.php
require("env.inc");
if (($chatuser!="") and ($chattext!="")) {
$chatstr="".date("h:i:s")."-".$chatuser.": ".$chattext;
$cmdstr="echo \"".$chatstr."\" >> ".$chatfile;
if (!file_exists($chatfile)) passthru("touch ".$chatfile);
passthru($cmdstr);
}
?>
method=post>
匿称:
">
发言:
程式先检查是否有输入字串,若无匿名及发言内容字串则显示发言的表单 (Form),若有资料则将字串及当时时间存入档案中 (利用 UNIX 的转向指令)。当然,为了防止错误,先检查是否有档案可存档,若没有则先 touch 该档,例中的档案就是 /tmp/abc。
">
// 档名: list.php
require("env.inc");
if (!file_exists($chatfile)) {
echo "尚未开张";
exit;
}
$uniqfile=$tempdir.uniqid(rand());
$shellcmd="/usr/bin/tail -50 ".$chatfile. " > ".$uniqfile;
passthru($shellcmd);
$chatfilearray=file($uniqfile);
$j=count($chatfilearray);
for ($i=1; $i
echo $chatfilearray[$j-$i]."
\n";
}
unlink($uniqfile);
?>
上面的程式就是使用 Client Pull 的技术,每五秒就重新更新一次。同样地,它也 require 共用的 env.inc 档,要改变其中的变数时,马上就可以让所有的程式用到,这对开发网站来说,是蛮重要的方法,可以将网页程式中都会出现的地方。例如 Copyright (C) 1996-2000 的字串,放在一个档案上,到了新的一年,只要改一个档,整个站都改了。
if (!file_exists($chatfile)) {
echo "尚未开张";
exit;
}
$uniqfile=$tempdir.uniqid(rand());
$shellcmd="/usr/bin/tail -50 ".$chatfile. " > ".$uniqfile;
passthru($shellcmd);程式先检查有没有使用者发送聊天内容的档案 /tmp/abc,若没有就显示尚未开张,等使用者送聊天内容。若已有聊天资料,就抓出最后五十笔,在在另外的档案中准备显示。
$chatfilearray=file($uniqfile);
$j=count($chatfilearray);
for ($i=1; $i
echo $chatfilearray[$j-$i]."
\n";
}
unlink($uniqfile);将档案读入阵列变数 $chatfilearray 中,并以最后的资料最先显示的方式送给浏览器端,当然可以使用对阵列排序的方法,但确定一定时最后存入的资料在最后面,将它排序实在很浪费 CPU 时间,因此就从最后 echo 到最前面的资料。使用完成还要用 unlink() 指令,将临时档杀掉。
这样就完成了最粗糙的聊天室系统,当然还有很多改进的空间,例如统计使用人数、呼叫个人....等,就要 Webmaster 再精雕细琢了。
留言版
大部份的网站,都会考虑到和使用者之间的互动关系。这时,用留言版的功能,可让使用者留下到此一游,或者是一些和网站的互动讯息。在设计上,可以很简单的只留下使用者的短篇留言,也可以设计到依性质分门别类很复杂的 Web BBS 系统。当然,要如何打造一个属于自己网站的留言版,就端赖网站的性质以及 Web 网站开发人员的巧思了。在这里介绍的范例,是简单的列示所有留言的内容。供使用者可以一次看到多笔留言的资料。系统的后端存放留言是用 Oracle 7.x 版的资料库系统。范例中的资料库 (database) 名称为 WWW,连线的使用者帐号为 user38、密码为 iam3849。要直接使用本例,必须先执行下面的 SQL 指令,建立 guestbook 的资料表格。
CREATE TABLE guestbook (
serial varchar2(255) not null,
ref varchar2(255) null,
id char(8) not null,
alias varchar2(32) not null,
ip varchar2(1024) null,
msgdate date not null,
email varchar2(1024) null,
msg varchar2(2000) not null,
flag char(1) default 1,
primary key(serial)
);
上面的 SQL 各栏位说明及详细资料见下表
序号 栏位 名称 资料形态 资料长度 栏位说明 限制 Key
0 流水号 serial varchar2 255 NN PK
1 参照流水号 ref varchar2 255 暂保留。供回
覆留言功能用
2 帐号 id char 8 使用者帐号 NN
3 匿名 alias varchar2 32 显示的名字 NN
4 网址 ip varchar2 1024 上网 IP
5 时间 msgdate date NN
6 电子邮件 email varchar2 1024
7 留言内容 msg varchar2 2000 NN
8 显示旗标 flag char 1 0: 不显示
1: 显示 (内定)
在本节的留言版相关程式中,若加入了使用者认证功能,则可以在 guestbook 资料表的帐号栏中留下使用者的认证帐号,方便 Webmaster 日后找寻不当的发信者。在这儿先留下栏位,让需要的读者们实习了。要使用本节的程式,首先要先装好 Oracle 7.x 版,并确定 Web Server 端的 SQL*net 可以顺利连上 Oracle 资料库。之后还要在编译 PHP 时加入 --with-oracle=/home/oracle/product/7.3.2 的选项,当然改成其它的路径也没关系,只要该路径真的是 Oracle 的路径即可。有关 Oracle 装设及使用上的细节请参考相关书籍。下面的程式是将使用者的留言资讯加到 guestbook 留言资料表中。若要设定使用者认证功能,可在程式刚开始时检查,发留言者就可以确认身份,而读取留言就不必身份检查。这种设定可以防止不当发言,却又不会让留言功能只有少数人使用。
//---------------------------
// 新增留言程式 addmsg.php
// Author: Wilson Peng
// Copyright (C) 2000
//---------------------------
//
// 可自行在这儿加入身份检查功能
//
if (($alias!="") and ($msg!="")) {
putenv("ORACLE_SID=WWW");
putenv("NLS_LANG=american_taiwan.zht16big5");
putenv("ORACLE_HOME=/home/oracle/product/7.3.2");
putenv("LD_LIBRARY_PATH=/home/oracle/product/7.3.2/lib");
putenv("ORA_NLS=/home/oracle/product/7.3.2/ocommon/nls/admin/data");
putenv("ORA_NLS32=/home/oracle/product/7.3.2/ocommon/nls/admin/data");
$handle=ora_logon("user38@WWW","iam3849") or die;
$cursor=ora_open($handle);
ora_commitoff($handle);
$serial=md5(uniqid(rand()));
$ref="";
$id=$PHP_AUTH_USER;
$ip=$REMOTE_ADDR;
$msg=base64_encode($msg);
$flag="1";
$query="INSERT into guestbook(serial, ref, id, alias, ip, msgdate, email, msg, flag) values('$serial', '$ref', '$id', '$alias', '$ip', sysdate, '$email', '$msg', '$flag')";
ora_parse($cursor, $query) or die;
ora_exec($cursor);
ora_close($cursor);
ora_logoff($handle);
Header("Location: ./index.php");
exit;
} else {
?>
填写留言
">
代号小名
电子邮件
内容
}
?>
上面的程式在执行时,先检查变数 alias 和 msg 是否有资料,若无资料则送出填写留言的表格到使用者端,供使用者填写留言若使用者填好留言,按下 "送出留言" 的按钮后,则执行程式的前半部份。程式大概分成五部份
设定 Oracle 需要的环境变数
连上 Oracle 资料库
整理资料,送入 Oracle 中
结束与 Oracle 的连线
结束程式,显示最新的留言资料
在设定 Oracle 环境的部份,用 PHP 的函式 putenv(),可设定作业系统层的环境变数。要使用中文要记得加入下面这行
putenv("NLS_LANG=american_taiwan.zht16big5");
之后就使用 Oracle 函式库的功能: ora_logon() 等等。详见 Oracle 资料库函式库。利用这个函式库,可以很轻易的操作 Oracle 资料库。
再来就是整理资料,以便置入 Oracle 资料库中
$serial=md5(uniqid(rand()));
$ref="";
$id=$PHP_AUTH_USER;
$ip=$REMOTE_ADDR;
$msg=base64_encode($msg);
$flag="1";
$query="INSERT into guestbook(serial, ref, id, alias, ip, msgdate, email, msg, flag) values('$serial', '$ref', '$id', '$alias', '$ip', sysdate, '$email', '$msg', '$flag')";
$serial 变数为独一无二的字串,程式先乱数产生独特的字串,再用 md5 编码,将字串弄乱,形成类似杂凑处理后的无意义字串。由于字串长,又变得很乱,可防止使用者,尤其是骇客或飞客利用序号来戳系统。
$ref 变数目前是无效的。$id 变数为使用者认证用,若在程式开始处有加入使用者认证的程式,则 $PHP_AUTH_USER 会变成使用者的帐号,传入 $id 变数中。至于使用者写的字串,为了防止资料库或处理时的复杂性甘脆将它用 BASE64 编码。可以让中文字的奇怪字元一字消失,当然这是锯箭法,不过对 Web 程式而言,执行快速、修改方便才是最重要的,实在没有必要再浪费精力去处理这些中文的冲码问题了。值得注意的是使用 BASE64 编码,会让字串膨胀大约 1/3,若资料库的储存空间有限,可能就不适合用这个方法了,话又说回来,现在硬碟便宜,随便就是十几 GB 以上,应该不会考虑资料库空间有限的问题才对。最后,将变数整理成 $query 字串,供资料库执行 SQL 指令使用就可以了。
ora_parse($cursor, $query) or die;
ora_exec($cursor);
ora_close($cursor);
ora_logoff($handle);
要执行 Oracle 的 SQL 指令前,要先经过 parse 的动作。若在前面加上 @ (如: @ora_prase();),可以不让使用者看到错误讯息。在执行 query 指令后,就可以关闭与 Oracle 之间的连线了。
Header("Location: ./index.php");
exit;
这二行让浏览器重导到 index.php。让使用者看到他的新留言,就完成了留言的动作。之后来看看留言的内容显示程式。
留言版
//---------------------------
// 留言显示程式 index.php
// Author: Wilson Peng
// Copyright (C) 2000
//---------------------------
$WebmasterIPArray = array(
"10.0.1.30", // 管理人员甲的机器 IP
"10.0.2.28" // 管理人员乙的机器 IP
);
$WebmasterIP=false;
for ($i=0; $i
if ($REMOTE_ADDR == $WebmasterIPArray[$i]) $WebmasterIP=true;
}
putenv("ORACLE_SID=WWW");
putenv("NLS_LANG=american_taiwan.zht16big5");
putenv("ORACLE_HOME=/home/oracle/product/7.3.2");
putenv("LD_LIBRARY_PATH=/home/oracle/product/7.3.2/lib");
putenv("ORA_NLS=/home/oracle/product/7.3.2/ocommon/nls/admin/data");
putenv("ORA_NLS32=/home/oracle/product/7.3.2/ocommon/nls/admin/data");
$handle=ora_logon("user38@WWW","iam3849") or die;
$cursor=ora_open($handle);
ora_commitoff($handle);
$query="SELECT serial, ref, id, alias, ip, TO_CHAR(msgdate, 'yyyy/mm/dd hh:mi:ss'), email, msg FROM guestbook where flag='1' order by msgdate desc";
ora_parse($cursor, $query) or die;
ora_exec($cursor);
$i=0;
while(ora_fetch($cursor)) {
$guestbook[$i][0] = ora_getcolumn($cursor,0);
$guestbook[$i][1] = ora_getcolumn($cursor,1);
$guestbook[$i][2] = ora_getcolumn($cursor,2);
$guestbook[$i][3] = ora_getcolumn($cursor,3);
$guestbook[$i][4] = ora_getcolumn($cursor,4);
$guestbook[$i][5] = ora_getcolumn($cursor,5);
$guestbook[$i][6] = ora_getcolumn($cursor,6);
$guestbook[$i][7] = ora_getcolumn($cursor,7);
$i++;
}
ora_close($cursor);
ora_logoff($handle);
echo "
if ($QUERY_STRING!="") {
$page = $QUERY_STRING;
} else {
$page = 0;
}
$i=count($guestbook);
$msgnum=20; // 每页二十笔
$start = $page * $msgnum;
$end = $start + $msgnum;
if ($end > $i) $end=$i;
$totalpage=$i/$msgnum;
$pagestr="";
if ($page>0) $pagestr=$pagestr." - ";
$pagestr=$pagestr."[第 ";
for ($i=0; $i
if ($i!=$page) {
$pagestr = $pagestr."".($i+1)." ";
} else {
$pagestr = $pagestr.($i+1)." ";
}
}
$pagestr=$pagestr." 页] ";
if ($page下页> ";
$pagestr="$pagestr";
echo "".$pagestr."\n";
for ($i=$start; $i
echo "\n";
echo "\n".$guestbook[$i][5]." ";
if ($guestbook[$i][6]!="") echo "";
echo "".$guestbook[$i][3]."";
if ($guestbook[$i][6]!="") echo "";
echo "
\n";
if ($WebmasterIP) echo "删除本篇!! (".$guestbook[$i][2].") ";
echo "from: ".$guestbook[$i][4]."\n";
$msg=base64_decode($guestbook[$i][7]);
$msg=nl2br($msg);
echo $msg;
echo "\n";
}
echo "\n";
echo $pagestr;
?>
在显示留言的部份,考虑到留言内容若很多,加上网路慢的话,可能会让使用者在线路慢的时候拖累整个资料库,因此,尽快的连上资料库,取得需要的资料后,马上关闭资料库,再慢慢送给使用者,应是最好的对策。
程式分成四部份
初始化
取资料库中的资料
计算要显示的页数
送出资料
$WebmasterIPArray = array(
"10.0.1.30", // 管理人员甲的机器 IP
"10.0.2.28" // 管理人员乙的机器 IP
);
$WebmasterIP=false;
for ($i=0; $i
if ($REMOTE_ADDR == $WebmasterIPArray[$i]) $WebmasterIP=true;
}
// 之后初始化 Oracle 程式略
显示程式和留言程式的初始化部份都差不多,但显示程式多加了一个功能,设定 Webmaster 的电脑。将 Webmaster 使用的 IP Address 加在 $WebmasterIPArray 阵列变数中,可以在显示留言时,显示删除留言的字串,方便处理不当的留言。
$handle=ora_logon("user38@WWW","iam3849") or die;
$cursor=ora_open($handle);
ora_commitoff($handle);
$query="SELECT serial, ref, id, alias, ip, TO_CHAR(msgdate, 'yyyy/mm/dd hh:mi:ss'), email, msg FROM guestbook where flag='1' order by msgdate desc";
ora_parse($cursor, $query) or die;
ora_exec($cursor);
$i=0;
while(ora_fetch($cursor)) {
$guestbook[$i][0] = ora_getcolumn($cursor,0);
$guestbook[$i][1] = ora_getcolumn($cursor,1);
$guestbook[$i][2] = ora_getcolumn($cursor,2);
$guestbook[$i][3] = ora_getcolumn($cursor,3);
$guestbook[$i][4] = ora_getcolumn($cursor,4);
$guestbook[$i][5] = ora_getcolumn($cursor,5);
$guestbook[$i][6] = ora_getcolumn($cursor,6);
$guestbook[$i][7] = ora_getcolumn($cursor,7);
$i++;
}
ora_close($cursor);
ora_logoff($handle);
在初始化后,就可以连上 Oracle 资料库,将留言的资料取出放在 $guestbook 阵列中。取得资料后,就赶紧将资料库关闭,再来处理 $guestbook 阵列的资料了
if ($QUERY_STRING!="") {
$page = $QUERY_STRING;
} else {
$page = 0;
}
这一段程式判断是要显示第几页,内定值是显示第一页。要显示第三页的页面,需要使用 http://xxxxxx/index.php?2 的格式,也就是传入 $QUERY_STRING,余类推。之后的数行程式,都是用来处理显示的页数及笔数的资料。
$msgnum=20; // 每页二十笔
要改变每页的显示笔数,可以改 $msgnum 变数。程式的内定值为 20 笔。
for ($i=$start; $i
echo "\n";
echo "\n".$guestbook[$i][5]." ";
if ($guestbook[$i][6]!="") echo "";
echo "".$guestbook[$i][3]."";
if ($guestbook[$i][6]!="") echo "";
echo "
\n";
if ($WebmasterIP) echo "删除本篇!! (".$guestbook[$i][2].") ";
echo "from: ".$guestbook[$i][4]."\n";
$msg=base64_decode($guestbook[$i][7]);
$msg=nl2br($msg);
echo $msg;
echo "\n";
}
这一段程式就是真正显示留言资料给使用者看的程式了。利用 for 回圈,将 $guestbook 阵列的资料按照设定的页数取出,显示给使用者看。值得一提的是,若看留言的机器 IP 为 $WebmasterIPArray 变数阵列中的一个元素的话,则会在留言者的匿称后显示 "删除本篇!!" 的字串,供管理人员删除不当留言。
相关阅读 更多 +