第三章:开发聊天程序
1 Mojavi应用程序构成
Mojavi应用程序结构如下:
Application
├Module
│ ├Action
│ ├Action
│ …
├Module
│ ├Action
│ ├Action
│ …
…
它是一个项目和活动的集合体,按如下方法访问活动:
index.php?module=项目名&action=活动名
模块名和活动名与实际的文件名和类相对应。例如,如下构成的文件:
webapp/
└modules
└Hello
├actions 类定义
│ ├MikeAction.class.php class MikeAction extends Action
│ ├JimmyAction.class.php class JimmyAction extends Action
│ └KenAction.class.php class KenAction extends Action
├templates
…
输入
index.php?module=Hello&action=Mike
启动Hello项目的Mike活动。
前一章我们只输入了http://localhost/mojavi/,此时默认的项目和活动被启动。他们是在config.php中定义的
define('DEFAULT_MODULE', 'Default');
define('DEFAULT_ACTION', 'DefaultIndex');
如果没指定的话,输入
index.php?module=Default&action=DefaultIndex
有效。另外,如
index.php?module=项目名
省略活动名时启动Index活动。指定不存在的项目和活动,默认项目将启动PageNotFound活动。
首先,将上一章的HelloWorld改成Sample项目的HelloWorld活动,webapp/modules/目录下建立四个目录
Sample
Sample/actions
Sample/views
Sample/templates
然后移动并修改HelloWorld
Default/actions/DefaultIndexAction.class.php
移动→Sample/actions/HelloAction.class.php
修改:
第一行:class HelloAction extends Action
Default/views/DefaultIndexView_success.class.php
移动→Sample/views/HelloView_success.class.php
修改:
第1行:class HelloView extends View
第6行:$renderer->setTemplate('hello.tpl');
Default/templates/defaultindex.tpl
移动→Sample/templates/hello.tpl
然后运行
http://localhost/mojavi/?module=Sample&action=Hello
即可。
2 接受用户输入
接下来我们说明接受用户输入的方法。我们改良一下HelloWorld程序,他它变成Hello+自由输入。HelloWorld程序Sample/actions/HelloAction.class.php的第6行作如下修改。
$request->setAttribute('message', $request->getParameter('message'));
Sample/templates/hello.tpl也要修改
<div>Hello <?=$template['message'] ?>!</div>
然后用http://localhost/mojavi/?module=Sample&action=Hello&message=Mike访问,显示~Hello Mike! ~。
用户的输入可以通过Request类所拥有的涉及参数处理的两个方法取出。
mixed &getParameter (string $name, [mixed $value = 'NULL'])
通过$name取值。
没有$name时,取$value值。
array &getParameters ()
按顺序取出所有的参数。
这里不再使用要求中的名为message的文字列,而使用参数message的内容。
这里说明一下Attribute(属性),Attribute和Parameter相似,也是Request类内部的参数序列,在从活动到显示文件传递数据时保存数据。下面的3个方法经常使用。
void setAttribute (string $name, mixed $value)
命名$name为$value的键值
mixed &getAttribute (string $name)
取得健值为$name的属性的值。
array &getAttributes ()
列出所有属性
3 GET和POST
先来康应用程序的具体构造。
当访问程序时,首先显示的是姓名,发言的输入框和发言按钮以及表示保存在文件中的以前发言的发言内容。填入输入框后按发言按钮发言。处理过程为
1.访问首页
2.从文件读数据,写入发言内容。
3.用户输入数据并按发言按钮。
4.将发言写入文件后,转2
只需将下面两个活动完成
画面表示活动
将输入信息写入文件的活动
Mojavi中有选择GET和POST的功能。主要是通过运行Action类内的getRequestMethods()方法,返回特定的值(REQ_POST,REQ_GET,REQ_NONE)来实现。看下面的程序
<?php
class DefaultIndexAction extends Action
{
function getDefaultView (&$controller, &$request, &$user)
{
return VIEW_INPUT;
}
function Execute (&$controller, &$request, &$user)
{
return VIEW_SUCCESS;
}
function getRequestMethods ()
{
return REQ_POST;
}
}
?>
上述程序在GET方式时运行function getDefaultView (&$controller, &$request, &$user),在POST方式时运行function Execute (&$controller, &$request, &$user)。如果用REQ_GET代替REQ_POST,则相反。
通常返回REQ_NONE时运行function getDefaultView (&$controller, &$request, &$user),返回REQ_GET | REQ_POST时运行function Execute (&$controller, &$request, &$user),默认为REQ_GET | REQ_POST。如下表
GET POST
REQ_POST getDefaultView Execute
REQ_GET Execute getDefaultView
REQ_GET|REQ_POST Execute Execute
REQ_NONE getDefaultView getDefaultView
这种GET/POST的使用方法是Mojavi的特色。
4 Mochat:目录做成
将聊天程序命名为Mochat,并做成如下路径。
webapp/
└modules
└Mochat
├actions
├templates
├views
└logs
log路径保存发言文件,系统下访问权限设为666。
5 Mochat:Action做成
首先开发必要的活动。为使只需输入项目名即可启动,将活动命名为Index,并写入Mochat/actions/IndexAction.class.php。
<?php
//定义保存数据的文件
define('DATA_FILE', BASE_DIR . 'modules/Mochat/logs/chat.dat');
class IndexAction extends Action
{
/*
* GET方式:读文件
*/
function getDefaultView (&$controller, &$request, &$user)
{
//从数组读出数据
$data = array();
//数据存在时,转到读文件
if(file_exists(DATA_FILE)){
//读模式打开文件
$fp = fopen(DATA_FILE, "r");
//配置文件的缓冲区大小
set_file_buffer($fp, 0);
//锁住文件
flock($fp, LOCK_EX);
//重置开档的读写位置指针
rewind($fp);
//每读出一行写入$data
while($line = fgets($fp,1000000)){
array_push($data,$line);
}
//解除文件锁
flock($fp, LOCK_UN);
//关闭文件
fclose($fp);
}//if(file_exist)
//设置属性
$request->setAttribute('data', $data);
return VIEW_INPUT;
}
/*
* POST方式:追加文件
*/
function Execute (&$controller, &$request, &$user)
{
if(file_exists(DATA_FILE)){
//文将存在时用追加模式打开文件
$fp = @fopen(DATA_FILE, "a");
}else{
//没有文件时产生文件
$fp = fopen(DATA_FILE, "w");
}
//锁住文件
flock($fp, LOCK_EX);
//获得输入数据
$name = $request->getParameter('name');
$comment = $request->getParameter('comment');
//读入 另起一行+名字:发言内容
fputs($fp,"$name : $comment \n");
//解除文件锁
flock($fp, LOCK_UN);
//关闭文件
fclose($fp);
//运行getDefaultView(GET方式下)转入页面处理
return $this->getDefaultView ($controller, $request, $user);
}
function getRequestMethods ()
{
return REQ_POST;
}
}
?>
归纳起来基本上只有两步
GET方式:读取文件并放入要求的属性中,返回VIEW_INPUT
POST方式:追加写入文件,转移到GET方式的处理
Execute方法的
return $this->getDefaultView ($controller, $request, $user);
因为POST方式处理,写入文件后调用的页面同GET方式一样,所以转移到GET方式。
6 Mochat:View做成
下面的显示文件是对应返回值为VIEW_INPUT的,所以命名为Mochat/views/IndexView_input.class.php 。
<?php
class IndexView extends View
{
function & execute (&$controller, &$request, &$user)
{
//获得信息并处理
$data = $request->getAttribute('data');
$body = '<HR>';
while($line = array_pop($data)){
$body = $body. $line . "<HR>";
}
//完成想象图
$renderer =& new Renderer($controller, $request, $user);
$renderer->setTemplate('mochat_input.tpl');
$renderer->setAttribute('body', $body);
return $renderer;
}
}
?>
将从活动接收的数据处理成
<HL>姓名 : 发言
<HL>姓名 : 发言
的HTML格式,并送到模板文件mochat_input.tpl中。
7 Mochat:模板做成
模板的路径为Mochat/templates/mochat_input.tpl,内容如下
<html>
<head>
<title>Mochat - 聊天</title>
</head>
<body>
<form method="POST" action="./?module=Mochat">
姓名:<input type=text name="name">
发言:<input type=text name="comment" size=50>
<input type=submit value="发言">
</form>
<?= $template['body'] ?>
</body>
</html>
8 完成
程序已基本完成,但仍有一些问题
不填数据时不出错
姓名要反复输入,不能自动更新,使用不方便
没有对HTML的特殊字符进行处理
没有限制数据容量
下一章将解决这些问题