前言:
目前网络上好多网站的新闻发布系统都采用了动态服务器技术生成静态HTML的做法,这样做的好处是:一是能减轻其服务器的负
担,二是因为生成了HTML静态页面,所以其网站被搜索引擎搜索到的机率更大一些。笔者的网站曾经使用PHP这一动态技术来构建新闻发布系统,其原理也就
是应用了PHP生成HTML静态页面的技术,相关平台是 Windows XP
Sp2+php4.32+mysql,因此,在这里,想简单地谈一下这种做法的思路。这篇文章适合于对PHP+MYSQL数据库操作,SQL语句以及网页
设计有点基础的朋友,如果您是一个从头开始学的朋友,那么请先打好基础吧!到这里就不用往下看了。如果您都符合上述条件的话,那么恭喜您,请接着往下看。
但是,在具体动手构建之前,您还要做好以下几点准备工作。
一、 具备本地调试PHP的功能
在WINDOWS
XP操作系统下,笔者建议你可以到网上下载一个PHP+MYSQL+APHCHE的服务器套装,如华军软件园,去那里搜索一下就可以下载到。下载完后默认
安装即可,这样您就具备了在本地测试PHP的功能了,省去了很多手动配置的麻烦,怎么样,简单吧,OK,这仅仅只是第一步。
二、 构思新闻发布系统所具备的功能
首 页的新闻发布往往是通过后台更新的,后台的更新无非是由添加、编辑、删除数据等基本的功能所实现的。在这里,你可以使用网页设计软件来构建你的想要的后台
界面,其功能的实现当然是要用到PHP喽。这一步建议您先想好新闻发布系统要有的功能。在这里,如何用PHP添加、编辑、删除数据就不再重复,因为重点是
如何在这基础上生成静态技术。
三、 PHP生成HTML的技术原理。
哈哈。费话说了那么多,终于到了该讲的地方了。其实,
这一原理并不复杂,综合地来讲的话,应该是PHP中一个替换数据语法的应用。OK,讲一个简单范例吧,一步一步地分析!相信聪明的你能看得明白的咯,仔细
看好每一步即可,在这里,只是引导大家如何做而已,具体的可以实践一下!
(1)在MYSQL里新建一数据库,命名为 database (可自定义),新建一表,命名为
news(因为是新闻发布嘛,取个好记的名字即可,可自定义),然后建立这几个字段名:
id (自动递增,这是关键,类型:INT)
title (顾名思义,新闻标题,类型可取 TEXT)
content (新闻内容,类型可取 TEXT)
path (HTML文件路径,类型可取 TEXT)
(2)建立 conn.php
这是连接数据库的PHP文件,你可以把连接数据的语句单独放在这一文件里,以后多个需要连接数据库的文件直接引用这个文件即可。
(3)设计添加新闻的表格 add.form 简单的源代码如下:
<form method=”post” action=”add.php”> //提交至 add.php
新闻标题:<input type=”text” name=”title” size=”20”><br>
新闻内容:<textarea name=”content” cols=”10” rows=”25”></textarea><br>
<input type=”submit” name=”提交”>
</form>
代码拷贝框
<form method=”post” action=”add.php”> //提交至 add.php
[Ctrl+A 全部选择 然后拷贝]
(4)建立一个 HTML 的模板,另存为model.htm,和 add.php可以在同一目录下。
示例源代码:
<html>
<body>
此新闻的标题:{title}
此新闻的内容:{content}
</body>
</html>
{ }大括号内的内容即是要被替换的内容,整个静态模板的设计可以根据自己的思路,但{
}内被替换的内容必须包含在内,如上面的{title},{content};咔咔~简单地说,设计好一个很好看的新闻模板后,把要被替换的如
{title},{content}等标记放到需要的地方就可以了撒。
(5)详解 add.php 源码
<?php
require_once(“conn.php”); //引用conn.php,连接数据库
$title=$_POST[“title”];
$content=$_POST[“content”]; //获得表单变量
//以下建立一文本文档,其值自动计数
$countfile="count.txt";
if(!file_exists($countfile))
{
fopen($countfile,"w"); //如果此文件不存在,则自动建立一个
}
$fp=fopen($countfile,"r");
$num=fgets($fp,20);
$num=$num+1; //每次其值自动加一
fclose($fp);
$fp=fopen($countfile,"w");
fwrite($fp,$num); //更新其值
fclose($fp);
代码拷贝框
<?php
[Ctrl+A 全部选择 然后拷贝]
//利用上面自动计数的值获得HTML的路径$path
$houzui=”.html”;
$path=$num.$houzui;
//这样形成的路径是自动增长的,如1.html,2.html,3.html……….添加一条新闻便自动加上1
//以下用SQL语句添加数据至表 news
$sql=”insert into news (title,content,path) values
(‘”.$title.”’,’”.$content.”’,’”.$path.”’)”;
$query=mysql_query($sql);
//以下为关键之处,把从表单获得的数据替换模板中的{title},{content}标记
//只读打开模板
$str=fread($fp,filesize(“mode.htm”));//读取模板中内容
$str=str_replace(“{title}”,$title,$str);
$str=str_replace(“{content}”,$content,$str);//替换内容
fclose($fp);
$handle=fopen($path,”w”); //写入方式打开新闻路径
fwrite($handle,$str); //把刚才替换的内容写进生成的HTML文件
fclose($handle);
代码拷贝框
$fp=fopen(“model.htm”,”r”) //只读打开模板
[Ctrl+A 全部选择 然后拷贝]
//收尾工作:
echo “<a href=$path target=_blank>查看刚才添加的新闻</a>”;
代码拷贝框
echo “<a href=$path target=_blank>查看刚才添加的新闻</a>”;
[Ctrl+A 全部选择 然后拷贝]
OK,整个生成HTML的示例源码就到这里,其关键是用了替换的方法。
$str=str_replace(“{被替换的内容}”,$替换的内容,$str);
因此,总结一下以上的做法:先设计好新闻模板,把需要被替换的内容用{
}放到模板中相应的位置,然后设计表单,再是最后的表单处理程序,把从表单中获取的变量替换模板中相应的内容即可,这样每次都会生成不同的HTML;如果
需要修改HTML的内容也是一样的,获得修改后的表单内容后,先用 update
语句更新数据库,再重新替换一下模板中的内容即可;删除的话,先delete表中要删除的内容,再用unlink($path) 来删除HTML的物理文件即可。
谈PHP生成静态页面
一、引 言
在速度上,静态页面要比动态页面的比方php快很多,这是毫无疑问的,但是由于静态页面的灵活性较差,如果不借助数据库或其他的设备保存相关信息的话,整体的管理上比较繁琐,比方修改编辑.比方阅读权限限制等,但是,对应一些我们经常频频使用的文件,比方说,开发的新闻发布系统,我们不希望很多用户都读取数据库才显示结果,这样一方面消耗了服务器的资源,另一方面占去了浏览者大量可贵的响应时间,所有,有了"静态页面话"的做法,当前很多网站都采用这种技术,一般都是由管理后台控制,或者生成html直接显示,或者xhtml用css控制显示,或者生成xml用xslt显示,这些技术都不是难的,在这里我就浅显的说说生成html的方法.
二、预备知识
模板技术:
[PHP] 模板引擎Smarty深入浅出介绍 --2005-12-31
[PHP] 笑谈配置,使用Smarty技术
缓存技术:
有些信息比方经常不变的,但是还是能变的信息放在缓存中以加快显示速度,这是很有价值的,所谓的缓存,通俗的理解就是一些保存在服务器端的共用信息.它是于服务器同生死的,我们在保存缓存的时候可以指定下次更新的时间的判断,比方要在5分钟更新一次,可以记录上次更新的时间,和当前时间比较,如果大于
5 分钟 ,读取数据库,更新换成,否则直接读取缓存数据,当然,缓存需要客户端用户激活的,只需一次.
ob_start()函数:打开输出缓冲区.
说明:当缓冲区激活时,所有来自PHP程序的非文件头信息均不会发送,而是保存在内部缓冲区。为了输出缓冲区的内容,可以使用ob_end_flush()或flush()输出缓冲区的内容。
Flush:刷新缓冲区的内容,输出。
ob_get_contents :返回内部缓冲区的内容。
ob_get_length:返回内部缓冲区的长度。
ob_end_clean:删除内部缓冲区的内容,并且关闭内部缓冲区
ob_end_flush:发送内部缓冲区的内容到浏览器,并且关闭输出缓冲区
ob_implicit_flush:打开或关闭绝对刷新
文件写入:
int fwrite ( resource handle, string string [, int length] )
fwrite() 把 string 的内容写入 文件指针 handle 处。 如果指定了 length,当写入了 length 个字节或者写完了 string
以后,写入就会停止,视乎先碰到哪种情况。
fwrite() 返回写入的字符数,出现错误时则返回 FALSE 。
相关参考官方网站: 文件参考
三、解决方案
思路:开启 ob_start缓冲,当已经调出数据的时候获取
ob_get_contents,然后生成静态页,ob_end_clean清除缓冲.ok,就这么来,来看一个例子(php+mysql的结合):
创建数据库:
CREATE TABLE `bihtml` (
`id` int(11) NOT NULL auto_increment,
`szdtitle` varchar(16) NOT NULL,
`szdcontent` text NOT NULL,
PRIMARY KEY (`id`)
) TYPE=MyISAM;
获取当前的ID,并导入模板:
四、说明事项
1: 一般建议管理员添加数据的时候就生成静态页面,可以考虑记录生成的文件名次和路径.
2: php主要是
ob_get_contents,生成静态页面的时候很有用,当然也可以考虑调出数据库直接替换模板里面的变量也是可以的.
3: 主要的模板使用smarty,phplib都是可以的,smarty使用比较简易.
ob_start();
$id=_POST['id']
if(!isset($id)&&is_integer($id))
{
@$db=new mysqli('localhost','root','admin','bihtml');
$result=$db->fetch_one_array("select * from szd_bi where id='$id'");
$tpl->display('default_1.tpl');
$this_my_f= ob_get_contents(); //此处关键
ob_end_clean();
$filename = "$id.html";
if(tohtmlfile_cjjer($filename,$this_my_f))
echo "生成成功 $filename";
else
echo "生成识别";
}
}
//把生成文件的过程写出函数
function tohtmlfile_cjjer($file_cjjer_name,$file_cjjer_content)
{
if (is_file ($file_cjjer_name)){
@unlink ($file_cjjer_name);
}
$cjjer_handle = fopen ($file_cjjer_name,"w");
if (!is_writable ($file_cjjer_name)){
return false;
}
if (!fwrite ($cjjer_handle,$file_cjjer_content)){
return false;
}
fclose ($cjjer_handle); //关闭指针
return $file_cjjer_name;
}
Posted by kevinwu at 02:51 PM | Permalink | Comments (0) | TrackBacks (0)
February 10, 2006
PHP unit testing tutorial - Grouping together unit tests and examples of writing
test cases
PHP unit testing tutorial - Grouping together unit tests and examples of writing
test cases
Posted by kevinwu at 02:00 PM | Permalink | Comments (0) | TrackBacks (0)
Download the Simple Test testing framework - Unit tests and mock objects for PHP
Download the Simple Test testing framework - Unit tests and mock objects for PHP
Posted by kevinwu at 01:18 PM | Permalink | Comments (0) | TrackBacks (0)
PHP unit testing tutorial - Creating an example test case in PHP
PHP unit testing tutorial - Creating an example test case in PHP
Posted by kevinwu at 01:14 PM | Permalink | Comments (0) | TrackBacks (0)
February 09, 2006
在PHP中使用SimpleTest进行单元测试
在PHP中使用SimpleTest进行单元测试 - 我与IT不得不说的故事
Posted by kevinwu at 01:15 PM | Permalink | Comments (0) | TrackBacks (0)
php 常用组件等整理
php 常用组件等整理--树的回忆
Posted by kevinwu at 12:07 PM | Permalink | Comments (0) | TrackBacks (0)
The three ants::一种PHP设计模式:DPT
The three ants::一种PHP设计模式:DPT
Posted by kevinwu at 11:56 AM | Permalink | Comments (0) | TrackBacks (0)
PHP单元测试工具PHPUnit初体验[转载]
看了PHPUnit的文档之后基本有了一些了解,
http://pear.php.net/manual/en/packages.php.phpunit.intro.php
工作流程如下:
1.设计你的class/API
2.创建测试程序集
3.实现class/API
4.运行测试
5.修正测试失败或错误,回到第4步。
我们来举个例子:
下面是你要测试的class,其中formatn函数一个取任意数字的5位有效数字的函数。
----------format_number.php-----------
class fo {
function fo() {
}
function formatn($num) {
$num = rtrim($num,"0");
$pos = strpos($num,".");
$num = str_replace(".","",$num);
$count1 = strlen($num);
$num = ltrim($num,"0");
$count2 = strlen($num);
$zeroc = $count1 - $count2;
$num = substr($num,0,6);
$num = round($num/10);
//$num = str_pad($num, 5, "0");
if ($pos !== false) {
$num = str_pad($num, (strlen($num)+$zeroc), "0", STR_PAD_LEFT);
$dotl = substr($num,0,$pos);
$dotr = substr($num,$pos);
$num = $dotl.".".$dotr;
}
return $num;
}
}
接着创建TestCase,继承自PHPUnit_TestCase
----------testcase.php-----------
require_once 'format_number.php';
require_once 'PHPUnit.php';
class foTest extends PHPUnit_TestCase {
//这个成员变量是存放要测试的类引用
var $abc;
//构造函数
function foTest($name) {
$this->;PHPUnit_TestCase($name);
}
//new一个要测试的类为成员变量abc赋值
function setUp() {
$this->;abc = new fo;
}
//unset要测试的类
function tearDown() {
unset($this->;abc);
}
//自定义的testcase
function testFormatn1() {
//调用要测试的类的方法,结果放到$result变量
$result = $this->;abc->;formatn("100.234");
//期望结果
$expected = "100.23";
//判断是否相等,这里使用assertTrue方法来判断布而值是否为true。
$this->;assertTrue($result == $expected);
}
function testFormatn2() {
$result = $this->;abc->;formatn("0.100234");
$expected = "0.10023";
$this->;assertTrue($result == $expected);
}
function testFormatn3() {
$result = $this->;abc->;formatn("0.100235");
$expected = "0.10024";
$this->;assertTrue($result == $expected);
}
function testFormatn4() {
$result = $this->;abc->;formatn("0.000100235");
$expected = "0.00010024";
$this->;assertTrue($result == $expected);
}
function testFormatn5() {
$result = $this->;abc->;formatn("0.000100232");
$expected = "0.00010023";
$this->;assertTrue($result == $expected);
}
function testFormatn6() {
$result = $this->;abc->;formatn("1343");
$expected = "1343";
$this->;assertTrue($result == $expected);
}
function testFormatn7() {
$result = $this->;abc->;formatn("1343.01");
$expected = "1343";
$this->;assertTrue($result == $expected);
}
function testFormatn8() {
$result = $this->;abc->;formatn("1343.05");
$expected = "1343.1";
$this->;assertTrue($result == $expected);
}
function testFormatn9() {
$result = $this->;abc->;formatn("0");
$expected = "0";
$this->;assertTrue($result == $expected);
}
function testFormatn10() {
$result = $this->;abc->;formatn("105.2342");
$expected = "105.23";
$this->;assertTrue($result == $expected);
}
function testFormatn11() {
$result = $this->;abc->;formatn("105.2375");
$expected = "105.24";
$this->;assertTrue($result == $expected);
}
function testFormatn12() {
$result = $this->;abc->;formatn("0.000523751");
$expected = "0.00052375";
$this->;assertTrue($result == $expected);
}
function testFormatn13() {
$result = $this->;abc->;formatn("0.000523755");
$expected = "0.00052376";
$this->;assertTrue($result == $expected);
}
}
最后还需要一个运行测试的程序
----------runtest.php-----------
require_once 'testcase.php';
require_once 'PHPUnit.php';
$suite = new PHPUnit_TestSuite("foTest");
$result = PHPUnit::run($suite);
echo $result->;toString();
?>;
现在就可以通过命令行运行这个testcase
php runtest.php
得到结果如下:
TestCase foTest->;testFormatn1() passed
TestCase foTest->;testFormatn2() passed
TestCase foTest->;testFormatn3() passed
TestCase foTest->;testFormatn4() passed
TestCase foTest->;testFormatn5() passed
TestCase foTest->;testFormatn7() passed
TestCase foTest->;testFormatn8() passed
TestCase foTest->;testFormatn9() passed
TestCase foTest->;testFormatn10() passed
TestCase foTest->;testFormatn11() passed
TestCase foTest->;testFormatn12() passed
TestCase foTest->;testFormatn13() passed
TestCase foTest->;testFormatn6() failed: expected TRUE, actual FALSE
其中testFormatn6的测试失败,
我们就可以去检查一下我们的代码在什么地方出问题了。
补充一点
也可以把assertTrue方法换assertEquals,如下:
function testFormatn6() {
$result = $this->;abc->;formatn("1343");
$expected = "1343";
$this->;assertEquals($expected, $result);
}
如果失败得到对应的结果会直观一些(可以显示错误的结果):
TestCase foTest->;testFormatn8() failed: expected 1343 , actual 134.
Posted by kevinwu at 11:44 AM | Permalink | Comments (0) | TrackBacks (0)
用phpUnit帮你调试php程序
调试程序是一个漫长的过程,程序越长越复杂,调试起来就愈加困难。如果你调试的是php程序,那么不妨采用phpUnit,它可以大大加快你的调试速度。
何谓PhpUnit
Phpunit 脱胎于Fred Yankowski编写的著名的Junit测试框架。你可以到它的网站
http://www.ontosys.com/phiki/phpunit
下载最新的版本。你可以利用phpUnit编写一套测试软件包。保证你的程序代码正确无误。只需一步便可自动完成所有的测试。
如果监测到bug,你就可以再写一小段测试代码来找出错误之所在。日后若再有相同的bug出现,只要运行你先前的测试包,马上就可以抓到它。经常运行测试包便可以保证你的程序代码的强壮性。
开 始
假设我们有一个银行账务处理程序。现在需要为Account (账户) 类编写一个测试软件包。
以下是Account类 源代码:
class Account{
var $balance;
function Account($initialBalance=0){
$this->balance = $initialBalance;
}
function withdraw($amount){
$this->balance -= $amount;
}
function deposit($amount){
$this->balance += $amount;
}
function getBalance(){
return $this->balance;
}
function transferFrom(&$sourceAccount,$amount){
$sourceAccount->withdraw($amount);
$this->deposit($amount);
}
?>
创建一个测试类
首先,我们建立一个测试类AccountTest,它是一个由PhpUnit提供的TestCase的子类。在这个TestCase类中有2个基本的方法:setUp和tearDown。
这2个方法的实现在父类中是空过程,必须由我们自己去重载。其中SetUp
用于进行AccountTest类的初始化处理。在本例中,我们对一些在测试中用到的账号进行初始化。tearDown
则用于AccountTest类的清空处理,在本例中无需使用。因此,就不对它进行重载。这样AccountTester类的源代码如下:
class AccountTester extends TestCase{
var $_ac1;
var $_ac2;
var $_ac3;
var $_ac4;
function AccountTester($name){
$this->TestCase($name); // call parent constructor
}
function setUp(){
$this->_ac1 = new Account(100); // data for testWithdraw
$this->_ac2 = new Account(20); // data for testDeposit
$this->_ac3 = new Account(30); // data for testTransferFrom
$this->_ac4 = new Account(50);
}
}
?>
加入专门的测试代码
现在,我们可以往向AccountTester类加入测试代码了。
// Make a withdrawal of 25 units from _ac1.
// _ac1's initial balance is 100
function testWithdraw(){
$this->_ac1->withdraw(25);
$this->assert($this->_ac1->getBalance() == 75); // 100 - 25 = 75
}
// Make a deposit of 10 units into _ac2.
// _ac1's initial balance is 20
function testDeposit(){
$this->_ac2->deposit(10);
$this->assertEquals(30,$this->_ac2->getBalance()); //20 +10 = 30
}
// Tranfers 10 units from _ac3 to _ac4
// _ac3's initial balance is 30
// _ac4's initial balance is 50
function testTransferFrom(){
$this->_ac4->transferFrom(&$this->_ac3,10);
$this->assertEquals(20,$this->_ac3->getBalance(),"Source account balance
incorrect"); // 30 - 10 = 20
$this->assertEquals(60,$this->_ac4->getBalance(),"Target account balance
incorrect"); // 50 + 10 = 60
}
?>
这段代码中,assert(如同C里的断言)方法是测试的关键部分。如果在assert中的条件表达式为真,那么测试通过。否则返回错误。由于assert方法大都用于判断两个变量的值是否相等。因此,testclass类引入了assertEquals方法专门实现这个功能。AssertEquals方法中有3个参数,依次分别为:期望值,测试值,两值不相等时返回的消息提示串。
运行测试过程
好了,现在可以运行一下我们编好的测试程序了。我们还必须建立一个runtest.php测试程序来运行所有的测试过程。
runtest.php源代码如下:
$tSuite = new TestSuite(); //creation of the test suite object 创建测试套件对象
$tSuite->addtest(new AccountTester("testWithdraw")); //Add inidividual tests
$tSuite->addtest(new AccountTester("testDeposit")); //加入专门测试方法。
$tSuite->addtest(new AccountTester("testTransferFrom"));
$res = new TextTestResult(); //Creation of the Result 建立一个测试结果类
$tSuite->run(&$res); //Run of the test 运行测试
$res->report(); //Print results 输出测试结果。
?>
程序说明:
首先创建测试套件对象tSuite,然后逐一加入专门测试方法,addtest方法的参数是测试方法的
再创建测试报告对象,随之运行测试。测试发现错误的结果由TestResult类捕捉,TestResult可以定制一套text/html的错误报告。如果有必要你也可以自己编写输出部分。测试结果封装在TestResult类中,为了输出测试结果。我们采用了phpUnit提供的另外一个类TextTestResult类,它可以输出文本或超文本格式的报告。当然我们也可以自己定制一个新的TestResult的子类控制更复杂的输出格式。
提示和技巧
1、在编写一个新的测试套件完成之后,我们可以先引入一个小小的bug以证明测试套件可以正常运行。
比如,在本例account类中,我们故意引入一个有问题的函数。
function withdraw($amount){
$this->balance -= $Amount;
// 变量名大小写错误,本意是调用$amount参数,结果引入一个新变量$Amount。
}
?>
好,现在让我们运行测试套件,如果不出意外的话,我们将很快发现错误之处。
2.要指出的是,并非所有的方法都需要测试。你只需对相关的方法进行测试。
3.如果在开始编码前就写好测试代码,会使你更进一步明白你的程序到底需要完成什么样的任务。
现在,通过引入phpUnit的测试套件类,你可以发现找bug的时间缩短了,而你作为一个程序员的工作效率也提高了。
那么,尽情享受抓虫子的乐趣吧。祝您好胃口。