PHP編寫網(wǎng)站程序的十個(gè)經(jīng)驗(yàn)技巧
PHP為普及的服務(wù)器端腳本語言之一。其特點(diǎn)是運(yùn)行速度快、穩(wěn)定可靠、跨平臺(tái),而且是開放源代碼軟件。隨你使用的水平不同,PHP可以很簡單,也可以很復(fù)雜,可以只使用它發(fā)送HTML表格元素,還可以在PHP應(yīng)用程序中集成Java和XML。
如果你對(duì)PHP有一定的了解或者看過一些初步的教材,這些技巧可以擴(kuò)展你對(duì)PHP的認(rèn)識(shí),使你掌握一些常見的和高級(jí)的PHP功能。
一、把PHP安裝為Apache的DSO
PHP在Linux/Unix平臺(tái)上經(jīng)常與Apache搭配使用,在安裝PHP時(shí),有三種安裝方式可供選擇:靜態(tài)模式、動(dòng)態(tài)模式(DSO)、CGI二進(jìn)制模式。
由于易于維護(hù)和升級(jí),我強(qiáng)烈建議以DSO方式安裝PHP。例如,初次安裝時(shí)如果安裝的PHP僅支持?jǐn)?shù)據(jù)庫,隨后希望再安裝支持加密的模塊,只要運(yùn)行“make clean”,添加新的配置選項(xiàng),然后再運(yùn)行“make”和“make install”即可,一個(gè)新的PHP模塊就會(huì)安裝在Apache中適當(dāng)?shù)奈恢蒙希缓笾匦聠?dòng)Apache,而無需重新編譯Apache。
下面的步驟將安裝一個(gè)全新的Apache,并以DSO方式安裝PHP:
1、從Apache軟件基金會(huì)得到最新版本的Apache源代碼;
2、把得到的源代碼放到/usr/local/或者/opt/目錄下,或者你指定的任意目錄中;
3、運(yùn)行Gunzip對(duì)文件進(jìn)行解壓縮,得到后綴為.tar的文件;
4、運(yùn)行下面的命令,把文件安裝到apache_[version]目錄中:
tar -xvf apache_[version].tar
5、進(jìn)入/usr/local/apache_[version]目錄(或者在步驟4中安裝壓縮文件的目錄);
6、鍵入下面的命令為編譯Apache作準(zhǔn)備,用你自己的路徑替換其中的[path],例如,/usr/local/apache[version],現(xiàn)在已經(jīng)設(shè)置了mod_so的新值,它將允許Apache使用DSO模塊;
7、回到提示符狀態(tài)后鍵入make,并等待再次回到提示符狀態(tài);
8、執(zhí)行“make install”命令。
至此,Apache已經(jīng)安裝完畢,系統(tǒng)將重回到提示符狀態(tài)。接下來我們開始安裝PHP:
1、在PHP主頁的下載區(qū)中找到最新版本的鏈接;
2、把文件下載到一個(gè)適當(dāng)?shù)哪夸浿校?usr/local/或/opt/或者你指定的任意目錄中;
3、運(yùn)行Gunzip對(duì)文件進(jìn)行解壓縮,得到后綴為.tar的文件;
4、執(zhí)行下面的命令把文件安裝在php-[version]目錄中:
tar -xvf php-[version]
5、進(jìn)入/usr/local/php-[version]目錄或在步驟4中指定的目錄;
至此,已經(jīng)作好了以DSO方式安裝PHP的準(zhǔn)備工作,唯一需要修改的配置選項(xiàng)是with-apxs(這是Apache的bin目錄中的一個(gè)文件)。為了得到較高的性能,我沒有安裝對(duì)MySQL的支持模塊。
./configure --with-mysql=/[path to mysql] --with-apxs=/[path to apxs]
6、回到提示符狀態(tài)后執(zhí)行make命令,等待重新返回到提示符狀態(tài);
7、執(zhí)行make install命令。
至此,系統(tǒng)以DSO方式在Apache的模塊目錄中安裝了PHP,并對(duì)Apache的httpd.conf文件作適當(dāng)?shù)男薷暮蠓祷氐教崾痉麪顟B(tài)。回到提示符狀態(tài)后,你還需要對(duì)Apache的httpd.conf文件作一些修改。
1、找到包含有ServerAdmin的一行,添加你的電子郵件地址,如下所示:
ServerAdmin you@yourdomain.com
2、找到以ServerName開頭的行,把它改為真正的值,例如:
ServerName localhost
3、找到內(nèi)容如下所示的小節(jié):
# And for PHP 4.x, use:
#
#AddType application/x-httpd-php .php
#AddType application/x-httpd-php-source .phps
修改這些行的內(nèi)容,使PHP 4.0的AddType不再成為注釋,并添加希望在PHP中使用的文件后綴名,上面的內(nèi)容變?yōu)槿缦滤镜膬?nèi)容:
# And for PHP 4.x, use:
#
AddType application/x-httpd-php .php .phtml
AddType application/x-httpd-php-source .phps
保存文件,回到上一級(jí)目錄,執(zhí)行下面的命令重新啟動(dòng)Apache:
./bin/apachectl start
如果在啟動(dòng)時(shí)沒有出現(xiàn)錯(cuò)誤提示信息,就可以通過創(chuàng)建一個(gè)名為phpinfo.php的只有如下所示一行內(nèi)容的文件,對(duì)安裝的Apache、PHP進(jìn)行測(cè)試:
<? phpinfo() ?>
把這個(gè)文件保存到Apache的文檔根目錄(htdocs)中,然后開啟瀏覽器,鍵入http://localhost/phpinfo.php地址,屏幕上就會(huì)出現(xiàn)許多的變量和它們的值。
如果要重新配置PHP,需要再次運(yùn)行make clean命令,然后執(zhí)行帶有一系列選項(xiàng)的./configure命令,然后再執(zhí)行make和make install命令,Apache的目錄模塊中就會(huì)出現(xiàn)一個(gè)新的模塊,只要再重新啟動(dòng)Apache加載這個(gè)新的模塊,就一切OK了。
二、使用PHP本身的對(duì)話
PHP 4.0中最令人期待的特性應(yīng)該是對(duì)對(duì)話的支持,PHP 3.0的用戶必須使用第三方的軟件否則就不能使用對(duì)話,不支持對(duì)話一直是PHP最大的缺憾之一。
只要用戶在瀏覽你的網(wǎng)站,你就可以利用對(duì)話維護(hù)與特定用戶有關(guān)的變量,而無需建立多個(gè)cookie、使用隱藏表格字段或?qū)⑿畔⒋鎯?chǔ)在數(shù)據(jù)庫中。
在一個(gè)網(wǎng)頁上啟動(dòng)一個(gè)對(duì)話,就會(huì)使PHP引擎知道你想啟動(dòng)一個(gè)對(duì)話(如果還沒有啟動(dòng))或者繼續(xù)當(dāng)前的對(duì)話:
session_start();
啟動(dòng)一個(gè)對(duì)話將通過cookie向用戶發(fā)送一個(gè)識(shí)別字符串(例如940f8b05a40d5119c030c9c7745aead9),在服務(wù)器端,會(huì)創(chuàng)建一個(gè)與識(shí)別字符串匹配的臨時(shí)文件,例如sess_940f8b05a40d5119c030c9c7745aead9,這個(gè)文件中包含注冊(cè)的對(duì)話變量以及它們的值。
用來顯示對(duì)話的作用的最常見的例子是訪問計(jì)數(shù)器。啟動(dòng)PHP模塊,確保PHP代碼是文件的第一行,在PHP代碼之前不要有空格、HTML代碼和其他的代碼。因?yàn)閷?duì)話會(huì)發(fā)送一個(gè)頭部,因此如果在session_start()之前有空格和HTML代碼,就會(huì)得到一個(gè)出錯(cuò)信息。
<?
// 如果還不存在一個(gè)針對(duì)某用戶的用戶,則啟動(dòng)一個(gè)對(duì)話:
session_start();
然后注冊(cè)一個(gè)名字為count的變量:
session_reGISter('count');
注冊(cè)一個(gè)對(duì)話變量后,只要對(duì)話存在,名字為count的變量也就存在。現(xiàn)在,count變量還沒有被賦值,如果對(duì)它執(zhí)行加1操作,它的值就變?yōu)榱?。
$count++;
把上述內(nèi)容綜合在一塊兒,如果還沒有啟動(dòng)一個(gè)對(duì)話,就會(huì)啟動(dòng)一個(gè)對(duì)話;如果不存在一個(gè)對(duì)話id,就為用戶指定一個(gè)好了,注冊(cè)一個(gè)名字為$count的變量,對(duì)$count執(zhí)行加1操作表示用戶已經(jīng)首次訪問了該網(wǎng)頁。
要知道用戶在當(dāng)前的對(duì)話中訪問本頁面的次數(shù),只要顯示$count變量的值即可:
echo "<P>You've been here $count times.</p>";
全部的訪問計(jì)數(shù)器代碼如下所示:
<?
session_start();
session_register('count');
$count++;
echo "<P>You've been here $count times.</p>";
?>
如果重新加載上述的腳本文件,就會(huì)發(fā)現(xiàn)變量count的值增加了1,很酷吧。
還可以在對(duì)話中注冊(cè)一個(gè)數(shù)組變量,假設(shè)我們注冊(cè)了一個(gè)名字為$faves的變量:
$faves = array ('chocolate','coffee','beer','linux');
可以象注冊(cè)一個(gè)簡單變量那樣注冊(cè)一個(gè)數(shù)組變量:
session_register('faves');
引用數(shù)組變量與引用簡單變量沒有什么二樣,如果一個(gè)用戶在網(wǎng)頁上指出在生活中的愛好時(shí),可以把他的愛好注冊(cè)到一個(gè)被稱作$faves的數(shù)組變量中,然后可以在另一個(gè)網(wǎng)頁中很方便地把這些愛好顯示出來:
<?
session_start();
echo "My user likes:
<ul>";
while (list(,$v) = each ($faves)) {
echo "<li>$v"; }
echo "</ul>";
?>
然后你就得到了一個(gè)關(guān)于用戶愛好的清單。
對(duì)話變量不能被查詢字符串覆蓋,也就是說我們不能輸入http:///www.yourdomain.com/your
如果要完全刪除一個(gè)對(duì)話變量,首先需要從系統(tǒng)中注銷它:
session_unregister('count');
要完全刪除一個(gè)對(duì)話變量的腳本是非常簡單,如下所示:
session_destroy();
使用對(duì)話變量可以減少訪問數(shù)據(jù)庫的頻率,使代碼更加清晰,而且可以減少對(duì)用戶發(fā)送的cookie的數(shù)量,它是最簡單的方法了。
三、文件是我們的朋友
無論你在開發(fā)的網(wǎng)站規(guī)模的大小,都應(yīng)該意識(shí)到代碼重用的重要性,無論這些代碼是HTML、還是PHP代碼。例如,你必須至少每年改變一次包含版權(quán)信息的頁腳,如果你的網(wǎng)站含有1000個(gè)頁面,每年修改一次也是個(gè)很煩人的事兒。
在PHP中,至少有幾個(gè)函數(shù)可以幫助你實(shí)現(xiàn)代碼重用的目的,所使用的函數(shù)取決于你所重用的代碼,主要的函數(shù)有:
* include() and include_once()
* require() and require_once()
include()函數(shù)包含并對(duì)給定的文件進(jìn)行計(jì)算,例如:
include('/home/me/myfile');
在include文件中的任何代碼都在include()出現(xiàn)的代碼范圍內(nèi)執(zhí)行,你可以通過聯(lián)合使用include()和fopen()在自己的服務(wù)器上包含靜態(tài)文件,在另一臺(tái)服務(wù)器上包含目標(biāo)文件。
include_once()的功能與include()相同,二者之間的區(qū)別在于它會(huì)檢查一個(gè)文件中的代碼是否已經(jīng)包含在現(xiàn)有的腳本中,如果代碼已經(jīng)存在,則不會(huì)再次包含它。
require()函數(shù)用給定文件的內(nèi)容取代它本身,這一代替過程發(fā)生在PHP引擎編譯代碼期間,而不是在執(zhí)行期間進(jìn)行,它不象include()那樣會(huì)首先進(jìn)行計(jì)算。require()函數(shù)更多地用在靜態(tài)元素中,而include()更多地用于動(dòng)態(tài)元素中。與include_once()類似的是,require_once()將首先檢查是否已經(jīng)插入給定的代碼,如果代碼已經(jīng)存在,就不再插入了。
為也了解其內(nèi)容,在版權(quán)信息、靜態(tài)文字和其他不包含變量的元素或者依賴其他正在執(zhí)行的腳本的元素中我更趨向于使用require函數(shù)。例如:
<HTML>
<HEAD><TITLE>Something</TITLE></HEAD>
<BODY>
[a lot of content]
<?
// insert copyright
require('/home/me/mycopyright');
?>
</BODY>
</HTML>
另一方面,我經(jīng)常在文件的開始使用include()來控制許多的函數(shù):
<?
//得到函數(shù)庫
include('/home/me/myfunctions');
// do PHP things with my functions ?>
<HTML>
<HEAD><TITLE>Something</TITLE></HEAD>
<BODY>
[a lot of content]
</BODY>
</HTML>
下一個(gè)問題就該是“include和require文件在哪里?”,對(duì)這個(gè)問題簡單的回答是,“系統(tǒng)中的任意地方。”如果你的代碼中包含有帶有用戶名和口令的數(shù)據(jù)庫連接,你肯定不會(huì)將它們都放在文檔根目錄中向所有的人都開放。
included或required文件可以在系統(tǒng)上的任何地方,只要PHP運(yùn)行的系統(tǒng)上的用戶可以訪問這些文件即可,你可以使這些文件具有任何后綴,或者不使用后綴。
使用include()和require()對(duì)在網(wǎng)站中的元素進(jìn)行具體化是一種普遍的現(xiàn)象,并在需要對(duì)網(wǎng)站升級(jí)時(shí),給你帶來很大的方便。
四、PHP和文件系統(tǒng)的維護(hù)
PHP中有許多與文件系統(tǒng)有關(guān)的函數(shù),這些函數(shù)不僅可以打開文件,還可以顯示目錄中的內(nèi)容、移動(dòng)文件和其他一些功能,許多人甚至用PHP開發(fā)基于互聯(lián)網(wǎng)的文件資源管理器。
關(guān)于文件路徑的解釋:在Windows中,可以在路徑中使用/和\符號(hào),而在其他的操作系統(tǒng)中只能使用/符號(hào)。出于一致性的緣故,我們統(tǒng)一使用/符號(hào)。
下面的腳本樣例可以顯示一個(gè)目錄清單,注釋已經(jīng)包含在代碼中:
<? /*把要讀取的目錄的全路徑名存入一個(gè)名字為$dir_name的變量中。 */
$dir_name = "/home/me/";
/* 創(chuàng)建一個(gè)句柄,其值是打開一個(gè)給定目錄的結(jié)果*/
$dir = opendir($dir_name);
/* 建立一個(gè)文字塊,用以放置列表元素(文件名字)*/
$file_list = "<ul>";
/* 使用一個(gè)while語句,讀取已經(jīng)打開的目錄中的所有元素,如果文件的名字不是“.”或“..”,則顯示列表中的名字*/
while ($file_name = readdir($dir)) {
if (($file_name != ".") && ($file_name != "..")) {
$file_list .= "<li>$file_name";
}
}
$file_list .= "</ul>";
/*關(guān)閉打開的目錄,結(jié)束PHP模塊*/
closedir($dir);
?>
<!-- Start your HTML -->
<HTML>
<HEAD>
<TITLE>Directory Listing</TITLE>
</HEAD>
<BODY>
<!-- Use PHP to print the name of the directory you read -->
<P>Files in: <? echo "$dir_name"; ?></p>
<!-- Use PHP to print the directory listing -->
<? echo "$file_list"; ?>
</BODY>
</HTML>
好了,我們已經(jīng)得到了一個(gè)目錄清單。需要注意的是,要讀取一個(gè)文件(稍后我們將進(jìn)行講解)或目錄的內(nèi)容,PHP運(yùn)行的系統(tǒng)上的用戶必須至少有讀取文件的權(quán)限。
下面是一個(gè)如何拷貝文件的例子:
<? /*把你要拷貝的原文件的全路徑賦給一個(gè)名字為$original的變量中,把拷貝的文件的全路徑賦予一個(gè)名字為$copied的變量中*/
$original = "/home/me/mydatabasedump";
$copied = "/archive/mydatabasedumo_1010";
/* 使用copy()函數(shù)拷貝原始文件,如果拷貝沒有完成則會(huì)顯示一個(gè)錯(cuò)誤信息*/
@copy($original, $copied) or die("Couldn't copy file.");
?>
這個(gè)例子是一個(gè)文件備份系統(tǒng)的原型。在這段腳本運(yùn)行時(shí),它把文件拷貝到一個(gè)不同的位置進(jìn)行保存。稍微修改一下守護(hù)程序,就可以在一天中你指定的時(shí)刻執(zhí)行它,而無需用戶的干預(yù)。
假定你在系統(tǒng)上安裝了Lynx,可以創(chuàng)建一個(gè)守護(hù)程序的條目訪問這個(gè)文件,訪問這個(gè)文件會(huì)運(yùn)行這個(gè)腳本并建立一個(gè)拷貝文件,下面的例子將在上午5點(diǎn)鐘運(yùn)行這個(gè)腳本,然后關(guān)閉Lynx:
0 5 * * * [username] lynx -dump http://localhost/copyfile.php 1>/dev/null 2>&1
如果運(yùn)行的是CGI版本的PHP,可以跳過Lynx部分,而直接調(diào)用二進(jìn)制文件:
0 5 * * * [username] php /path/to/copyfile.php 1>/dev/null 2>&1
五、豐富的數(shù)組函數(shù)
PHP 4.0中新添加了30個(gè)與組數(shù)有關(guān)的函數(shù),其中一些常見的函數(shù)可以判斷一個(gè)數(shù)組中是否包含某個(gè)元素,對(duì)一個(gè)數(shù)組中的元素進(jìn)行計(jì)數(shù),添加或刪除數(shù)組中的元素或者對(duì)數(shù)組中的元素進(jìn)行排序。
如果有一個(gè)很大的數(shù)組,而你需要找出其中是否包含一個(gè)特定的元素,就可以使用in_array()。下面的例子將顯示“Not found in this array”,因?yàn)樵谝粋(gè)名字為$namesArray的數(shù)組中查找Albert,而在$namesArray數(shù)組中不存在這樣一個(gè)元素。
<? $namesArray = array("Joe", "Jane", "Bob", "Mary", "Paul", "Eddie", "John");
$lookingFor = "Albert";
if (in_array($lookingFor, $namesArray)) {
echo "You've found it!";
} else {
echo "Not found in this array!";
}
?>
如果把$lookingFor的值改為Mary,就會(huì)得到“You've found it!”的信息,因?yàn)镸ary是$namesArray數(shù)組中的一個(gè)元素。
如果要對(duì)一個(gè)數(shù)組中的元素個(gè)數(shù)進(jìn)行計(jì)數(shù),只要簡單地使用count()函數(shù)即可:
<? $namesArray = array("Joe", "Jane", "Bob", "Mary", "Paul", "Eddie", "John");
$count = count($namesArray); ?>
返回的$count的值為7。
可以在一個(gè)數(shù)組的開頭或結(jié)尾處添加元素,還可以使用array_merge()來建立一個(gè)包含二個(gè)或更多數(shù)組中元素的新數(shù)組,合并時(shí),元素的順序會(huì)按指定的順序排列,如果原來的數(shù)組是被排過序的,在合并后需要對(duì)它重新排序。
我們可以首先利用array_push()在數(shù)組的結(jié)尾處添加一個(gè)元素:
<? /* 建立一個(gè)數(shù)組 */
$fruitArray = array("apple", "orange", "banana", "kiwi", "pear");
/* 向數(shù)組中添加元素 */
array_push($fruitArray, "grape", "pineapple", "tomato");
/*顯示每個(gè)元素及其序號(hào)*/
while (list($key,$value) = each($fruitArray)) {
echo "$key : $value<br>";
}
?>
運(yùn)行上面的程序?qū)⒌玫较旅娴慕Y(jié)果:
0 : apple
1 : orange
2 : banana
3 : kiwi
4 : pear
5 : grape
6 : pineapple
7 : tomato
如果需要在數(shù)組的開頭添加元素,其代碼與上面的代碼差不多,唯一的不同之處是需要用array_unshift()代替array_push()。
<?
/* 建立一個(gè)數(shù)組*/
$fruitArray = array("apple", "orange", "banana", "kiwi", "pear");
/* 向數(shù)組中添加元素*/
array_unshift($fruitArray, "grape", "pineapple", "tomato");
/* 顯示每個(gè)元素及其序號(hào)*/
while (list($key,$value) = each($fruitArray)) {
echo "$key : $value<br>";
}
?>
運(yùn)行上面的程序?qū)⒌玫较旅娴慕Y(jié)果:
0 : grape
1 : pineapple
2 : tomato
3 : apple
4 : orange
5 : banana
6 : kiwi
7 : pear
array_merge()函數(shù)可以把二個(gè)或更多的數(shù)組合并為一個(gè)數(shù)組。
<? /*建立第一個(gè)數(shù)組*/
$fruitArray = array("apple", "orange", "banana", "kiwi", "pear");
/*/建立第二個(gè)數(shù)組*/
$vegArray = array("carrot", "green beans", "ASParagus", "artichoke", "corn");
/*把這二個(gè)數(shù)組合并為一個(gè)數(shù)組*/
$goodfoodArray = array_merge($fruitArray, $vegArray);
/* 顯示每個(gè)元素及其序號(hào)*/
while (list($key,$value) = each($goodfoodArray)) {
echo "$key : $value<br>";
}
?>
運(yùn)行上面的腳本將得到下面的結(jié)果:
0 : apple
1 : orange
2 : banana
3 : kiwi
4 : pear
5 : carrot
6 : green beans
7 : asparagus
8 : artichoke
9 : corn
現(xiàn)在我們已經(jīng)掌握了如何添加元素和合并數(shù)組,我們?cè)賮砜纯慈绾螐囊粋(gè)數(shù)組中刪除元素。從一個(gè)數(shù)組的末尾刪除一個(gè)元素可以使用array_pop()函數(shù),使用array_shift()函數(shù)可以從一個(gè)數(shù)組的開頭刪除一個(gè)元素。盡管使用array_pop()或 array_shift()從數(shù)組中刪除了一個(gè)元素,你還可以把這個(gè)元素當(dāng)作一個(gè)變量來使用。
使用array_pop()從一個(gè)數(shù)組的末尾刪除一個(gè)元素:
<?
/*建立一個(gè)數(shù)組*/
$fruitArray = array("apple", "orange", "banana", "kiwi", "pear");
/* 從數(shù)組的末尾刪除一個(gè)元素*/
$popped = array_pop($fruitArray);
/* 顯示刪除后數(shù)組的內(nèi)容和你刪除的元素*/
while (list($key,$value) = each($fruitArray)) {
echo "$key : $value<br>";
}
echo "<br>and finally, in $popped: $popped";
?>
運(yùn)行上面的腳本會(huì)得到下面的結(jié)果:
0 : apple
1 : orange
2 : banana
3 : kiwi
and finally, in $popped: pear
我們?cè)賮碛懻撘粋(gè)從一個(gè)數(shù)組的末尾刪除元素的例子:
<?
/* 建立一個(gè)數(shù)組*/
$fruitArray = array("apple", "orange", "banana", "kiwi", "pear");
/*從一個(gè)數(shù)組的開始刪除一個(gè)元素*/
$shifted = array_shift($fruitArray);
/* 顯示刪除后數(shù)組的內(nèi)容和你刪除的元素*/
while (list($key,$value) = each($fruitArray)) {
echo "$key : $value<br>";
}
echo "<br>and finally, in $shifted: $shifted";
?>
運(yùn)行上述腳本會(huì)得到如下的顯示結(jié)果:
0 : orange
1 : banana
2 : kiwi
3 : pear
and finally, in $shifted: apple
另外還有幾個(gè)函數(shù)可以對(duì)數(shù)組中的元素進(jìn)行排序,但在這里我們將只簡要介紹基本的排序函數(shù),說明排序的過程:
<? /*建立一個(gè)數(shù)組*/
$fruitArray = array("apple", "orange", "banana", "kiwi", "pear");
/* 對(duì)數(shù)組進(jìn)行排序*/
sort($fruitArray);
/*顯示每個(gè)元素及其序號(hào)*/
while (list($key,$value) = each($fruitArray)) {
echo "$key : $value<br>";
}
?>
運(yùn)行上述的腳本會(huì)得到如下的顯示結(jié)果:
0 : apple
1 : banana
2 : kiwi
3 : orange
4 : pear
六、動(dòng)態(tài)圖像的創(chuàng)建
只要安裝一些第三方的庫文件并具有一定的幾何知識(shí),就可以利用PHP來創(chuàng)建和處理圖像了。事實(shí)上,這不需要太多的幾何知識(shí),因?yàn)槲掖髮W(xué)沒有畢業(yè),仍然可以利用PHP創(chuàng)建圖像。
在使用基本的圖像創(chuàng)建函數(shù)之前,需要安裝GD庫文件。如果要使用與JPEG有關(guān)的圖像創(chuàng)建函數(shù),還需要安裝jpeg-6b,如果要在圖像中使用Type 1型字體,則必須安裝t1lib。
在建立圖像創(chuàng)建環(huán)境之前,還需要作一些準(zhǔn)備工作。首先,安裝t1lib;其次安裝jpeg-6b,然后再安裝GD庫文件。在安裝時(shí)一定要按這里給定的順序進(jìn)行安裝,因?yàn)樵诰幾gGD為庫時(shí)會(huì)用到j(luò)peg-6b,如果沒有安裝jpeg-6b,在編譯時(shí)就會(huì)出錯(cuò)。
在安裝完這三個(gè)組件后,還需要重新配置PHP,這也是你對(duì)采用DSO方式安裝PHP感到慶幸的地方之一。運(yùn)行make clean,然后在當(dāng)前的配置中添加下面的內(nèi)容:
--with-gd=[/path/to/gd]
--with-jpeg-dir=[/path/to/jpeg-6b]
--with-t1lib=[/path/to/t1lib]
完成添加后執(zhí)行make命令,然后再執(zhí)行make install命令。重新啟動(dòng)Apache后運(yùn)行phpinfo()來檢查一下新的設(shè)置是否生效了。現(xiàn)在就可以開始圖像創(chuàng)建工作了。
根據(jù)所安裝的GD庫文件的版本不同,你也許能或者不能創(chuàng)建GIF或PNG格式的圖形文件,如果安裝的是gd-1.6或以前的版本,可以使用GIF格式的文件但不能創(chuàng)建PNG格式,如果安裝的是gd-1.6以后的版本,可以創(chuàng)建PNG文件但不能創(chuàng)建GIF格式的文件。
創(chuàng)建一幅簡單的圖像也需要用到許多的函數(shù),我們將一步一步地進(jìn)行說明。
在這個(gè)例子中,我們將創(chuàng)建一個(gè)PNG格式的圖像文件,下面的代碼是一個(gè)包含所創(chuàng)建的圖像的MIME類型的頭部:
<? header ("Content-type: image/png");
使用ImageCreate()創(chuàng)建一個(gè)代表空白圖像的變量,這個(gè)函數(shù)要求以像素為單位的圖像大小的參數(shù),其格式是ImageCreate(x_size, y_size)。如果要?jiǎng)?chuàng)建一個(gè)大小為250X250的圖像,就可以使用下面的語句:
$newImg = ImageCreate(250,250);
由于圖像還是空白的,因此你可能會(huì)希望用一些彩色來填充它。然而,你需要首先使用ImageColorAllocate()函數(shù)用其RGB值為這種顏色指定一個(gè)名字,這一函數(shù)的格式為ImageColorAllocate([image], [red], [green], [blue])。如果要定義天藍(lán)色,可以使用如下的語句:
$skyblue = ImageColorAllocate($newImg,136,193,255);
接下來,需要使用ImageFill()函數(shù)用這種顏色填充這個(gè)圖像,ImageFill()函數(shù)有幾個(gè)版本,例如ImageFillRectangle()、ImageFillPolygon()等。為簡單起見,我們通過如下的格式使用ImageFill()函數(shù):
ImageFill([image], [start x point], [start y point], [color])
ImageFill($newImg,0,0,$skyblue);
最后,建立圖像后釋放圖像句柄和所占用的內(nèi)存:
ImagePNG($newImg);
ImageDestroy($newImg); ?>
這樣,創(chuàng)建圖像的全部代碼如下所示:
<? header ("Content-type: image/png");
$newImg = ImageCreate(250,250);
$skyblue = ImageColorAllocate($newImg,136,193,255);
ImageFill($newImg,0,0,$skyblue);
ImagePNG($newImg);
ImageDestroy($newImg);
?>
如果把這個(gè)腳本文件保存為skyblue.php,并用瀏覽器訪問它,就會(huì)看到一個(gè)天藍(lán)色的250X250的PNG格式的圖像。
我們還可以使用圖像創(chuàng)建函數(shù)對(duì)圖像進(jìn)行處理,例如把一個(gè)較大圖像作成一個(gè)小圖像:
假設(shè)你有一幅圖像,想從中裁剪出一個(gè)35X35大小的圖像。你所需要作的是創(chuàng)建一個(gè)35X35大小的空白圖像,創(chuàng)建一個(gè)包含原來圖像的圖像流,然后把一個(gè)經(jīng)過調(diào)整大小的原來的圖像放到新的空白圖像中。
要完成這一任務(wù)的關(guān)健函數(shù)是ImageCopyResized(),它要求的格式如下所示:ImageCopyResized([new image handle],[original image handle],[new image X], [new Image Y], [original image X], [original image Y], [new image X], [new image Y], [original image X], [original image Y])。
<? /* 發(fā)送一個(gè)頭部,以便讓瀏覽器知道該文件所包含的內(nèi)容類型*/
header("Content-type: image/png");
/* 建立保存新圖像高度和寬度的變量*/
$newWidth = 35;
$newHeight = 35;
/* 建立給定高度和寬度的新的空白圖像*/
$newImg = ImageCreate($newWidth,$newHeight);
/* 從原來較大的圖像中得到數(shù)據(jù)*/
$origImg = ImageCreateFromPNG("test.png");
/*拷貝調(diào)整大小后的圖像,使用ImageSX()、ImageSY()得到原來的圖像在X、Y方面上的大小 */
ImageCopyResized($newImg,$origImg,0,0,0,0,$newWidth,$newHeight,ImageSX($origImg),ImageSY($origImg));
/*創(chuàng)建希望得到的圖像,釋放內(nèi)存 */
ImagePNG($newImg);
ImageDestroy($newImg); ?>
如果把這一小段腳本保存為resized.php,然后用瀏覽器對(duì)它進(jìn)行訪問,就會(huì)看到一個(gè)35X35大小的PNG格式的圖形。
七、基于PHP的用戶認(rèn)證
如果希望在每一段腳本上都進(jìn)行口令保護(hù),可以結(jié)合使用header()語句、$PHP_AUTH_USER和$PHP_AUTH_PW來建立基本的認(rèn)證方案,通常的基于服務(wù)器的提問/響應(yīng)順序都如下所示:
1、用戶從服務(wù)器上請(qǐng)求一個(gè)文件。如果這個(gè)文件在服務(wù)器上是被保護(hù)的,則在響應(yīng)的頭部向用戶返回一個(gè)401(示經(jīng)授權(quán)的用戶)字符串。
2、瀏覽器收到這個(gè)響應(yīng)后,彈出要求用戶輸入用戶名/口令的對(duì)話框。
3、用戶在對(duì)話框中輸入一個(gè)用戶名和口令,點(diǎn)擊OK按鈕將信息返回服務(wù)器供認(rèn)證使用。
4、如果用戶名和口令有效,被保護(hù)的文件將向用戶開放,只要用戶還在使用文件,認(rèn)證會(huì)一直有效。
一段簡單的PHP腳本文件通過向用戶發(fā)送一個(gè)適當(dāng)?shù)哪軌蛞鹱詣?dòng)顯示用戶名/口令對(duì)話框的HTTP頭部就可以模仿HTTP的提問/響應(yīng)系統(tǒng),PHP把用戶在用戶名/口令對(duì)話框中輸入的信息存儲(chǔ)在$PHP_AUTH_USER和$PHP_AUTH_PW中,使用這二個(gè)變量,就可以與存儲(chǔ)在文本文件、數(shù)據(jù)庫等文件中的用戶名/口令進(jìn)行比較。
這個(gè)例子采用了二個(gè)硬編碼的值進(jìn)行認(rèn)證,但無論用戶名和口令放在什么地方,其原理都是相同的。
<?
/* 檢查$PHP_AUTH_USER和$PHP_AUTH_PW中的值*/
if ((!isset($PHP_AUTH_USER)) || (!isset($PHP_AUTH_PW))) {
/* 如果沒有值,則發(fā)送一個(gè)能夠引發(fā)對(duì)話框出現(xiàn)的頭部*/
header('WWW-Authenticate: Basic realm="My Private Stuff"');
header('HTTP/1.0 401 Unauthorized');
echo 'Authorization Required.';
exit;
} else if ((isset($PHP_AUTH_USER)) && (isset($PHP_AUTH_PW))){
/* 變量中有值,檢查它們是否正確*/
if (($PHP_AUTH_USER != "validname") || ($PHP_AUTH_PW != "goodpassword")) {
/* 如果輸入的用戶名和口令中有一個(gè)不正確,則發(fā)送一個(gè)能夠引發(fā)對(duì)話框出現(xiàn)的頭部 */
header('WWW-Authenticate: Basic realm="My Private Stuff"');
header('HTTP/1.0 401 Unauthorized');
echo 'Authorization Required.';
exit;
} else if (($PHP_AUTH_USER == "validname") || ($PHP_AUTH_PW == "goodpassword")) {
/* 如果二個(gè)值都正確,顯示成功的信息 */
echo "<P>You're authorized!</p>";
}
}
?>
需要注意的是,如果你使用的是基于文件的保護(hù)機(jī)制,它并不能保證目錄中所有的文件的安全。它可能保護(hù)大部分的文件,如果你認(rèn)為它能夠保護(hù)給定目錄中的所有文件,你的這種認(rèn)識(shí)就需要變變了。
八、PHP和COM
如果你喜歡冒險(xiǎn),并且在Windows上運(yùn)行CGI、ISAPI或Apache模塊版本的PHP,就可以訪問COM的函數(shù)。好了,詳細(xì)解釋COM的工作就交給微軟和許多大部頭的書了,為了能簡單地了解一下COM的功能,下面是一小段常見的腳本。
這一段PHP腳本在后端啟動(dòng)微軟的字處理Word,打開一個(gè)新的文檔,輸入一些文字,保存文檔,并關(guān)閉Word。
<?
// 建立一個(gè)指向新COM組件的索引
$word = new COM("word.application") or die("Can't start Word!");
// 顯示目前正在使用的Word的版本號(hào)
echo "Loading Word, v. {$word->Version}<br>";
// 把它的可見性設(shè)置為0(假),如果要使它在最前端打開,使用1(真)
// to open the application in the forefront, use 1 (true)
$word->Visible = 0;
// 在Word中創(chuàng)建新的文檔
$word->Documents->Add();
// 在新文檔中添加文字
$word->Selection->TypeText("Testing 1-2-3...");
//把文檔保存在Windows臨時(shí)目錄中
$word->Documents[1]->SaveAs("/Windows/temp/comtest.doc");
// 關(guān)閉與COM組件之間的連接
$word->Quit();
// 在屏幕上顯示其他信息
echo "Check for the file...";
?>
如果你有一個(gè)intranet網(wǎng)站,數(shù)據(jù)存儲(chǔ)在SQL Server中,用戶需要這些數(shù)據(jù)的Excel格式,則可以讓PHP運(yùn)行必要的SQL查詢并對(duì)輸出進(jìn)行格式化,然后利用COM打開Excel,把數(shù)據(jù)轉(zhuǎn)化為Excel格式的數(shù)據(jù),然后把數(shù)據(jù)保存在用戶的臺(tái)式機(jī)上。
九、PHP和Java
PHP另一個(gè)有趣的功能是它可以調(diào)用現(xiàn)有的Java 對(duì)象中的方法,使得你可以在基于Java的應(yīng)用中集成PHP。如果要在工作中推廣PHP的應(yīng)用,這一功能就非常有用了,你得到的結(jié)果是,“這里的一切都是基于Java的。”
要利用這一功能,你的服務(wù)器上必須安裝有JVM(Java虛擬機(jī)器)。如果安裝的是由Sun、Kaffe、IBM或Blackdown的JDK,就已經(jīng)安裝有了JVM。
在配置PHP時(shí),需要在配置文件中添加with-java小節(jié),然后修改php.ini文件中的一部分,對(duì)php.ini文件的修改主要是需要添加下面的內(nèi)容:
[Java]
java.library.path=/path/to/library
java.class.path=/classpath/
extension_dir=/path/to/extensions
extension=libphp_java.so
需要注意的是,所作的修改與你的安裝類型有關(guān),你需要閱讀PHP安裝目錄下ext/java目錄中README文件,學(xué)習(xí)如何配置Java功能。
下面是一段如何創(chuàng)建一個(gè)新的Java對(duì)象的PHP腳本的例子,這段腳本將訪問并在顯示器是顯示一些Java屬性。它與COM的例子同樣有趣,應(yīng)該會(huì)給我們一些啟發(fā)。
<?
$system = new Java("java.lang.System");
echo "<P>Java version = " . $system->getProperty("java.version") . "<br>";
echo "Java vendor = " . $system->getProperty("java.vendor") . "</p>";
?>
如果你有Java知識(shí),將會(huì)對(duì)開發(fā)工作帶來很大的幫助,這種集成的能力是未來PHP被接受和增長的關(guān)健。
十、PHP和XML
PHP中包含有一個(gè)可選的支持Expat解析的XML擴(kuò)展,利用PHP中與XML相關(guān)的函數(shù),可以創(chuàng)建一個(gè)分析程序來處理有效的XML文檔。如果你使用的是1.3.7版或版本更高的Apache軟件,就不需要再安裝額外的庫文件了,你所需要作的就只是配置PHP中的with-xml。
象Java和COM一樣,PHP中對(duì)XML的支持也很有趣,而且增長也很快,如果你了解Expat或LibXML,請(qǐng)加入這一方面的開發(fā)吧。
關(guān)鍵字:網(wǎng)站、程序、PHP、服務(wù)器
新文章:
- CentOS7下圖形配置網(wǎng)絡(luò)的方法
- CentOS 7如何添加刪除用戶
- 如何解決centos7雙系統(tǒng)后丟失windows啟動(dòng)項(xiàng)
- CentOS單網(wǎng)卡如何批量添加不同IP段
- CentOS下iconv命令的介紹
- Centos7 SSH密鑰登陸及密碼密鑰雙重驗(yàn)證詳解
- CentOS 7.1添加刪除用戶的方法
- CentOS查找/掃描局域網(wǎng)打印機(jī)IP講解
- CentOS7使用hostapd實(shí)現(xiàn)無AP模式的詳解
- su命令不能切換root的解決方法
- 解決VMware下CentOS7網(wǎng)絡(luò)重啟出錯(cuò)
- 解決Centos7雙系統(tǒng)后丟失windows啟動(dòng)項(xiàng)
- CentOS下如何避免文件覆蓋
- CentOS7和CentOS6系統(tǒng)有什么不同呢
- Centos 6.6默認(rèn)iptable規(guī)則詳解