|
|
您是第
个访问者 版权所有:昆明市思若科技有限公司 联系方式:MSN:kmsiruo@hotmail.com QQ:914907568、794340636 电话:0871-5635372 24小时服务手机:13888849906 传真:0871-5635372 Copyright@ http://www.siruo.net.cn all rights reserved Powered by SIRUO Code © 2003-08 SIRUO SYSTEM [昆明市思若科技有限公司]倾情开发 |
在本章的剩余部分中,将解决我们在第1章中为自己定下的目标:
对于学分保存方案,需要编写一个允许我们输入、编辑测试和测验分数的脚本。
对于历史同盟,需要开发一个有关美国总统的联机测验,使之成为交互式的,以便不做任何事情就可以为这个Web 站点的访问者产生试题。
我们也想允许历史同盟成员联机编辑它们的目录项,使信息维持最新并减少我们自己编辑项的数量。
每个脚本都产生多个Web 页面,并依靠在创建页面中嵌入的信息来在脚本的调用之间进行通信。
输入学生分数
在本节中,我们将把注意力转向学分保存方案。我们Web 站点上的这个区域的URL 是http://pit-viper.snake.net/gp/,应该为它编写一个简短的主页i n d e x . p h p,下面的页面就正在做这件事。它包括了与第7 章编写的score_browser 脚本的连接,因为这个脚本适合于学分保存方案。

现在让我们考虑如何设计和实现脚本score _ e n t r y. p h p,它将让我们输入一组新的测试或测验分数,或者修改一组已经存在的分数。后者的性能对于处理由于生病或者其他原因缺席(或者,放弃这个想法以免输入分数失败)造成考试或测验比其他学生晚的学生的分数是必要的。分数项脚本的概要是这样的:
1) 最初的页面代表一系列已知的登记事件,并允许选择一个事件或者指定应该创建的新事件。
2) 如果选择创建一个新事件,脚本就给出允许指定日期和事件类型的页面。创建这个事件记录之后,脚本重新显示事件列表页面来显示这个新事件。
3) 当选择了事件后,脚本给出在顶部(事件ID、日期、类型)显示事件信息的分数项页面,后接每个学生一项的列表。对于新事件,项将是空白的。对于已存在的事件,项将显示每个学生已存在的分数。选择提交按钮时,分数输入到score 表中。
脚本需要执行几个不同的操作,这意味着我们需要从一个页面到另一个页面周而复始地传递状态变量,以便脚本在每次调用时能够知道假设要做什么。在PHP 中很容易做到这一点,因为PHP 处理作为URL 参数传递的变量,并把它们转换为与参数具有相同名称的变量。例
如,可以在脚本URL 的末尾对参数action 进行如下编码:
http://pit-viper.snake.net/gp/score_entry.php?action=value
当调用score _ e n t r y.php 时,参数action 作为变量$action 来编码,这样就可以直接访问它了。这也适用于格式中的域。设想一个包括域name 和address 的表格,当客户机传递表格时,Web 服务器就调用脚本访问表格的内容。脚本能够找出通过检查变量$name 和$address 的值而输入到表格中的值。对于包括许多域的表格,全部给出唯一的命名是有困难的。PHP 很容易地把数组在表格中传入和传出。如果使用了如x [ 0 ]、x[1] 等等的域名,则PHP 把它们作为$x 数组的元素进行编码。可以将这些元素作为$ x [ 0 ]、$x[1] 等等来访问。
我们通过使用页面中的action 参数,可以将信息从score _ e n t r y.php 脚本的一个调用传送到另一个调用,并在脚本中用变量$action 检查它的值。脚本的框架是这样的:


变量$action 可以取若干值,我们已在switch() 语句中测试过了(为避免在脚本中使用文字的数字,可以用PHP 的define() 构造来定义常量)。PHP switch() 语句与它在C 中相应的部分相类似。在score _ e n t r y.php 中,它用来确定采用什么操作,并且调用实现这个操作的函数。
检查一下每次处理一个操作的函数。第一个函数d i s p l a y _ e v e n t s ( ),检索来自MySQL的event 表的行并加以显示。表的每一行都列出了事件ID、日期和时间类型(测试或测验),还有编写事件ID作为可以选择用来修改事件分数的连接:

表中的连接用$PHP_SELF 来构造。这个变量包括了脚本自己的U R L,它为脚本再次调用自己提供了一个方便的方法。然而,请注意函数开始处的global 行:
global $PHP_SELF;
在PHP 函数中,全局变量是不可访问的,除非显式地声明要使用它们。没有global 行,$PHP_SELF 将被看成局部变量(因为我们没有将值赋给它,因此是空的)。在函数内部,使用global 来访问依靠URL 参数或者作为表格域传递到脚本中的参数也是必需的。
用来生成表的函数display_cell() 与第7 章编写的同名DBI 函数相类似。PHP 版本如下:

如果在display_events() 给出的表中选择了“ New Event ”连接,则脚本通过操作SOLICIT_ EVENT进行再次调用。它引发了对solicit_event_info() 的调用,这个函数显示了允许输入新事件信息的表格:

由solocit_event_info() 生成的表格包括输入数据的编辑域、指定新事件是测试还是测验的两个单选按钮、Submit 按钮。当递交表格时, ADD_EVENT 操作将调用score _ e n t r y. p h p。调用add_new_event() 函数在event 表中输入一个新的行:

在add_new_event() 中,我们使用global 访问在新事件项表格中使用的域值( date 和type,用变量$date 和$type 访问)。做出最低限度的安全检查,确定数据为非空白之后,在event 表中输入一个新记录。输入这个事件记录之后,主程序将再次显示事件列表,这样就可以选择新事件并开始输入分数了。
函数display_scores() 为给定的事件查找已存在的分数,并列出显示他们的表格,包括学生姓名:

display_scores() 用于检索所选事件的分数信息的查询并不是表之间的简单连接,因为它不会为事件中没有分数的学生选择行。特别是,对于新的事件,连接会选择无记录,这就有了一个空项表格!我们使用LEFT JOIN 强迫为每个学生检索行,无论学生是否在score表中已经有了分数。与display_scores() 用来检索来自于MySQL的分数记录相类似的查询背景,已在3 . 8 . 2节“检查表中未给出的值”中给出了介绍。那里的查询只选择缺失分数,这里的查询只选择特殊事件的分数。
分数在表格中使用了有名称的域进行编码,如score [n],这里的n是student_id 的值。当表格送回Web 服务器时,PHP 将这些域转换为$score 数组的元素,我们可以访问数组元素以恢复表格的内容。
当完成输入或者编辑分数,并提交给表格后,ENTER_SCORES 操作调用score _ e n t r y. p h p,并且调用函数enter_scores() 处理表格信息:

学生ID 的值和相关的分数通过迭代PHP 的each 函数的$score 数组来获得。每个分数处理如下:
如果分数是空白的,则表明什么也没有输入,但是我们还要试图删除这个分数,以免它以前曾经存在(也许以前我们为缺席的学生错误地输入了分数)
如果分数不是空白的,就对值进行一些根本的确认。用函数trim() 去掉前后的空格之后,如果剩余部分是空白或者整数,就接受这个结果。然而,表格值通常作为字符串来编码,因此不能用is_long() 或者is_int() 检查值是否为整数。即使值只包括数字,这些函数也会返回FA L S E。既然这样,最好用模型匹配操作。如果字符串从开始到结束每个字符都是数字,则下面的测试为T R U E:
ereg("^[0-9]+$",$str)
如果分数检查完毕,我们就将它加到score 表中。查询使用REPLACE 而不用INSERT,因为我们可能替换了已存在的分数而不是输入一个新的分数( REPLACE 在两种情况下都适用)。
注意score _ e n t r y.php 脚本。现在所有的分数项和编辑项都能从Web 浏览器执行。一个明显的缺点是:脚本没有提供安全措施,连接到Web 服务器的任何人都可以对分数进行编辑。以后,我们用编辑历史同盟成员项编写的脚本来说明这个脚本所采取的简单确认方案。也可以使用PHPLIB 程序包来提供更完善的确认。
美国总统测验
历史同盟Web 站点的目标之一就是用它给出测验的在线版本,这类似于同盟在时事通信“美国编年史”的儿童部分发表的一些测验。实际上我们创建了president 表,因此对基于历史的测验可以用它作为问题的来源。为了给出这个测验,我们将编写称为pres_quiz.php 的脚本。
基本的想法是随机挑选一个总统,问一个关于他的问题,然后请求用户回答并且察看答案是否正确。为了简单一点,可以把主题限制为询问总统出生在哪里。另外一种简单的衡量就是以多个选择的格式给出这个问题。这对用户来讲很容易,他只需从一组选择中挑选一个,而不用将之键入等待回应。这对我们来讲也是容易的,因为我们不需做任何棘手的匹配字符串来检查用户可能键入的内容,而只需对用户的选择和我们寻找的值做一个简单的比较。