第1章 php3 入门
什么是php3?
php3.0版本是一种服务器端html-嵌入式脚本描述语言。
php3能做什么?
也许php3最强大和最重要的特征是他的数据库集成层,使用它完成一个含有数据库功能的网页是不可置信的简单。目前支持下面所列的数据库。
oracle
adabas d
sybase
filepro
msql
velocis
mysql
informix
solid
dbase
odbc
unix dbm
postgresql
php的简要历史
php从1994年秋天开始孕育,他的创始人是rasmus lerdorf。早期没有发布的版本是被他用在自己的网页上来跟踪有谁来参观过他的在线个人简历。被其他人使用的第一个版本是在1995年发布的,当时叫做personal home page tools。他包含了一个非常简单的语法分析引擎,只能理解一些指定的宏和一些home page后台的常见功能,如留言本,计数器和一些其他的素材。在1995年中期,重写了这个语法分析引擎并且命名为php/fi 2.0版本。fi来源于rasmus所写的另一个可以接受html表单数据的程序包。他组合了personal home page tools 脚本和form interpreter,并且加入了对msql的支持,于是php/fi 2.0诞生了。php/fi以惊人的速度发展,并且其他的人也开始对他的源码加以改进和修改。
很难给出任何精确的统计数字,但是据估计到1996年末至少有15,000个web站点在使用php/fi 2.0,到了1997年中,这个数字已经成长为50,000个,1997年中php的发展也已经有了一些变化,他已经从rasmus的宠物项目变成了更加有组织的团体项目。语法分析引擎也由zeev suraski 和 andi gutmans进行了重新改写,这个引擎构成了php3的基础。php/fi中的大部分通用代码都经过改写后引入了php3中。
今天(1998年中),有许多商业的产品如c2's stronghold web server和red hat linux都开始支持php3或php/fi,根据由netcraft提供的数字进行保守的推断,现在在世界各地大概有150,000个web站点在使用php或php/fi。从前景上看,在internet上这些站点远远比运行netscape's flagship enterprise server的要多。
使用php3进行http认证
只有在php以apache的模块方式运行的时候才可以使用http认证的功能。在apache的模块php脚本中,可以使用header()函数向客户断浏览器发送一个”authentication required”的消息,使浏览器弹出一个用户名/密码(username/password)的输入窗口,当用户输入用户名和密码后,包含php脚本的url将会被再次调用,使用分别代表用户名,密码,和确认方式的$php_auth_user, $php_auth_pw,$php_auth_type变量。现在只有”basic”的确认方式被支持。
在一个页面中强迫用户进行身份认证的代码段的例子如下:
example 2-1. http 认证举例:
<?php
if(!isset($php_auth_user)) {
header("www-authenticate: basic realm=\"my realm\"");
header("http/1.0 401 unauthorized");
echo "text to send if user hits cancel button\n";
exit;
}
else {
echo "hello $php_auth_user.<p>";
echo "you entered $php_auth_pw as your password.<p>";
}
?>
除了简单的输出$php_auth_user 和 $php_auth_pw变量的值以外,你还可以检查用户名和密码的合法性,也许是对数据库进行查询,也许是在dbm文件中搜索用户。
当心臭虫成堆的internet explorer浏览器,他对hearders的顺序非常挑剔.所以采用在送出http/1.0 401 header 请求之前送出www-authenticate header请求是一个很好的解决方法。
为了阻止一些人写一些脚本来显示一个经过传统外部机制验证过的页面的密码,采用如下方式:如果这一页面使用外部验证机制,将不会生成php_auth变量.这样,$remote_user变量可以被用来表示已经被外部机制验证的用户.
注意,上面的方法并不能防止某些人在同一台服务器上利用无身份验证的url偷取有身份鉴别的url的密码。
无论netscape还是ie,在接到服务器的401回复之后,都将清空本地浏览器窗口的身份验证缓存。这种做法可以有效的使用户登录退出,从而强迫他们再次输入他们的用户名和密码。一些人使用这个方式来实现“超时”注册,或者提供登录退出的按钮。
这种方法不是标准的http基本身份鉴定所必须的,所以您可能从来都不依靠它。使用lynx进行的测试并没有弄清楚401服务器回应的身份鉴定,所以如果使用“向前”或“向后”功能将打开源文件(只要信用需求还没有被改变)。
虽然已经指出这种语言不能工作在microsoft的iis服务器上,但是php语言cgi版本将受到iis的限制。
使用php建立gif
php并不仅仅可以用来建立html输出。它还可以用来制作gif图形文件,甚至制作更简便的gif图象流。要想这样做,您将需要使用gd函数库来编译php源文件。
example 2-2. 使用php来创建gif文件
<?php
header("content-type: image/gif");
$string=implode($argv," ");
$im = imagecreatefromgif("images/button1.gif");
$orange = imagecolorallocate($im, 220, 210, 60);
$px = (imagesx($im)-7.5*strlen($string))/2;
imagestring($im,3,$px,9,$string,$orange);
imagegif($im);
imagedestroy($im);
?>
这个例子将被一个页面使用类似于:<img src="button.php3?text">的方法来调用。其中关于button.php3的脚本将把这一段文本覆盖在基本的图形上(在这里是“images/button1.gif”)然后输出结果图形。这是一个很简便的方法来防止每当用户希望改变按键的文本时候都重新画一次按钮图形。使用这种方法,他们将被动态的使用。
文件上载支持
php有能力接受任何rfc-1867适应浏览器(包括netscape navigator 3.0或以后的版本, microsoft internet explorer 3.0(使用了补丁程序)或以后的版本)的文件上载。这个特性让用户可以上载文本和二进制文件。使用php 的身份鉴定和文件处理函数,您可以完全控制谁可以上载文件和被上载的文件可以做些什么。
可以采用类似下面的建立表单的方法来建立一个文件上载的屏幕。
example 2-3.文件上载表单
<form enctype="multipart/form-data" action="_url_" method=post>
<input type="hidden" name="max_file_size" value="1000">
send this file: <input name="userfile" type="file">
<input type="submit" value="send file">
</form>
其中“_url_”指向一个php的html文件。max_file_size隐藏领域必须先于文件输入领域,它的值是可以接受的最大的文件大小。该值的单位是字节。在该目标文件中,下列变数用来定义是否成功的上载了文件:
$userfile:在将要存放上载文件的服务器上的临时文件名字。
$userfile_name:在发送者系统中的初始文件名。
$userfile_size:按字节计算的上载文件的大小。
$userfile_type:多用途网际邮件扩充协议类型的文件,如果浏览器提供这种信息。一个例子是“image/gif”。
注释:在这里“userfile”部分是可以变化的,它可以取任何的名字只要在上载表单中类型仍然为“type=file”即可。在上面的例子中,我们选择它的名字为“userfile”。
文件将被默认的存放在服务器默认的临时目录下。在php运行的环境下,可以改变环境变量tmpdir来更改这个设置。设置时,请在php脚本没有运行的情况下使用一个putenv()函数。
接受上载文件的php脚本语言将贯彻何种逻辑结构是必须的来决定对上载的文件可以做些什么。例如,用户可以使用“$file_size”变量来发送任何或者太小或者太大的文件来尝试一下结果。可以使用“$file_type”变量来发送任何不符合的确定类型标准的文件。无论何中逻辑结构,您都需要在临时目录中删除这个文件,或者把它移走。
如果没有被改名字或移动,那么在请求的最后该文件将被从临时文件夹中删除。
请注意,在从客户端获得mime的连接类型之后,“cern httpd”软件似乎将剥离任何内容而以最初的白板形式出现。在这种场合,“cern httpd”软件将不支持上载文件的特性。
http cookie支持
php很明显的支持http cookie。cookie是一个在远程浏览器上存储数据和跟踪或鉴定返回的用户的结构。您可以使用函数setcookie()来设置cookie。cookie是http文件头的一部分,所以该setcookie()函数必须在任何输出向浏览器发送前被调用。这种情况和函数header()的限制是类似的。
任何从客户计算机发送到您那儿的cookie都将被自动的转化成一个类似于get和post方法数据的php变量。如果您希望给一个cookie指派多个值,只需要在该cookie的名字后面加上“[ ]”即可。关于更多的细节问题请参看setcookie()函数。
数据库支持
php支持大量本地模式和完全odbc等不同类型的数据库,包括:
adabas d
mysql
dbase
oracle
empress
postgresql
filepro
solid
informix
sybase
interbase
velocis
msql
unix dbm
正则表达式格式
正则表达式在php中被用来处理复杂的文字串。支持正则表达式的函数有:
ereg()
ereg replace()
eregi replace()
split()
这些函数都将正则表达式作为他们的第一个参数。php使用posix扩展规则表达式(使用posix 1003.2)。要找到所有的关于posix扩展规则表达式的描述,请查看包括在php发行版本之内的regex man页面。
example 2-4. regular expression examples
ereg("abc",$string);
/* returns true if "abc"
is found anywhere in $string. */
ereg("^abc",$string);
/* returns true if "abc"
is found at the beginning of $string. */
ereg("abc$",$string);
/* returns true if "abc"
is found at the end of $string. */
eregi("(ozilla.[23]|msie.3)",$http_user_agent);
/* returns true if client browser
is netscape 2, 3 or msie 3. */
ereg("([[:alnum:]]+) ([[:alnum:]]+) ([[:alnum:]]+ )",
$string,$regs);
/* places three space separated words
into $regs[1], $regs[2] and $regs[3]. */
ereg_replace("^","<br>",$string);
/* put a <br> tag at the beginning of $string. */
ereg_replace("$","<br>",$string);
/* put a <br> tag at the end of $string. */
ereg_replace("\n","",$string);
/* get rid of any carriage return
characters in $string. */
出错操作
在php中有四种类型的错误和警告。它们是:
通常函数错误:1
通常警告:2
分析错误:4
注释(警告用户,可以忽略该信息,但是这个问题可能给您的代码会带来一些错误):8
信息后面的四个数字是该信息类型的表示值,把它们加起来作为错误报告的级别。却省的报告级别是7(即1+2+4),或除了“注释”的其他组合。这个级别能够通过改变php3.ini文件中错误报告指示的方法来改变。它也可以在用户的httpd.conf文件中改变php3错误报告的方法来设置,或者在运行的时候使用脚本语言函数error reporting()来改变。
所有的php表达式都可以使用前缀“@”来调用,对于这种特殊的表达式将关闭错误报告。如果一个错误在运行这样一个表达式时发生了,而且“track error”特性被置为可用,那么用户可以在全局变量$php_errormsg中找到这些错误信息。
第3章 安装
本章将引导您如何安装和设置php3。并介绍必要的知识和软件。
基本的unix技巧(学会如何操作和“制作”一个c编译器)
一个标准的ansi c的编译器
一个web服务器(显然需要)
通过unix源码编译安装
下载源文件
最新的源代码可以在以下网址找到:http://www.php.net
快速安装说明书(apache module 版本)
1. gunzip apache_1.3.x.tar.gz
2. tar xvf apache_1.3.x.tar
3. gunzip php-3.0.x.tar.gz
4. tar xvf php-3.0.x.tar
5. cd apache_1.3.x
6. ./configure --prefix=/www
7. cd ../php-3.0.x
8. ./configure --with-mysql --with-apache=../apache_1.3.x --enable-track-vars
9. make
10. make install
11. cd ../apache_1.3.x
12. ./configure --prefix=/www --activate-module=src/modules/php3/libphp3.a
13. make
14. make install
instead of this step you may prefer to simply copy the httpd binaryovertop of your existing binary. make sure you shut down yourserver first though.
(也可以使用直接拷贝httpd的二进制文件覆盖已经存在的二进制文件的方法代替上面的步骤,但是,您必须首先关闭您的服务器。)
15. cd ../php-3.0.x
16. cp php3.ini-dist /usr/local/lib/php3.ini
you can edit /usr/local/lib/php3.ini file to set php options. if you prefer this file in another location, use --with-config-file=/path in step 8.
(您可以直接编辑/usr/local/lib/php3.ini文件来设置php选项,如果您将此文件存放在另一个位置,那么请在步骤8中使用with-config-file=/path)
17. edit your httpd.conf or srm.conf file and add:
addtype application/x-httpd-php3 .php3 you can choose any extension you wish here. .php3 is simply the one we suggest.
(您可以选择任何您希望的扩展,我们认为php3是一个十分简单的东西。)
18. use your normal procedure for starting the apache server.
(you must stop and restart the server, not just cause the server to reload by use a hup or usr1 signal.)
(您必须停止和重新启动服务器,而不能仅仅使用服务器的reload(重新载入)功能。)
这里有两种方法来设置php3
1.使用跟随php3而来的“setup”脚本语言。该脚本语言会询问用户一系列的问题(大多数类似于php/fi 2.0的“install”脚本语言)在最后运行“configure”。要运行这个脚本,请输入:“./setup”。
这个脚本还将建立一个叫做“do-conf”的文件,这个文件将要传到设置里面去的数据。您可以编辑这个文件以改变一些设置(仅仅是一些)而无须重新运行setup程序。然后,输入:“./do-conf”使用这些选项来设置。
2.手动的运行设置。查看您可以使用的设置选项,请输入:“./configure --help”。
不同设置的详细资料将在下面列出。
apache 模式
按照apache模式来建立php3,对问题“build as an apache module?”(按照apache 模式建立?)应该回答“yes”(是)(设置—with-apache=dir)然后详细的说明apache分配的基本目录。如果您已经在“/usr/local/www/apache_1.2.4”中解压缩了了您的apache配给包,那么这就是您的apache分配的基本目录。缺省的目录为“/usr/local/etc/httpd”。
fhttpd 模式
按照fhttpd 模式来建立php3,对问题“build as an fhttpd module?”回答“yes”(设置—with-fhttpd=dir)同时指定fhttpd 模式的源数据目录。缺省的目录是“/usr/local/src/fhttpd”如果您正在运行fhttpd,按照该模式建立php将提供更好的性能,更强的控制和远程执行能力。
cgi 版本
缺省的设置是按照一个cgi程序来建立php3。如果您正在运行一个web服务器端的php3有这种模式的支持,那么一般的您出于性能的原因将会选择这种解决方案。然而,cgi版本的php3允许apache用户在不同用户身份下的运行不同的使用php3的页面。请仔细的阅读有关安全的章节,如果您将以cgi形式来运行php。
数据库支持选项
php对许多数据库有内置的支持(也有odbc)
adabas d
--with-adabas=dir
编译的时候加入对adabas d 数据库的支持。这个参数是adabas d的安装目录,缺省是/usr/local/adabasd。
dbase
--with-dbase
激活内置的dbase数据库的支持,不需要外部的库。
filepro
激活内置的只读的filepro的支持,不需要外部的库。
msql
--with-msql=dir
为了激活msql的支持,这个选项的参数是msql的安装目录,并且缺省是/usr/local/hughes。这是msql 2.0安装是的默认目录。configure能自动侦测出系统所安装的msql版本,php3支持1.0和2.0两个版本。如果你编译的是php3和msql1.0版本,你只能存取1.0中的数据库和代替调度算法。
mysql
--with-mysql=dir
为了激活mysql的支持,这个选项的参数是mysql的安装目录,缺省是/usr/local/。这是mysql安装是的缺省目录。
iodbc
--with-iodbc=dir
包括iodbc的支持。这个特性一开始是为iodbc驱动程序管理器设计开发的,iodbc是一个免费的重新发布的odbc驱动程序管理器,能够在很多中unix系统下工作。这个参数是iodbc安装的目录,默认是 /usr/local。
openlink odbc
--with-openlink=dir
包括openlink odbc支持。这个选项的参数是openlink odbc的安装目录,默认是 /usr/local/openlink。
oracle
--with-oracle=dir
包括oracle支持。经过测试,至少在oracle7.0和7.3下能正常工作。这个参数是oracle_home目录,如果你的oracle环境已经被配制好了的话,你就不用指定这个参数。
postgresql
--with-pgsql=dir
包括对postgresql的支持。这个参数是postgresql的安装时的基准目录,默认是 /usr/local/pgsql。
其他的常见数据库的支持也同上面所列的大致相同,需要时请参阅您所选择的数据库的使用说明。
其他配制选项
--enable-sysvsem
包括对sys v 信号(大部分unix系统都支持)。请参看信号和共享内存文档来获取更多信息。
--enable-sysvshm
包括对sys v 共享内存的支持(大部分的unix系统都支持)。请参阅信号和共享内存文档来获取更多信息。
--with-xml
包括对一种非正式版本的xml语法的支持,使用的是james clark’s expat library。参阅xml 函数指南获取细节。
--enable-maintainer-mode
打开额外的相关和编译警告信息,这些信息经常被php3的开发人员所使用。
--with-system-regex
使用系统正则表达式的库胜于使用捆绑的那一个。如果你将php3编译为服务器组件,编译时和连接服务器时必须使用同一个库。如果系统中有你所需要的东西,就打开这个选项,如果可能,推荐你使用同php3捆绑在一起的库。
--with-config-file-path
这个路径是php3启动时用来寻找php3.ini文件位置的。
--with-exec-dir
仅仅允许在处于安全模式下的目录里执行,默认是 /usr/local/bin/。这个选项只能被设置为默认,他可以后来通过修改配制文件里的safe_mode_exec_dir来实现。
--disable-debug
在库中或执行中不包括调试信息。调试信息可以帮助你迅速查明问题所在,因此,只要php还处在alpha或beta的测试阶段,最好保留调试信息。
--enable-safe-mode
缺省是打开”safe_mode”(安全模式)选项,这个选项强加于php功能一些限制,如你只能在打开你在web根目录下面的文件,请详细阅读安全那一章以获得详细信息。cgi用户应该总保持这个选项是打开的。这个选项只能被设置为缺省,但是你可以后来通过修改配置文件(php3.ini)来打开或关闭这个选项。
--enable-track-vars
使用php3来保存从http_get_vars, http_post_vars 或 http_cookie_vars. 来的请求gwt/post/cookie的轨迹。这个选项被设为缺省值,用户也可以在以后在 configuration file中设置track_vars的值来改变它的属性(enabled或者disabled)。
--enable-magic-quotes
设置使魔术引用成为缺省值。这个选项仅仅设置这种缺省情况,它可以使用在configuration file中指定magic_quotes_runtime的方法设置为可用或不可用。请参考有关 magic_quotes_gpc 和magic_quotes_sybase的相应内容。
--enable-debugger
激活内在的php3 debugger支持。这个特性还仅仅处于实验的阶段。请参考configuration file.中debugger configuration 的有关内容。
--enable-discard-path
如果该属性被置为可用,php的二进制cgi能够安全的被防置在wed树以外的地方,同时他人不能采用某种特殊的手段来获得存取权。请参考section in the security chapter中关于这个选项的内容。
--enable-bcmath
使bc风格的任意精度数学函数可以使用。请参考configuration file中有关 configuration file的选项。
--enable-force-cgi-redirect
使用安全检查内部服务器的重新定向。如果用户在apache上运行cgi程序需要使用这个特性。
当把php当成cgi二进制来使用时,作为缺省的设置,php将首先检查它是否被重新定向所使用(例如,在apache上使用活动指示)。这将确认php二进制不能被用来直接调用从而跳过标准的web服务器身份鉴定程序,例如:http://my.host/cgi-bin/php/secret/doc.html。这个例子存取了http://my.host/secret/doc.html,但是没有进行过httpd为目录/secret所做的安全设置。
不使用这个选项而关闭这种检查同时使用旁路httpd安全和身份设置。如果您要这样做的话,除非是您的服务器软件不能指出一种安全的重新定向;同时在您的文件夹根目录和用户目录中的文件将被任何人存取。
请参考安全那一章中有关这个选项的内容。
--disable-short-tags
禁止短形势的php3标签<? ?>。如果你想使用xml(扩展标记语言)的话,就必须禁用<? ?>,那么,php的代码标签就只剩下<?php ?>了。这个选项只能被设置为默认。可以通过修改配置文件里的short open tag指令来打开或者关闭这个选项。
--enable-url-includes
通过include()函数,php3能够直接运行其它http和ftp站点的代码。参阅配置文件里的include path选项。
--disable-syntax-hl
关闭语法突出显示功能。
cppflags and ldflags
为了能在php的安装过程中能在不同的路径下找到头文件和库文件,修改cppllags和ldflags环境变量。如果你正在使用一种智能shell(命令解释程序),你应当能够设置ldflags=-l/my/lib/dir cppflags=-i/my/include/dir ./configure
创建
配置完php3,你即将创建可执行的cgi或php3的库。 make的命令应该注意到这些问题,如果失败了,你将不知道为什么?请察看问题那一章。
测试
如果你已经把php3作为cgi程序进行了创建,你可以通过make test命令来测试你的工作。建议你进行测试,在你的平台上早点发现你的php3的问题,好过你日后为这个问题的解决焦头烂额。
从html中脱离
这儿有三种方法从html中脱离,同时加入“php代码模式”
example 5-1. 从html中脱离的方法
1. <? echo("this is the simplest, an sgml processing instruction\n"); ?>
2. <?php echo("if you want to serve xml documents, do like this\n"); ?>
3. <script language="php">
echo ("some editors (like frontpage) don't
like processing instructions");
</script>;
4. <% echo("as of php 3.0.4 you may optionally use asp-style tags"); %>
语句的脱离方法
语句的脱离方法和c及perl是一样的------终止每一个语句时使用分号(;)。
结束标签(?>)也暗示了说明的结束,所以下面的两句话是等价的:
<php
echo "this is a test";
?>
<php echo "this is a test" ?>
变量类型
php支持如下的变量类型:
integer :整数
double :双精度数
string :字符串
array :队列数组
object :对象
pdfdoc (only if enabled pdf support) :pdf文本(仅仅在起用pdf支持之后生效)
pdfinfo (only if enabled pdf support) :pdf信息(仅仅在起用pdf支持之后生效)
这些变量的类型通常不由程序员来设置;特别的,它在运行时由php依据上下文来设置使用什么类型。
如果您喜欢强制将某个变量转换到指定的类型,您还可以对该变量进行“cast”操作,或者使用函数“settype()”。
注意这些变量可能会在确定的情形下被不同的控制者使用,这依赖于此时该变量的类型是什么。想要获得更进一步的信息,请参考“type juggling”部分。
变量的初始化
在php中初始化一个变量,您只需要简单的分派给它一个值即可。对于大多数类型,这样做是十分简单的;但是对于类型“array(数组)和objects(对象)”来说,需要使用有些不同的方法。
初始化数组
一个数组可以使用如下的方法来初始化:使用连续的指定值,同时使用“array()”结构(这将在“array 函数函数说明部分中被证明)。
对一个数组(array)变量连续的添加值。您简单指定无标号的array变量的值即可。这些值会添加在该array变量最后的元素中。
$names[] = "jill"; // $names[0] = "jill"
$names[] = "jack"; // $names[1] = "jack"
和在c和perl中一样,数组元素的开始号码是0而不是1。
初始化object(对象)变量
要初始化object变量,您使用下面例子中所示的申明方法:
class foo {
function do_foo () {
echo "doing foo.";
}
}
$bar = new foo;
$bar -> do_foo ();
变量的活动范围
变量的活动范围仅仅限于定义它的上下文。对于绝大多数部分中所有的php变量仅仅只有单独的活动范围。然而,在用户自定义的函数中,引入了一个本地函数范围的概念。在这个函数中使用的任何变量缺省被限制在该函数的本地函数范围之中。例如:
$a = 1; /* global scope */
function test () {
echo $a; /* reference to local scope variable */ }
test ();
这段脚本将不会造成任何的输出,因为给显示的提交给本地译文的变量“$a”的申明,同时这个变量没有在它的活动范围中被指定一个值。您可以注意到这和c语言有一些不同,在c语言中全局变量是自动被设定为可用的,除非在函数中进行了特别的说明。由于人们可能会不小心的改变了全局变量的值,所以这可会在程序中导致许多问题。在php中全局变量必须在一个函数中被公告,如果想要在这个函数中使用它的话。例子如下:
$a = 1;
$b = 2;
function sum () {
global $a, $b;
$b = $a + $b;
}
sum ();
echo $b;
上面的脚本将输出“3”。在函数中申明了全局变量$a和$b,任何对这两个变量的引用都被指定到了该全局变量。这里没有函数可以操作的限制全局变量的数目。
第二种接受全局变量的方法是使用php特殊的定义数组$globals,例子如下所示:
$a = 1;
$b = 2;
function sum () {
$globals["b"] = $globals["a"] + $globals["b"];
}
sum ();
echo $b;
$globals数组是一个联合数组使用“global”为变量的名字,全局变量作为该变量数组其中某个元素的值。
另一个关于变量活动范围的重要特性是“静态变量”。一个静态变量仅仅在本地函数的活动范围中存在,但是当程序离开这个范围时,它的值并不丢失。请参考下面的例子:
function test () {
$a = 0;
echo $a;
$a++;
}
这个函数每次被调用时都把变量$a置为0同时打印“0”,所以几乎是没有作用的。表达式“$a++”将增加变量的值,但是每次退出函数时变量$a就消失了。想要使用一个不丢失当前计算的记数函数,用户可以将变量$a设置为静态的,示例如下:
function test () {
static $a = 0;
echo $a;
$a++;
}
现在,每一次当test()函数被调用的时候,它将打印出变量$a和它当时增加之后的数值。
当函数被递归调用的时候,使用静态变量是一种很重要的方法。递归函数就是可以调用自身的函数。当编写递归函数的时候,必须注意可能会发生的循环定义。您必须有一个适当的方法来中断这个递归过程。下面的例子递归了10次:
function test () {
static $count = 0;
$count++;
echo $count;
if ($count < 10) {
test (); }
$count--;
}
变化变量
有些时候使用变化变量是十分方便的。也就是说,一个变量的名字将被动态的设置和使用。一个普通的变量将会使用如下的申明:
$a = "hello";
一个变化变量获得一个变量的值,并将其视该变量的名字。在上面的例子中,“hello”,能够使用变量的名字加上两个$来进行使用,例如。
$$a = "world";
在这一点上,两个变量被定义和存储在php的符号树上;$a的内容为“hello”,而$hello的值为“world”。因此如下的申明:
echo "$a ${$a}";
制作了和如下确切相同的输出:
echo "$a $hello";
他们都输出:“hello world”
要在数组中使用变化变量,您必须解决一个含糊的问题。它是:如果您写入了“$$a[1]”,然后解析程序将需要知道您想使用$a[1]作为变量还是使用$$a作为变量,这样索引“[1]”可能就会发生歧义。解决这种歧义的语法如下:“${$a[1]}”或者使用“${$a}[1]”(对上述的第二种情况)。
外界php变量
html表单(get和post)
当表单被提交给php脚本时,从该表单获得的变量将自动的被该php脚本设置为可用。请参考如下示例:
example 5-2. simple form variable (简单的表单变量)
<form action="foo.php3" method="post">
name: <input type="text" name="name"><br>
<input type="submit">
</form>
当提交之后,php将建立一个变量“$name”,它将包含任何在表单中输入在“name”中的内容。
php同时也知道如何安排表单变量的上下文关系,但是仅仅限于一次。您可以,例如,将一组变量同时叙述,或者使用这个特性来重新从多重选择输入中获得值:
example 5-3. more complex form variables
<form action="array.html" method="post">
name: <input type="text" name="personal[name]"><br>
email: <input type="text" name="personal[email]"><br>
beer: <br>
<select multiple name="beer[]">
<option value="warthog">warthog
<option value="guinness">guinness
</select>
<input type="submit">
</form>
如果php的track_var特性被打开了,任何关于它的结构设置或者<?php_track_vars?>指示,然后经由post或get模式的变量提交将发觉使用全局联合数组“$http_post_vars”和“$http_get_vars”是合适的。
图形提交变量名字
当提交一个表单时,有可能使用一幅图象来代替标准的带标签的提交按钮,例如:
<input type=image src="image.gif" name="sub">
当用户点击该图象的任何位置时,相应的表单将被使用两个附加的变量(sub_x和sub_y)来传送到服务器上。他们包含用户点击在该图形上的相应位置信息。这将包含从浏览器发出的真实变量名字(甚至包含下划线),但是php将会把它自动的转化成带下划线的形式。
http cookies
php当然的支持使用netscape's spec定义的http cookies。cookies是一种在远程浏览器上存放数据的装置,用于跟踪和鉴定用户的身份。您可以使用setcookie()函数来对cookies进行设置。cookies是http头的一部分,所以setcookie程序必须在被进行向浏览器输出前被调用。这和header()函数的设置是类似的。任何从服务器送到用户处的cookies将自动的被转化成为一个php变量,就象使用get和post模式的数据一样。
如果您希望对单个的cookie分派多值,只要在cookie的名字后面简单的加上一个“[ ]”即可。例如:
setcookie ("mycookie[]", "testing", time()+3600);
注意,如果不是在您的浏览器上的域或者路径不一样的话cookie将会使用相同的名字来顶替先前的一个cookie。所以,对于购物单应用程序,您可能希望保持一个计数器同时通过cookie来传送它,例如:
example 5-4. setcookie example (设置cookie的例子)
$count++;
setcookie ("count", $count, time()+3600);
setcookie ("cart[$count]", $item, time()+3600);
环境变量
php自动的使用环境变量作为php的普通变量,例子如下。
echo $home; /* shows the home environment variable, if set. */
既然信息随同get,post,cookie等机制被传递进来,并且自动创建了php变量,有时最好是准确的从外界环境中读出一个变量以确信你正在使用正确的版本。getenv()函数就是做这个工作的,你也可以使用putenv()函数来设置一个环境变量。
服务器设置指示
变量类型变化(juggling)
php不需要(或者说不支持)在声名变量明确他的变量类型;一个变量的类型是由这个变量被使用的前后关系来决定的,也就是说,如果你给一个变量var赋了一个字符串的值,var就变成了字符串变量。如果你再将一个整数赋值给var,他又变成了一个整数型变量。
一个php自动转化变量类型的例子是加法的操作符’+’。如果任何一个操作数都是双精度数,那么所有的操作数被当作双精度数求值,并且结果也是双精度数。否则,操作数将被认为是整数,结果也将会是整数。注意这并不影响每个操作数本身的变量类型,唯一的变化就是操作数在计算的过程中被如何处理。
$foo = "0"; // $foo 是一个字符串 ,值是“0”(ascii 48)
$foo++; // $foo 是一个字符串,值是“1”(ascii 49)
$foo += 1; // $foo 现在是一个整数(2)了
$foo = $foo + 1.3; // $foo 现在是一个双精度数(3.3)了
$foo = 5 + "10 little piggies"; // $foo 是一个整数 (15)
$foo = 5 + "10 small pigs"; // $foo 是一个整数 (15)
如果你觉得上面例子中最后两个表达式看起来有点奇怪的话,请看 “字符串的转化”部分。
如果你希望强制一个变量被当作某种固定的类型来计算,请看 “类型强制(casting)” 一节。如果你希望转变一个变量的类型,请看函数“settype()”的说明。
确定一个变量的类型
因为php自己决定变量的类型并且一般按照需要转化他们,一个特定的变量的类型不是在任何时间都非常明显。php包括一些函数可以找出这个变量的类型。这些函数是gettype(), is_long(), is_double(), is_string(), is_array(), 和 is_object().
类型强制(type casting)
在php中类型强制同在c语言中大抵相似:将需要的类型的种类写在要强制的变量的前面的圆括号中。
$foo = 10; // $foo 是一个整数
$bar = (double) $foo; // $bar 是一个双精度数
以下的强制方式是允许的:
(int), (integer) – 强制成整数
(real), (double), (float) – 强制成双精度数
(string) – 强制成字符串
(array) – 强制成数组
(object) – 强制成对象
注意在圆括号中允许制表符(tabs)和空格(spaces) ,因此下面的语句是等价的:
$foo = (int) $bar;
$foo = ( int ) $bar;
字符串转化
当一个字符串被当作数字型的值来计算时,他的结果和类型如下面所述的决定。
如果这个字符串含有字符’.’,’e’,或者’e’,则被当作双精度类型变量来处理,否则当作是整数。
这个字符串的值由词首部分决定。如果这个字符串以任何有效的数字的数据开始,那么这个数字数据就是这个字符串参加运算的值。否则,值为零(zero)。有效的数字数据是遵循下面的这些标记的,跟随在一个或多个数字后面(可以包含小数点),跟随在一个可选的指数后面。指数是由一个或多个数字跟在’e’或’e’后面构成的。
$foo = 1 + "10.5"; // $foo 是双精度数 (11.5)
$foo = 1 + "-1.3e3"; // $foo 是双精度数(-1299)
$foo = 1 + "bob-1.3e3"; // $foo 是整数 (1)
$foo = 1 + "bob3"; // $foo 是整数 (1)
$foo = 1 + "10 small pigs"; // $foo 是整数 (11)
$foo = 1 + "10 little piggies"; // $foo 是整数 (11);
// 这个字符串包括字符'e'
为了获取更多信息,请参考unix手册关于strtod(3)的部分。
数组操作
php同时支持标量数组(scalar array)和关联数组(associative arrays)。事实上,这两者之间没有任何区别。你可以使用函数list()或array()来创建数组,或者你可以明确的设置每一个数组元素的值。
$a[0] = "abc";
$a[1] = "def";
$b["foo"] = 13;
你也可以通过向数组里添加数值来创建数组。
$a[] = "hello"; // $a[2] == "hello"
$a[] = "world"; // $a[3] == "world"
数组可以通过函数 asort(), arsort(), ksort(), rsort(), sort(), uasort(), usort(), 和ksort() 来进行排序,具体使用那一个函数要根据你所想的排序的类型来定。
你可以使用cunt( )函数来统计数组中元素的个数。
你可以使用next()和prev()函数来遍历数组。另一个普通的遍历数组的方式是使用函数each()。
任何php脚本语言都是使用连续的语句创建的。一个语句可以是一个赋值语句,一个函数调用,一个循环,一个条件语句甚至一个不做任何事情的语句(一个空的语句)。语句经常使用分号(;)结尾。另外,利用卷支持可以把一组语句压缩从而使语句可以被组成语句组。一个语句组是一个关于自身的申明。不同的语句类型将在本章被描述。
常量
php定义了一些常量提供给结构使它能够在运行时定义更多的类型。常量和变量十分的类似,但是他们在语法上有些微的不同。
被预定义的常量是__file__ 和__line__,在处理他们时,会发现他们与文件名和行号相符合。请参考如下示例:
example 6-1. using __file__ and __line__ //使用__file__ 和__line__
<?php
function report_error($file, $line, $message) {
echo "an error occured in $file on line $line: $message.";
}
report_error(__file__,__line__, "something went wrong!");
?>
您可以使用函数define() 和undefine()来定义其它的常量。
example 6-2. defining constants //定义常量
<?php
define("constant", "hello world.");
echo constant; // outputs "hello world."
undefine ("constant");
?>
表达式
表达式是php最重要的基石。在php中,您所写的几乎所有的内容都是表达式。最简单同时也是最精确的定义一个表达式的方法是“任何内容都有它的值”。
立刻进入大脑的简单例子是:常量和变量。当您输入“$a = 5”,您就把值“5”赋给了变量“$a”,明显的,获得这个数值5,或者说’5’是一个值为5的表达式(在这个例子中,’5’是一个整数常量)。
赋值以后$a的值是5, 因此如果你这样写$b = $a,你它同$b = 5所表达的意思是一样的.换句话说,$a是一个值为5的表达式.如果一切工作正常,这些将是所发生的一切.
再稍微复杂一点的表达式的例子是函数(function) .例如,考虑以下下面的函数:
function foo () {
return 5;
}
假设你熟悉函数的概念(如果你不熟悉,看一下第四章),你可能假设$c=foo()从本质上说同$c=5是一致的,你是正确的.函数是以他们的返回值为值得表达式.既然foo()返回5,表达式’foo()’的值就是5。一般来说,函数不会仅仅返回一个态的值,他们一般都计算一些东西。
当然,php里面的值不必须是整数,并且经常他们不是php支持三种标量类型的数值:整数,浮点数,和字符串。(标量值是不能被再分为更小部分的数值,例如它不能是数组)。php也支持两种合成类型的数值:数组和对象。每一种数据类型都能被赋值给变量或者通过函数返回。
迄今为止,php/fi 2的用户不应该感觉到任何改变。然而,php把表达式带入了一个更深的层次,如同许多其它语言所作的一样。php是一种面向表达式的语言,几乎每一件事都是一个表达式.考虑一下我们已经处理过的表达式“$a=5”.可以非常容易的看出这里包含了两个值,常量’5’的值,和$a的值。$a的值也已经被更新成5。但是事实是这里还有一个额外的值包含其中,并且这个值就是赋值语句本身.这个赋值语句本身计算所赋值的数值,在这个例子中是5。实际上,它意味着“$a=5”,不管他做什么,是一个值为5的表达式。因此,一些像’$b=($a=5)’的表达式,实际上同’$a=5;$b=5’(分号代表表达式的结束)是一样的.既然赋值语句被以从右到左的顺序解析,你还可以这样写’$b=$a=5’。
另一个很好的表达式的例子是前和后递增量的方向性.php/fi 2的用户和许多其他语言的用户也许对符号(variable(变量)++和variable--)非常熟悉.这些就是递增和递减符号.在php/fi 2中,语句’$a++’没有任何值(不是一个表达式),并且因此你不能给它赋值或以任何方式来使用它.php通过发展这些表达式加强了递增(increment)/递减(decrement)的能力,像c语言中一样.在php中,有两种递增形式-前递增和后递增.这两种递增本质上都是使变量加1,并且对变量的影响都是一样的.他们的区别是递增表达式本身的值.前递增的形式是’++$variable(变量)’,计算递增值(php 在读出它的值之前递增变量的值,因此叫前递增)后递增的形式是’$variable++’,在变量递增前计算$variable的原始值(php先读出变量的值,然后再递增,因此叫后递增).
表达式的最后一个例子我们将处理组合操作符赋值表达式.你已经知道了如果你想将变量$a的值加1,你可以简单的写成’$a++’或’++$a’.但是如果你想加的数值不只是1呢,例如3?你可以多次使用’$a++’,但是很明显这样不是一个有效的,简洁的方式.通常的方法是这样写’$a=$a+3’. ’$a=$a+3’计算变量$a加3后的值,并且被重新赋值给了变量$a,最终的结果是变量$a的值加了3.在php中,如同像c一样的其它一些语言,你可以用更简短的方式来做这些.给变量$a的当前值加3可以写’$a+=3’.这个表达式正确的意思是”读出$a的值,加3,然后把它赋值给$a”.除了更加简洁和简略外,这样的语句执行起来速度更快.表达式’$a+=3’的值,像一个正则赋值语句的值.是被赋予的值.注意它不是3,而是$a+3的组合的值(这是一个被赋给$a的值).任何二元操作符都可以被用来组合成复合赋值操作符.例如,’$a-=5’($a=$a-5),’$b*=7’($b乘以7),等等.
如果你没有在其它语言中加过的话,你会认为下面的表达式看起来非常奇怪.这就是三元条件算子:
$first ? $second : $third
如果第一个子表达式的值为真的话(非0),那么他的第二个子表达式将被计算,并且这就是整个条件表达式的值.否则,第三个子表达式将被预算,结果作为整个条件表达式的值.
下面的例子可以帮助你大体上理解前,后递增和表达式.
function double($i) { return $i*2;}
$b = $a = 5; /* 把5赋值$a和$b */
$c = $a++; /* 后递增, 把$a的原始值(5)赋值给$c */
$e = $d = ++$b; /* 前递增, 把经过递增操作的$b的值(6)赋值给$e和$d */
/* 这时,$d和$e都等于(6) */
$f = double($d++); /* 把$d的原始值(6)加倍,然后赋值给$f.$f等于(12)*/
$g = double(++$e); /* 先把$e执行递增操作,然后加倍, 2*7 = 14赋值给$g*/
$h = $g += 10; /* 首先,$g加10,并且最终结果是24.将这个值赋值给$h,并且$h最终的结果也是24.*/
在本章的一开始,我们就说过”我们将描述各种类型的语句”.表达式可以成为语句,然而,并不是每一个表达式都是一个语句.既然这样,一个语句具有’expr’’;’的形式,一个表达式加上一个分号.在’$b=$a=5;’中,$a=5是一个有效的表达式,但是他不能由他自己构成一个语句.但是’$b=$a=5;’却是一个有效的语句.
最后一个值得提起的事情是一个表达式的值的真假.在很多事件中,主要在条件执行和循环中,你对表达式的确切的值并不感兴趣,你仅仅对他是否以为着 true(真)或false(假)(php没有专门的boolean类型).在php中计算表达式的真假的方式同perl非常相似.任何非零的数值都是true,零是false!注意负数也非零,所以也为真!空字符串和字符’0’为false;所有其他字符串为true.对于非标量的数值(数组或对象)-如果值没有包含任何元素,则被认为为false,否则为true.
php提供了一个完整而且强大的表达式工具,并且完全说明他已经超出了本手册的范围.关于表达式是什么,你怎么才能构造一个有效的表达市,上面的例子应该给了你一个很好的提示.贯穿这个手册的其余部分,我们将用’expr’代表有效的php表达式.
if
if结构是任何语言中最重要的特性之一,php也包括了它。它允许进行条件判断同时执行相应的程序段。php中if语句的特性和c是十分类似的:
if (expr)
statement
在对该表达式片段的描述后,会判断表达式的值是否为真。如果表达式的值为真,php会执行该语句,如果该值为假,那么php将会跳过该语句。
接下来的例子中如果$a比$b大,那么将显示“a is bigger than b”。
if ($a > $b)
print "a is bigger than b";
通常的情况,是用户希望使用不只一条语句被有条件的执行。当然,在这里没有必要对每一个语句使用if条件判断。用户可以使用一组语句来实现这个功能。例如,如果$a比$b大,那么下面的代码将显示“a is bigger than b”,同时将$a的值赋给$b。
if ($a > $b) {
print "a is bigger than b";
$b = $a;
}
if语句可以嵌套在另一个if语句之中,利用这一点,用户可以根据不同的情况执行程序中不同的部分。
else
通常,可能在条件符合时希望运行某个语句,而在条件不符合时希望运行另一段程序。这就是else语句的作用。else扩展了if语句的作用,当条件为假时,else后面的语句将被执行。例如,接下来的程序段将在$a大于$b的时候显示“a is bigger than b”,在其他的情况下显示“a is not bigger than b”。
if ($a > $b) {
print "a is bigger than b";
} else {
print "a is not bigger than b";
}
else语句并不仅仅起到在if表达式值为假的时候执行语句的作用,如果在它后面接上if的话,就成为了elseif语句,使用它可以进一步的分析假的情况(见下文)。
elseif
正如它的名字所暗示的,elseif是if和else的组合。和else一样它扩展了if语句对false(假)的处理。但是和else不一样的是,elseif将已经为假的条件再进行一次判断,并根据判断的结果进行处理。例如,下列代码在$a>$b的情况下将显示“a is bigger than b”,当$a不大于$b的时候就再进行一次判断,如果$a==$b,将显示“a is equal to b”,如果$a<$b将显示“a is smaller than b”。
if ($a > $b) {
print "a is bigger than b";
} elseif ($a == $b) {
print "a is equal to b";
} else {
print "a is smaller than b";
}
在同一个if语句中可以有多个elseif语句。第一个elseif表达式(if any)如果为真,那么将被执行。在php3中,您也可以写成“else if”(使用两个词)同时效果和使用“elseif”(一个词)是一样的。他们的语言仅仅有些微的不一样(如果您熟悉c语言的话,您会发现这个不一样和在c中类似)但是最终他们的结果是完全一样的。
elseif语句仅仅在if语句或前一个elseif的表达式为假,同时当前的elseif语句表达式为真的情况下执行。
if语句的交互语法:if().. ..endif
php3提供了一种不同的方法在if语句中建立语句组。这种方式在您将html嵌套进if语句中非常常见,但是您可以将着种方法应用到任何位置。除了使用{}之外,if表达式可以跟随一个冒号,一个或多个语句,然后使用endif结尾;请注意如下的例子:
<?php if ($a==5): ?>
a = 5
<?php endif; ?>
在上面所示的例子中,利用交互语法,html语句“a = 5”被嵌套进了if语句之中。这个html语句会在$a为5的时候被显示。
这种交互语法也可以应用在else和elseif语句之中。接下来的例子是使用交互格式的if、elseif和else语句。
if ($a == 5):
print "a equals 5";
print "...";
elseif ($a == 6):
print "a equals 6";
print "!!!";
else:
print "a is neither 5 nor 6";
endif;