Cookies
用 PHP 來設定以及讀取 cookie 是一件極其簡 -- 我們敢說嗎?-- 單的事情。我們不想要大力鼓吹 cookie,不過它們實在既重要又有用。有時候,在做某些事情時,它們是唯一適用的工具。
要建立並修改一個 cookie,你可以使用 PHP 函數 setcookie()。取決於你想要控制 cookie 的程度,以及誰可以讀取它的值,setcookie() 最多可有六個參數。
設定 cookie 最簡單的方式如下:
setcookie('name', 'bret');
然後,在用戶登出之前,接下來每一個使用同樣的瀏覽器觀看的網頁,都會有一個內含值為 'bret' 的變數 $name, 如此一來在 PHP 程式碼裡,就可以很容易取得這個值。這類 cookie 被稱為 session cookie,因為它的生命週期是一個用戶連結(user session)的時間。
如果你要在用戶關閉他的瀏覽器之後,保留這個 cookie,你必須傳送第三個參數給 setcookie() 函數,亦即設定這個 cookie 的有效日期。既然 PHP 的整體出身背景是源於 Unix 的人們腦中,你可以把這個有效期限以從 1970 年一月一日起算的總秒數來代表。 如果你是個 Unix 程式設計師,這種算法對你而言可能是合理合理的。但是,如果你是來自 Windows 或 Macintosh 背景的人,你可能只能搖頭嘆息,不知道那些 Unix 陣容的怪傢伙在想些什麼。
不要害怕。PHP 提供一個很好用的函數 mktime()。 你只要照順序傳送給 mktime() 你想要表示的小時,分鐘, 秒數,月份,日期,以及年份,mktime() 就會回傳給你該日期自從 1970 年一月一日的總秒數。因此,如果你要模擬 Y2K 問題:
<?php
$y2k = mktime(0,0,0,1,1,2000);
setcookie('name', 'bret', $y2k);
?>
現在,你的 cookie 將會在千禧年失效。
如果你想更新 cookie,讓它儲存新的值,你只要把它原來的值蓋掉即可。因此,即使你已經在過去幾頁裡面送出剛剛的 cookie 了,你還是可以把名字改為 "jeff"。
<?php
$y2k = mktime(0,0,0,1,1,2000);
setcookie('name', 'jeff', $y2k);
?>
請注意,這樣做並不會改變變數 $name 的值。它在當初網頁載入的時候,就已經定下來了。如果你想要同時改變 cookie 以及 $name 變數,你可以編寫程式如下:
<?php
$name = 'jeff';
$y2k = mktime(0,0,0,1,1,2000);
setcookie('name', $name, $y2k);
?>
setcookie() 的下兩個參數可以讓你控制從哪個網域, 哪個目錄路徑送來的程式碼,才可以讀取你的 cookie。原本的設定是,只有在與送出 cookie 的同一個伺服器且同層級或以下的目錄架構內的程式才可以讀取 cookie,這是為了網路安全起見而做的設定。然而,如果你有一個網路帳號,是 "www.domain.com" 但也是 "other.domain.com" 而且你的帳戶允許你從 ~/myhome 目錄送出動態網頁,你就應該如下更改你的 setcookie():
<?php
setcookie('name', 'jeff', $y2k, '~/myhome', '.domain.com');
?>
setcookie() 的最後一個參數,我們從未用過,是設定 cookie 只傳送給有實行安全保密連線諸如 SSL 的網頁伺服器。要使這項功能生效,只要把第六個參數設為一。
刪除掉 cookie 很簡單,只要將你的 cookie 的名次傳送給 setcookie(),PHP 就會安排把它刪除掉。
<?php setcookie('name'); ?>
最後一個有關使用 cookie 的重要的事項是,因為 cookie 與 HTTP 的某種協定方式,你必須在你印出任何文字前,把所有的 cookie 傳送出去。否則的話,PHP 會送給你一個警告,然後你的 cookie 也不會被傳送出去。因此,這樣做是對的:
<?php
setcookie('name', 'jeff');
echo "Hello Everyone!";
?>
但是你不可以這樣做:
<?php
echo "Hello Everyone!";
setcookie('name', 'jeff');
?>
日期及時間
PHP 有很多便於使用的函數,可以幫你顯示及操作日期。
要以某種格式顯示日期或時間,使用 date() 函數。它需要兩個參數: 一個是要如何顯示日期的格式,另一個是代表你所要顯示日期的時間。這個時間必須是先前所提自從 1970 年起算的總秒數。(如果你要使用現在的時間,你可以使用 time() 函數,這個函數會回傳「現在」這個時間的秒數。) date() 有一拖拉庫的格式選項,就跟 C 語言的 strftime() 函數或者 Perl 語言的 POSIX::strftime()函數一樣。
<?php
$birthday_stamp = mktime(19,45,0,3,10,1975);
$birthday_formatted = date('F d, Y - g:i a',$birthday_stamp);
echo "David was born on $birthday_formatted."
?>
程式碼會產生結果如下
David was born on March 10, 1975--7:45 p.m.
當然,如果你要的是某個已知的特定日期,這種花俏的格式函數並不會有多大用處,因為,你事先已經知道你的格式會是什麼。這些函數會當在某個表單中,需要網路用戶選擇某日期的時候,會比較有用:
<SELECT NAME="when">
<?php
$d = time();
for ($i = 0; $i < 10; $i++) {
echo '<OPTION VALUE="'.$d.'">'.date('F d',$d);
$d += 86400;
}
?>
</SELECT>
以上會引出一個選單,其中有十個選擇 -- 今天以及以後九天。在程式中迴圈敘述開始之前,我們會將現在時間存在 $d 變數裡面。某一個 <OPTION> 的值會被印出來, 其中的值會是以 Unix 算法計算的總秒數,而且所顯示出來的文字設定為月份以及日期("July 27," "July 28," 等等。)在顯示過 <OPTION> 的值後,$d 變數會被加上 86,400(這就是一天二十四小時的總秒數 -- 24 小時 * 60 分鐘 * 60 秒)。
將 mktime() 以及 date() 合用,你就可以得出關於某個用戶輸入日期的相關資訊。那如果你要尋找從某個日期算起的第一個星期天(或者一個禮拜中的任一天)呢?首先,你先編寫一個會印出適當格式的函數:
<?php
function display_form() {
global $PHP_SELF;
$dotw = array('Sunday','Monday','Tuesday','Wednesday','Thursday',
'Friday','Saturday');
$months = array( 1 => 'January','February','March','April','May','June',
'July','August','September','October','November','December');
?>
<FORM TARGET="<?php echo $PHP_SELF; ?>" METHOD=GET>
Find the first
<SELECT NAME="dotw">
<?php
for ($i = 0; $i < 7; $i++) {
echo "<OPTION> $dotw[$i]";
}
echo '</SELECT> after <SELECT NAME="month">';
for ($i = 1; $i <= 12; $i++) {
echo "<OPTION VALUE=\"$i\"> $months[$i]";
}
echo '</SELECT> <SELECT NAME="day">';
for ($i = 1; $i <= 31; $i++) {
echo "<OPTION> $i";
}
echo '</SELECT>, <SELECT NAME="year">';
$start_year = date('Y') - 10;
$end_year = $start_year + 20;
for ($i = $start_year; $i <= $end_year; $i++) {
echo "<OPTION> $i";
}
echo '<INPUT TYPE="HIDDEN" NAME="stage" VALUE="process">';
echo '</SELECT> <INPUT TYPE="SUBMIT" VALUE="Do it!"7></FORM>';
}
?>
這當中含有一些函數是我們到目前為止還沒討論到的。$months 陣列寫得有點不一樣, 因為我們要讓一月份的陣列索引為 1,而非 0。另外,以程式自動產生這個表單要比將所有這個表單元素的值一一手動列出,要來得簡單多了,因此 display_form() 函數中唯一不是屬於 PHP 模式的部分,在於表單的開端部分。還有,使用 date('Y') 設定 $start_year 變數以及 $end_year 變數,讓我們能夠方便計算今年算起十年前以及十年後的時間範圍。
下面是處理表單的函數:
<?php
function process_form() {
global $dotw;
global $month;
global $day;
global $year;
$timestamp = mktime(0,0,0,$month,$day,$year);
$next_dotw = '';
$next_timestamp = $timestamp;
while ($next_dotw != $dotw) {
$next_timestamp += 86400;
$next_dotw = date('l',$next_timestamp);
}
$formatted_first = date('F d, Y',$timestamp);
$formatted_next = date('F d, Y',$next_timestamp);
echo "The first $dotw after $formatted_first is $formatted_next.";
}
?>
首先,這段程式碼將所得到的日期以 Unix 方式計算總秒數。如果我們要更固執,更謹慎的話,我們可以加某些程式碼,以便檢查所得到的日期是否在合法的日期範圍內,不過在這裡我們沒有必要這樣做。
接下來的迴圈敘述,只要我們要尋找的某個日期的下一個星期數,不是網路用戶所輸入的要找的那一個星期數,就會一直迴圈下去。當星期數不一樣時,日期所代表的總秒數就會被增加(又是那個 86400 秒 = 24 小時 * 60 分鐘 * 60 秒)然後那個秒數所代表的星期數就會被重新計算。
一旦星期數一致了(equal),process_form() 函數就會印出一行訊息:
The first Sunday after June 25, 1999 is June 27, 1999.
我們也需要那個大家都熟悉的主要敘述,將這些函數綁在一起:
<?php
if (empty($stage)) { display_form(); }
else { process_form(); }
?>
日期處理程式碼有時需要再複雜一點,才能處理日光節約(daylight savings time)時間,還有不同的時區,不過 date() 以及 mktime() 函數都是基本的變換 Unix 總秒數的函數, 它們操作簡單,而且也以易讀易懂的方式,表達日期跟時間。date() 以及 mktime() 函數以你的機器所在時區來操作時間。如果你想要用格林威治時間(GMT),你可以使用 gmdate() 以及 gmmktime()。
例如,在一部處於美國東部日光節約時間的機器(落後格林威治時間四小時):
<?php
$today = mktime(12,0,0,6,25,1999);
echo 'Here it is '.date('g:i:s a, F d, Y',$today);
echo '';
echo 'In GMT it is '.gmdate('g:i:s a, F d, Y',$today);
?>
會產生如下結果
Here it is 12:00:00 pm, June 25, 1999
In GMT it is 4:00:00 pm, June 25, 1999
結論
PHP 是個很不錯的工具,為你的網站帶來動態的網頁內容。它所使用的語法感覺起來不陌生,而且也不會佔用多大的電腦資源 -- 還有你也不必為必須注意很多繁瑣的細節而感到沮喪,你所需要的只是寫簡單的描述語言。
這篇文章中所介紹的只是 PHP 語言強大功能的開端。PHP 還可以讓你從各式各樣的資料庫擷取以及儲存資料,包括: MySQL,Oracle, Microsoft SQL Server,還有很多其他資料庫軟體。你可以隨時製作以及修改影像。你可以使用 regular expression 操控文字資料。 你可能被這一連串英文縮寫所搞混了,不過你可以用 IMAP,LDAP,PDF,SNMP,WDDX,XML,等等,來改善你的程式。
想知道有關 PHP 的最新資訊,你可以到它的官方網站。另外,其線上使用手冊 則是用來查詢如何使用某些函數好地方。你甚至可以跟那些 PHP 程式設計師夥伴們分享你的想法。因此,本質上,連手冊都是開放原始碼(open source)的。
你果你有興趣與 PHP 社群的愛好者們做互動,這裡有個討論區,所有的主要程式開發工程師都會來這裡看看並且回答一些問題。客戶支援網頁 上面有更多有關這個討論區的資訊,同時它也提供其他有用的資源。
文:Adam Trachtenberg 和 David Sklar/ 林志峰 譯
[ 本帖最後由 ltk0020 於 2006-8-13 21:04 編輯 ]