Mysql入门系列PHP基础.docx
《Mysql入门系列PHP基础.docx》由会员分享,可在线阅读,更多相关《Mysql入门系列PHP基础.docx(23页珍藏版)》请在冰豆网上搜索。
Mysql入门系列PHP基础
Mysql入门系列:
PHP基础
PHP的基本功能就是解释一个脚本,来生成发送到客户机的Web页面。
具有代表性的是,脚本包括逐字发送到客户机的HTML和作为程序执行的PHP代码的混合编码。
无论代码生成什么样的输出,都会发送到客户机,因此客户机永远不会看到代码,它只能看结果的输出。
当PHP开始读取文件时,假设文件内容表示文字的HTML,则它仅仅拷贝在那里找到的输出内容。
当PHP解释程序遇到一个特殊的打开标记时,就从HTML模式切换到PHP代码模式,而作为要执行的PHP代码也开始解释文件。
代码的结尾由另一个特殊的标记指出,解
释程序在这个位置从代码模式切换回HTML模式。
这就允许将静态的文本(HTML部分)与动态产生的结果(PHP代码部分的输出)相混合,产生依赖于调用环境变化的页面。
例如,可以使用PHP脚本来处理表格的结果,在这个格式中,用户已经输入了数据库搜索的参数。
由于格式填入内容的不同,所以每次搜索的参数可能也不同,因此当脚本执行搜索的时候,每个作为结果的页面将反映不同的搜索。
让我们通过一个非常简单的PHP脚本看一看它是如何工作的:
hello,world
这个脚本并不很有趣,因为它不包括PHP代码!
因此您会问:
那它有什么好处?
这个问题的回答是:
它有时有助于建立包括想要生成页面的HTML框架的脚本,然后再加入PHP代码。
这是非常有效的,PHP解释程序用于它是没有问题的。
为了在脚本中包括PHP代码,您可从用两个特殊标记(脚本开始处的‘
php’和脚本结束处的‘?
>’)把它与周围的文本区分开来。
当PHP解释程序遇到开始的‘
php’标记时,就从HTML模式切换到PHP模式,并解释它找到的任何PHP代码,直到看见结束的‘?
>’标记为止。
它产生的所有输出解释并替换了两个标记之间的脚本。
将前面的实例再重新编写一下,它包括了少量的PHP代码,如下所示:
此时,代码部分是很小的,由单行组成。
当解释代码时,产生了输出“hello,world”,它作为输出部分发送到客户机浏览器。
这样,这个脚本产生的Web页面与前面实例产生的Web页面一样,前面实例的脚本完全由HTML组成。
可以使用PHP代码产生Web页面的任何部分。
我们已经看到了一个特别的实例,在那里整个脚本都由文字的HTML组成,而不包括PHP代码。
另一个特别的实例是整个脚本都是PHP代码而不包括文字的HTML:
这说明PHP在如何产生输出方面有很大的灵活性。
但PHP也留下一个问题,那就是确定如何组合HTML和PHP代码才是合适的。
不必把所有代码都放在一个地方,PHP在这方面也很灵活。
只要您高兴,就可以通过脚本在HTML和PHP代码模式之间进行转换。
PHP脚本标记
除了本章实例中使用的标记之外,PHP还支持其他的脚本标记。
您可以在其他人编写的PHP代码中看到它们,或者可以自己使用这些标记。
PHP识别四种标记风格:
缺省标记风格。
这是PHP配置为缺省时使用的风格:
phpprint("hello,world");?
>
简洁开标记风格。
这个风格除了开标记较简洁外,其他与缺省风格相类似:
print("hello,world");?
>
兼容ASP的风格。
这个风格在ActiveServerPage环境内部是通用的:
<%print("hello,world");%>
缺省时,简洁开标记风格和兼容ASP风格无效。
请参阅附录H有关开启它们的说明。
独立的PHP脚本
当处理命令解释程序脚本或Perl脚本时,可以编写从命令行调用的独立的PHP脚本。
这里有一个实例:
#!
/usr/local/bin/php-q
phpprint("hello,world");?
>
前面的脚本可命名为hello.php,利用chmod+x使之成为可执行的,并从命令解释程序中调用:
%hello.php
hello,world
本章中我们不编写任何独立的脚本。
这里编写的所有实例都期望Web服务器调用它们来生成Web页面。
下一个脚本有一些实质性的内容,但仍然相当简短。
它说明了如何较容易地从PHP访问MySQL数据库,并在Web页面中使用查询结果。
此脚本在第5章表达得很简短,它形成了历史同盟Web站点主页的基础。
在我们继续往下做的时候,应该使脚本更精巧一些,但直到
现在为止,它所做的只是显示简短的欢迎消息和当前同盟会员资格的计数:
欢迎消息就是一个静态文本,因此它作为文字的HTML是最容易编写的。
另一方面,会员资格的计算是动态的,而且随时会更改,因此必须在它不工作时通过查询samp_db数据库中的member表来确定。
在开和闭脚本标记之间的代码文本执行一个简单的任务。
首先,它打开了与MySQL服务器的连接,并使samp_db数据库成为缺省数据库。
然后,它发送一个到服务器的查询来确定此刻历史同盟有多少成员(我们将它作为member表中的行数)。
查询结果将作为包括会员
资格计数消息的一部分显示出来,然后再做处理。
在处理过程中,如果任何一点发生错误,该脚本都会简单地退出。
它由于太简单而不产生错误输出,因此把访问该Web站点的人们搞糊涂了(如果依靠PHP代码生成整个Web页面,当因错误而退出,且不产生任何输出时,可能会使访问页面的人非常恼火,因为有些浏
览器将显示“这个页面没有数据”的对话框)。
让我们把该脚本分成几段,看看它是如何工作的。
第一步是用mysql_pconnect()连接到服务器:
上一篇 目录 下一篇=@mysql_pconnect("","paul","secret")
orexit();
mysql_pconnect()把主机名、用户名和口令作为参数。
连接建立成功,则返回连接标识符,如果发生错误,则返回FALSE。
如果连接失败,脚本立刻调用exit()来结束脚本,并且不再产生输出。
在mysql_pconnect()调用前的‘@’字符是什么意思呢?
就是“请关闭”的意思。
有些PHP函数在失败时除了返回状态代码之外还写出错误消息。
在mysql_pconnect()情况下,失败的连接导致了下面的消息出现在发送到客户机浏览器的Web页面上:
Warning:
MySQLConnectionFailed:
Accessdeniedforuser:
'paul0pit-'(Usingpassword:
YES)
这样很难看,参观我们站点的人们可能不知道它是如何造成的和该怎样处理它。
把‘@’字符放到mysql_pconnect()调用的前面,就可以取消这个错误消息,以使我们能在返回值的基础上自己选择如何处理错误。
对于该脚本,如果发生错误,最好根本不产生属于会员资格计数的输出。
这样,页面将只包含欢迎消息。
任何PHP函数都可以使用‘@’,但以笔者的经验来说,初始的mysql_pconnect()调用是最可能失败的一个。
因此,本章的例子禁止来自该函数中的消息。
将名称和口令嵌入到所有人都能看到的脚本中,可能会使您紧张不安。
是这样的,名称和口令出现在发送到客户机的Web页面上是对的,因为该脚本的内容由其输出的结果替换掉了。
然而,如果Web服务器不知何故配置不当,没有识别出脚本需要由PHP代码来处理,
它就会将脚本以纯文本发送出去,且会暴露连接参数。
在8.2.1节“使用函数和include文件”中,将简要地处理这类情况。
mysql_pconnect()返回的连接标识符可以传递到PHPAPI中的几个与MySQL相关的调用中。
然而,对于这样的调用,标识符总是可选择的。
例如,可以使用下列格式之一来调用mysql_select_db():
mysql_select_db($db_name,上一篇 目录 下一篇);
mysql_select_db($db_name);
mysql_pconnect()与mysql_connect()的对比函数mysql_pconnect()与函数mysql_connect()相似,都具有主机名、用户名和口令
参数,并返回连接标识符或FALSE来说明连接是否成功。
两个调用之间的不同在于:
mysql_pconnect()建立了一个持久的连接,而mysql_connect()建立了一个非持久的连接。
与非持久连接不同,持久连接在脚本终止时不关闭。
如果另外一个PHP脚本随后由同一
个Apache子处理执行,并用同样的参数调用mysql_pconnect(),将重新使用这个连接。
这比关闭后再建立连接的效率要高。
如果忽略了从一些相关MySQL的PHP调用中得到的连接参数,调用就会使用最近打开的连接。
这样,如果脚本只打开单个连接,那么在任何MySQL调用中永远不必指定连接参数——即连接是缺省的。
这就是C或DBIAPI与MySQL程序设计的极大不同之处,因为它
们没有这样的缺省。
笔者使用上一篇 目录 下一篇变量在简单的主页上编写了下面的连接代码,使mysql_pconnect()返回哪种类型的值更加清晰:
上一篇 目录 下一篇=@mysql_pconnect("pit-","paul","secret")
orexit();
然而,实际上,我们在脚本的其他地方都没有使用$link,因此代码可更简单地写成:
@mysql_pconnect("","paul","secret")
orexit();
假设连接建立成功,则下一步是选择一个数据库:
mysql_select_db("samp_db")
orexit();
如果mysql_select_db失败,我们将会默默地退出。
如果我们能够连接到服务器,并且数据库存在,那么似乎不可能发生错误,但是仍然要严格地检查问题并采取相应的行动。
选择数据库之后,可将查询发送到服务器,提取结果,加以显示,然后释放结果集:
$result=mysql_query("SELECTCOUNT(*)FROMmember
orexit();
if($row=mysql_fetch_array($result))
echo"
TheLeaguecurrentlyhas".$row[0]."members";
mysql_free_result($result);
mysql_query()函数将查询发送到服务器中去执行。
查询不用分号或者‘g’终止。
如果查询非法或因为某些原因不能执行,则mysql_query()返回FALSE,否则返回一个结果集标识符。
该标识符是我们能用来获得有关结果集信息的值。
对于查询,该结果集由表示会员资格计数的单列值的单行组成。
为得到这个值,我们可以把结果集标识符传给mysql_fetch_row()
来获取行,将此行赋给变量$row,并以$row[0]形式访问第一个元素(只有一个元素时也是这样)。
当处理完结果集时,将结果集传递给mysql_free_result()进行释放。
实际上这种调用在我们的脚本中是不必要的,因为当脚本结束时,PHP会自动地释放所有活动的结果集。
mysql_free_result()有助于执行大型查询或大量查询的脚本。
它防止大量内存的使用。
为了使用脚本,需要在某处安装它。
本章将采用这样的约定:
美国历史同盟在Apache文档树的最高一级中有自己的目录,称为ushl,因此主页面脚本作为该树的ushl/index.php进行安装。
我们也将为学分保存方案开发脚本,因此给出目录gp。
如果Web站点主机是pit-,那么这两个目录中的页面将有如下开头的URL:
http:
//pit-
http:
//pit-
例如,每个目录的主页面都可称为index.php,并以如下方式进行访问:
http:
//pit-
http:
//pit-
使用函数和include文件
PHP脚本与DBI脚本的不同之处在于,PHP脚本位于Web服务器文档树的内部,而DBI脚本位于cgi-bin目录中,这个目录在文档树的外部。
这就提出了一个安全性问题:
服务器配置不当的错误可能导致位于文档树内部的页面会以纯文本方式泄露给客户机。
这意味着
建立与MySQL服务器连接的用户名和口令如果在PHP脚本而非DBI脚本中使用,则将处于暴露给外界的很高的危险之中。
PHP中的变量
在PHP中,可以通过简单地使用变量而使它们存在。
主页脚本使用了三个变量:
$link、$result和$row,没有一个变量会在所有地方都声明(声明变量的地方有上下文,如在函数内部引用全局变量时,我们随后会谈到这个问题)。
变量由美元符号(‘$’)为开头的标识符表示。
无论它表示什么类型的值都是正确的,尽管对于数组和对象要添加一些额外内容来访问值的单个元素。
如果变量$x表示单个值,例如,数字或字符串,则可以写成$x来访问它。
如果$x表示有数字索引的数组,则可
以写成$x[0]、$x[1]等等来访问它的元素。
如果$x表示有关联索引的数组,如“yellow”或者“large”,则可以写成$x[“yellow”]、$x[“large”]来访问它的元素。
PHP数组可以同时拥有数字索引的元素和相关索引的元素。
例如,$x[1]和$x[“large”]都能作为同一数组的元素。
如果$x代表一个对象,则可写成$x->property_name来访问它所具有的属性。
例如,$x->yellow和$x->large都是$x的属性。
作为属性名,数字是不合法的,因此$x->1在PHP中是不合法的。
初始的历史同盟主页脚本也存在这个问题,因为它包括MySQL用户名和口令的直接值。
让我们用两个PHP性能:
函数和include文件,把这些连接参数移到脚本外面。
我们将编写函数samp_db_connect()来建立这个连接,并把函数放到一个include文件中—不是主脚本部分的,但可以从脚本中引用的文件。
这种方法的优点如下:
编写连接建立代码比较容易。
不需要写出所有参数,就可以在连接后用samp_db_connect()选择数据库,使一个函数可以进行两个PHP函数的工作。
由于你可以将精力集中于脚本的独特标记,而不必为连接建立代码分心,因此也使得脚本更加易于理解。
可从脚本中访问include文件,但可移到Apache文档树的外面。
这使它的内容对于客户机来说是不可访问的,即使Web服务器配置不当,连接参数也不会暴露给它们。
使用include文件,对于隐藏不想由Web服务器发送到站点的任何类型的敏感信息都是个良策。
虽然如此,但这并不意味着用户名和口令在任何意义上说都是安全的。
如果没有采取预防措施,在Web服务器主机上注册的用户,能够直接读取include文件。
请参阅7.4.3节“从Web脚本连接到MySQL服务器”关于安装DBI配置文件所描述的预防措施,它们用于保护口令和用户名不受其他用户侵害。
对PHP的include文件也要应用同样的防范措施。
PHP语言上的影响
如果有C程序设计经验,则可能注意到:
脚本中许多语法的结构与C程序设计中的非常类似。
实际上,PHP语法很大程度上来自于C,因此这种相似处并不是巧合。
如果有些C的背景知识,就可以将它的许多内容转换到PHP。
事实上,如果不能确信如何用PHP编写表达式或控制结构,则可以试用C中编写它们的方法,这很可能也是正确的。
虽然PHP的基本部分主要在C中,但也包含了使用Java和Perl的成分。
可以在注释语法中查看它,在那里允许以下形式:
#Perl-stylecommentfrom'#'toendofline
//c++orJava-stylecommentfrom'//'toendofline
//*C-stylecommentbetweenslash-startostar-slash*/
Perl的其他相似性包括‘.’字符串连接操作符(包括‘.=’作为额外的连接),变量引用和转义序列的方法是在双引号内而非单引号内解释的。
include文件可以由多个脚本使用。
这提高了代码的可重用性,使代码更加可维护。
同时也允许对访问这个文件的每个脚本不费力地做出全局性的更改。
例如,如果我们将数据库samp_db从pit-viper移动到boa,则不必更改一簇单个脚本,而只要更改包含
samp_db_connect()函数的include文件中mysql_pconnect()调用的主机名参数即可。
为了使用include文件,必须有存放它们的地方,而且必须使PHP找到它们。
如果系统已经有了这样一个位置,则可以使用。
如果没有,则使用下面的过程建立一个include文件的位置:
1)创建一个目录来存放PHP的include文件。
该目录不能位于Web服务器文档树内部!
笔者使用/usr/local/apache/php的PHPinclude目录,它与我的文档树在同一层次上(/usr/local/apache/htdocs),而不是在其内部。
2)通过完整的路径名或者告诉PHP在搜索时寻找哪个目录来引用include文件。
后者的方法更方便些,因为如果我们使用了文件的基名,PHP就会找到它(PHPinclude文件与C头文件有些类似,其中包括的PHP将在多个目录中搜寻include文件,就像C预处理程序在多个目录中搜寻C头文件一样)。
为了告诉PHP去哪里查看,修改PHP初始化文件(系统上的/usr/local/lib/php3.ini)来改变include_path的值。
如果它没有值,可以将它设置为新的包含路径的完整路径名:
include_path="current_value:
/usr/local/apache/php"
如果include_path已经有值了,则把新的目录加到那个值中:
include_path="current_value:
/usr/local/apache/php"
3)创建想使用的include文件并将它放到include目录中。
文件应该有一些有特点的名称,为了这个目的,这里我们使用samp_db.inc。
它的内容将在下面列出。
对于我们这里开发的脚本,当连接到MySQL服务器上时,会一直使用samp_db数据库,因此连接函数samp_db_connect()也可以为我们选择samp_db数据库。
如果连接成功并选择了这个数据库,这个函数就返回一个连接标识符;如果发生错误,则返回FALSE。
发生错误时将不打印消息,并且允许调用者静静地退出,或者在环境允许时再打印消息。
观察一下,samp_db.inc文件的内容由‘
php’和‘?
>’括在一起。
这是因为PHP是在HTML模式中开始读取文件的。
如果没有这些标记PHP会把文件以纯文本发送出去,而不是作为PHP代码解释。
如果想在文件中包含文字的HTML是很好的选择。
但是,如果文件包含PHP代码,就必须在脚本标记内部封闭代码。
4)使用下面的行从脚本中引用文件:
include("samp_db.inc");
当PHP看到这一行时,就搜寻文件并读取内容。
对于脚本的下列部分,文件中的任何事物都变成可访问的。
在建立了我们的include文件samp_db.inc之后,就可以修改历史同盟主页来引用include文件,并通过调用samp_db_connect()函数连接到MySQL服务器上:
include()与require()的对比
PHP的require()性能与include()相类似。
不同之处在于,对include()来说,在include()执行时文件每次都要进行读取和评估;而对于require()来说,文件只处理一次(实际上,文件内容替换了require()语句)。
这意味着如果有包含这些指令之一的代码和
可能执行多次的代码,则使用require()的效率比较高。
另一方面,如果每次执行代码时想读取不同的文件,或者有通过一组文件迭代的循环,就使用include(),因为可以给想要包括的文件名设置一个变量,当参数为include()时使用这个变量。
samp_db.inc文件对其他函数也是有用的,我们可以将它作为各种其他事物的储藏库。
实际上,还可以再创建两个函数放入到文件中。
我们编写的每个脚本在页面的开头都会产生一组相当醒目的HTML标记,而另一组在结尾。
不必在每个脚本中将它们逐字地写出,我们可以通过编写函数html_begin()和html_end()来做这些事。
函数html_begin()能够提取几个指定了页面标题和头的参数。
两个函数的代码如下:
然后我们可以修改历史同盟主页来使用这两个新函数,如下所示:
请注意代码被分成了两块,两块代码之间出现了欢迎消息的文字HTML文本。
产生页面开始和最后部分的函数用法给了我们一个重要的能力。
如果想改变使用这些函数的页面头和尾的外观,可以在函数中包含一些代码。
使用它们的每个脚本也都将自动地受到影响。
例如,您可以把消息“CopyrightUSHL”放在每个历史同盟页面的底部。
页面尾部函数html_end()会很容易地做到这一点。
一个简单的查询页面
已经嵌入到历史同盟主页中的脚本运行了一个只返回单个行的查询。
下一个脚本介绍了如何处理多行的结果集。
它获取并显