top
Loading...
留言簿(帶Oracle數據庫分頁的顯示功能)

(摘自CCU新聞組,本來出處可能是臺灣出版的一本關于PHP的書:PHP寶典)

大部份的網站,都會考慮到和使用者之間的互動關系。這時,用留言版的功能,可讓使用者留下到此一游,或者是一些和網站的互動訊息。
在設計上,可以很簡單的只留下使用者的短篇留言,也可以設計到依性質分門別類很復雜的 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 留言資料表中。若要設定使用者認證功能,可在程式剛開始時檢查,發留言者就可以確認身份,而讀取留言就不必身份檢查。這種設定可以防止不當發言,卻又不會讓留言功能只有少數人使用。


<?php
file://---------------------------
// 新增留言程式 addmsg.php
// Author: Wilson Peng
// Copyright (C) 2000
file://---------------------------
//
// 可自行在這兒加入身份檢查功能
//
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 {
?>
<html>
<head>
<title>填寫留言</title>
</head>
<body bgcolor=ffffff>
<form method=POST action="<? echo $PHP_SELF; ?>">
<table border=0 cellpadding=2 width=395>
<tr>
<td nowrap><font color=004080>代號小名</font></td>
<td width=20%><input type=text name=alias size=8></td>
<td nowrap><font color=004080>電子郵件</font></td>
<td width=50%><input type=text name=email size=18></td>
</tr>
<tr>
<td nowrapvalign=top><font color=004080>內容</font></td>
<td width=80% colspan=3><textarea rows=5 name=msg
cols=33></textarea></td>
</tr>
<tr>
<td width=100% colspan=4 align=center>
<input type=submit value="送出留言">
<input type=reset value="擦掉留言">
</td>
</tr>
</table>
</form>
</body>
</html>
<?php
}
?>


上面的程式在執行時,先檢查變數 alias 和 msg 是否有資料,若無資料則送出填寫留言的表格到使用者端,供使用者填寫留言。

若使用者填好留言,按下 "送出留言" 的按鈕后,則執行程式的前半部份。

程式大概分成五部份

1.. 設定 Oracle 需要的環境變數
2.. 連上 Oracle 資料庫
3.. 整理資料,送入 Oracle 中
4.. 結束與 Oracle 的連線
5.. 結束程式,顯示最新的留言資料
在設定 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。讓使用者看到他的新留言,就完成了留言的動作。

之后來看看留言的內容顯示程式。


<html>
<head>
<meta content="text/html; charset=gb2312"
http-equiv=Content-Type>
<title>留言版</title>
</head>
<body bgcolor=ffffff>
<?php
file://---------------------------
// 留言顯示程式 index.php
// Author: Wilson Peng
// Copyright (C) 2000
file://---------------------------

$WebmasterIPArray =
ay(
"10.0.1.30", // 管理人員甲的機器 IP
"10.0.2.28" // 管理人員乙的機器 IP
);

$WebmasterIP=false;
for ($i=0; $i<Count($WebmasterIPArray); $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);
$gu
estbook[$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 "<a href=addmsg.php>新增留言....</a><p>";

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."<a
href=index.php?".($page-1)."><上頁</a> - ";
$pagestr=$pagestr."[第 ";
for ($i=0; $i<$totalpage; $i++)

if ($i!=$page)

$pagestr = $pagestr."<a href=index.php?$i>".($i+1)."</a> ";
} else

$pagestr = $pagestr.($i+1)." ";
}
}
$pagestr=$pagestr." 頁] ";
if ($page<($totalpage-1)) $pagestr=$pagestr."- <a
href=index.php?".($page+1).">下頁></a> ";

$pagestr="<div align=center>$pagestr</div>";
echo "<p>".$pagestr."<hr><p>";

for ($i=$start; $i<$end; $i++)

echo "<p><hr><p>";
echo "<p><font color=e06060>".$guestbook[$i][5]."</font>
  ";
if ($guestbook[$i][6]!="") echo "<a
href=mailto:".$guestbook[$i][6].">";
echo "<strong>".$guestbook[$i][3]."</strong>";
if ($guestbook[$i][6]!="") echo "</a>";
echo "<br>";
if ($WebmasterIP) echo "<a
href=erase.php?".$guestbook[$i][0].">刪除本篇!!</a> (".$guestbook[$i][2].")
  ";
echo "<font size=-1 color=c0c0c0>from:
".$guestbook[$i][4]."</font><p>";
$msg=base64_decode($guestbook[$i][7]);
$msg=nl2br($msg);
echo $msg;
echo "<p>";
}

echo "<p><hr><p>";
echo $pagestr;

?>
</body>
</html>

在顯示留言的部份,考慮到留言內容若很多,加上網路慢的話,可能會讓使用者在線路慢的時候拖累整個資料庫,因此,盡快的連上資料庫,取得需要的資料后,馬上關閉資料庫,再慢慢送給使用者,應是最好的對策。

程式分成四部份

1.. 初始化
2.. 取資料庫中的資料
3.. 計算要顯示的頁數
4.. 送出資料
這個程式在 BIGLOBE 上有實作,由于這是一間 ISP 公司,因此在設定時限定撥
接或專線的會員才能看到,進入前要輸入帳號及密碼。有興趣者不妨買個 BIGLOBE 的
撥接帳號參考。為了保護留言者的隱私,留言以馬賽克處理。

$WebmasterIPArray = array(
"10.0.1.30", // 管理人員甲的機器 IP
"10.0.2.28" // 管理人員乙的機器 IP
);

$WebmasterIP=false;
for ($i=0; $i<Count($WebmasterIPArray); $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<$end; $i++) {
echo "<p><hr><p>";
echo "<p><font color=e06060>".$guestbook[$i][5]."</font>   ";
if ($guestbook[$i][6]!="") echo "<a
href=mailto:".$guestbook[$i][6].">";
echo "<strong>".$guestbook[$i][3]."</strong>";
if ($guestbook[$i][6]!="") echo "</a>";
echo "<br>";
if ($WebmasterIP) echo "<a href=erase.php?".$guestbook[$i][0].">刪除
本篇!!</a> (".$guestbook[$i][2].")   ";
echo "<font size=-1 color=c0c0c0>from:
".$guestbook[$i][4]."</font><p>";
$msg=base64_decode($guestbook[$i][7]);
$msg=nl2br($msg);
echo $msg;
echo "<p>";
}

這一段程式就是真正顯示留言資料給使用者看的程式了。利用 for 回圈,將$guestbook 陣列的資料按照設定的頁數取出,顯示給使用者看。值得一提的是,若看留言的機器 IP 為 $WebmasterIPArray 變數陣列中的一個元素的話,則會在留言者的匿稱后顯示 "刪除本篇!!" 的字串,供管理人員刪除不當留言。

以下即為刪除留言的程式。


<?php
file://---------------------------
// 留言刪除程式 erase.php
// Author: Wilson Peng
// Copyright (C) 2000
file://---------------------------
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="UPDATE guestbook set flag='0' where
serial='".$QUERY_STRING."'";
ora_parse($cursor, $query) or die;
ora_exec($cursor);

ora_close($cursor);
ora_logoff($handle);

Header("Location: ./index.php");
?>

其實這個程式很單純,只要打開 Oracle 資料庫,將欲刪除的序號那筆資料的flag 欄位設成 0 就可以了,不用將資料真的從資料庫上移除。

北斗有巢氏 有巢氏北斗