[推荐]PHP的十个高级技巧 / J# a& H$ D0 }: g& l5 Q! A0 h
全球超过300万个互联网网站的管理员都在使用PHP,使得它成为最为普及的服务器端脚本语言之一。其特点是运行速度快、稳定可靠、跨平台,而且是开放源代码软件。随你使用的水平不同,PHP可以很简单,也可以很复杂,可以只使用它发送HTML表格元素,还可以在PHP应用程序中集成Java和XML。
: s( I& M: \, m 如果你对PHP有一定的了解或者看过一些初步的教材,这些技巧可以扩展你对PHP的认识,使你掌握一些常见的和高级的PHP功能。
) z$ y! W7 N5 o4 |% U8 G- A7 W一、把PHP安装为Apache的DSO
/ A5 q' I: `$ R4 s5 {: W PHP在Linux/Unix平台上经常与Apache搭配使用,在安装PHP时,有三种安装方式可供选择:静态模式、动态模式(DSO)、CGI二进制模式。
0 U# k1 m% L. A5 F 由于易于维护和升级,我强烈建议以DSO方式安装PHP。例如,初次安装时如果安装的PHP仅支持数据库,随后希望再安装支持加密的模块,只要运行“make clean”,添加新的配置选项,然后再运行“make”和“make install”即可,一个新的PHP模块就会安装在Apache中适当的位置上,然后重新启动Apache,而无需重新编译Apache。
8 q1 f+ T$ G( \9 F 下面的步骤将安装一个全新的Apache,并以DSO方式安装PHP: $ F0 ?' o4 m( i6 j! D
1、从Apache软件基金会得到最新版本的Apache源代码;
. T) g3 x6 c! o/ S R 2、把得到的源代码放到/usr/local/或者/opt/目录下,或者你指定的任意目录中; 7 W; O8 I( F6 @' b
3、运行Gunzip对文件进行解压缩,得到后缀为.tar的文件; 1 n& E% p8 P$ b7 d
4、运行下面的命令,把文件安装到apache_[version]目录中: O7 x$ P% O' ~
tar -xvf apache_[version].tar / X6 p$ r% [- I8 S" K- `4 w8 t
5、进入/usr/local/apache_[version]目录(或者在步骤4中安装压缩文件的目录);
! N% }* _" a' h8 j/ k# s5 ~ 6、键入下面的命令为编译Apache作准备,用你自己的路径替换其中的[path],例如,/usr/local/apache[version],现在已经设置了mod_so的新值,它将允许Apache使用DSO模块; ( I; i7 a6 i% N# V4 o2 H8 Q# _1 L
7、回到提示符状态后键入make,并等待再次回到提示符状态; ! ?% U, ]9 ^# p5 Z2 T
8、执行“make install”命令。 * X% ]) U: }! x5 Y+ w9 N4 g
至此,Apache已经安装完毕,系统将重回到提示符状态。接下来我们开始安装PHP:
) i% P' l8 w/ Z6 [, A 1、在PHP主页的下载区中找到最新版本的链接; 2 E- I+ r" d: x' V% k7 E
2、把文件下载到一个适当的目录中,例如/usr/local/或/opt/或者你指定的任意目录中; % u! z5 W7 L5 w; ~0 l: w4 B, G
3、运行Gunzip对文件进行解压缩,得到后缀为.tar的文件; 1 y" Z+ Z+ a' A
4、执行下面的命令把文件安装在php-[version]目录中:
. B; k# o/ M! V; r" _ tar -xvf php-[version]
: P$ K5 B1 W) D( u! P9 Z 5、进入/usr/local/php-[version]目录或在步骤4中指定的目录;
8 W5 k" \3 E2 x0 U0 x, W! r' x 至此,已经作好了以DSO方式安装PHP的准备工作,唯一需要修改的配置选项是with-apxs(这是Apache的bin目录中的一个文件)。为了得到较高的性能,我没有安装对MySQL的支持模块。 & W' F$ a7 R/ @ S
./configure --with-mysql=/[path to mysql] --with-apxs=/[path to apxs]
8 G) m9 F8 m2 ` l 6、回到提示符状态后执行make命令,等待重新返回到提示符状态; 4 @* V k2 Z6 p- [5 t
7、执行make install命令。 $ U1 t( y" T& w# t7 E2 `
至此,系统以DSO方式在Apache的模块目录中安装了PHP,并对Apache的httpd.conf文件作适当的修改后返回到提示符状态。回到提示符状态后,你还需要对Apache的httpd.conf文件作一些修改。 5 i& N# b' _, ^' \+ y; d, i
1、找到包含有ServerAdmin的一行,添加你的电子邮件地址,如下所示:
& d: X' F: S* c& m* ^ ServerAdmin you@yourdomain.com
* G/ `1 _1 P/ m! M# P 2、找到以ServerName开头的行,把它改为真正的值,例如: 2 \' C2 W5 R. Y5 m
ServerName localhost 5 f- b9 H% |% g- Q3 Q# _+ V
3、找到内容如下所示的小节:
! Y; b: H# @" m; L, @ # And for PHP 4.x, use: ' v6 ~( y8 B, P% |
#
% h0 {& a; A" W4 H) k #AddType application/x-httpd-php .php & A4 j3 w3 h9 \3 p" |0 d
#AddType application/x-httpd-php-source .phps - b( y) |! u$ S5 j
修改这些行的内容,使PHP 4.0的AddType不再成为注释,并添加希望在PHP中使用的文件后缀名,上面的内容变为如下所示的内容:
$ B {+ [/ M! l4 d # And for PHP 4.x, use:
9 K. h- o- Z0 {8 H6 X+ B% C: ] #
# j7 s& l( _+ ^7 X" ?' t AddType application/x-httpd-php .php .phtml 3 o' u8 {9 q6 C2 L
AddType application/x-httpd-php-source .phps : h& R% e: d% x8 Y, a
保存文件,回到上一级目录,执行下面的命令重新启动Apache: 9 d: W1 ]+ H+ r/ W. e& D% |0 P: T
./bin/apachectl start
* P$ j/ x8 L" w- H+ `% d$ A4 u 如果在启动时没有出现错误提示信息,就可以通过创建一个名为phpinfo.php的只有如下所示一行内容的文件,对安装的Apache、PHP进行测试: . x( W4 f. x5 A- `- f1 c
<? phpinfo() ?> 8 s( R+ }+ w+ B
把这个文件保存到Apache的文档根目录(htdocs)中,然后开启浏览器,键入http://localhost/phpinfo.php地址,?..淞亢退堑闹怠?/a> : q) x- ?! m% y" O! {
如果要重新配置PHP,需要再次运行make clean命令,然后执行带有一系列选项的./configure命令,然后再执行make和make install命令,Apache的目录模块中就会出现一个新的模块,只要再重新启动Apache加载这个新的模块,就一切OK了。
2 d, o0 W8 L, ^" X- R; s二、使用PHP本身的对话
6 q g' c3 \8 t, a6 I2 l PHP 4.0中最令人期待的特性应该是对对话的支持,PHP 3.0的用户必须使用第三方的软件否则就不能使用对话,不支持对话一直是PHP最大的缺憾之一。
: o7 d6 j" O" k% y2 Z" Q 只要用户在浏览你的网站,你就可以利用对话维护与特定用户有关的变量,而无需建立多个cookie、使用隐藏表格字段或将信息存储在数据库中。
0 Z7 R3 g% s5 r' j2 [- J. Y# v1 j 在一个网页上启动一个对话,就会使PHP引擎知道你想启动一个对话(如果还没有启动)或者继续当前的对话:
- o5 h# P6 \ Csession_start();
9 S& e. u( `1 c) O! K( y# g+ D 启动一个对话将通过cookie向用户发送一个识别字符串(例如940f8b05a40d5119c030c9c7745aead9),在服务器端,会创建一个与识别字符串匹配的临时文件,例如sess_940f8b05a40d5119c030c9c7745aead9,这个文件中包含注册的对话变量以及它们的值。
0 `1 O$ y' ]6 Z# @! O2 S 用来显示对话的作用的最常见的例子是访问计数器。启动PHP模块,确保PHP代码是文件的第一行,在PHP代码之前不要有空格、HTML代码和其他的代码。因为对话会发送一个头部,因此如果在session_start()之前有空格和HTML代码,就会得到一个出错信息。
" ^& b8 h+ q' L0 n' r <? : @5 j0 _) I2 `0 v
// 如果还不存在一个针对某用户的用户,则启动一个对话:
. Q, `- A$ t* r- z session_start();
9 l7 b% _; V$ n1 @ 然后注册一个名字为count的变量:
N" O1 @; \# ` p0 [ session_register(';count';); " y6 S U% _3 [& k: K0 F0 U0 L
注册一个对话变量后,只要对话存在,名字为count的变量也就存在。现在,count变量还没有被赋值,如果对它执行加1操作,它的值就变为了1。 1 P( Z5 T$ m0 B
$count++;
+ G2 g# {* |7 z& c; s, _! j7 X8 X2 ? 把上述内容综合在一块儿,如果还没有启动一个对话,就会启动一个对话;如果不存在一个对话id,就为用户指定一个好了,注册一个名字为$count的变量,对$count执行加1操作表示用户已经首次访问了该网页。
$ E8 a, W' D' x" \8 s' V 要知道用户在当前的对话中访问本页面的次数,只要显示$count变量的值即可: % x5 r9 G3 z% h2 f$ X$ d
echo "<P>You';ve been here $count times.</p>"; " d$ q4 M) w1 Z* Y1 c! n
全部的访问计数器代码如下所示: % q: N1 U5 o N& E; T4 R# j
<? ' I! a+ Z' H' S5 e# S7 G8 i
session_start();
& J; H2 y* c7 g* ?8 W session_register(';count';);
Z4 P2 j' _" P! e! J$ o! P $count++;
9 V0 i1 N) ^& z& W" p1 Q) I echo "<P>You';ve been here $count times.</p>"; ; X/ Q9 U q7 G! o
?>
7 A, f, f0 X. q* }3 k( t9 c/ b* m, b5 O 如果重新加载上述的脚本文件,就会发现变量count的值增加了1,很酷吧。 $ ~$ m: R" u/ L1 ~
还可以在对话中注册一个数组变量,假设我们注册了一个名字为$faves的变量:
. Z+ t" t* v, z5 M1 P- p $faves = array (';chocolate';,';coffee';,';beer';,';linux';);
, r( B5 [: b: X5 o 可以象注册一个简单变量那样注册一个数组变量: : a w/ J9 P K5 z# P1 }* E
session_register(';faves';);
' W( R# y* U8 O, a/ X6 P 引用数组变量与引用简单变量没有什么二样,如果一个用户在网页上指出在生活中的爱好时,可以把他的爱好注册到一个被称作$faves的数组变量中,然后可以在另一个网页中很方便地把这些爱好显示出来:
% X; u' U: C9 K <?
, {6 |& m$ F$ N& T! j- M session_start();
8 u' F y! b. P- K& t echo "My user likes:
4 k) n3 [; s8 o <ul>";
0 R, ~$ w1 k. ^9 F: u1 d while (list(,$v) = each ($faves)) {
* {7 Y, W2 `9 R9 v echo "<li>$v"; } : Y* y, a# O0 R$ o
echo "</ul>"; 6 a6 ~- i+ W! T# \
?> ; f. J+ S4 T" ^3 x
然后你就得到了一个关于用户爱好的清单。 : Q6 f' [$ \$ ^5 j V
对话变量不能被查询字符串覆盖,也就是说我们不能输入http:///www.yourdomain.com/yourscri...nt=56给注册变量$count指定一个新值,这一点对于安全很重要:只能在服务器端的脚本中删除一个没有注册的对话变量。
+ d# ^2 v! ? z2 f9 n7 \ 如果要完全删除一个对话变量,首先需要从系统中注销它: 6 p6 {9 r5 i R
session_unregister(';count';); f( Y% G4 t" M3 h9 C1 m
要完全删除一个对话变量的脚本是非常简单,如下所示: " g+ _* q* V/ D6 L9 x9 \
session_destroy();
5 g% U$ t7 y* `0 t( W% | 使用对话变量可以减少访问数据库的频率,使代码更加清晰,而且可以减少对用户发送的cookie的数量,它是最简单的方法了。 2 V, s8 {& K6 P* @
三、文件是我们的朋友
5 C; ]" }' Q1 @8 e+ s 无论你在开发的网站规模的大小,都应该意识到代码重用的重要性,无论这些代码是HTML、还是PHP代码。例如,你必须至少每年改变一次包含版权信息的页脚,如果你的网站含有1000个页面,每年修改一次也是个很烦人的事儿。
3 p k; t: X) [9 I! H6 N 在PHP中,至少有几个函数可以帮助你实现代码重用的目的,所使用的函数取决于你所重用的代码,主要的函数有: 9 o1 v" ~+ _: o N
* include() and include_once()
/ l5 K% n# ?) P$ T * require() and require_once()
* G; k [! n# ~5 \ include()函数包含并对给定的文件进行计算,例如: . s2 h& \* p( G! O. r3 g( m
include(';/home/me/myfile';); ) K! x) D9 c2 K- s7 M# y+ y
在include文件中的任何代码都在include()出现的代码范围内执行,你可以通过联合使用include()和fopen()在自己的服务器上包含静态文件,在另一台服务器上包含目标文件。
( z3 _! }8 A% c& H& O include_once()的功能与include()相同,二者之间的区别在于它会检查一个文件中的代码是否已经包含在现有的脚本中,如果代码已经存在,则不会再次包含它。 % s7 r6 j; i R2 i
require()函数用给定文件的内容取代它本身,这一代替过程发生在PHP引擎编译代码期间,而不是在执行期间进行,它不象include()那样会首先进行计算。require()函数更多地用在静态元素中,而include()更多地用于动态元素中。与include_once()类似的是,require_once()将首先检查是否已经插入给定的代码,如果代码已经存在,就不再插入了。
8 e' N' B) l8 K- i3 J 为也了解其内容,在版权信息、静态文字和其他不包含变量的元素或者依赖其他正在执行的脚本的元素中我更趋向于使用require函数。例如:
4 d! X" x0 j: Z, M7 w: W+ f <HTML> ? E% O! t7 m9 j- x% A3 H7 q
<HEAD><TITLE>Something</TITLE></HEAD> ; A) g' I, ]8 L+ j! q6 o
<BODY>
! b r% a# w( G Q1 S2 Y4 j5 C4 \% h [a lot of content] ' Y* p' A1 `3 e" M4 U6 l
<?
- d3 m' r* H8 k2 F // insert copyright
f- Y5 ?+ ~% N7 o require(';/home/me/mycopyright';);
; ?. C7 `- h4 m; ^/ h ?>
" X! W) S) x/ s: ?2 j </BODY>
' Z; d9 i/ x2 @- g </HTML> ; {; d: y, S2 {3 x5 r1 k8 ^: d
另一方面,我经常在文件的开始使用include()来控制许多的函数: % k- x4 F" `5 p9 Z" b4 m: A3 ^0 _
<? ! t, i( O$ ^, }; p3 O
//得到函数库 ' T# m9 h( k, B) |& H% H
include(';/home/me/myfunctions';); # o& O* p, N# K7 E1 o
// do PHP things with my functions ?>
& X: r5 Z6 F8 Z! r <HTML> 5 \+ A$ F$ h L
<HEAD><TITLE>Something</TITLE></HEAD>
. n$ }! B9 o' }2 G! } <BODY>
, D+ @3 X$ I( y' q! @% k" e [a lot of content]
5 M6 P E, L: a) H5 R7 F1 F. H </BODY> y) w3 R4 w/ E( ~2 M; V6 y% @, r
</HTML>
5 O( c2 s; I( y& x0 I! D 下一个问题就该是“include和require文件在哪里?”,对这个问题简单的回答是,“系统中的任意地方。”如果你的代码中包含有带有用户名和口令的数据库连接,你肯定不会将它们都放在文档根目录中向所有的人都开放。
0 y) x; J( u ^ included或required文件可以在系统上的任何地方,只要PHP运行的系统上的用户可以访问这些文件即可,你可以使这些文件具有任何后缀,或者不使用后缀。 0 x/ Q& l! i6 W$ O. r0 |
使用include()和require()对在网站中的元素进行具体化是一种普遍的现象,并在需要对网站升级时,给你带来很大的方便。 $ b, s( ~+ i" E/ d2 h' l
四、PHP和文件系统的维护
+ ]0 d: V5 f6 y5 |& a PHP中有许多与文件系统有关的函数,这些函数不仅可以打开文件,还可以显示目录中的内容、移动文件和其他一些功能,许多人甚至用PHP开发基于互联网的文件资源管理器。
$ i2 f% ?, U' y2 g& ~( @" M 关于文件路径的解释:在Windows中,可以在路径中使用/和\符号,而在其他的操作系统中只能使用/符号。出于一致性的缘故,我们统一使用/符号。 6 @3 |& l6 v& z$ O' e8 j1 r! A
下面的脚本样例可以显示一个目录清单,注释已经包含在代码中: 5 j& Z% @+ d. B3 F9 t V
<? /*把要读取的目录的全路径名存入一个名字为$dir_name的变量中。 */
7 Q5 X* K2 Z* `+ {) K% O) O $dir_name = "/home/me/"; ) _6 g2 D+ n- o/ N( m
/* 创建一个句柄,其值是打开一个给定目录的结果*/ & K" R# u( l; X
$dir = opendir($dir_name); $ w, \, c$ |+ s, A" g
/* 建立一个文字块,用以放置列表元素(文件名字)*/ ! a6 D# C! H0 Q
$file_list = "<ul>"; 5 k' I3 E2 ?& s6 U3 {
/* 使用一个while语句,读取已经打开的目录中的所有元素,如果文件的名字不是“.”或“..”,则显示列表中的名字*/
) \2 U' w8 `) v0 ?; S- K4 `2 T while ($file_name = readdir($dir)) {
9 D. c, ]. w0 h if (($file_name != ".") && ($file_name != "..")) { ' r$ i( ?! d1 J+ X2 U, r; T7 P
$file_list .= "<li>$file_name"; 7 O0 Q2 i6 U6 Z+ w
} ( q- M- [4 s7 d) G: t
} ' X6 L5 n, }# r& m
$file_list .= "</ul>";
! Q9 V% O4 O v \ /*关闭打开的目录,结束PHP模块*/
, P8 \" J" V% u$ J/ N2 c closedir($dir);
; A: O4 F8 o# q ?> 2 ]0 x% R& n7 }6 X: ~- N$ P
<!-- Start your HTML --> 0 H; }- Y$ @# ?4 @# Q( V: d7 E
<HTML>
7 x) j R2 N `7 S+ o9 x <HEAD> , J) A) a. I% I( m( J
<TITLE>Directory Listing</TITLE> * B- b [4 { d0 I' K3 F
</HEAD> : `/ `" g! h, P0 p# r
<BODY> ' f) N& h5 T# T3 [
<!-- Use PHP to print the name of the directory you read --> 0 u5 M" ]1 U" M* r, j( B$ A, K
<P>Files in: <? echo "$dir_name"; ?></p> 5 v5 b6 v2 G* H7 Y9 W
<!-- Use PHP to print the directory listing -->
/ A! K9 {1 _! E' _ <? echo "$file_list"; ?>
9 h" x' G5 C7 O </BODY>
& c L( j% {6 U7 s </HTML>
' P% O, A. Z. Q% R2 J S m 好了,我们已经得到了一个目录清单。需要注意的是,要读取一个文件(稍后我们将进行讲解)或目录的内容,PHP运行的系统上的用户必须至少有读取文件的权限。
7 g n" p8 S. {% L7 M7 U 下面是一个如何拷贝文件的例子: " W+ G: ~/ e! S, w& t4 R# a
<? /*把你要拷贝的原文件的全路径赋给一个名字为$original的变量中,把拷贝的文件的全路径赋予一个名字为$copied的变量中*/
# B3 V, |% n2 u $original = "/home/me/mydatabasedump";
3 i+ ]# B4 u0 a Q% `0 } $copied = "/archive/mydatabasedumo_1010"; 9 m: E' d- N4 f5 b3 m2 r
/* 使用copy()函数拷贝原始文件,如果拷贝没有完成则会显示一个错误信息*/
' ?, j, W' L( X7 | \ @copy($original, $copied) or die("Couldn';t copy file."); & c3 p/ z( G0 p/ y2 H4 n o
?> ( ]& W' U" y; q- k( @* C
这个例子是一个文件备份系统的原型。在这段脚本运行时,它把文件拷贝到一个不同的位置进行保存。稍微修改一下守护程序,就可以在一天中你指定的时刻执行它,而无需用户的干预。 , Q% l7 \, [$ n( [/ F
假定你在系统上安装了Lynx,可以创建一个守护程序的条目访问这个文件,访问这个文件会运行这个脚本并建立一个拷贝文件,下面的例子将在上午5点钟运行这个脚本,然后关闭Lynx:
) R- i; I3 U' @+ L7 y3 K, U% h- W5 x; A5 T 0 5 * * * [username] lynx -dump http://localhost/copyfile.php ;1>/dev/null 2>&1
3 U- o( d! I; C# ` 如果运行的是CGI版本的PHP,可以跳过Lynx部分,而直接调用二进制文件:
! s# S# m5 L& c9 \, p 0 5 * * * [username] php /path/to/copyfile.php 1>/dev/null 2>&1
0 u9 w! _( x+ S |