PHP完全中文操作手冊

天地JPLOP | PHP首頁 | 函數索引
用戶認證
在專門蘿Web 網站上,常常會需要用戶的帳號及密碼,也就是身份確認的步驟。早期的 NCSA httpd 服務器並沒有提供這項用戶確認的功能,Webmaster 隻能用手工打造一個身份確認的 CGI 程序。

自 CERN httpd 之後的 Web 服務器大部份都提供了用戶身份確認的功能。僅管每套 Web 服務器的配置都不太相同,但在配置上都大同小異。

以下就是 Apache 服務器上的用戶身份確認的配置。

<Directory /home/MyMember>
AuthType Basic
AuthName MyMember
AuthUserFile /usr/local/MyMember.txt
Options Includes ExecCGI
<Limit GET POST>
require valid-user
</Limit>
</Directory>
 

在這個例子中,當用戶在看 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 上有了另外的選擇,這也是本節的主題。 <



整理: 夕垌菪姬 (天地JPLOP)

PHP 的 HTTP 相關函數庫提供了 header() 的函數。許多 Web 服務器與客戶端的互動,都可以使用這個函數來變戲法。例如在某個 PHP 頁面最開始處,也就是第一行或第二行,加入以下的程序,可以將用戶重定向到作者的網頁。

<?php
header
("Location:http://wilson.gs");
exit;
?>

當然,在上述程序之後的 HTML 文字或者是 PHP 程序都永遠不會出現在用戶端了。

同樣的道理,我們就用 header() 來變用戶認證的把戲。可以在 PHP 的最開頭送出字符串到用戶端,就會在用戶端出現下圖的窗口。

<?php
Header
("WWW-Authenticate:Basicrealm=\"Member\"");
Header("HTTP/1.0401Unauthorized");
?>

載入圖片中

在程序中字符串 realm=\"Member\" 中的 Member 字樣出現在圖中,當然若使用中文字取代,瀏覽器端也會出現中文字,如上面的 MySEED 圖。若 Web 網站用戶還有其它語文,如英文或日文,送出中文的 realm 字符串似乎就比較不合適。無論如何,這都要視網站的性質及用戶定位而決定。

當然這還是很粗糙,因為除了送出窗口後,就沒有下文了,帳號輸入正確也好,輸入錯誤也罷,都不會有任何的結果。我們需要再更進階的程序來處理。



整理: 夕垌菪姬 (天地JPLOP)

在後端的使用認證上,考慮使用數據庫作為儲存帳號及密碼的後端,在這種架構可以容納許多的用戶,管它一萬個用戶還是十萬個用戶。若您的站已有數十萬個用戶帳號,那麼恭喜您,您的站算是世界級的大站了。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 < /tmp/memberauth.sql

在準備好了之後,就可以輸入用戶帳號及密碼在 memberauth 資料表中了。當然還是使用 phpMyAdmin 方便,用 mysql 程序就要一筆筆的 INSERT 了。

載入圖片中

接著進入了設計函數的階段了。

<?php
//---------------------------
//用戶認證函數auth.inc
//Author:WilsonPeng
//Copyright(C)1999
//---------------------------
$error401="/home/phpdocs/error/401.php";
if(
$PHP_AUTH_PW==""){
Header("WWW-Authenticate:Basicrealm=\"超金卡會員\"");
Header("HTTP/1.0401Unauthorized");
include(
$error401);
exit;
}else{

$db_id=mysql_pconnect("localhost","myid","mypw");
$result=mysql_db_query("mymember","selectpassword,enablefromMemberAuthwhereusername='$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:Basicrealm=\"超金卡會員\"");
Header("HTTP/1.0401Unauthorized");
include(
$error401);
exit;
}
}
?>
Copyright (C) 1999, Wilson Peng

要使用這個 auth.inc,要在每個 PHP 的第一行加入
<? require("auth.inc"); ?> 。在加入本程序的 PHP 文件都會檢查帳號密碼,圖片等就不會檢查,比起使用 Web 服務器功能的某目錄下全都檢查,PHP 顯得有彈性多了。

$error401="/home/phpdocs/error/401.php";

這行表示在用戶按下取消,或檢查失敗時,要顯示給用戶看的文件。

if($PHP_AUTH_PW==""){
Header("WWW-Authenticate:Basicrealm=\"超金卡會員\"");
Header("HTTP/1.0401Unauthorized");
include(
$error401);
exit;
}else{

到 else 之前,若沒有傳入密碼,則送出輸入密碼的窗口。其中的 $PHP_AUTH_USER、$PHP_AUTH_PW 是 PHP 中特殊的變量,分別代表用戶確認的帳號及密碼。上面的程序也是利用這兩個變量來處理用戶認證。

載入圖片中

$db_id=mysql_pconnect("localhost","myid","mypw");
$result=mysql_db_query("mymember","selectpassword,enablefromMemberAuthwhereusername='$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:Basicrealm=\"超金卡會員\"");
Header("HTTP/1.0401Unauthorized");
include(
$error401);
exit;
}

密碼錯誤則再次向用戶要求輸入帳號及密碼。

在實際使用時,可以視需要加入的網頁再加入 auth.inc 這個文件,就不用連看張圖形也要查一次密碼,轎募頭務器和用戶二端的資源。當然,和 MySQL 的連繫上,可以使用 mysql_pconnect() 一直和 MySQL 服務器連接。或是使用 mysql_connect() 每次重新連接,用這個函數要記得早點使用 mysql_close() 將數據庫關閉。下面的程序 auth1.inc 是另一版本的認證程序,就是打開連接後馬上關閉,釋放資源的例子。

<?php
//---------------------------
//用戶認證函數-1auth1.inc
//Author:WilsonPeng
//Copyright(C)1999
//---------------------------
$error401="/home/phpdocs/error/401.php";
if(
$PHP_AUTH_PW==""){
Header("WWW-Authenticate:Basicrealm=\"超金卡會員\"");
Header("HTTP/1.0401Unauthorized");
include(
$error401);
exit;
}else{

$db_id=mysql_connect("localhost","myid","mypw");
$result=mysql_db_query("mymember","selectpassword,enablefromMemberAuthwhereusername='$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:Basicrealm=\"超金卡會員\"");
Header("HTTP/1.0401Unauthorized");
include(
$error401);
exit;
}
}
?>
Copyright (C) 1999, Wilson Peng

在實際應用時,可以在數據庫中加入更多功能,如用戶分組 (CUG) 的功能;或是加入時間字段,可做到期檢查。其中的變化,端賴設計者的巧思了。

[ 上一頁 下一頁 ]
版權所有,天地JPLOP、爵堤亞(夕垌菪姬)。網頁背景音樂和各鍊結標題
及鍊結內容和文章小說,版面編排皆歸原權利人所有對本版面
有任何意見或指教,歡迎至論壇指教。