PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的WEB
站点。本教程并不想让你完全了解这种语言,只是能使你尽快加入开发动态web站点的行列。我假定你有一些HTM
L(或者HTML编辑器)的基本知识和一些编程思想。
1.简介
PHP是能让你生成动态网页的工具之一。PHP网页文件被当作一般HTML网页文件来处理并且在编辑时你可以用编辑
HTML的常规方法编写PHP。
PHP代表:超文本预处理器(PHP:Hypertext
Preprocessor)。PHP是完全免费的,不用花钱,你可以从PHP官方站点(http://www.php.net)自由下载。PHP遵
守GNU公共许可(GPL),在这一许可下诞生了许多流行的软件诸如Linux和Emacs。你可以不受限制的获得源码,
甚至可以从中加进你自己需要的特色。PHP在大多数Unix平台,GUN/Linux和微软Windows平台上均可以运行。怎
样在Windows环境的PC机器或Unix机器上安装PHP的资料可以在PHP官方站点上找到。安装过程很简单。
如果你的机器解决了2000问题,那么PHP也一样没有千年虫问题!
1.1 历史
三年前,RasmusLerdorf为了创建他的在线简历而创造了"个人主页工具"(Personal Home Page
Tools)。这是一种非常简单的语言。其后越来越多的人们注意到了这种语言并对其扩展提出了各种建议。在许
多人的无私奉献下以及这种语言本身的源代码自由性质,它演变成为一种特点丰富的语言,而且现在还在成长中
。
PHP虽然很容易学习,但是速度上比mod_perl(植入web服务器的perl模块)慢。现在有了可以与mod_perl速度想
媲美的被称作Zend的新引擎,而PHP4就可以充分利用这个引擎。PHP4还处在BETA测试阶段。AndyGutmans和Zeev
Suraki是Zend的主要作者。可以去Zend站点(http://www.zend.com)了解更多。
PHP的应用在个人性质的web工程中增长显著。根据Netcraft在1999年10月的报告,有931122个域和321128个IP地
址利用PHP技术。
1.2 PHP的先进之处
应用PHP有许多好处。当然已知的不利之处在于PHP由于是开放源码项目,没有什么商业支持,并且由此而带来的
执行速度缓慢(直到PHP4之前)。但是PHP的邮件列表很是有用而且除非你正在运行像Yahoo!或者Amazon.com这
样的极受欢迎的站点,你不会感觉出PHP的速度与其他的有什么不同。最起码我就没有感觉出来!好了,让我们
来看看PHP有那些优点:
- 学习过程
我个人更喜欢PHP的非常简单的学习过程。与Java和Perl不同,你不必把头埋进100多页的文档中努力学习才可以
写出一个象样的程序。只要了解一些基本的语法和语言特色,你就可以开始你的PHP编码之旅了。之后你在编码
过程中如果遇到了什么麻烦,还可以再去翻阅相关文档。
PHP的语法与C,Perl,ASP或者JSP。对于那些对上述之一的语言较熟悉的人来说,PHP太简单了。相反的,如果
你对PHP了解较多,那么你对于其他几种语言的学习都很简单了。
你只需要30分钟就可以将PHP的核心语言特点全部掌握,你可能已经非常了解HTML,甚至你已经知道怎样用编辑
设计软件或者手工来制作好看的WEB站点。由于PHP代码能够无障碍的添加进你的站点,在你设计和维护站点的同
时,你可以很轻松的加入PHP使得你的站点更加具有动态特性。
- 数据库连接
PHP可以编译成具有与许多数据库相连接的函数。PHP与MySQL是现在绝佳的组合。你还可以自己编写外围的函数
取间接存取数据库。通过这样的途径当你更换使用的数据库时,可以轻松的更改编码以适应这样的变化。PHPLIB
就是最常用的可以提供一般事务需要的一系列基库。
- 可扩展性
就像前面说的那样,PHP已经进入了一个高速发展的时期。对于一个非程序员来说为PHP扩展附加功能可能会比较
难,但是对于一个PHP程序员来说并不困难。
- 面向对象编程
PHP提供了类和对象。基于web的编程工作非常需要面向对象编程能力。PHP支持构造器、提取类等。
- 可伸缩性
传统上网页的交互作用是通过CGI来实现的。CGI程序的伸缩性不很理想,因为它为每一个正在运行的CGI程序开
一个独立进程。解决方法就是将经常用来编写CGI程序的语言的解释器编译进你的web服务器(比如mod_perl,JSP)
。PHP就可以以这种方式安装,虽然很少有人愿意这样以CGI方式安装它。内嵌的PHP可以具有更高的可伸缩性。
- 更多特点
PHP的开发者们为了更适合web编程,开发了许多外围的流行基库,这些库包含了更易用的层。你可以利用PHP连
接包括Oracle,MS-Access,Mysql在内的大部分数据库。你可以在苍蝇上画图,编写程序下载或者显示e-mail。
你甚至可以完成网络相关的功能。最好的是,你可以选择你的PHP安装版本需要哪些功能。引用Nissan的Xterra
的话来说就是PHP可以做到你想让它做到的一切而且无所不能!
1.3竞争对手:ASP,mod_perl,JSP
我当然不清楚ASP/JSP能做些什么。不过明确的是编写那样的代码有多简单,购买它们会有多昂贵以及它们需要
多么昂贵和强大的硬件。如果你有什么中立的观点(比如说没有被SUN和Microsoft的百万美金所影响),请顺便
通知我。
据我所知,JSP基于Java,因此Java程序员可以轻松开始编码。ASP只是一个一般的引擎,具有支持多种语言的能
力,不过默认的并且是最常用的还是VBScript。
mod_perl与Perl一样强大,只是更快一些。
PHP站点的在线教程已经很棒了。在那里还有一些其他教程的链接。而本文的该部分将让你对PHP熟悉一点。我不可能做到没有任何遗漏,我的目的只在于能让你迅速开始你的PHP编程。
2.1 首要条件
你首先必须要有一个正在工作着的支持PHP的web服务器。我假定在你的服务器上所有PHP文件的扩展名为.php3。
2.2 PHP的安装
生成一个名为test.php3的文件,含有以下内容:
<? phpinfo();?>
然后在你的浏览器中打开此文件。看看这个页面你就知道你的PHP安装使用的选项了。
2.3 语法
就像前面提到的一样,你可以混合编写你的PHP代码和HTML代码。因此你必须有办法将两者区别开来。以下就是你可以采用的几种方法。你可以选用其中一种你最适应的并且就这样坚持这种方法!
从HTML中分离
以下是可以使用的方法:
<? . . . ?>
<?php . . . ?>
<scriptlanguage="php"> . . . </script>
<% . . . %>
语句
与Perl和C一样,在PHP中用(;)来分隔语句。那些从HTML中分离出来的标志也表示语句的结束。
注释
PHP支持C,C++和Unix风格的注释方式:
/* C,C++风格多行注释 */
// C++风格单行注释
# Unix风格单行注释
Hello,World!
通过我们已经学过的知识,你可以编写一个最简单的程序输出一个也许是程序世界中最有名的词语:
<HTML>
<HEAD>
<TITLE>
<?
echo "HelloWorld!";
?>
</TITLE>
</HEAD>
<BODY>
<H1>
First PHP page
</H1>
<HR>
<?
// Single line C++style comment
/*
printing the message
*/
echo "HelloWorld!";
# Unix style singleline comment
?>
</BODY>
</HTML>
2.4 数据类型
PHP支持整数、浮点数、字符串、数组和对象。变量类型通常不由程序员决定而由PHP运行过程决定(真是好的解脱!)。但是类型也可以被函数cast或者settype()明确的设定。
数值
数值类型可以是整数或是浮点数。你可以用以下的语句来为一个数值赋值:
$a = 1234; # 十进制数
$a = -123; # 负数
$a = 0123; # 八进制数(等于十进制数的83)
$a = 0x12; #十六进制数(等于十进制数的18)
$a = 1.234; #浮点数"双精度数"
$a = 1.2e3; #双精度数的指数形式
字符串
字符串可以由单引号或双引号引出的字段定义。注意不同的是被单引号引出的字符串是以字面定义的,而双引号引出的字符串可以被扩展。反斜杠(/)可以被用来分割某些特殊字符。举例如下:
$first = 'Hello';
$second ="World";
$full1 = "$first$second"; # 产生 Hello World
$full2 = '$first$second';# 产生 $first $second
可以将字符和数字利用运算符号连接起来。字符被转化成数字,利用其最初位置。在PHP手册中有详细的例子。
数组与哈希表
数组与哈希表以同样的方法被支持。怎样运用取决于你怎样定义它们。你可以用list()或者array()来定义它们,也可以直接为数组赋值。数组的索引从0开始。虽然我在这里没有说明,但是你一样可以轻易的使用多维数组。
// 一个包含两个元素的数组
$a[0] ="first";
$a[1] ="second";
$a[] ="third"; // 添加数组元素的简单方法
//现在$a[2]被赋值为"third"
echo count($a); //打印出3,因为该是数组有3个元素
// 用一个语句定义一个数组并赋值
$myphonebook = array(
"sbabu"=> "5348",
"keith"=> "4829",
"carole"=> "4533"
);
// 噢,忘了教长吧,让我们添加一个元素
$myphonebook["dean"]= "5397";
//你定义的carale元素错了,让我们更正它
$myphonebook["carole"]=> "4522"
//我还没有告诉你怎样使用数组的相似支持方式吗?让我们看一看
echo"$myphonebook[0]"; // sbabu
echo"$myphonebook[1]"; // 5348
其他一些对数组或哈希表有用的函数包括sort(),next(),prev()和each()。
对象
使用new语句产生一个对象:
class foo
{
function do_foo ()
{
echo "Doingfoo.";
}
}
$bar = new foo;
$bar->do_foo();
改变变量类型
在PHP手册中提到:"PHP不支持(也不需要)直接在声明变量时定义变量类型;变量类型将根据其被应用的情况决定。如果你为变量var赋值为一个字符串,那么它变成了一个字符串。如果你又为它赋了整数值,那么它就变成了整数。"
$foo = "0";// $foo是字符串(ASCII 48)
$foo++; //$foo是字符串"1" (ASCII 49)
$foo += 1; //$foo现在是整数(2)
$foo = $foo + 1.3; //$foo是一个双精度数(3.3)
$foo = 5 + "10Little Piggies"; // $foo是一个整数(15)
$foo = 5 + "10Small Pigs"; // $foo是一个整数(15)
如果想要强行转换变量类型,可以使用与C语言相同的函数settype()。
2.5 变量与常量
可能你已经注意到,变量都有一个美元符号($)的前缀。所有变量都是局部变量,为了使得定义的函数中可以使用外部变量,使用global语句。而你要将该变量的作用范围限制在该函数之内,使用static语句。
$g_var = 1 ; // 全局范围
function test()
{
global $g_var; //这样就可以声明全局变量了
}
更先进一些的是变量的变量表示。请参考PHP手册。这在有时会显得很有用。
PHP内置了许多已定义的变量。你也可以用define函数定义你自己的常量,比如define("CONSTANT","value")。
2.6 运算符
PHP具有C,C++和Java中的通常见到的运算符。这些运算符的优先权也是一致的。赋值同样使用"="。
算术和字符
以下只有一种运算符是有关字符的:
$a + $b :加
$a - $b :减
$a * $b :乘
$a / $b :除
$a % $b :取模(余数)
$a . $b :字符串连接
逻辑和比较
逻辑运算符有:
$a || $b :或
$a or $b :或
$a && $b :与
$a and $b :与
$a xor $b :异或(当$a或$b为true时为true,两者一样时为false)
! $a :非
比较运算符有:
$a == $b :相等
$a != $b :不等
$a < $b :小于
$a <= $b :小于等于
$a > $b :大于
$a >= $b :大于等于
与C一样PHP也有三重运算符(?:)。位操作符在PHP同样存在。
优先权
就和C以及Java一样!
2.7 控制流程结构
PHP有着与C一样的流程控制。我将在下面大概介绍。
if, else, elseif,if(): endif
if (表达式一)
{
. . .
}
elseif (表达式二)
{
. . .
}
else
{
. . .
}
// 或者像Python一样
if (表达式一) :
. . .
. . .
elseif (表达式二) :
. . .
else :
. . .
endif ;
Loops. while,do..while, for
while (表达式)
{
. . .
}
do
{
. . .
}
while (表达式);
for (表达式一; 表达式二;表达式三)
{
. . .
}
//或者像Python一样
while (expr) :
. . .
endwhile ;
switch
switch是对多重if-elseif-else结构的最好的替换:
switch ($i)
{
case 0:
print "i equals0";
case 1:
print "i equals1";
case 2:
print "i equals2";
}
break, continue
break中断当前的循环控制结构。
continue被用来跳出剩下的当前循环并继续执行下一次循环。
require, include
就像C中的#include预处理一样。你在require中指定的那个文件将替代其在主文件中的位置。在有条件的引用文件时,可以使用include()。这样就使得你可以将复杂的PHP文件分割成多个文件并且在不同需要时分别引用它们。
2.8 函数
你可以像以下的例子一样定义自己的函数。函数的返回值可以是任何数据类型:
function foo (变量名一,变量名二, . . . , 变量名n)
{
echo "Examplefunction./n";
return $retval;
}
所有PHP代码都可以出现在函数定义中,甚至包括对其他函数和类的定义。函数必须在引用之前定义。
2.9 类
利用类模型建立类。可以参考PHP手册中对类的详细解释。
class Employee
{
var $empno; // 员工人数
var $empnm; // 员工姓名
functionadd_employee($in_num, $in_name)
{
$this->empno =$in_num;
$this->empnm =$in_name;
}
function show()
{
echo"$this->empno, $this->empnm";
return;
}
functionchangenm($in_name)
{
$this->empnm =$in_name;
}
}
$sbabu = newEmployee;
$sbabu->add_employee(10,"sbabu");
$sbabu->changenm("babu");
$sbabu->show();
PHP的许多特点与其他软件或者工具有关。利用迄今为止我们所学到的PHP知识,我们可以试着建立一个简单交互的网
站。利用这一过程我们又可以学到不少东西。好吧,我们现在开始专注于一个典型个人网站的建设。
3.1 计划一个站点
一般一个个人站点包括一个欢迎页面、一个留言本页面、一个书签链接页面、一个计数器、联系信息,甚至还有照片
集和一些音乐文件等等。让我们从一个标题页面、一个联系信息页面和一个简历页面开始。我们同样需要标准的通用
的页面头部和底部。
标题页面--front.html
这里我们有一个非常简单的html文件:
<HTML>
<HEAD>
<TITLE>
我的个人主页--欢迎
</TITLE>
</HEAD>
<BODY>
<H1>
我的个人主页
</H1>
<H2>
欢迎
</H2>
<HR>
<P>
欢迎来我的寒舍,虽然这里现在暂时还没有什么。
</P>
<P>
不过我希望马上就可以多起来。
</P>
<HR>
<PALIGN="CENTER">
<SMALL><I>
Copyright ? 我自己,1999
</I></SMALL>
</P>
</BODY>
</HTML>
联系信息页面--count.html
同样我们又有了一个简单页面:
<HTML>
<HEAD>
<TITLE>
我的个人主页--联系信息
</TITLE>
</HEAD>
<BODY>
<H1>
我的个人主页
</H1>
<H2>
联系信息
</H2>
<HR>
<P>
你可以通过1-800-PHP-INFO联系我
</P>
<HR>
<PALIGN="CENTER">
<SMALL><I>
Copyright ? 我自己,1999
</I></SMALL>
</P>
</BODY>
</HTML>
3.2 HTML到PHP
从上面你可以看出,每个页面有相同的头部和底部。像上面那样每个页面都写入相同的信息在工作量少的时候还可以
,但是想象一下当有100多页面且你需要全部更改其头部或底部时你要花费多大精力?一页一页的手工更改是一件多么
冗长无趣的事情啊!所以我们应该为这些页面编写PHP的头部和底部文件,之后我们只要在每个HTML页面中引用它们就
行了。我们将把这些include文件放在一个叫include的子目录下。下面我们就把这些站点的通用内容写进文件中。
全站通用变量设定:common.inc
<?
// 全站通用变量
$MyEmail ="phptalk@tnc.org";
$MyEmailLink ="<a href=/"mailto:$MyEmail/">$MyEmail</a>";
$MyName = "PHPTalk";
$MySiteName =$MyName."'s Home Page";
?>
通用页面头部:header.inc
<?
// 定义通用页面头部
?>
<HTML>
<HEAD>
<TITLE>
<? echo"$MySiteName - $title"; ?>
</TITLE>
</HEAD>
<BODY>
<H1>
<? echo"$MySiteName"; ?>
</H1>
<H2>
<? echo"$title"; ?>
</H2>
<HR>
通用页面底部:footer.inc
<?
// 通用页面底部
?>
<HR>
<PALIGN="CENTER">
<SMALL><I>
Copyright ? by
<? echo"$MyName ($MyEmailLink)"; ?>
, 1999
</I></SMALL>
</P>
</BODY>
</HTML>
新的页面front.php3:
<?
include("include/common.inc");
$title ="Welcome";
include("include/header.inc");
?>
<P>
欢迎来我的寒舍,虽然这里现在暂时还没有什么。
</P>
<P>
不过我希望马上就可以多起来。
</P>
<?
include("include/footer.inc");
?>
新的cont.php3:
<?
include("include/common.inc");
$title ="Contact Information";
include("include/header.inc");
?>
<P>
你可以通过1-800-PHP-INFO联系我
</P>
<?
include("include/footer.inc");
?>
现在你就可以猜出这样安排的好处了。如果你想改动页面的头部或者底部,你只需要改动相应的文件就可以了。如果
你要修改你的e-mail地址甚至你的名字,只要修改common.inc文件就行了。另外值得注意的是你可以把具有任何文件
名或者文件扩展名的文件包含进你的文件中,你甚至可以包含其他站点上的文件。
3.3 计数器
让我们在首页上加上一个计数器。这个例子已经被讲过多次了,但是还是有利于演示怎样读写文件以及创建自己的函
数。counter.inc包含以下代码:
<?
/*
|| 一个简单的计数器
*/
functionget_hitcount($counter_file)
{
/* 将计数器归零
这样如果计数器还未被使用,初始值将是1
你当然也可以把初始值设成20000来骗人咯
*/
$count=0;
//如果存放计数器文件已经存在,读取其中的内容
if (file_exists($counter_file) )
{
$fp=fopen($counter_file,"r");
//我们只取了前20位,希望你的站点不要太受欢迎啊
$count=0+fgets($fp,20);
//由于函数fgets()返回字符串,我们可以通过加0的方法将其自动转换为整数
fclose($fp);
// 对文件操作完毕
}
// 增加一次计数值
$count++;
// 将新的计数值写入文件
$fp=fopen($counter_file,"w");
fputs($fp,$count);
fclose($fp);
# 返回计数值
return ($count);
}
?>
然后我们更改front.php3文件以显示这个计数器:
<?
include("include/counter.inc");
//我把计数值放在文件counter.txt中,读出并输出
printf("<CENTER><B>%06d</B></CENTER> <BR>/n",
get_hitcount("counter.txt"));
include("include/footer.inc");
?>
看看我们的新front.php3
3.4 反馈表单
让我们再添加一个反馈表单以便你的浏览者填写并e-mail给你。举例来说我们用一种很简单的方法实现它,我们只需
要两个页面:一个为浏览者提供输入表单;一个获得表单数据并处理、mail给你。
PHP中获取表单数据是很简单的。当一个表单被发送后,表单中所包含的各个元素被赋上了相应的值,而这样就可以像
引用一般变量一样使用了。
<FORMname="myform" ACTION="process_form.php3"METHOD="POST">
<INPUTTYPE="TEXT" NAME="mytext" VALUE="Some Value">
</FORM>
在process_form.php3中,变量$mytext就被赋予了输入的值--非常简单!同样的,你可以从列表框、多选框、单选框
、按钮等表单元素中取得变量值。你唯一要做的就是为表单中的每一个元素取名以便将来可以引用。
根据这个方法,我们可以生成一个简单的包含三个元素的表单:姓名、e-mail地址和留言。当浏览者发送表单后,处
理该表单的PHP页面(sendfdbk.php3)读取数据,检查姓名是否为空,最后将数据mail给你。
表单:form.php3
<?
include("include/common.inc");
$title ="Feedback";
include("include/header.inc");
?>
<P>
<FORMACTION="sendfdbk.php3" METHOD="POST">
<INPUTTYPE="text" NAME="name" value="Your name"SIZE="20" MAXLENGTH="30">
<INPUTTYPE="text" MAXLENGTH="40" WIDTH="20"value="Your Email" NAME="email">
<BR>
<TEXTAREAROWS="7" COLS="40" NAME="comment">
Your feedback on myhome page.
</TEXTAREA>
<BR>
<INPUTTYPE="submit" VALUE="Send Feedback!">
</FORM>
</P>
<?
include("include/footer.inc");
?>
处理表单:sendfdbk.php3
<?
include("include/common.inc");
$title ="Feedback";
include("include/header.inc");
if ( $name =="" )
{
// 现在我很讨厌匿名的留言!
echo "Duh ? Howcome you are anonymous?";
}
elseif ($name =="Your name")
{
// 这个浏览者真是不想透露姓名啊!
echo "Hello ?<B>Your name</B> is supposed to be replaced with
your actualname!</B>";
}
else
{
// 输出一段礼貌的感谢语
echo "
Hello, $name.
<BR>
Thank you for yourfeedback. It is greatly appreciated.
<BR>
Thanking you
<BR>
$MyName <BR>
$MyEmailLink
";
// 最后mail出去
mail($MyEmail,"Feedback.","
Name : $name
E-mail : $email
Comment : $comment
");
}
include("include/footer.inc");
?>
3.5 简单的站内搜索引擎
PHP可以调用外部程序。在Unix环境下我们可以利用程序grep实现一个简单的搜索引擎。我们可以做的稍微复杂一些:
使用一个页面既输出一个表单供用户输入搜索字串又输出查询结果。
<?
include("include/common.inc");
$title ="Search";
include("include/header.inc");
?>
<P>
<FORMACTION="<? echo "$PHP_SELF"; ?>"METHOD="POST">
<INPUTTYPE="text" NAME="searchstr" value="<? echo"$searchstr"; ?>"
SIZE="20"MAXLENGTH="30">
<INPUTTYPE="submit" VALUE="Search!">
</FORM>
</P>
<?
if ( !empty($searchstr) )
{
//empty()用来检查查询字串是否为空
// 如果不为空,调用grep查询
echo"<HR>/n";
//调用grep对所有文件进行大小写非敏感模式的查询
$cmdstr = "grep-i $searchstr *";
$fp = popen( $cmdstr,"r" ); // 执行命令并输出管道
$myresult = array();// 存储查询结果
while( $buffer =fgetss ($fp, 4096))
{
// grep返回这样格式:文件名:匹配字串出现行数
//因此我们利用函数split()分离处理数据
list($fname, $fline)= split(":",$buffer, 2);
// 我们只输出第一次匹配的结果
if (!defined($myresult[$fname]))
$myresult[$fname] =$fline;
}
//现在我们将结果存储在数组中,下面就可以处理并输出了
if ( count($myresult))
{
echo"<OL>/n";
while(list($fname,$fline)= each($myresult))
echo "<LI>
<AHREF=/"$fname/">$fname</A> : $fline </LI>/n";
echo"</OL>/n";
}
else
{
// 如果没有查询结果
echo "Sorry.Search on <B>$searchstr</B>
returned noresults.<BR>/n";
}
pclose($fp);
}
?>
<?
include("include/footer.inc");
?>
注释:
PHP_SELF是PHP内建的变量。包含当前文件名。
fgets()按行读取文件,最多4096(指定)字符长度。
fgetss()与fgets()相似,只是解析输出的HTML标记。
split()有一个参数是2,因为我们只需要把输出分成两部分。另外需要省略":"。
each()是一个数组操作函数,用来更方便的遍历整个数组。
popen()、pclose()与fopen()、fclose()的功能很相似,只是增加了管道处理。
请注意以上的代码并不是实现一个搜索引擎的好办法。这只是有助于我们更好学习PHP而举出的一个例子而已。理想的
情况是你应该建立一个包含关键字的数据库然后进行搜索。
通过PHP你可以轻松的连接到数据库,请求数据并将其显示在你的web站点中,甚至修改数据库中的数据。MySQL是一种很
流行的数据库,并且在互联网中有许多有关PHP与MySQL的教程。MySQL是免费的,这一点也许就吸引了不少人。由于其广
泛应用,我就不想在这里赘述MySQL的使用方法了。Oracle被大量在企业应用中采用,因此我们就利用Oracle来介绍PHP与
数据库的连接。我们当然不会提及Oracle数据库的设计原理,原因是这已经超出了我们的讨论范围。
PHP提供了两套函数与Oracle连接,分别是ORA_和OCI函数。其中ORA_函数略显陈旧。OCI函数更新据说更好一些。两者的
使用语法几乎相差无几。如前所述,你的PHP安装选项应该可以支持两者的使用。
想获得更多有关在Microsoft
Windows平台上安装支持PHP3的Apache服务器的知识以及更多有关Oracle数据库的知识,请查阅以下URL:www.csoft.net/
~vsbabu/articles/oraphp.html。
4.1 连接
<?
if($conn=Ora_Logon("user@TNSNAME","password"))
{
echo"<B>SUCCESS ! Connected to database<B>/n";
}
else
{
echo"<B>Failed :-( Could not connect to database<B>/n";
}
Ora_Logoff($conn);
phpinfo();
?>
以上代码使用TNSNAME(在你的tnsnames.ora文件中指明)定义的Oracle数据库名称、用户名称和密码连接数据库。在成
功连接的基础上,ora_logon函数返回一个非零的连接ID并储存在变量$conn中。
4.2 查询
假设与数据库已经连接就绪,下面我们就来实际的应用对数据库的查询。下面的代码演示了一个连接并查询的典型例子:
<?
/*
* 连接数据库并执行查询
*/
functionprintoraerr($in_cur)
{
// 检查Oracle是否出错
// 如果存在错误则显示
//当指针被激活时每次请求Oracle后调用该函数
if(ora_errorcode($in_cur))
echo "Oraclecode - ".ora_error($in_cur)."/n";
return;
}
/** 主程序 */
if(!($conn=ora_logon("user@TNSNAME","password")))
{
echo "Connectionto database failed/n";
exit;
}
echo "Connectedas connection - <b>$conn</b><br>/n";
echo "Openingcursor ...<br>/n";
$cursor=ora_open($conn);printoraerr($cursor);
echo "Openedcursor - <b>$cursor</b><br>/n";
$qry="selectuser,sysdate from dual";
echo "Parsingthe query <b>$qry</b> ...<br>/n";
ora_parse($cursor,$qry,0);printoraerr($cursor);
echo "Queryparsed <br>/n";
echo "Executingcursor ...<br>/n";
ora_exec($cursor);printoraerr($cursor);
echo "Executedcursor<br>/n";
echo "Fetchingcursor ...<br>/n";
while(ora_fetch($cursor))
{
$user=ora_getcolumn($cursor,0);printoraerr($cursor);
$sysdate=ora_getcolumn($cursor,1);printoraerr($cursor);
echo " row =<B>$user, $sysdate </B><br>/n";
}
echo "Fetchedall records<br>/n";
echo "Closingcursor ...<br>/n";
ora_close($cursor);
echo "Closedcursor<br>/n";
echo "Loggingoff from oracle... <br>/n";
ora_logoff($conn);
echo "Logged offfrom oracle <br>/n";
?>
(译者注:以上代码段缺少注释,请读者参考PHPManual的Oracle数据库函数部分)
4.3 显示结果
以下代码演示了怎样查询数据库并将结果输出:
<?
functionprintoraerr($in_cur, $conn)
{
// 检查Oracle是否出错
// 如果存在错误则显示
//当指针被激活时每次请求Oracle后调用该函数
// If it encounteredan error, we exit immediately
if(ora_errorcode($in_cur))
{
echo "Oraclecode - ".ora_error($in_cur)."<br>n";
ora_logoff($conn);
exit;
}
return;
}
functionexequery($w_qry,$conn)
{
$cursor=ora_open($conn);printoraerr($cursor,$conn);
ora_parse($cursor,$w_qry,0);printoraerr($cursor,$conn);
ora_exec($cursor);printoraerr($cursor,$conn);
$numrows=0;
$w_numcols=ora_numcols($cursor);
// 显示头部
echo "
<TABLEWIDTH=/"100%/" BORDER=/"0/" CELLSPACING=/"1/"CELLPADDING=/"2/">
<TR>/n";
for($i=0;$i<$w_numcols;$i++)
{
$align=(ora_columntype($cursor,$i)=="NUMBER")?"RIGHT":"LEFT";
echo "/t<THVALIGN=TOPALIGN=$align>".ora_columnname($cursor,$i)."</TH>/n";
}
echo"</TR>/n";
while(ora_fetch($cursor))
{
echo"<TR>/n";
for($i=0;$i<$w_numcols;$i++)
{
$align=(ora_columntype($cursor,$i)=="NUMBER")?"RIGHT":"LEFT";
if(ora_columntype($cursor,$i)=="LONG")
echo "<TDVALIGN=TOP ALIGN=$align><PRE>".
ora_getcolumn($cursor,$i)."</PRE></TD>/n";
else
echo "<TDVALIGN=TOPALIGN=$align>".ora_getcolumn($cursor,$i)."</TD>/n";
printoraerr($cursor,$conn);
}
$numrows++;
echo"</TR>/n";
}
if ($numrows==0)
echo"<TR><TD COLSPAN=/"$w_numcols/"><B>Queryreturned no records
</B></TD></TR>/n";
else
{
echo"<TR>/n";
echo "<THCOLSPAN=/"".($w_numcols-1)."/"ALIGN=RIGHT>Count</TH>/n";
echo "<THALIGN=RIGHT>$numrows</TH>/n";
echo"</TR>/n";
}
echo"</TABLE>/n";
ora_close($cursor);
return;
}
// 主程序
if(!($conn=ora_logon("user@SID","password")))
{
echo "Error:Cannot connect to database/n";
exit;
}
$qry="SELECT
deptno/"Dept/"
,empno/"Emp/"
,empnm/"Name/"
,salary/"Salary/"
FROM
employee
ORDER BY 1,2";
exequery($qry);
ora_logoff($conn);
?>
(译者注:以上代码段缺少注释,请读者参考PHPManual的Oracle数据库函数部分)
4.4 基于HTTP的Oracle登录
将以下代码加在PHP页面代码之前以确认Oracle登录。注意你必须正确设定$SID。
<?
if(!isset($PHP_AUTH_USER))
{
Header("WWW-authenticate:basic realm=/"$SID/"");
Header("HTTP/1.0401 Unauthorized");
$title="LoginInstructions";
echo"<blockquote>
You are notauthorized to enter the site
</blockquote>/n";
exit;
}
else
{
if(!($conn=ora_logon("$PHP_AUTH_USER@$SID",$PHP_AUTH_PW)))
{
Header("WWW-authenticate:basic realm=/"$SID/"");
Header("HTTP/1.0401 Unauthorized");
$title="LoginInstructions";
echo"<blockquote>
You are notauthorised to enter the site
</blockquote>/n";
exit;
}
}
?>
PHP可以操作处理图像。如果你已经安装了GD库,你甚至可以利用PHP生成图像。
<?
Header("Content-type:image/gif");
$string=implode($argv,"");
$im =imagecreatefromgif("images/button1.gif");
$orange =ImageColorAllocate($im, 220, 210, 60);
$px =(imagesx($im)-7.5*strlen($string))/2;
ImageString($im,3,$px,9,$string,$orange);
ImageGif($im);
ImageDestroy($im);
?>
(译者注:以上代码段缺少注释,请读者参考PHPManual的图像处理函数部分)
这段代码在其他页面中通过以下标记<imgsrc="button.php3?text">调用,然后以上的那段button.php3代码取得text值并在另外取得的图像文件中加上该值--在以上的代码中该图像文件是images/button1.gif--最后输出到浏览器。假如你想在表单域中使用图像按钮,但是又不希望在每次按钮上的文字改变后不得不重新生成新的图像,就可以利用这样简单的方法动态生成图像文件。
5.2 Cookies
PHP支持基于HTTP的cookies。在需要时你可以像使用一般变量一样方便的使用cookie。Cookies是浏览器保存于客户端的一些信息片段,由此你可以知道是否一台特定PC上的任何人都访问过你的站点,浏览者者在你的站点上的踪迹等等。使用cookies的典型例子就是对浏览者偏好的甄别。Cookies由函数setcookie()设定。与输出HTTP标头的函数header()一样,setcookie()必须在任何实际内容杯输出到浏览器之前调用。以下是一个简单例子:
<?
if(empty($VisitedBefore))
{
//如果没有设定cookie,为cookie赋上当前时间值
//函数中的最后一个参数声明了该cookie保存的时间
// 在这个例子中是1年
//time()函数返回自1970年1月1日以来的以秒数计的时间
SetCookie("VisitedBefore",time(),time()+(60*60*24*365));
}
else
{
// 欢迎浏览者再次光临
echo "Hellothere, welcome back<BR>";
// 读取cookie并判断
if ( (time() -$VisitedBefore) >= "(60*60*24*7)" )
echo "Why didyou take a week to come back. You should be here more often!? ";
}
?>
5.3 基于HTTP验证
基于HTTP验证当PHP以CGI模式运行时不能实现。我们可以使用函数header()发送HTTP标头强制验证,客户端浏览器则弹出供输入用户名和密码的对话框。这两个变量被储存在$PHP_AUTH_USER和$PHP_AUTH_PW中,你可以使用这两个变量验证合法并允许进入。以下的例子通过用户名称/密码对为tnc/nature的验证一名用户的登录:
<?
if(!isset($PHP_AUTH_USER))
{
Header("WWW-Authenticate:Basic realm=/"My Realm/"");
Header("HTTP/1.0401 Unauthorized");
echo "Text tosend if user hits Cancel button/n";
exit;
}
else
{
if (!($PHP_AUTH_USER=="tnc" && $PHP_AUTH_PW=="nature"))
{
//如果是错误的用户名称/密码对,强制再验证
Header("WWW-Authenticate:Basic realm=/"My Realm/"");
Header("HTTP/1.0401 Unauthorized");
echo "ERROR :$PHP_AUTH_USER/$PHP_AUTH_PW is invalid.";
exit;
}
else
{
echo "Welcometnc!";
}
?>
事实上再实际引用中不大可能如上面使用代码段明显的用户名称/密码对,而是利用数据库或者加密的密码文件存取它们。
5.4 文件上传
你可以利用PHP实现文件的功能,注意客户端的浏览器应该是Netscape3以上或者IE3以上。以下就是该功能的简单演示:
( upload.html ):
<HTML>
<HEAD>
<TITLE>UploadYour File</TITLE>
</HEAD>
<BODY>
<FORMACTION="receiver.php3"
ENCTYPE="multipart/form-data"METHOD=POST>
<INPUTTYPE="HIDDEN"
NAME="MAX_FILE_SIZE"VALUE="2000000">
<INPUTTYPE="FILE"
NAME="uploadfile"SIZE="24" MAXLENGTH="80">
<BR><BR>
<INPUTTYPE="SUBMIT" VALUE="Upload File!"
NAME="sendit">
<INPUTTYPE="SUBMIT" VALUE="Cancel"
NAME="cancelit"><BR>
</FORM>
<I><FONTSIZE="2">(You may notice a slight
delay while we uploadyour file.)</FONT></I>
</BODY>
</HTML>
下面是处理上传的文件:
( receiver.php3 ):
<?
function do_upload ()
{
global $uploadfile,$uploadfile_size;
global $local_file,$error_msg;
if ( $uploadfile =="none" )
{
$error_msg ="You did not specify a file for uploading.";
return;
}
if ( $uploadfile_size> 2000000 )
{
$error_msg ="Sorry, your file is too large.";
return;
}
$the_time = time ();
// 你需要对以下目录有写权限
$upload_dir ="/local/uploads";
$local_file ="$upload_dir/$the_time";
if ( file_exists ('$local_file' ) )
{
$seq = 1;
while ( file_exists ("$upload_dir/$the_time$seq" ) ) { $seq++; }
$local_file ="$upload_dir/$the_time$seq";
};
rename ( $uploadfile,$local_file );
display_page ();
}
function display_page()
{
// 这里是你的页面内容
}
<HTML>
<HEAD>
<TITLE>php3Receiving Script</TITLE>
</HEAD>
<BODY>
<?
if ( $error_msg ) {echo "<B>$error_msg</B><BR><BR>"; }
if ( $sendit )
{
do_upload ();
}
elseif ( $cancelit )
{
header ("Location: $some_other_script" );
exit;
}
else
{
some_other_func ();
}
?>
</BODY>
</HTML>
5.5 常用函数
我们简单来看看一些常用的函数。
数组
array - 生成数组
count - 数组元素个数
sort -数组排序,另有其他几种排序函数可供使用
list - 列出数组元素
each -返回下一个key/value对
current - 返回当前数组元素
next,prev -传回当前数组元素前后指针
日期和时间
checkdate - 验证日期/时间格式
date - 生成日期/时间格式
time - 当前时间信息
strftime - 格式化日期/时间
目录、文件系统
chdir - 改变目录
dir - 目录类别
opendir, readdir,closedir - 开启、读取、关闭目录
fopen, fclose -开启、关闭文件
fgets, fgetss -逐行读取内容
file - 将整个文件读入一个数组变量中
正则表达式
ereg - 匹配正则表达式
eregi - 大小写非敏感匹配正则表达式
ereg_replace-匹配正则表达式并替换
eregi_replace-大小写非敏感匹配正则表达式并替换
split -依规则切开字符串并以数组形势存储
字符串
AddSlashes -加上斜杠后使用字符串
echo - 输出一个或多个字符串
join, implode -将数组元素合并为字符串
htmlentities,htmlspecialchars - 将HTML特殊字符转换为HTML标记形式
split -依规则切开字符串并以数组形势存储
5.6 扩展我们的范例主页
我们将使用以上提到的一些函数和思想为我们的范例主页添加更多的动态内容。我们可以在每个页面的顶部加上导航栏,同时使得当前页自动的不被链接显示;同时还可以添加一个用户验证表单以便上传音乐、图像等文件并自动更新页面。
导航栏
实际上就是在footer.inc文件中加上一段代码。假设你的web站点中所有后缀为.php3的文件都会出现在导航栏中,以下就是被存为include/navbar.inc的代码:
<?
/*输出该导航栏,链接所有除当前页的站内.php3文件 */
# 读取目录
$d =dir("./");
echo "<PALIGN=/"CENTER/"> | /n";
while($entry =$d->read())
{
// 忽略无文件情况
if ( !is_file($entry))
continue;
/*将文件名与扩展名分开。由于.是正则表达式特殊字符,应该用/引出 */
list($filenm,$fileext) = split("/.",$entry, 2);
// 忽略非.php3文件情况
if( $fileext !="php3" )
continue;
/*现在我们已经把.php3文件都选出,下面搜寻文件中的第一行(标题)
类似$title="something";
并将以上标题内容分开,用作链接文字 */
$linknm ="";
$fp=fopen($entry,"r");
while($buffer=fgets($fp,4096))
{
$buffer =trim($buffer);
//我们已经把每个文件的标题放在文件的第一行以便搜索
//但是当你改变变量名称时可能会带来大麻烦
if (ereg("title*= */"", $buffer))
{
/*我们已经取得了标题内容并可以在此基础上
进行去除空格等处理。
必须以PHP代码方式处理,比如$title= "blah blah" */
eval($buffer);
// 然后将链接文字显示为标题文字
$linknm = $title;
break;
}
}
fclose($fp);
if ( $entry ==basename($PHP_SELF) )
echo"$linknm";
else
echo "<AHREF=/"$entry/">$linknm</A>";
echo " | ";
}
$d->close();
echo "</P>/n";
?>
照片收藏夹
我们将引用基于HTTP的验证、文件系统函数和文件上传功能维护放置图像文件的目录。
同时我们需要建立一个可以列出在该目录下所有照片的页面。
文件上传
<?
include("include/common.inc");
// 我们在这里再做一次用户验证
if(!isset($PHP_AUTH_USER))
{
Header("WWW-Authenticate:Basic realm=/"$MySiteName/"");
Header("HTTP/1.0401 Unauthorized");
echo "Sorry, youare not authorized to upload files/n";
exit;
}
else
{
if (!($PHP_AUTH_USER==$MyName && $PHP_AUTH_PW==$MyPassword ) )
{
//如果是错误的用户名称/密码对,强制再次认证
Header("WWW-Authenticate:Basic realm=/"My Realm/"");
Header("HTTP/1.0401 Unauthorized");
echo "ERROR :$PHP_AUTH_USER/$PHP_AUTH_PW is invalid.<P>";
exit;
}
}
if ( $cancelit )
{
//当浏览者按下"取消"按钮则转向首页面
header ("Location: front_2.php3" );
exit;
}
function do_upload (){
global $userfile,$userfile_size, $userfile_name, $userfile_type;
global $local_file,$error_msg;
global $HTTP_REFERER;
if ( $userfile =="none" ) {
$error_msg ="You did not specify a file for uploading.";
return;
}
if ( $userfile_size> 2000000 )
{
$error_msg ="Sorry, your file is too large.";
return;
}
// Wherever you havewrite permission below...
$upload_dir ="photos";
$local_file ="$upload_dir/$userfile_name";
if ( file_exists ($local_file ) ) {
$error_msg ="Sorry, a file with that name already exists";
return;
};
//你还可以由此检查文件名称/类型对以确定是何种文件:gif,jpg,mp3…
rename($userfile,$local_file);
echo "The fileis uploaded<BR>/n";
echo "<AHREF=/"$HTTP_REFERER/">Go Back</A><BR>/n";
}
$title = "UploadFile";
include("include/header.inc");
if (empty($userfile)|| $userfile=="none")
{
// 输出以下表单
?>
<FORMACTION="<? echo "$PHP_SELF"; ?>"ENCTYPE="multipart/form-data" METHOD=POST>
<INPUTTYPE="HIDDEN" NAME="MAX_FILE_SIZE"VALUE="2000000">
<INPUTTYPE="FILE" NAME="userfile" SIZE="24"MAXLENGTH="80">
<BR><BR>
<INPUTTYPE="SUBMIT" VALUE="Upload File!"NAME="sendit">
<INPUTTYPE="SUBMIT" VALUE="Cancel"NAME="cancelit"><BR>
</FORM>
<I><FONTSIZE="2">(You may notice a slight delay while we upload yourfile.)</FONT></I>
<?
} else {
if ( $error_msg ) {echo "<B>$error_msg</B><BR><BR>"; }
if ( $sendit ) {
do_upload ();
}
}
include("include/footer.inc");
?>
照片图库
<?
include("include/common.inc");
$title ="Gallery";
include("include/header.inc");
?>
<P>
Here are some of ourfamily photos. This PHP script can really
be made better, bysplitting into multiple pages.
</P>
<?
$d =dir("photos");
while($entry =$d->read())
{
if(is_file("photos/$entry"))
echo "<IMGSRC=/"photos/$entry/">/n";
}
$d->close();
?>
<?
include("include/footer.inc");
?>
另外,你可以在文件上传的表单中加上一个输入元素去描述该上传的文件。这个元素将被存储在文件中,然后被以上的照片图库的那段代码所读出并显示出来。
6.1 站点
PHP的爆炸性流行使得一夜之间出现了很多基于PHP的站点,其中不少站点有在线教程、范例代码、技巧和提示等内容。
国内
http://www.phpuser.com - PHP中文用户,也就是这里了
http://www.phpx.com - 中国PHP联盟
http://www.phpsite.net - PHP专门站
http://www.phpchina.com - PHP CHINA
http://www.cpcw.com/netschool/homepage/cgi/- 电脑报网页陶吧
国外
http://www.php.net/ - PHP官方站点
http://www.devshed.com/ - 极好的教程
http://px.sklar.com - 代码交换
http://www.phpbuilder.com/ - 教程、专栏和邮件列表档案
http://www.weberdev.com/ - 文章和代码
http://www.phpwizard.net/ - 提示与技巧
http://www.iometrics.com/php/phplist.php3/- IOMetrics scripts的档案
http://www.e-gineer.com/phpkb/ -PHP知识库
6.2 邮件列表
你可以在PHP官方站点的"支持"栏目内登记获得以下的邮件列表。值得注意的是这些都是高流量流表,一般每天会有100份e-mail。
php3@lists.php.net -主要的列表
php-dev@lists.php.net- 主要针对开发者
php-list@exp.com.cn -本站的邮件列表,与论坛相通
6.3 引人注目的工程
一些基于PHP的工程已经发展得比较完善。其中一些更出色更引人注目的是:
http://phplib.netuse.de - PHPLib,一整套PHP函数库
http://www.phorum.org - Phorum是一个很完善的BBS系统
http://www.fishcartsql.org -FishCartSQL是一个电子商务解决方案
http://www.midgard-project.org -Midgard是一个网络应用开发平台