PHP基础

<script type="text/javascript"><!-- google_ad_client = "pub-2947489232296736"; /* 728x15, 创建于 08-4-23MSDN */ google_ad_slot = "3624277373"; google_ad_width = 728; google_ad_height = 15; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"><!-- google_ad_client = "pub-2947489232296736"; /* 160x600, 创建于 08-4-23MSDN */ google_ad_slot = "4367022601"; google_ad_width = 160; google_ad_height = 600; //--> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
    PHP 的基本功能就是解释一个脚本,来生成发送到客户机的Web 页面。具有代表性的是,脚本包括逐字发送到客户机的HTML 和作为程序执行的PHP 代码的混合编码。无论代码生成什么样的输出,都会发送到客户机,因此客户机永远不会看到代码,它只能看结果的输出。
    当PHP 开始读取文件时,假设文件内容表示文字的H T M L,则它仅仅拷贝在那里找到的输出内容。当PHP 解释程序遇到一个特殊的打开标记时,就从HTML 模式切换到PHP 代码模式,而作为要执行的PHP 代码也开始解释文件。代码的结尾由另一个特殊的标记指出,解
释绦蛟谡飧鑫恢么哟肽J角谢换豀TML 模式。这就允许将静态的文本( HTML 部分)与动态产生的结果( PHP 代码部分的输出)相混合,产生依赖于调用环境变化的页面。例如,可以使用PHP 脚本来处理表格的结果,在这个格式中,用户已经输入了数据库搜索的参数。
由于格式填入内容的不同,所以每次搜索的参数可能也不同,因此当脚本执行搜索的时候,每个作为结果的页面将反映不同的搜索。
    让我们通过一个非常简单的PHP 脚本看一看它是如何工作的:
    <HTML>
    <BODY>
    hello,world
    </body>
    </HTML>
    这个脚本并不很有趣,因为它不包括PHP 代码!因此您会问:那它有什么好处?这个问题的回答是:它有时有助于建立包括想要生成页面的HTML 框架的脚本,然后再加入PHP代码。这是非常有效的,PHP 解释程序用于它是没有问题的。
    为了在脚本中包括PHP 代码,您可从用两个特殊标记(脚本开始处的‘ < ? p h p’和脚本结束处的‘? >’)把它与周围的文本区分开来。当PHP 解释程序遇到开始的‘< ? p h p’标记时,就从HTML 模式切换到PHP 模式,并解释它找到的任何PHP 代码,直到看见结束的‘ ? >’标记为止。它产生的所有输出解释并替换了两个标记之间的脚本。将前面的实例再重新编写一下,它包括了少量的PHP 代码,如下所示:
11ANPI4P12256.jpg
    此时,代码部分是很小的,由单行组成。当解释代码时,产生了输出“ hello, world”,它作为输出部分发送到客户机浏览器。这样,这个脚本产生的Web 页面与前面实例产生的Web页面一样,前面实例的脚本完全由HTML 组成。
    可以使用PHP 代码产生Web 页面的任何部分。我们已经看到了一个特别的实例,在那里整个脚本都由文字的HTML 组成,而不包括PHP 代码。另一个特别的实例是整个脚本都是PHP 代码而不包括文字的H T M L:
11ANPIX021K3.jpg
    这说明PHP 在如何产生输出方面有很大的灵活性。但PHP 也留下一个问题,那就是确定如何组合HTML 和PHP 代码才是合适的。不必把所有代码都放在一个地方, PHP 在这方面也很灵活。只要您高兴,就可以通过脚本在HTML 和PHP 代码模式之间进行转换。
PHP 脚本标记
    除了本章实例中使用的标记之外, PHP还支持其他的脚本标记。您可以在其他人编写的PHP 代码中看到它们,或者可以自己使用这些标记。PHP 识别四种标记风格:
    缺省标记风格。这是PHP 配置为缺省时使用的风格:
    <?PHP print ("hello,world/n");?>
    简洁开标记风格。这个风格除了开标记较简洁外,其他与缺省风格相类似:
    <? print ("hello,world/n");?>
    兼容ASP 的风格。这个风格在Active Server Page 环境内部是通用的:
    <% print ("hello,world/n");%>
    <SCRIPT> 标记风格。如果使用与其他标记风格不同的HTML 编辑器,这个风格是有用的。当然,它比较冗长,但是当您使用其他标记风格时,编辑器可能不处理PHP 代码,这时您将发现它是必需的:
    <SCRIPT LANGUAGE="PHP">print ("hello,world/n");</SCRIPT>
    缺省时,简洁开标记风格和兼容ASP 风格无效。请参阅附录H 有关开启它们的说明。
独立的PHP 脚本
    当处理命令解释程序脚本或Perl 脚本时,可以编写从命令行调用的独立的PHP 脚本。这里有一个实例:
    #! /usr/local/bin/PHP -q
    <?PHP print ("hello,world/n");?>
    前面的脚本可命名为h e l l o . p h p,利用chmod +x 使之成为可执行的,并从命令解释程序中调用:
    % hello.PHP
    hello,world
    本章中我们不编写任何独立的脚本。这里编写的所有实例都期望Web 服务器调用它们来生成Web 页面。
    下一个脚本有一些实质性的内容,但仍然相当简短。它说明了如何较容易地从PHP 访问MySQL数据库,并在Web 页面中使用查询结果。此脚本在第5 章表达得很简短,它形成了历史同盟Web 站点主页的基础。在我们继续往下做的时候,应该使脚本更精巧一些,但直到
现在为止,它所做的只是显示简短的欢迎消息和当前同盟会员资格的计数:
11ANPJ25036152.jpg
11ANPJG042303.jpg
    欢迎消息就是一个静态文本,因此它作为文字的HTML 是最容易编写的。另一方面,会员资格的计算是动态的,而且随时会更改,因此必须在它不工作时通过查询samp_db 数据库中的member 表来确定。
    在开和闭脚本标记之间的代码文本执行一个简单的任务。首先,它打开了与MySQL服务器的连接,并使samp_db 数据库成为缺省数据库。然后,它发送一个到服务器的查询来确定此刻历史同盟有多少成员(我们将它作为member 表中的行数)。查询结果将作为包括会员
资格计数消息的一部分显示出来,然后再做处理。
    在处理过程中,如果任何一点发生错误,该脚本都会简单地退出。它由于太简单而不产生错误输出,因此把访问该Web 站点的人们搞糊涂了(如果依靠PHP 代码生成整个Web 页面,当因错误而退出,且不产生任何输出时,可能会使访问页面的人非常恼火,因为有些浏
览器将显示“这个页面没有数据”的对话框)。
    让我们把该脚本分成几段,看看它是如何工作的。第一步是用mysql_pconnect() 连接到服务器:
    上一篇      目录      下一篇=@mysql_pconnect ("pit.viper.snake.net","paul","secret")
    or exit ();
    mysql_pconnect() 把主机名、用户名和口令作为参数。连接建立成功,则返回连接标识符,如果发生错误,则返回FA L S E。如果连接失败,脚本立刻调用exit() 来结束脚本,并且不再产生输出。
    在mysql_pconnect() 调用前的‘@’字符是什么意思呢?就是“请关闭”的意思。有些PHP 函数在失败时除了返回状态代码之外还写出错误消息。在mysql_pconnect() 情况下,失败的连接导致了下面的消息出现在发送到客户机浏览器的Web 页面上:
    Warning:MySQLConnection Failed:Access denied for user:
    'paul0pit-viper.snake.net' (Using password:YES)
    这样很难看,参观我们站点的人们可能不知道它是如何造成的和该怎样处理它。把‘ @’字符放到mysql_pconnect() 调用的前面,就可以取消这个错误消息,以使我们能在返回值的基础上自己选择如何处理错误。对于该脚本,如果发生错误,最好根本不产生属于会员资格计数的输出。这样,页面将只包含欢迎消息。
    任何PHP 函数都可以使用‘@’,但以笔者的经验来说,初始的mysql_pconnect() 调用是最可能失败的一个。因此,本章的例子禁止来自该函数中的消息。
    将名称和口令嵌入到所有人都能看到的脚本中,可能会使您紧张不安。是这样的,名称和口令出现在发送到客户机的Web 页面上是对的,因为该脚本的内容由其输出的结果替换掉了。然而,如果Web 服务器不知何故配置不当,没有识别出脚本需要由PHP 代码来处理,
它就会将脚本以纯文本发送出去,且会暴露连接参数。在8 . 2 . 1节“使用函数和include 文件”中,将简要地处理这类情况。
    mysql_pconnect() 返回的连接标识符可以传递到PHP API 中的几个与MySQL相关的调用中。然而,对于这样的调用,标识符总是可选择的。例如,可以使用下列格式之一来调用mysql_ s e l e c t _ 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_ p c o n n e c t ( ),将重新使用这个连接。这比关闭后再建立连接的效率要高。
    如果忽略了从一些相关MySQL的PHP 调用中得到的连接参数,调用就会使用最近打开的连接。这样,如果脚本只打开单个连接,那么在任何MySQL调用中永远不必指定连接参数——即连接是缺省的。这就是C 或DBI API 与MySQL程序设计的极大不同之处,因为它
们没有这样的缺省。
    笔者使用上一篇      目录      下一篇 变量在简单的主页上编写了下面的连接代码,使mysql_pconnect() 返回哪种类型的值更加清晰:
    上一篇      目录      下一篇=@mysql_pconnect("pit-viper.snake.net","paul","secret")
    or exit();
    然而,实际上,我们在脚本的其他地方都没有使用$ l i n k,因此代码可更简单地写成:
    @mysql_pconnect("pit.viper.snake.net","paul","secret")
    or exit();
    假设连接建立成功,则下一步是选择一个数据库:
    mysql_select_db("samp_db")
    or exit();
    如果mysql_select_db 失败,我们将会默默地退出。如果我们能够连接到服务器,并且数据库存在,那么似乎不可能发生错误,但是仍然要严格地检查问题并采取相应的行动。选择数据库之后,可将查询发送到服务器,提取结果,加以显示,然后释放结果集:
    $result=mysql_query("SELECT COUNT(*) FROM member
    or exit();
    if ($row = mysql_fetch_array ($result))
        echo "<p>The League currently has ". $row[0] . "members";
    mysql_free_result($result);
    mysql_query() 函数将查询发送到服务器中去执行。查询不用分号或者‘ / g’终止。如果查询非法或因为某些原因不能执行,则mysql_query() 返回FA L S E,否则返回一个结果集标识符。该标识符是我们能用来获得有关结果集信息的值。对于查询,该结果集由表示会员资格计数的单列值的单行组成。为得到这个值,我们可以把结果集标识符传给mysql_ f e t c h _ r o w ( )
来获取行,将此行赋给变量$ r o w,并以$row[0] 形式访问第一个元素(只有一个元素时也是这样)。
    当处理完结果集时,将结果集传递给mysql_free_result() 进行释放。实际上这种调用在我们的脚本中是不必要的,因为当脚本结束时, PHP 会自动地释放所有活动的结果集。
    mysql_free_result() 有助于执行大型查询或大量查询的脚本。它防止大量内存的使用。
    为了使用脚本,需要在某处安装它。本章将采用这样的约定:美国历史同盟在Apache 文档树的最高一级中有自己的目录,称为us h l,因此主页面脚本作为该树的ushl/index.PHP 进行安装。我们也将为学分保存方案开发脚本,因此给出目录g p。如果Web 站点主机是pit-viper.snake.net,那么这两个目录中的页面将有如下开头的URL:
    http://pit-viper.snake.net/ushl/
    http://pit-viper.snake.net/gp/
    例如,每个目录的主页面都可称为i n d e x . p h p,并以如下方式进行访问:
    http://pit-viper.snake.net/ushl/index.PHP
    http://pit-viper.snake.net/gp/index.PHP

使用函数和include 文件

    PHP 脚本与DBI 脚本的不同之处在于, PHP 脚本位于Web 服务器文档树的内部,而DBI 脚本位于cgi-bin 目录中,这个目录在文档树的外部。这就提出了一个安全性问题:服务器配置不当的错误可能导致位于文档树内部的页面会以纯文本方式泄露给客户机。这意味着
建立与MySQL服务器连接的用户名和口令如果在PHP 脚本而非DBI 脚本中使用,则将处于暴露给外界的很高的危险之中。
    PHP 中的变量
    在PHP中,可以通过简单地使用变量而使它们存在。主页脚本使用了三个变量:$ l i n k、$result 和$ r o w,没有一个变量会在所有地方都声明(声明变量的地方有上下文,如在函数内部引用全局变量时,我们随后会谈到这个问题)。
    变量由美元符号(‘$’)为开头的标识符表示。无论它表示什么类型的值都是正确的,尽管对于数组和对象要添加一些额外内容来访问值的单个元素。如果变量$x 表示单个值,例如,数字或字符串,则可以写成$x 来访问它。如果$x 表示有数字索引的数组,则可
以写成$ x [ 0 ]、$x[1] 等等来访问它的元素。如果$x 表示有关联索引的数组,如“ y e l l o w”或者“l a rg e”,则可以写成$ x [“y e l l o w”]、$ x [“l a rg e”] 来访问它的元素。
    PHP 数组可以同时拥有数字索引的元素和相关索引的元素。例如, $x[1] 和 $ x [“ l a rg e”] 都能作为同一数组的元素。如果$x 代表一个对象,则可写成$ x ->property_name 来访问它所具有的属性。例如, $x->yellow 和$ x - > l a rge 都是$x 的属性。
作为属性名,数字是不合法的,因此$x->1在PHP 中是不合法的。
    初始的历史同盟主页脚本也存在这个问题,因为它包括MySQL用户名和口令的直接值。让我们用两个PHP 性能:函数和include 文件,把这些连接参数移到脚本外面。我们将编写函数samp_db _ c o n n e c t ( )来建立这个连接,并把函数放到一个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-style comment from '#' to end of line
    //c++ or Java-style comment from '//' to end of line
    //* C-style comment between slash-star to star-slash */
    Perl 的其他相似性包括‘ .’字符串连接操作符(包括‘ . =’作为额外的连接),变量引用和转义序列的方法是在双引号内而非单引号内解释的。
    include 文件可以由多个脚本使用。这提高了代码的可重用性,使代码更加可维护。同时也允许对访问这个文件的每个脚本不费力地做出全局性的更改。例如,如果我们将数据库samp_db 从pit-viper 移动到b o a,则不必更改一簇单个脚本,而只要更改包含
samp_db_connect() 函数的include 文件中mysql_pconnect() 调用的主机名参数即可。
    为了使用include 文件,必须有存放它们的地方,而且必须使PHP 找到它们。如果系统已经有了这样一个位置,则可以使用。如果没有,则使用下面的过程建立一个include 文件的位置:
    1) 创建一个目录来存放PHP 的include 文件。该目录不能位于Web 服务器文档树内部!笔者使用/usr/local/apache/PHPPHP include 目录,它与我的文档树在同一层次上(/ us r / l o c a l / a p a c h e / h t d o c s),而不是在其内部。
    2) 通过完整的路径名或者告诉PHP 在搜索时寻找哪个目录来引用include 文件。后者的方法更方便些,因为如果我们使用了文件的基名, PHP 就会找到它( PHP include 文件与C头文件有些类似,其中包括的PHP 将在多个目录中搜寻include 文件,就像C 预处理程序在多个目录中搜寻C 头文件一样)。为了告诉PHP 去哪里查看,修改PHP 初始化文件(系统上的/ us r / l o c a l / l i b / p h p 3 . i n i)来改变include_path 的值。如果它没有值,可以将它设置为新的包含路径的完整路径名:
    include_path="current_value:/usr/local/apache/PHP"
    如果include_path 已经有值了,则把新的目录加到那个值中:
    include_path="current_value:/usr/local/apache/PHP"
    3) 创建想使用的include 文件并将它放到i n c l ud e目录中。文件应该有一些有特点的名称,为了这个目的,这里我们使用samp_db . i n c。它的内容将在下面列出。对于我们这里开发的脚本,当连接到MySQL服务器上时,会一直使用samp_db 数据库,因此连接函数samp_db_connect() 也可以为我们选择samp_db 数据库。如果连接成功并选择了这个数据库,这个函数就返回一个连接标识符;如果发生错误,则返回FA L S E。发生错误时将不打印消息,并且允许调用者静静地退出,或者在环境允许时再打印消息。
11ANPK06053O3.jpg
    观察一下,samp_db.inc 文件的内容由‘< ? p h p’和‘? >’括在一起。这是因为PHP 是在HTML 模式中开始读取文件的。如果没有这些标记PHP 会把文件以纯文本发送出去,而不是作为PHP 代码解释。如果想在文件中包含文字的HTML 是很好的选择。但是,如果文件包含PHP 代码,就必须在脚本标记内部封闭代码。
    4) 使用下面的行从脚本中引用文件:
    include("samp_db.inc");
    当PHP 看到这一行时,就搜寻文件并读取内容。对于脚本的下列部分,文件中的任何事物都变成可访问的。
    在建立了我们的include 文件samp_db.inc 之后,就可以修改历史同盟主页来引用i n c l ud e文件,并通过调用samp_db_connect() 函数连接到MySQL服务器上:
11ANPK52064117.jpg
    include( ) 与require( ) 的对比
    PHP 的require() 性能与include() 相类似。不同之处在于,对include() 来说,在include() 执行时文件每次都要进行读取和评估;而对于require() 来说,文件只处理一次(实际上,文件内容替换了require() 语句)。这意味着如果有包含这些指令之一的代码和
可能执行多次的代码,则使用require() 的效率比较高。另一方面,如果每次执行代码时想读取不同的文件,或者有通过一组文件迭代的循环,就使用i n c l ud e ( ),因为可以给想要包括的文件名设置一个变量,当参数为include() 时使用这个变量。
    samp_db.inc 文件对其他函数也是有用的,我们可以将它作为各种其他事物的储藏库。实际上,还可以再创建两个函数放入到文件中。我们编写的每个脚本在页面的开头都会产生一组相当醒目的HTML 标记,而另一组在结尾。不必在每个脚本中将它们逐字地写出,我们可以通过编写函数html_begin() 和html_end() 来做这些事。函数html_begin() 能够提取几个指定了页面标题和头的参数。两个函数的代码如下:
11ANPK930Jc3.jpg
    然后我们可以修改历史同盟主页来使用这两个新函数,如下所示:
11ANPL460Q319.jpg
    请注意代码被分成了两块,两块代码之间出现了欢迎消息的文字HTML 文本。
    产生页面开始和最后部分的函数用法给了我们一个重要的能力。如果想改变使用这些函数的页面头和尾的外观,可以在函数中包含一些代码。使用它们的每个脚本也都将自动地受到影响。例如,您可以把消息“ Copyright USHL”放在每个历史同盟页面的底部。页面尾部函数html_end() 会很容易地做到这一点。

一个简单的查询页面

    已经嵌入到历史同盟主页中的脚本运行了一个只返回单个行的查询。下一个脚本介绍了如何处理多行的结果集。它获取并显示了member 表中的内容。这就是第7 章开发的dump_members DBI 脚本的PHP 等价物,因此称它为d um p _ member s . p h p。它与DBI 版本的不同之处在于,它希望在Web 环境中使用而不是在命令行中使用。由于这个原因,它需要产生HTML 输出而不是简单地写出制表符分隔的文本。为了使行和列漂亮地排列,我们将以HTML 表形式编写会员资格记录。脚本如下:
11ANPM06093039.jpg
    这个脚本使用了die() 函数来打印消息,如果发生错误则退出( die() 函数与exit() 函数相类似,但是它在退出之前打印消息)。与我们在历史同盟主页中使用的静静地退出方法相比,这是一种不同的错误处理方法。在dump_membes.PHP 中,我们希望看到一个特殊的结果,因此打印错误消息来说明发生的问题是有道理的。
    脚本可以安装在ushl 目录并用http://pit-viper.snake.net/ushl/dump_members.PHP 访问。可以在历史同盟主页的新脚本中增加一个连接,以便人们了解它: 共2页: 上一页 1 [2] 下一页 <script type="text/javascript"><!-- google_ad_client = "pub-2947489232296736"; /* 728x15, 创建于 08-4-23MSDN */ google_ad_slot = "3624277373"; google_ad_width = 728; google_ad_height = 15; //--> </script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
<script type="text/javascript"><!-- google_ad_client = "pub-2947489232296736"; /* 160x600, 创建于 08-4-23MSDN */ google_ad_slot = "4367022601"; google_ad_width = 160; google_ad_height = 600; //--> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>
阅读更多
个人分类: 数据库
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭