分类:
2008-05-30 08:29:33
我们首先将学习PHP的include函数,使用这个函数,我们可以在许多页面中重复使用同一个PHP代码段。我们还看到如何利用这个函数提高我们的网站的安全性。
虽然PHP一般是相当快速和有效率的,但是它会加重服务器的运行时间和工作量。对于一个高流量的站点来说,这种负担可能会达到无法接受的程度。但是这并不意味着我们需要放弃我们的站点的数据库驱动的特征。我们会看到如何使用PHP在后台建立半动态页面而不必过分加重服务器的负担。
经常有人问论坛是如何利用一个标记来接受文件的上载的。我们也将学习到如何用PHP实现这种功能,而且我们还会看到如果将其有效地结合到一个数据库驱动的站点中。
最后,PHP还有一个相当强大的功能是可以很简单地将动态生成的内容很方便地作为email的信息发送出去。不论你是想要使用PHP使得访问者将你的站点的内容发送给它们的朋友,还是仅仅想提供一种方法让用户可以得到他们遗忘的口令,PHP的email函数都可以很好地实现这种功能!
PHP的服务器端包含
如果你已经在Internet上工作过一段时间,你也许接触过服务器端包含(SSI)这个术语;如果你没有接触过,你可以参看有关这个问题的Matt Mickiewicz的迷你指南。
从本质上说,SSI允许你将存储在你的Web服务器上的某一个文件的内容插入到另一个文件中去,最常见的应用是将一个网站的公用设计部分写入一个小的HTML文件当中,这个文件可以被Web页面所包含。对这个小文件的所有变动立即会影响所有包含它的文件。就象一个PHP脚本一样,Web的浏览者不需要对此有所了解,因为Web服务器会在将被请求的页面发送到浏览器之前做好所有的工作。
PHP有一个函数可以提供类似的功能。但是在包含文件中除了可以含有正式的HTML以及其它静态的内容以外,还可以含有脚本程序。让我们来看看下面这个例子:
echo( " Soylent Green is made from people! " ); |
在上面的文件中,include-me.inc包含了一些简单的PHP代码。请注意这个文件的文件名的结尾是.inc,而不是.php。这表示这个文件与一般的Web服务器所认为的PHP脚本有所不同。这会保证这个文件只有被插入到一个.php文件中才会被执行,此外这也有助于你分辨你的PHP Web页面和PHP包含文件。
你还需要下面的文件:
include("include-me.inc"); ?> |
这个文件和我们以前使用过的PHP脚本差不多,它的扩展名是.php extension(如果你的服务器需要,也可以是.php3)。请注意对include函数的调用。我们指定了我们要插入的文件名(include-me.inc),PHP会试图获取这个文件并将其插入到现在的文件中以取代include。将这两个文件都上载到你的Web服务器(或者将它们拷贝到你的Web服务器的文档文件夹,如果你正在这个服务器上工作的话),然后用你的浏览器装载testinclude.php。你会看到一个包含我们的插入文件信息的Web页面的,一切和你当初预料的没有什么两样。
如果这个例子不能工作,你也许需要配置你的php.ini文件中的include_path选项。用你常用的文本编辑器打开这个文件找到以include_path开始的一行(一般是在文件的中间)。就象你所熟悉的系统PATH环境变量的设置一样,这里包含了一个目录的列表,PHP会从这些位置寻找你所要包含的文件。它应该包括"."(当前目录)。
根据你的服务器的操作系统是Windows还是UNIX,你也许需要确定是否要用到引号:
include_path=.:/another/directory 对于Windows: include_path=".;c:anotherdirectory" |
利用插入文件提高安全性
PHP脚本有时会包含一些诸如用户名、口令以及其它一些你不想公开的敏感信息。你也许已经使用过mysql_connect函数,这个函数要求你在需要访问数据库的PHP脚本中输入你的MySQL用户名和口令。虽然你可以简单地对MySQL进行设置以使得这个用户名和口令只能供PHP使用,而为会被可能出现的黑客利用(通过在第八章中学习的方法对用户表的主机字段进行设置),你也许还是需要其它的比较方便的对你的用户名和口令的保护。
“但是等一下,”可能你会这样说,“因为PHP是由服务器处理的,没人会看到我的口令,对吗?”不错,但是你是否考虑到这样一个情况,服务器对PHP的解析可能会因为偶然的原因而停止。这可能是因为某个善意的同事对软件的错误配置,也可能是因为其它的因素,如果发生了这样的情况,PHP页面会当成纯文本文件来处理,于是你的所有的PHP代码(包括你的口令)将是完全公开的!
为了预防这样的安全漏洞,你可以将包含敏感信息的代码放到一个插入文件中,然后将它放到一个不属于你的Web服务的目录结构的目录中去。将这个目录添加到你的PHP的include_path中(在php.ini中添加),你可以指定PHP包含函数所使用的目录,而不必担心其中文件的安全,因为你的Web服务器不会将其作为Web页来显示。
例如,如果你的Web服务器定义所有的Web页面必须存在于/home/httpd/及其子目录中,你可以建立一个名为/home/phplib/来保存你的包含文件。将这个目录添加到你的include_path中,这样就行了!下面的例子显示了如何将你的数据库连接代码放置到一个包含文件中:
$cnx = mysql_connect("localhost", "root", "rootpassword"); ?> |
以及一个使用这个包含文件的文件:
// Connect to MySQL include("dbConnect.inc"); mysql_select_db("myDatabase",$cnx); ... |
正如你看到的,如果你的服务器的PHP停止了工作,被暴露的仅仅是对包含函数的调用。用户名和口令被安全地存储在dbConnect.inc中,而这个文件不能从网站直接访问。
半动态页面
作为一个成功的(或者是即将成功的)网站的所有者,你肯定希望你的网站的访问量越来越高。不幸的是,大的访问量恰恰也是Web服务器的管理者所担心的事--特别是当网站主要是由动态生成的、由数据库驱动的页面组成的时候,情况更是这样。这样的页面与处理传统的HTML文件相比,意味着运行Web服务软件的计算机的巨大负担。因为对每一个页面的请求都相当于在计算机上运行一个小程序。
虽然数据库驱动的站点的有些页面必须严格地实时地从数据库中调用相关的数据,但是大部分页面的要求并不这么严格。例如对于一个Web站点的首页来说,典型的情况是,它会向访问者简要介绍这个站点最近做了哪些更新。但是事实上这样的更新多长时间做一次呢?一天一次?还是一周一次?而且对于你的站点的访问者来说非常及时地了解这些更新又有多大价值?也许对于这类变动在你网站上的反应稍微有点滞后也不会有多大问题。
通过将高访问量的动态页面转换成“半动态”的页面,也就是一个可以按照一定时间间隔“刷新”内容以动态地重新生成的静态页面,你可以大大减轻你的Web服务器处理数据库驱动的页面的工作量。
例如,我们有一个名为index.php的首页,它提供你的网站的新内容的摘要。通过对服务器日志的检查,你可以发现这是你的网站中被访问得最多的页面之一。通过前面的讨论,你应该已经意识到对于这个页面我们并不需要在每次请求时动态地生成。只在在每次将新内容添加到你的站点的同时更新这个页面,就可以充分保证它的动态效果了。使用一个PHP程序,你可以生成动态输出的页面一个静态的“映像”,你可以将其命名为index.html以取代原来的动态页面。
我们需要学习一些有关文件读取、写入以及修改的知识。PHP可以很好地完成这些工作,只是我们之前没看到过这些我们所需要的函数:
fopen 打开一个文件,以用来进行读写操作。这个文件可以存储在服务器的硬盘上,也可以通过一个URL装载。 fclose 通知PHP你将不再对某一文件进行读写操作,释放它以备其它程序或脚本使用。 fread 将一个文件的数据读入到一个PHP变量中。允许你指定读取多少信息(也就是多少字符或多少字节)。 fwrite 将一个来自于PHP变量的数据写入到文件中。 copy 执行一个文件拷贝的操作。 unlink 从硬盘中删除一个文件。 |
你明白了吗?如果还没有,不要担心--等一下我们会进行详细讲解。
建立一个名为generateindex.php的文件。它用来模拟一个Web浏览器从index.php(你的首页的动态版本)读取内容,并将其以静态文本的格式写入index.html中。如果在这个处理过程中发生了什么错误,我们需要避免对原来的index.html“好的”拷贝的破坏,所以我们的这个脚本先将新的静态版本写入到一个临时文件(tempindex.html)中,如果中途没发生什么问题,再用其覆盖index.html。
下面是generateindex.php的代码,我们加入足够多的注解以保证你能顺利地读懂这段程序:
//设置我们将要使用的文件 $srcurl = ""; $tempfilename = "tempindex.html"; $targetfilename = "index.html"; ?> Generating Generating ... //首先删除上次操作可能遗留下来的临时文件。 //这个过程可能会提示错误,所以我们使用@以防止报错。 @unlink($tempfilename); //通过一个URL的请求装入动态版本。 //在我们接收到相关内容之前,Web服务器会对PHP进行处理 //(因为本质上我们是在模拟一个Web浏览器), //所以我们将获得的是一个静态的HTML页面。 //'r'指出我们只要求对这个“文件”进行读操作。 $dynpage = fopen($srcurl, 'r'); //处理错误 if (!$dynpage) { echo(" Unable to load $srcurl. Static page ". exit(); } //将这个URL的内容读入到一个PHP变量中。 //指定我们将读取1MB的数据(超过这个数据量一般是意味着出错了)。 $htmldata = fread($dynpage, 1024*1024); //当我们完成工作后,关闭到源“文件”的连接。 fclose($dynpage); //打开临时文件(同时在这个过程中建立)以用来写入(注意'w'的用法). $tempfile = fopen($tempfilename, 'w'); //处理错误 if (!$tempfile) { echo(" Unable to open temporary file ". exit(); } //将静态页面的数据写入到临时文件中 fwrite($tempfile, $htmldata); //完成写入后,关闭临时文件。 fclose($tempfile); //如果到了这里,我们应该已经成功地写好了一个临时文件, //现在我们可以用它来覆盖原来的静态页面了。 $ok = copy($tempfilename, $targetfilename); //最后删除这个临时文件。 unlink($tempfilename); ?> Static page successfully updated! |
上面的代码看上去很令人恐怖,其实这只是因为我们在其中包含了大量的注释。删除这些注释。你会看到这段代码其实很简单。
现在,每当我们运行generateindex.php(也就是说通过一个浏览器请求这个页面),就会从index.php生成一个新刷新的index.html。通过将index.php和generateindex.php移动到一个访问有限制的目录,你可以保证只有站点管理者能够更新你的主页。将这个脚本作一下扩充,你可以生成你的站点上的所有的半动态页面,你还可以在你的内容管理系统中增加“更新主页”的连接!
如果你希望你的主页能够自动地刷新,你只需要设置你的服务器定期地运行generateindex.php(例如说,每隔一个小时)。在新的Windows 9x下,你可以使用任务管理程序(对于旧的版本,你必须使用补丁包)每隔一个小时自动运行php.exe。你只需要建立一个包含以下行的名为generateindex.bat的批处理文件。
C:PHPphp.exe C:WWWgenerateindex.php |
如果必要的话,对路径和文件名进行调整,然后设置任务管理程序每隔一个小时执行一次generateindex.bat(你需要设置24个每天在固定时间运行的任务)。
在Linux下(或其它基于UNIX的平台下)你可以使用cron--一个可以在各种UNIX系统下用来定义任务和运行时间的程序来完成类似的工作。如果你对cron还不了解的话,你可以请教你熟悉的Linux专家,或者查阅你熟悉的Linux网站。
你使用cron设置任务和我们之前讨论的在Windows下的用法很类似。但是,你需要一个单机版的PHP,这不是指在第一章中编译的Apache中可导入的PHP模块。你需要对用来编译Apache模块的同一软件包中单独地进行编译。如果你需要帮助,你可以参看软件包提供的说明,也可以查阅PHP官方网站!
对于一个有经验的cron使用者来说,你只需要在你的crontab文件中增加下面的这一行:
0 0-23 * * * php /path/to/generateindex.php > /dev/null |
处理文件的上载
到目前为止,这个教程中数据库驱动的站点的所有例子都是处理的文本的数据。笑话、文章、作者...所有的这些都可以完全由文本形式的字符串来表示。但是如果你在运行时,有一个在线的数字图库需要人们能够上载用数字照相机拍摄的图片,我们就需要允许访问者向我们的站点上载他们的图片,我们也需要相应的处理程序。
让我们先从基本的开始:写一个HTML表单用来供用户上载文件。在HTML中,这很简单,只需要用一个标志就行了。但是,默认情况是只有用户选择的文件名被发送了。要通过表单数据提交文件自身,我们需要在