Perl语言全面编译(四)

3/5/2006来源:Perl教程人气:7794

第六节 HTML模板编程方式——真正的WEB程序 
什么是真正的程序(PRogram)?我们平时使用aspphp这些都不属于程序,它们只是一种页(Page),动态页面(Dynamic Page),但是我们一般称作页面编程(Web Programming),但这种说法不确切(并非不正确)。程序就是程序,并非所有的语言都叫做程序或编程语言。很多权威的书籍、文章和网站(例如:Yahoo!)都没有将ASP、PHP当作程序(编程语言)来解释。ASP是一种语言介质,PHP在Yahoo的定义页只是类似于SSI。他们说要做的东西顶多就是一个“后台(服务器端)的HTML(或者说是Script)”,可以想象,页(Page)和程序(Program)的差异,至少可以说页是由程序来解析输出结果的。那么也就是说,页想要做的事情比程序要局限得多。PHP不是一种程序,如果用ASP或PHP做一个Http服务器,你会有什么感觉?你见过吗?你见过ASP、PHP做的非Web“程序”吗?我想你没有见过。你相信用ASP、PHP编制出类似于Windows的图形(GUI)界面程序吗?那是一种什么感觉呢?所以,做程序和页面是两种不同的概念,在国内不知道是翻译的时候错误,还是大家都是这样理解的。 
如果你要写一个Web页,做一些小动作,用ASP、PHP、ePerl等未尝不可。但是它不是来给你做大宗Web项目或者软件而设计的。至少我是这样认为。而且我觉得Perl目前在程序中直接使用HTML是一种不好的习惯或者行为。它将增加维护成本,降低工作效率等诸多不便因素。其实我觉得外制式的模板方式的HTML套入法是适合时代潮流以及未来软件升级扩展的。至少可以让客户在不触及程序核心的前提下,随意修改界面,可以得到个性化、特性化的设置——未来趋势。而且我们可以降低很大维护的成本,同时某些不变的(诸如:版权、声明、标示)内容仍然可以使用内置式或者在套入模板的过程中进行相应修改等。如果你真的不喜欢他人修改模板,那么你可以使用加密方式,对模板文件进行加密,可以达到程序操作目的,和降低维护成本,而禁止他人修改的目的(推荐使用:Crypt::RC4)。 
本章将会着重讲述在Perl程序中(不但只是为了编译Perl)使用套入法,套入模板HTML,并且进行灵活的HTML操作。 
以下是标准的内置式和外制式的HTML操作: 
内置式HTML程序: 
#!perl 

  

$Var="HELLO WORLD"; 

  

print <
Content-type: text/html 

  

 

 

$Var

 

 

 

  

HTML 

  

exit; 
外置式HTML程序: 

 #!perl 

  

$Var="HELLO WORLD"; 

  

open (HTML,"../HelloWorld.html");#打开HelloWorld.html文件 

@HTML=; 

close (HTML); 

print Content-type :text/html ; 

foreach (@HTML) {#循环 

         $_ =~ s/\*Var/$Var/g;#替换Hellworld.html 文件中*Var的内容为变量$Var的内容 

         print "$_";#输出 

} 

  

exit; 
 
 
外置式HTML文件 HellWorld.html: 
 

 

*Var

 

 

 
 
上面的例子都是现实操作中广泛(流行)用法,大家可能感觉到外置式有些复杂,其实不然,你只要把它做成一个函数或者对象就相当容易了。 
关键问题在于,变量的替换,若使用上面的方法,有些不妥,因为默写模板页面不一定是适合的那些变量,如果你把所有的变量都放在foreach里面,那么势必对于程序运行资源造成极大浪费,而且得不偿失,影响效率。这样做成一个函数或者对象,对会有不通用的问题。 
所以建立一个灵活的分析方法,对于模板HTML处理提供良好的快捷的运作模式。 
这个时候我们就要利用Perl强大的语法分析,来做一个自己的HTML语言分析语句了。这个语句看似简单缺令人头疼。 
我们现在以“*”符号作为模板中的变量(类似于Perl 中的$),这样有助于辨析。那么我想要把所有以“*”开头的变量,自动变换成程序内的对应变量,例如:要把*abc成为内部的$abc。一般情况我们需要逐个设置,这样大大浪费了时间,我们现在需要做一个通用的方法,无论什么的量都自动转换。这个语法很简单: 
$_ =~ /\*(\w )/; 
看似简单的一局话,却有很大的作用,这句就是把以*开头的字符的名找出来,但是有趣的是,你不需要进行太复杂的,只要遇到空格或者其它非标准字符,就会自动排除。 
现在我们要把找到的字符名(即HTML的自定义变量)发给一个临时变量中(该步骤可以不做):$tmp = $1 ; 
现在要做的就是把这个*abc换成量$abc的值: 
$_ =~ s/\*$tmp/$Html{"$tmp"}/g 
这里的$Html是散列变量(HASH),为了方便和容易理解,我在这里采用HASH,这样对应的$Html{‘abc’}就被提出来,换掉*abc了。 
下面就是我做的模板套用函数与例子。 
打开文件的函数RTF: 
#!perl 

  

sub RTF{ 

open(READTXTFILE,"$_[0]"); 

@readtxtfile=; 

close(READTXTFILE); 

return @readtxtfile; 

} 
 
 
分析模板的函数PHF: 
#!perl 

  

sub PHF { 

         my $file = "$_[0]"; 

         @HtmlFileMessages=&RTF("$file");#Open File; 

         foreach (@HtmlFileMessages) { 

                   $_ =~ /\*(\w )/; #替换网页的变量,批量处理,寻找“*
 
--------------------------------------------------------------------------------
 

第七节 联合编译以及实例 
本章至关重要,你已经知道Perl的两种最好的编译方法。但是他们都有利弊,只要稍动脑筋,就可以实现“强强联合”,这样可以尽量避免那些缺憾。 
联合编译的道理很简单,但操作起来也不那样一帆风顺,其中有很多地方值得注意。联合编译主要有一个主程序和多个子程序(FILE)组成。它们之间是使用require函数连接。主程序只做连接等分析工作,子程序做细节工作,包括对象操作,模块引用。我们采用PerlCC 翻译C的方式来编译主程序成为一个可以执行的文件,在把子程序用Bytecode方式编译,这样即可免去无法使用部分模块的问题,也可以直接使用Perl程序,只要在主程序的前面定义一下模块引用路径,方法: 
use lib ‘<路径>’; 
这样就可以了,把那些需要调入的模块,放在制定路径中就好了。而且在CGI或者Socket的网络编程和页面编程中,使用该模是有助于提高效率,降低资源占用率。如果使用整体编译方法,那么每次启动必然会耗费相当大的内存,同样这个程序要重复关闭启动,做Fast CGI也是相当不方便的,这也是Fast CGI在Perl中的最好的方法。根据不同的请求套入不同的子程序。 
首先我们使用 cgi-lib.pl得去POST和GET数据(这个时候有些人会问,为什么不使用cgi.pm,我不是不想用它,而是cgi.pm在perlcc的任何编译模式都会有问题) 
然后根据不同的请求,我在这里设置为action。 
例如: 
require “cgi-lib”; 
if ($in{‘action’} eq “”) { 
require “display.pl”; 
&display; 
exit;#可选 
}elsif ($in{‘action’ }eq “love”) { 
require “love.pl”; 
&love; 
exit;#可选 
} 
这样是很好的。我们使用perlcc 标准编译方法编译它,然后用-b模式编译display.pl和love.pl。然后把它们的名字改回.pl。 
注意在使用perlcc编译程序的时候,编译出来的程序必须带有应用程序扩展文件,如dll和so。因为你的程序还需它们支持,这个文件在Perl的解析软件目录下,例如perl5.6就是perl56.dll,必须把它拷贝到执行文件目录地下。在linux下是.so。你最好在一个没有Perl 平台解析器的环境下进行测试,把那些需要使用的包也包括在里面。即使是VC等软件编译出来的程序,都需要在纯环境下测试,这是必要的。这样就可以测试出程序的一些不必要的问题。 
另外perlcc 的任何模式对语法都是很挑剔的,所以你最好使用比较正规的编写方法,而且单个perl程序如果程序量太大,必须截取到另一个文件中,否则编译后容易出现内存溢出现象。 
大家要知道如果你的子程序使用了ByteCode编译,但是他人仍然可以把你的子程序改成源代码形式,这样就好像我说的会被套出很多量。最好的的方法,是采用ByteCode 编译的程序写入一个Auth认证函数。当然最保险的方法是使用文件内容验证,但是效率影响,我认为不大必要。 
主程序: 
# !perl 

require “cgi-lib”; 

if ($in{‘action’} eq “”) { 

           auth (“display.pl”); 

&display; 

exit;#可选 

}elsif ($in{‘action’ }eq “love”) { 

           auth (“love.pl”); 

           &love; 

           exit;#可选 

} 

sub auth { 

require "$_[0] " ; 

$auth = &check ; 

if ($auth ne "checkabcdefg "){ 

exit ; 

} 

} 
Display.pl 
# !perl 

sub check { 

$check= "checkabcdefg " ; 

return $check ; 

} 

sub display { 

print "content-type :text/html \n\n" ; 

print "hello baby " ; 

} 
 
上面是一种简单的,不过也会造成一些问题,所以下面是一个麻烦(并非复杂)方法,但是很安全。 
检查编译程序是否真实: 
# !perl 

open (FILE,"./print.pl"); 

@FILE=; 

close (FILE); 

foreach (@FILE) { 

         if ($_ =~/程序编译后的部分代码/){ 

         }else {exit ;} 

} 
 
首先把程序进行bytecode编译,然后截取部分独特的其它程序没有的代码,放入其中,来检查引入程序是否正确合法。 
你可以把bytecode的程序改名成.dll等,这样其它人就不知道是怎么回事啦。 
结束语 
Perl是一个强大的而且是最早的解析性程序语言,它的编译程序是B模块,大家可以详细常见,它有多种编译方式,都是采用反向编译(BackEnd)不同于反编译。所以经本上是不可能被反编译。我认为本文对所有的Perl程序员都有很大的帮助。 
Perl还有很多其它方式的编译、加密方法,但是我觉得本文介绍的几种方式都是最好的(兼容性和运行效率),有一些人,把写的程序进行部分字符乱码或者是取消缩近的书写格式(把所有程序写在一行上),我认为这些方法是“愚蠢的”,所以建议大家不要花那么多时间去研究这些“无谓”的东西。 
部分字符编码例子——原本: 
# !perl 

sub Hello { 

      $hello=abc ; 

print $hello ; 

} 

  

&hello ; 
部分字符编码例子——编码后 
# !perl 

sub adfjierei123489dkajd_dfefnkdj { 

$iernvmdnvcjnaldffgh=abc; 

print $iernvmdnvcjnaldffgh; 

} 

&adfjierei123489dkajd_dfefnkdj; 
 
我希望通过本文促使Perl在国内的商业发展,也同样加快了Perl技术在国内的发展速度。但是我仍然希望大家可以写更多的公开源代码的程序出来,这样可以让初学者有较快的提高速度。 
如果你有任何问题和想法都可以通过电子邮件(tanshuai@BIGFOOT.COM, tanshuai@163.COM, tanshuai@TANSHUAI.NET)或者ICQ:25856530 OICQ:66552联络我,其它资料可以到我的网站查询http://www.tanshuai.net http://www2.tanshuai.net        (全文完)