资源描述
CGI编程的COOKIE技术应用
我们在一些留言本、BBS讨论区发贴时常会出现这种现象:当进入发贴界面时在要求填写用户名和密码的地方就已经自动地填上了你的资料。这是什么会事呢?这是因为程序中引入了COOKIE技术的缘故。原来在你第一次登录时,程序就已在你的电脑中安装了一个COOKIE信息包,在你今后登陆时电脑就自动检索你的COOKIE并取出信息包的信息供程序调用,所以出现上面所述的现象。
COOKIE只不过是CGI程序要求浏览器持有的一个信息包,这个信息包可以由CGI程序在任何时候收回。每当CGI程序要求创建COOKIE时,COOKIE可以从服务器传送到浏览器所属的子目录下(通常是保存在C:\WINDOWS\Temporary Internet Files的目录下,这个过程称为COOKIE的安装。
COOKIE的安装和读出通常都由一个CGI模块来完成,下面我就将此模块的原代码公布给大家,有了这个COOKIE模块我们在编写程序时如要应用COOKIE技术可以说易如反掌。
cookie的语法:
http cookie的发送是通过http头部来实现的,他早于文件的传递,头部set-cookie的语法如下:
Set-cookie:name=name;expires=date;path=path;domain=domain;secure name=name: 需要设置cookie的值(name不能使用“;”和","号),有多个name值时用";"分隔例如:name1=name1;name2=name2;name3=name3。
expires=date: cookie的有效期限,格式: expires="Wdy,DD-Mon-YYYY HH:MM:SS"
path=path: 设置cookie支持的路径,如果path是一个路径,则cookie对这个目录下的所有文件及子目录生效,例如:path="/cgi-bin/",如果path是一个文件,则cookie指对这个文件生效,例如:path="/cgi-bin/cookie.cgi"。
domain=domain: 对cookie生效的域名,例如:domain=""
secure: 如果给出此标志,表示cookie只能通过SSL协议的https服务器来传递。
cookie的接收是通过设置环境变量HTTP_COOKIE来实现的,CGI程序可以通过检索该变量获取cookie信息。
以下是一个cookie的模块,可以为你编写程序带来方便
$Cookie_Exp_Date = '';#此处设置cookie的有效时间
$Cookie_Path = '';#此处设置cookie的有效路径,默认脚本存在的目录。
$Cookie_Domain = ''; #此处设置cookie的有效域名,默认脚本调用的域名。
$Secure_Cookie = '0';
@Cookie_Encode_Chars = ('\%', '\+', '\;', '\,', '\=', '\&', '\:\:', '\s');
%Cookie_Encode_Chars = ('\%', '%25',
'\+', '%2B',
'\;', '%3B',
'\,', '%2C',
'\=', '%3D',
'\&', '%26',
'\:\:', '%3A%3A',
'\s', '+');# 特殊字符的解码
@Cookie_Decode_Chars = ('\+', '\%3A\%3A', '\%26', '\%3D', '\%2C', '\%3B', '\%2B', '\%25');
%Cookie_Decode_Chars = ('\+', ' ',
'\%3A\%3A', '::',
'\%26', '&',
'\%3D', '=',
'\%2C', ',',
'\%3B', ';',
'\%2B', '+',
'\%25', '%');# 特殊字符的解码
#########获取cookie信息子程序#####################
sub GetCookies {
local(@ReturnCookies) = @_;
local($cookie_flag) = 0;
local($cookie,$value);
if ($ENV{'HTTP_COOKIE'}) {
if ($ReturnCookies[0] ne '') {
foreach (split(/; /,$ENV{'HTTP_COOKIE'})) {#分割HTTP_COOKIE变量的字符串
($cookie,$value) = split(/=/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;#调用转码函数
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;#调用转码函数
}
foreach $ReturnCookie (@ReturnCookies) {
if ($ReturnCookie eq $cookie) {
$Cookies{$cookie} = $value;
$cookie_flag = "1";
}
}
}
}
else {
foreach (split(/; /,$ENV{'HTTP_COOKIE'})) {
($cookie,$value) = split(/=/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
$Cookies{$cookie} = $value;
}
$cookie_flag = 1;
}
}
return $cookie_flag;
}
########## 设置Cookie信息子程序#######################
sub SetSecureCookie {
if ($_[0] =~ /^[01]$/) {
$Secure_Cookie = $_[0];
return 1;
}
else {
return 0;
}
}
sub SetCookies {
local(@cookies) = @_;
local($cookie,$value,$char);
while( ($cookie,$value) = @cookies ) {
foreach $char (@Cookie_Encode_Chars) {
$cookie =~ s/$char/$Cookie_Encode_Chars{$char}/g;#调用转码函数
$value =~ s/$char/$Cookie_Encode_Chars{$char}/g;#调用转码函数
}
print 'Set-Cookie: ' . $cookie . '=' . $value . ';';#设置cookie值
if ($Cookie_Exp_Date) { print ' expires=' . $Cookie_Exp_Date . ';'; }#设置有效时间
if ($Cookie_Path) { print ' path=' . $Cookie_Path . ';'; }#设置有效路径
if ($Cookie_Domain) { print ' domain=' . $Cookie_Domain . ';'; }#设置有效域名
if ($Secure_Cookie) { print ' secure'; }
print "\n";
shift(@cookies); shift(@cookies);
}
}
sub SetCompressedCookies {
local($cookie_name,@cookies) = @_;
local($cookie,$value,$cookie_value);
while ( ($cookie,$value) = @cookies ) {
foreach $char (@Cookie_Encode_Chars) {
$cookie =~ s/$char/$Cookie_Encode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Encode_Chars{$char}/g;
}
if ($cookie_value) { $cookie_value .= '&' . $cookie . '::' . $value; }
else { $cookie_value = $cookie . '::' . $value; }
shift(@cookies); shift(@cookies);
}
&SetCookies("$cookie_name","$cookie_value");
}
sub GetCompressedCookies {
local($cookie_name,@ReturnCookies) = @_;
local($cookie_flag) = 0;
local($ReturnCookie,$cookie,$value);
if (&GetCookies($cookie_name)) {
if ($ReturnCookies[0] ne '') {
foreach (split(/&/,$Cookies{$cookie_name})) {
($cookie,$value) = split(/::/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
foreach $ReturnCookie (@ReturnCookies) {
if ($ReturnCookie eq $cookie) {
$Cookies{$cookie} = $value;
$cookie_flag = 1;
}
}
}
}
else {
foreach (split(/&/,$Cookies{$cookie_name})) {
($cookie,$value) = split(/::/);
foreach $char (@Cookie_Decode_Chars) {
$cookie =~ s/$char/$Cookie_Decode_Chars{$char}/g;
$value =~ s/$char/$Cookie_Decode_Chars{$char}/g;
}
$Cookies{$cookie} = $value;
}
$cookie_flag = 1;
}
delete($Cookies{$cookie_name});
}
return $cookie_flag;
}
########结束#################
下面是cookie信息包安装代码段
<SCRIPT LANGUAGE="JavaScript">
<!-- HIDE
expireDate = new Date;
if (expireDate.getYear() < 100) {
expireDate.setYear(expireDate.getYear() + 1900 + 1);
} else {
expireDate.setYear(expireDate.getYear()+1);
}
var username = getCookie("UserName");
var password = getCookie("Password");
if (password == null) {
var CookieName = "$username";
var CookiePW = "$userpsd";
if (password == null) {
document.cookie = "username=" + CookieName + ";expires=" + expireDate.toGMTString() + ";";
document.cookie = "password=" + CookiePW + ";expires=" + expireDate.toGMTString() + ";";
}
}
function getCookie(name){
var cname = name + "=";
var dc = document.cookie;
if (dc.length > 0) {
begin = dc.indexOf(cname);
if (begin != -1) {
begin += cname.length;
end = dc.indexOf(";", begin);
if (end == -1) end = dc.length;
return dc.substring(begin, end); }
}
return null;
}
// STOP HIDING FROM OTHER BROWSERS -->
</SCRIPT>
###########结束#####################
下面是读取信息包代码,很简单:
&GetCookies;
$name=$Cookies{'username'};
$pass=$Cookies{'password'};
本站用的“BBS讨论区”程序和本人写的“会员管理”程序就采用了此模块。思维稿
MYSQL数据库的使用方法
现在网上有很多交互式的程序如BBS、留言本等都使用PHP来编写,而PHP是支持MYSQL数据库的,因此很多人在用PHP编程时都使用MYSQL数据库。最近有一个网友送给我一份用PHP+MYSQL编写的留言本程序,在这里我将在调试此程序的体会讲一下(重点是MYSQL数据库部分),希望能对喜欢PHP+MYSQL的朋友提供有用的参考。
此程序由4个文件组成,一个是显示贴子的子程序,一个是贴子输入程序,一个是产生框架结构页面的HTM文件,一个是数据库结构文本文件。要使用此程序,你的空间必须要支持PHP和MYSQL数据库,我现在使用的空间是由WWW.51.NET所提供的满足上述要求。安装此程序的第一步是要安装程序所用的数据库,要成功生成一个数据库你必须要知道你的MYSQL服务器的主机名、密码、和在MYSQL服务器中分配给你使用的数据库目录名,这些参数都由ISP商提供给你,然后用文本编辑器编写一个数据库结构的一般文本文件,格式如下:
设你的主机名是:localhost;密码是:12345;用户名:gzdzw;数据库目录名:test
# 数据表的结构表 'catv'
#
CREATE TABLE catv (
id int(11) NOT NULL auto_increment,
mail varchar(60),
home varchar(60),
content text,
reply text,
aaa varchar(20),
ip varchar(255),
replydate varchar(255),
date varchar(255),
name varchar(10),
PRIMARY KEY (id)
);
接着用phpMyAdmin程序(此程序是一个专门针对MYSQL数据库而编写的PHP程序,它可对MYSQL数据库进行包括:数据库的生成、数据库结构的修改、字段的修改、数据的删除、数据库结构和数据的导出和导入等操作,是使用MYSQL的必备工具程序。此程序在网上有很多网站都提供免费下载。)下面讲一讲此程序的设置:
找到此程序下的文件:config.inc.php,修改其中的
$cfgServers[1]['host'] = 'localhost'; // 你的主机名
$cfgServers[1]['port'] = ''; // 端口设置,空为默认值可不作修改
$cfgServers[1]['adv_auth'] = false; // 出错处理,false是默认值可不修改。
$cfgServers[1]['stduser'] = 'root'; // MYSQL默认用户名
$cfgServers[1]['stdpass'] = ''; // MYSQL默认用户密码(一般为空)
$cfgServers[1]['user'] = 'gzdzw'; // MySQL指定使用者的用户名
$cfgServers[1]['password'] = '12345'; // MySQL指定使用者的密码
$cfgServers[1]['only_db'] = 'test'; // 指定使用的数据库目录名
$cfgServers[1]['verbose'] = ''; // 指定使用的数据库名
然后修改require("english.inc.php");为require("chinese_gb.inc.php");这时程序运行时将显示中文。
修改完毕后,将整个程序用FTP软件上传到你的使用空间,然后运行index.php出现上图的界面,双击左上角的数据库目录名(分配给你的数据库目录名),会出现下图的界面,此时点选“浏览”按钮选取你的库结构文件,然后按“开始”按钮这时程序就自动地将数据库结构导入到MYSQL数据库中并产生一个名为CATV的数据库文件了,OK!此时你就可以调试你的程序了。
那末如何在本地机上调试MYSQL的程序呢?很简单只要安装一个MYSQL服务器软件(在网上有下载),再将phpMyAdmin的config.inc.php文件修改一下就万事大吉了。本站的“站务论坛”就是应用了MYSQL数据库技术编写的。思维稿
SMTP服务器软件的设置
ADR(Advanced Direct Remailer)是一套专门发送邮件的软件,它能够更快、更安全、简便地发送邮件,通过它不仅能节省金钱,还能节省时间。ADR的主要功能是在我们自己的微机上建立一个本地SMTP服务器,在发送邮件时使用自身的SMTP端口而不需使用ISP提供的发信服务器,ADR通过DNS解析收件人的地址把邮件直接快速地发送到对方的邮件服务器上。在此期间,由于不受ISP提供的SMTP服务器是否拥挤的影响,而且几乎不用转发服务器,所以邮件发送更加快速、更加安全,而不会造成丢信的现象,更不会因为SMTP服务器的关闭而影响邮件的发送。对于经常使用E-mail的广大网友来说,不失为一种绝好的选择。下面,将ADR的使用方法详细介绍给大家。
一、软件的下载和安装
我们可以到
二、软件的使用
软件安装完毕后,会在“程序”组中生成Advanced Direct Remailer项,在桌面上生成快捷图标。双击快捷图标执行程序后,软件会退至任务栏托盘内,形成一个蓝色箭头状的小图标。右击这个图标,会弹出一个菜单,程序提供的各种功能可以在这个菜单中进行调用。
1.ADR的设置:
在右击图标弹出的菜单中选择“General Settings”,弹出设置窗口,在设置窗口中共有八个标签,下面我们分别予以介绍:
●General:在这个标签页中共有八个复选框:“Run program when Windows startup”,如果选中,则表示软件将随系统同时启动;“Show Monitor window always topmost”,如果选中此项,则软件的窗口始终在桌面的最上方,不被其他窗口覆盖;“Delete messages after sending,don't move it in ‘Sent’”,这个选项如果被选中,则发送的邮件信息将被直接删除,而不是放到Sent文件夹中;“Integration with Eserv”,建议选中这个选项,因为Eserv网站是一个集邮件服务器、新闻服务器、代理服务器、Web服务器于一身的服务器,把这个选项选中,软件将会更好地运行;“Beep when message is moved in ‘Bad’”,当发送出现错误并把邮件转移到Bad文件夹中时发声;“Beep when all mail will be sent”,当发送所有邮件时发声(这里提到的发声是通过声卡的外接喇叭发声,而不是通过计算机的小喇叭);“Use message priority in Outbox queue”,如果把此项选中,则在发送邮件时,将首先发送标识为高优先级的邮件;而最后一项“Use delay list”则是过滤垃圾邮件之用。在这几个选项中,我们可以根据自己的情况灵活选用。
●Actions:在这个标签页中设置邮件的发送情况。在“Start delivery”中有三个单选按钮:“Manually throught program menu”表示通过手工发送邮件;“When dial-up connection is established”表示通过指定的连接进行发送,而如果此时连接的名称设定为“Any connection”,则表示只要连接到互联网上就会发送邮件;“Automatically when mail present in Outbox”是给使用专线之类长期在线的用户设置的,自动发送邮件。在“Purge old mail”中有两个选项:“In Sent box after several last days”表示如果在“Sent box”(待发信箱)中信件存放超过指定天数,则将其删除,默认是15;“In Bad box after several last days”就表示在“Bad Box”中的信息存放到指定天数时将其删除。
●DNS:ADR需要指定DNS(即域名服务器),它需要通过DNS解析收件人的邮件地址。这个DNS服务器地址,我们可以向ISP询问,也可以在软件运行时连入互联网,在这个页面内的“Windows DNS setting”下有显示,按显示顺序顺次填入“Primary DNS”(主控DNS)、“Secondary DNS”(辅助DNS)中。在该页面内还有两个复选框,一个是“Try to deliver by name to host,if host was not found in DNS”,默认状态下是选中该项,不用更改。第二个选项是“Don't use internal DNS cache”,这个选项不要选中。因为在发送邮件时,如果不使用DNS cache,则会在每次发送时都要通过DNS进行搜索,即使是向同一个邮件服务器发送邮件也是如此,而如果使用DNS cache,则在向相同的邮件服务器发送邮件时只须DNS解析一次即可,这样能够提高发信速度。
●Proxy:ADR支持Socks5代理服务器,如果我们是通过代理服务器接入互联网,就可以在这个页面里把代理服务器的地址填入,否则不要进行设置。
对于其他几个标签页,如Logs、Mailbox等不用设置,软件即可正常工作。
2.邮件软件的设置
ADR运行之后,我们自己的微机上就已经开通了一个SMTP服务器,所以在发邮件时再也不用通过ISP提供的SMTP服务器了,那么在收发邮件的软件中该如何进行设置呢?
在Outlook Express 5.0中,我们可以选择主菜单上的“工具”→“账号”,选择“邮件”标签,选中邮件名称,按下“属性”按钮,选择“服务器”标签,在“外发邮件(SMTP)”中输入“localhost”,也就是本机地址,或者填入127.0.0.1,按下“确定”即可。
在FoxMail中,选择主菜单上的“账户”→“属性”,选择“邮件服务器”,在“发送邮件服务器”中填入“localhost”。
如果是在局域网中,则需要查询一下安装ADR软件的IP地址(局域网内地址),然后把其他机器邮件软件的发送邮件服务器地址填为这个地址即可。
3.邮件的发送
把ADR和邮件软件设置好后,我们就可以通过我们自己的机器向外直接发送邮件了。和以前一样,在OE或者FoxMail中撰写好一封邮件,然后按下发送按钮,我们就会看到邮件非常快速地被发送出去。但邮件真的被发到了对方的邮件服务器上了吗?不是,邮件首先被发送到ADR构造的SMTP服务器上,此时我们需要右击托盘内的图标,选择“Open Monitor”查看一下。
在Monitor界面上我们可以看到三个标签,一个称为“OutBox”,一个是“Sent”,另一个是“Bad”。我们在邮件软件中发送的邮件被送到OutBox中待发。如果我们在前面设置时把ADR设置为手工发送邮件。在这里可以按下“发送”快捷按钮(黑三角形)进行真正的发送邮件,选择主菜单上的“Delivery”-“Run Delivery”也可以完成这个功能。发送时,在下面的提示行内会有一个蓝色的进度指示条表示邮件发送的进度,当待发邮件全部发送出去后,OutBox将会被清空。如果在发送中途想中止或停止发送,可以按下“暂停”按钮或“终止”按钮。
发送邮件也可以不打开Monitor程序,而直接右击托盘内的图标,选择“Run Delivery”进行发送,选择“Pause Delivery”暂停,选择“Stop Delivery”终止发送。
由于这款软件不经过ISP提供的SMTP服务器,所以发信速度很快,尤其是发送大邮件时更加明显。同时,经过ADR发送的邮件直接传输到对方的邮件服务器上,我们在邮件发出后,对方可以马上收到,几乎不存在延迟现象。但由于它是一款英文软件,对于一般网友来说在使用过程中稍有困难,好在它的操作、设置都非常简单。
CGI聊天室程序的剖析
一般用CGI编写的聊天程序其页面结构均为框架式结构,通常分为四个框架:聊天区、在线人员名单显示区、发言区、其他项目附加区。这些区都显示由CGI程序所生成的四个不同的页面。
一、发言区
发言区其实是一个普通表单页面,根据功能的多少可设置多个参数,如发言者的表情、字体颜色、悄悄话、发言内容、发言者的姓名等,每一个功能都有一个对应的变量,这些变量通过提交按钮传给服务器端的CGI程序进行处理。
另外,在此区内还可设置一些必要的管理功能,如聊天区的清屏、人员管制(如踢人功能)等功能。这些功能的提交方式一般是用超连接方式进行,即运行CGI程序的相应模块来完成相应的操作。
二、在线人员名单显示区
此区主要是显示在线聊天的人员名单,进入聊天室的人员首先需通过一个入口表单,填入如姓名、密码、性别等参数,然后提交到CGI程序,程序就会将此人的这些资料写入到一个在线人员记录文件中,然后利用<META HTTP-EQUIV=REFRESH CONTENT=12;URL=聊天主程序?job=运行参数>这条语句对此文件进行定时读取和写入(定时时间可自定),并将读取的数据显示在“在线人员名单显示区”内同时程序还定时地对在线人员是否离线进行检测,如某人已离线,程序将清除此人在人员记录数据文件中的资料。
三、聊天区
当在发言区按下提交按钮后,表单的所有参数都通过CGI程序写入到一个聊天内容记录文件中,同时也是利用<META HTTP-EQUIV=REFRESH CONTENT=12;URL=聊天主程序?job=运行参数>这条语句对此文件进行定时读取和写入,将读取的此记录文件中的内容显示在聊天区内,并写入新的发言内容。即对聊天内容记录文件进行不断的定时刷新。
四、其他项目附加区
此区一般都是放置一些作者信息或其他的辅助功能。
综上所述,聊天室程序一般由六大块模块所组成:
1、入口登陆信息处理模块。
2、发言表单生成模块。
3、在线人员读写显示模块。
4、聊天内容读写显示模块。
5、框架页面生成模块。
6、基本设置模块。
从以上分析可知,程序在运行时要不断地对记录文件进行读写,这严重地耗费服务器的资源,使服务器运行其他程序的速度变慢,难怪ISP商们都严禁将这种聊天程序放在普通服务器上运行。
本人编写的CGI聊天程序就以此思路进行编写的,初学CGI编程的朋友可随意下载回去作为学习参考。思维稿
CGI程序运行时数据丢失的改进
在用PERL写的CGI程序在运行当中,常常会发生数据文件丢失的问题,如本站的浏览计数程序就曾经发生过多次数据丢失的情况。这是什么原因呢?据我分析,数据丢失是发生在多个用户对数据文件进行操作时。在程序中对数据文件中的数据更新的程序通常如下:
open(re,"tj.txt");#设此时tj.txt文件里面的数据为100
$a=<re>;
close(re);
$a++;
open(WR,">tj.txt");#注意此时tj.txt数据文件已经被清空
print WR "$a";
close(WR);
执行上面的程序后,数据文件tj.txt里面的数据应该为101。如两个人在一定的时间差内执行以上程序,当第一个人执行完open(WR,">tj.txt");这一语句(注意此时tj.txt数据文件已经被清空),这个时候第二个人刚好跟着执行这一语句,有于数据文件里面的数据是空的,那么变量a的值为零,当后者执行完整个进程后,显而易见,数据文件里面的数据为1。综观整个进程,造成数据丢失的关键语句是open(WR,">tj.txt");。
针对以上问题,有两种改进方法:
1、给数据文件加锁,即当某一进程打开数据文件后,马上对这一数据文件加锁,防止了其他进程使用它。在完成了对数据文件的操作后,才对数据文件解锁,释放给其他进程使用。加锁语句:flock(WR,1),只要将此语句放到open(WR,">tj.txt")的下面即可,当进程执行完close(WR)语句后,将自动解锁。此语句只能在UNIX和WINDOWS NT系统下使用。
2、将open(WR,">tj.txt")语句改成open(WR,"+〈tj.txt"),在执行此语句时,并不清空数据文件里面的数据,从而防止了数据丢失。思维稿
展开阅读全文