一、PHP简介
PHP是一种易于学习和使用的伺服器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的WEB站点。本教程并不想让你完全了解这种语言,只是能使你尽快加入开发动态web站点的行列。我假定你有一些HTML(或者HTML编辑器)的基本知识和一些编程思想。
1.简介
PHP是能让你生成动态网页的工具之一。PHP网页档被当作一般HTML网页档来处理并且在编辑时你可以用编辑HTML的常规方法编写PHP。
PHP代表:超文本预处理器(PHP: Hypertext Preprocessor)。PHP是完全免费的,不用花钱,你可以从PHP官方站点(
http://www....net)自由下载。PHP遵守GNU公共许可(GPL),在这一许可下诞生了许多流行的软体诸如Linux和Emacs。你可以不受限制的获得源码,甚至可以从中加进你自己需要的特色。PHP在大多数Unix平台,GUN/Linux和微软Windows平台上均可以运行。怎样在Windows环境的PC机器或Unix机器上安装PHP的资料可以在PHP官方站点上找到。安装过程很简单。
如果你的机器解决了2000问题,那么PHP也一样没有千年虫问题!
1.1 历史
三年前,Rasmus Lerdorf为了创建他的线上简历而创造了"个人主页工具"(Personal Home Page Tools)。这是一种非常简单的语言。其后越来越多的人们注意到了这种语言并对其扩展提出了各种建议。在许多人的无私奉献下以及这种语言本身的源代码自由性质,它演变成为一种特点丰富的语言,而且现在还在成长中。
PHP虽然很容易学习,但是速度上比mod_perl(植入web伺服器的perl模组)慢。现在有了可以与mod_perl速度想媲美的被称作Zend的新引擎,而PHP4就可以充分利用这个引擎。PHP4还处在BETA测试阶段。Andy Gutmans和Zeev Suraki是Zend的主要作者。可以去Zend站点(
http://www.z...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熟悉一点。我不可能做到没有任何遗漏,我的目的只在于能让你迅速开始你的PHP编程。
2.1 首要条件
你首先必须要有一个正在工作着的支援PHP的web伺服器。我假定在你的伺服器上所有PHP档的副档名为.php3。
2.2 PHP的安装
生成一个名为test.php3的档,含有以下内容:
<? phpinfo(); ?>
然后在你的流览器中打开此文件。看看这个页面你就知道你的PHP安装使用的选项了。
2.3 语法
就像前面提到的一样,你可以混合编写你的PHP代码和HTML代码。因此你必须有办法将两者区别开来。以下就是你可以采用的几种方法。你可以选用其中一种你最适应的并且就这样坚持这种方法!
从HTML中分离
以下是可以使用的方法:
<? . . . ?>
<?php . . . ?>
<script language="php"> . . . </script>
<% . . . %>
语句
与Perl和C一样,在PHP中用(;)来分隔语句。那些从HTML中分离出来的标志也表示语句的结束。
注释
PHP支援C,C++和Unix风格的注释方式:
/* C,C++风格多行注释 */
// C++风格单行注释
# Unix风格单行注释
Hello,World!
通过我们已经学过的知识,你可以编写一个最简单的程式输出一个也许是程式世界中最有名的词语:
<HTML>
<HEAD>
<TITLE>
<?
echo "Hello World!";
?>
</TITLE>
</HEAD>
<BODY>
<H1>
First PHP page
</H1>
<HR>
<?
// Single line C++ style comment
/*
printing the message
*/
echo "Hello World!";
# Unix style single line 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 "Doing foo.";
}
}
$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 + "10 Little Piggies"; // $foo是一个整数(15)
$foo = 5 + "10 Small 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 equals 0";
case 1:
print "i equals 1";
case 2:
print "i equals 2";
}
break, continue
break中断当前的回圈控制结构。
continue被用来跳出剩下的当前回圈并继续执行下一次回圈。
require, include
就像C中的#include预处理一样。你在require中指定的那个档将替代其在主文件中的位置。在有条件的引用档时,可以使用include()。这样就使得你可以将复杂的PHP档分割成多个档并且在不同需要时分别引用它们。
2.8 函数
你可以像以下的例子一样定义自己的函数。函数的返回值可以是任何资料类型:
function foo (变数名一, 变数名二, . . . , 变数名n)
{
echo "Example function.\n";
return $retval;
}
所有PHP代码都可以出现在函数定义中,甚至包括对其他函数和类的定义。函数必须在引用之前定义。
2.9 类
利用类模型建立类。可以参考PHP手册中对类的详细解释。
class Employee
{
var $empno; // 员工人数
var $empnm; // 员工姓名
function add_employee($in_num, $in_name)
{
$this->empno = $in_num;
$this->empnm = $in_name;
}
function show()
{
echo "$this->empno, $this->empnm";
return;
}
function changenm($in_name)
{
$this->empnm = $in_name;
}
}
$sbabu = new Employee;
$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>
<P ALIGN="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>
<P ALIGN="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 = "PHP Talk";
$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>
<P ALIGN="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包含以下代码:
<?
/*
|| 一个简单的计数器
*/
function get_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中获取表单数据是很简单的。当一个表单被发送后,表单中所包含的各个元素被赋上了相应的值,而这样就可以像引用一般变数一样使用了。
<FORM name="myform" ACTION="process_form.php3" METHOD="POST">
<INPUT TYPE="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>
<FORM ACTION="sendfdbk.php3" METHOD="POST">
<INPUT TYPE="text" NAME="name" value="Your name" SIZE="20" MAXLENGTH="30">
<INPUT TYPE="text" MAXLENGTH="40" WIDTH="20" value="Your Email" NAME="email">
<BR>
<TEXTAREA ROWS="7" COLS="40" NAME="comment">
Your feedback on my home page.
</TEXTAREA>
<BR>
<INPUT TYPE="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 ? How come you are anonymous?";
}
elseif ($name == "Your name")
{
// 这个流览者真是不想透露姓名啊!
echo "Hello ? <B>Your name</B> is supposed to be replaced with
your actual name!</B>";
}
else
{
// 输出一段礼貌的感谢语
echo "
Hello, $name.
<BR>
Thank you for your feedback. 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>
<FORM ACTION="<? echo "$PHP_SELF"; ?>" METHOD="POST">
<INPUT TYPE="text" NAME="searchstr" value="<? echo "$searchstr"; ?>"
SIZE="20" MAXLENGTH="30">
<INPUT TYPE="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>
<A HREF=\"$fname\">$fname</A> : $fline </LI>\n";
echo "</OL>\n";
}
else
{
// 如果没有查询结果
echo "Sorry. Search on <B>$searchstr</B>
returned no results.<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 查询
假设与资料库已经连接就绪,下面我们就来实际的应用对资料库的查询。下面的代码演示了一个连接并查询的典型例子:
<?
/*
* 连接资料库并执行查询
*/
function printoraerr($in_cur)
{
// 检查Oracle是否出错
// 如果存在错误则显示
// 当指标被启动时每次请求Oracle后调用该函数
if(ora_errorcode($in_cur))
echo "Oracle code - ".ora_error($in_cur)."\n";
return;
}
/** 主程序 */
if (!($conn=ora_logon("user@TNSNAME","password")))
{
echo "Connection to database failed\n";
exit;
}
echo "Connected as connection - <b>$conn</b><br>\n";
echo "Opening cursor ...<br>\n";
$cursor=ora_open($conn); printoraerr($cursor);
echo "Opened cursor - <b>$cursor</b><br>\n";
$qry="select user,sysdate from dual";
echo "Parsing the query <b>$qry</b> ...<br>\n";
ora_parse($cursor,$qry,0); printoraerr($cursor);
echo "Query parsed <br>\n";
echo "Executing cursor ...<br>\n";
ora_exec($cursor); printoraerr($cursor);
echo "Executed cursor<br>\n";
echo "Fetching cursor ...<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 "Fetched all records<br>\n";
echo "Closing cursor ...<br>\n";
ora_close($cursor);
echo "Closed cursor<br>\n";
echo "Logging off from oracle... <br>\n";
ora_logoff($conn);
echo "Logged off from oracle <br>\n";
?>
(译者注:以上代码段缺少注释,请读者参考PHP Manual的Oracle资料库函数部分)
4.3 显示结果
以下代码演示了怎样查询资料库并将结果输出:
<?
function printoraerr($in_cur, $conn)
{
// 检查Oracle是否出错
// 如果存在错误则显示
// 当指标被启动时每次请求Oracle后调用该函数
// If it encountered an error, we exit immediately
if(ora_errorcode($in_cur))
{
echo "Oracle code - ".ora_error($in_cur)."<br>n";
ora_logoff($conn);
exit;
}
return;
}
function exequery($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 "
<TABLE WIDTH=\"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<TH VALIGN=TOP ALIGN=$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 "<TD VALIGN=TOP ALIGN=$align><PRE>".
ora_getcolumn($cursor,$i)."</PRE></TD>\n";
else
echo "<TD VALIGN=TOP ALIGN=$align>".ora_getcolumn($cursor,$i)."</TD>\n";
printoraerr($cursor,$conn);
}
$numrows++;
echo "</TR>\n";
}
if ($numrows==0)
echo "<TR><TD COLSPAN=\"$w_numcols\"><B>Query returned no records
</B></TD></TR>\n";
else
{
echo "<TR>\n";
echo "<TH COLSPAN=\"".($w_numcols-1)."\" ALIGN=RIGHT>Count</TH>\n";
echo "<TH ALIGN=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);
?>
(译者注:以上代码段缺少注释,请读者参考PHP Manual的Oracle资料库函数部分)
4.4 基于HTTP的Oracle登录
将以下代码加在PHP页面代码之前以确认Oracle登录。注意你必须正确设定$ SID。
<?
if(!isset($PHP_AUTH_USER))
{
Header("WWW-authenticate: basic realm=\"$SID\"");
Header("HTTP/1.0 401 Unauthorized");
$title="Login Instructions";
echo "<blockquote>
You are not authorized 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.0 401 Unauthorized");
$title="Login Instructions";
echo "<blockquote>
You are not authorised to enter the site
</blockquote> \n";
exit;
}
}
?>
五、其他功能\
5.1 生成图像
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);
?>
(译者注:以上代码段缺少注释,请读者参考PHP Manual的图像处理函数部分)
这段代码在其他页面中通过以下标记<img src="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 "Hello there, welcome back<BR>";
// 读取cookie并判断
if ( (time() - $VisitedBefore) >= "(60*60*24*7)" )
echo "Why did you 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.0 401 Unauthorized");
echo "Text to send 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.0 401 Unauthorized");
echo "ERROR : $PHP_AUTH_USER/$PHP_AUTH_PW is invalid.";
exit;
}
else
{
echo "Welcome tnc!";
}
?>
事实上再实际引用中不大可能如上面使用代码段明显的用户名称/密码对,而是利用资料库或者加密的密码档存取它们。
5.4 文件上传
你可以利用PHP实现档的功能,注意用户端的流览器应该是Netscape3以上或者IE3以上。以下就是该功能的简单演示:
( upload.html ):
<HTML>
<HEAD>
<TITLE>Upload Your File</TITLE>
</HEAD>
<BODY>
<FORM ACTION="receiver.php3"
ENCTYPE="multipart/form-data" METHOD=POST>
<INPUT TYPE="HIDDEN"
NAME="MAX_FILE_SIZE" VALUE="2000000">
<INPUT TYPE="FILE"
NAME="uploadfile" SIZE="24" MAXLENGTH="80">
<BR><BR>
<INPUT TYPE="SUBMIT" VALUE="Upload File!"
NAME="sendit">
<INPUT TYPE="SUBMIT" VALUE="Cancel"
NAME="cancelit"><BR>
</FORM>
<I><FONT SIZE="2">(You may notice a slight
delay while we upload your 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>php3 Receiving 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 "<P ALIGN=\"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 "<A HREF=\"$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.0 401 Unauthorized");
echo "Sorry, you are 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.0 401 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 have write 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 file is uploaded<BR>\n";
echo "<A HREF=\"$HTTP_REFERER\">Go Back</A><BR>\n";
}
$title = "Upload File";
include("include/header.inc");
if (empty($userfile) || $userfile=="none")
{
// 输出以下表单
?>
<FORM ACTION="<? echo "$PHP_SELF"; ?>" ENCTYPE="multipart/form-data" METHOD=POST>
<INPUT TYPE="HIDDEN" NAME="MAX_FILE_SIZE" VALUE="2000000">
<INPUT TYPE="FILE" NAME="userfile" SIZE="24" MAXLENGTH="80">
<BR><BR>
<INPUT TYPE="SUBMIT" VALUE="Upload File!" NAME="sendit">
<INPUT TYPE="SUBMIT" VALUE="Cancel" NAME="cancelit"><BR>
</FORM>
<I><FONT SIZE="2">(You may notice a slight delay while we upload your file.)</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 our family photos. This PHP script can really
be made better, by splitting into multiple pages.
</P>
<?
$d = dir("photos");
while($entry = $d->read())
{
if (is_file("photos/$entry"))
echo "<IMG SRC=\"photos/$entry\">\n";
}
$d->close();
?>
<?
include("include/footer.inc");
?>
另外,你可以在档上传的表单中加上一个输入元素去描述该上传的档。这个元素将被存储在档中,然后被以上的照片图库的那段代码所读出并显示出来。
六、网路资源
你可以通过web上的众多资源更多的了解PHP3。许多邮件列表和书籍对你都非常有用。
6.1 站点
PHP的爆炸性流行使得一夜之间出现了很多基于PHP的站点,其中不少站点有线上教程、范例代码、技巧和提示等内容。
国内
http://www.ph....com - PHP中文用户,也就是这里了
http://www.p...com - 中国PHP联盟
http://www.ph....net - PHP专门站
http://www.php....com - PHP CHINA
http://www.cpcw.com/nets...page/cgi/ - 电脑报网页陶吧
国外
http://www.p...et/ - PHP官方站点
http://www.dev...com/ - 极好的教程
http://px.sk...com - 代码交换
http://www.phpb....com/ - 教程、专栏和邮件列表档案
http://www.web....com/ - 文章和代码
http://www.phpw....net/ - 提示与技巧
http://www.iometrics.co...ist.php3/ - IOMetrics scripts的档案
http://www.e-gine...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.ph....org - Phorum是一个很完善的BBS系统
http://www.fish...l.org - FishCartSQL是一个电子商务解决方案
http://www.midgar...ct.org - Midgard是一个网路应用开发平台