在学python的过程中,一直弄不明白sys.argv[]的意思,虽知道是表示命令行参数,但还是有些稀里糊涂的感觉。

今天又好好学习了一把,总算是大彻大悟了。

Sys.argv[]是用来获取命令行参数的,sys.argv[0]表示代码本身文件路径,所以参数从1开始,以下两个例子说明:

1、使用sys.argv[]的一简单实例,

import sys,os
os.system(sys.argv[1])

这个例子os.system接收命令行参数,运行参数指令,保存为sample1.py,命令行带参数运行sample1.py notepad,将打开记事本程序。

2这个例子是简明python教程上的,明白它之后你就明白sys.argv[]了。

import sys
def readfile(filename):  #从文件中读出文件内容
'''Print a file to the standard output.'''
f = file(filename)
while True:
line = f.readline()
if len(line) == 0:
break
print line, # notice comma  分别输出每行内容
f.close()
# Script starts from here
if len(sys.argv) < 2:
print 'No action specified.'
sys.exit()
if sys.argv[1].startswith('--'):
option = sys.argv[1][2:]
# fetch sys.argv[1] but without the first two characters
if option == 'version'#当命令行参数为-- version,显示版本号
print 'Version 1.2'
elif option == 'help'#当命令行参数为--help时,显示相关帮助内容
print '''"
This program prints files to the standard output.
Any number of files can be specified.
Options include:
--version : Prints the version number
--help    : Display this help'''
else:
print 'Unknown option.'
sys.exit()
else:
for filename in sys.argv[1:]: #当参数为文件名时,传入readfile,读出其内容
readfile(filename)

 

保存程序为sample.py.我们验证一下:

命令行带参数运行:sample.py –version 输出结果为:version 1.2

命令行带参数运行:sample.py –help 输出结果为:This program prints files……

在与sample.py同一目录下,新建a.txt的记事本文件,内容为:test argv;命令行带参数运行:sample.py a.txt,输出结果为a.txt文件内容:test argv,这里也可多带几个参数,程序会先后输出参数文件内容。

posted @ 2009-03-23 16:43 小马歌 阅读(956) | 评论 (0)编辑 收藏
 
提出解决办法的是微软某个MVP工程师,方法是在注册表添加某个键值:
在HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main添加DWORD项RunOnceHasShown,RunOnceComplete并修改成1!
行是行,但是没开启CLEARTYPE,而且每次新建标签都要弹到about:tabs那去
posted @ 2009-03-23 10:26 小马歌 阅读(190) | 评论 (0)编辑 收藏
 


php include_path设置
2008-12-25 10:16

一般情况下,我们设置php的include_path都会通过修改php.ini来实现。
有时候,我们没有服务器的权限。有时候,我们把一个目录加到include_path会让已有的程序冲突。受cakephp的启发:在app/webroot目录下index.php有如下代码
ini_set('include_path', CAKE_CORE_INCLUDE_PATH . PATH_SEPARATOR . ROOT . DS . APP_DIR . DS . PATH_SEPARATOR . ini_get('include_path'));
我们看到这个程序动态修改include_path。不过cake在这儿是把 CAKE_CORE_INCLUDE_PATH 和 APP_DIR 加到 include_path里,并且优先在这两个目录下找包含程序。
注意到它这里用到了PATH_SEPARATOR这个变量。这样这段代码在windows和linux下能通用。

从中受到启发,我们可以根据自己的需要把一些include目录动态的加入进来。比如说我们有很多libs:lib1,lib2,lib3等等。我们不必把这些libs都加到include_path里,因为它们之间可能冲突。
可以建立一个inc_dir,并把这个目录加入到include_path。在inc_dir下,分别建立inc_path1.php inc_path2.php inc_path3.php
分别写入
<?php
ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.$dirToLib1);
<?php
ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.$dirToLib2);
<?php
ini_set('include_path', ini_get('include_path').PATH_SEPARATOR.$dirToLib3);

在写程序的时候,比如要用lib2的functions.php
就可以这么写
<?php
require 'inc_path2.php';
require 'functions.php';
//....

来源:http://hi.baidu.com/_doc/blog/item/f3135fdf16b38e16495403a7.html

posted @ 2009-03-20 10:34 小马歌 阅读(1148) | 评论 (0)编辑 收藏
 

from:http://huaidan.org/archives/2085.html

一、验证码的基本知识

1. 验证码的主要目的是强制人机交互来抵御机器自动化攻击的。

2. 大部分的验证码设计者并不得要领,不了解图像处理,机器视觉,模式识别,人工智能的基本概念。

3. 利用验证码,可以发财,当然要犯罪:比如招商银行密码只有6位,验证码形同虚设,计算机很快就能破解一个有钱的账户,很多帐户是可以网上交易的。

4. 也有设计的比较好的,比如Yahoo,Google,Microsoft等。而国内Tencent的中文验证码虽然难,但算不上好。

二、人工智能,模式识别,机器视觉,图像处理的基本知识

1)主要流程:

比如我们要从一副图片中,识别出验证码;比如我们要从一副图片中,检测并识别出一张人脸。 大概有哪些步骤呢?

1.图像采集:验证码呢,就直接通过HTTP抓HTML,然后分析出图片的url,然后下载保存就可以了。 如果是人脸检测识别,一般要通过视屏采集设备,采集回来,通过A/D转操作,存为数字图片或者视频频。

2.预处理:检测是正确的图像格式,转换到合适的格式,压缩,剪切出ROI,去除噪音,灰度化,转换色彩空间这些。

3.检测:车牌检测识别系统要先找到车牌的大概位置,人脸检测系统要找出图片中所有的人脸(包括疑似人脸);验证码识别呢,主要是找出文字所在的主要区域。

4.前处理:人脸检测和识别,会对人脸在识别前作一些校正,比如面内面外的旋转,扭曲等。我这里的验证码识别,“一般”要做文字的切割

5.训练:通过各种模式识别,机器学习算法,来挑选和训练合适数量的训练集。不是训练的样本越多越好。过学习,泛化能力差的问题可能在这里出现。这一步不是必须的,有些识别算法是不需要训练的。

6.识别:输入待识别的处理后的图片,转换成分类器需要的输入格式,然后通过输出的类和置信度,来判断大概可能是哪个字母。识别本质上就是分类。

2)关键概念:

图像处理:一般指针对数字图像的某种数学处理。比如投影,钝化,锐化,细化,边缘检测,二值化,压缩,各种数据变换等等。

1.二值化:一般图片都是彩色的,按照逼真程度,可能很多级别。为了降低计算复杂度,方便后续的处理,如果在不损失关键信息的情况下,能将图片处理成黑白两种颜色,那就最好不过了。

2.细化:找出图像的骨架,图像线条可能是很宽的,通过细化将宽度将为1,某些地方可能大于1。不同的细化算法,可能有不同的差异,比如是否更靠近线条中间,比如是否保持联通行等。

3.边缘检测:主要是理解边缘的概念。边缘实际上是图像中图像像素属性变化剧烈的地方。可能通过一个固定的门限值来判断,也可能是自适应的。门限可能是图像全局的,也可能是局部的。不能说那个就一定好,不过大部分时候,自适应的局部的门限可能要好点。被分析的,可能是颜色,也可能是灰度图像的灰度。

机器视觉:利用计算机来模式实现人的视觉。 比如物体检测,定位,识别。按照对图像理解的层次的差别,分高阶和低阶的理解。

模式识别:对事物或者现象的某种表示方式(数值,文字,我们这里主要想说的是数值),通过一些处理和分析,来描述,归类,理解,解释这些事物,现象及其某种抽象。

人工智能:这种概念比较宽,上面这些都属于人工智能这个大的方向。简单点不要过分学院派的理解就是,把人类的很“智能”的东西给模拟出来协助生物的人来处理问题,特别是在计算机里面。

三、常见的验证码的破解分析

以http://libcaca.zoy.org/wiki/PWNtcha这里PWNtcha项目中的资料为例分析,各种验证码的破解。(方法很多,仅仅从我个人乍看之下觉得可行的方法来分析)

1)Authimage


使用的反破解技巧:

1.不连续的点组成字符
2.有一定程度的倾斜

设计不好的地方:

1.通过纵横的直方图投影,可以找到字幕区域
2.通过Hough变换,适当的参数,可以找到近似的横线,可以做倾斜矫正
3.字符串的倾斜式面内的,没有太多的破解难度
4.字母宽度一定,大小一定

2)Clubic


使用的反破解技巧:

1.字符是手写体

设计不好的地方:

1.检测切割阶段没有任何技术含量,属于设计的比较丑的
2.只有数字,而且手写体变化不大
3.表面看起来对识别阶段有难度,仔细分析,发现几乎不用任何高级的训练识别算法,就固定的招某些像素点是否有色彩就够了

3)linuxfr.org


使用的反破解技巧:

1.背景颜色块
2.前景的横线或矩形

设计不好的地方:

1.背景色是单一色块,有形状,通过Region-Growth区域增长来很容易把背景给去掉
2.前景色是标准的线条,色彩单一
3.字母无粘连
4.都是印刷体

4)Ourcolony


使用的反破解技巧:

1.设计的太低级,不屑于去评价

设计不好的地方:

1.这种验证码,设计的最丑,但还是能把菜鸟搞定,毕竟学计算机的少,搞这个破解的更少,正所谓隔行如隔山

5)LiveJournal


使用的反破解技巧:

1.这个设计略微好点,使用个随机噪音,而且作为前景
2.字母位置粗细都有变化

设计不好的地方:

1.字母没有粘连
2.噪音类型单一
3.通过在X轴的直方图投影,能准确分割字幕
4.然后在Y周作直方图投影,能准确定位高度
5.识别阶段,都是印刷体,简单地很

四、网上的一些高级验证码

1)ICQ


2)IMDb


3)MS MVPS

4)MVN Forum

这些类型是被很多人认为比较难得类型,分析一下可以发现,字符检测,定位和分割都不是难。 唯一影响识别率的是IMDBb和MVPS这两类,字体变形略大。

总体来说,这些类型的破解也不难,很容易做到50%以上的识别率。

五、高级验证码的破解分析

时间关系,我简单介绍如何利用图像处理和模式识别技术,自动识别比较高级的验证码。
(以风头正劲的Google为例)


1)至少从目前的AI的发展程度看,没有简单的做法能自动处理各种不同的验证码,即使能力很强,那么系统自然也十分复杂强大。所以,要想在很简单的算法实现比较高级的验证码破解,必须分析不同验证码算法的特点:

作为一般的图像处理和计算机视觉,会考虑色彩,纹理,形状等直接的特征,同时也考虑直方图,灰度等统计特征,还考虑FFT,Wavelet等各种变换后的特征。但最终目标都是Dimension Reduction(降维)然后利于识别,不仅仅是速度的考虑。从图像的角度看,很多系统都考虑转换为灰度级甚者黑白图片。
 
Google的图片可以看出,颜色变化是虚晃一枪,不存在任何处理难度。难度是字体变形和字符粘连。
 
如果能成功的分割字符,那么后期识别无论是用SVM等分类算法,还是分析笔顺比划走向来硬识别,都相对好做。
 
2)图像处理和粘连分割

代码中的part1目录主要完成图像预处理和粘连字符分割
001:将图像从jpg等格式转换为位图便于处理
002:采用Fix/Adaptive的Threshold门限算法,将图片Bin-Value二值化。
(可用003算法)
003:采用OSTU分水岭算法,将图片Bin-Value二值化。
(更通用,大部分时候效果更好)
005:获取ROI感兴趣的区域。
006:Edge Trace边缘跟踪。
007:Edge Detection边界检测。
008:Thin细化去骨架。
009:做了一些Tidy整理。
  (这个一般要根据特定的Captcha算法调整)
010:做切割,注意图片中红色的交叉点。
011:将边缘检测和骨干交叉点监测的图像合并。
  (合并过程可以做分析: 比如X坐标偏移门限分析,交叉点区域纹理分析,线条走势分析,等等各种方法,找出更可能的切分点和分离后部件的组合管理。)


代码:(代码质量不高,从其他项目拷贝过来,简单修改的。)

查看代码(./pstzine_09_01.txt)

注: 在这里,我们可以看到,基本的部件(字母是分割开了,但可以造成统一字母的被切割成多个Component。 一种做法是:利用先验知识,做分割; 另外一种做法是,和第二部分的识别结合起来。 比如按照从左至右,尝试增加component来识别,如果不能识别而且component的总宽度,总面积还比较小,继续增加。 当然不排除拒识的可能性。 )

3)字符部件组合和识别。

part2的代码展示了切割后的字母组合,和基于svm的字符识别的训练和识别过程。Detection.cpp中展示了ImageSpam检测过程中的一些字符分割和组合,layout的分析和利用的简单技术。 而Google的验证码的识别,完全可以不用到,仅做参考。

SVM及使用:

本质上,SVM是一个分类器,原始的SVM是一个两类分类的分类器。可以通过1:1或者1:n的方式来组合成一个多类分类的分类器。 天生通过核函数的使用支持高维数据的分类。从几何意义上讲,就是找到最能表示类别特征的那些向量(支持向量SV),然后找到一条线,能最大化分类的Margin。

libSVM是一个不错的实现。

训练间断和识别阶段的数据整理和归一化是一样的。 这里的简单做法是:

首先:

#define SVM_MAX +0.999
#define SVM_MIN +0.001

其次:

扫描黑白待识别字幕图片的每个像素,如果为0(黑色,是字母上的像素),那么svm中该位置就SVM_MAX,反之则反。

最后:

训练阶段,在svm的input的前面,为该类打上标记,即是那一个字母。
识别阶段,当然这个类别标记是SVM分类出来。

注意:

如果是SVM菜鸟,最好找一个在SVM外边做了包装的工具,比如样本选择,交叉验证,核函数选择这些,让程序自动选择和分析。

代码:通过ReginGrowth来提取单个单个的字符,然后开始识别。

查看代码(./pstzine_09_02.txt)

六、对验证码设计的一些建议

1.在噪音等类型的使用上,尽力让字符和用来混淆的前景和背景不容易区分。尽力让坏人(噪音)长得和好人(字母)一样。

2.特别好的验证码的设计,要尽力发挥人类擅长而AI算法不擅长的。 比如粘连字符的分割和手写体(通过印刷体做特别的变形也可以)。 而不要一味的去加一些看起来比较复杂的噪音或者其他的花哨的东西。即使你做的足够复杂,但如果人也难识别,显然别人认为你是没事找抽型的。

3. 从专业的机器视觉的角度说,验证码的设计,一定要让破解者在识别阶段,反复在低阶视觉和高阶视觉之间多反复几次才能识别出来。 这样可以大大降低破解难度和破解的准确率。

七、个人郑重申明

1.这个问题,本身是人工智能,计算机视觉,模式识别领域的一个难题。我是虾米,菜得不能再菜的那种。作为破解者来说,是出于劣势地位。要做的很好,是很难得。总体来说,我走的是比较学院派的线路,能真正的破解难度比较高的验证码,不同于网上很多不太入流的破解方法。我能做的只有利用有限的知识,抛砖引玉而已。 很多OCR的技术,特别是离线手写体中文等文字识别的技术,个人了解有限的很,都不敢在这里乱写。

2.希望不要把这种技术用于非法用途。

posted @ 2009-03-14 09:54 小马歌 阅读(588) | 评论 (0)编辑 收藏
 

[转自:http://www.dotcomunderground.com/blogs/2006/09/02/gws21-google-web-server/ ]

Google Web Server

www.google.com的头信息如下:

URL: http://www.google.com/
HTTP Header:
Status: HTTP/1.0 200 OK
Cache-Control: private
Content-Type: text/html
Set-Cookie: PREF=ID=90107988a9ae4a88:TM=1157210262:LM=1157210262:S=ltFJ-O9yIsDIPVaS; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
Server: GWS/2.1
Content-Length: 0
Date: Sat, 02 Sep 2006 15:17:42 GMT
Connection: Keep-Alive

List of Google Server Types - Services and Server Software used by Google
Main Search: GWS/2.1
Google Accounts: GFE/1.3*
Google AdSense: GFE/1.3*
Google AdWords: GFE/1.3*
Google Analytics (Login Page): GWS/2.1
Google Analytics (Auth Page): GFE/1.3*
Google Analytics (Other Pages): ucfe*
Google Analytics (Analysis Image and JS): ucfe
Google Analytics (Images/JS/CSS/Flash): ga-reporting-fe
Google Answers: GFE/1.3
Google Base: asfe
Blogger: Apache
Google Book Search: OFE/0.1
Google Calendar: GFE/1.3
Google Catalogs: OFE/0.1
Google Code: codesite/2104877
Google Desktop: GFE/1.3
Google Directory: GWS/2.1
Google Downloads: GWS/2.1
Google Finance: SFE/0.8
Google Finance Stock Charts (Images): FTS (C)1997-2006 IS.Teledata AG
Froogle: cffe
Google Groups: GWS-GRFE/0.50
Hello: Apache/2.0.53
Google Help Pages: TrakhelpServer/1.0a
Google Images: GWS/2.1
Google Labs: Apache
Google Local / Maps: mfe
Google Local/Maps (Images): tfe
Google Mail: GWS/2.1
Google Mobile: GWS/2.1
Google Moon: mfe
Google Moon (Images): GWS/2.1
Google Music Search: mws
Google News: NFE/1.0
Orkut: GFE/1.3*
Google Pack: COMINST/1.0
Picasa (.com): Apache/2.0.53
Picasa (.google.com): GWS/2.1
Google Page Creator (Sign-up page): GFE/1.3*
Google Page Creator (User pages): GFE/1.3
Google Personalized Homepage: igfe
Google Scholar: GWS/2.1
Google Search History: Search-History HTTP Server
Google Sets: Apache
Google Site-Flavored: GWS/2.1
Google Sitemaps: GFE/1.3
Google SMS: GWS/2.1
Google SMS Search Requests: SMPP server 1.0
Google SMS (GMail Registration): GFE/1.3*
Google SMS (Page Viewer): GFE/1.3
Google Suggest: Auto-Completion Server
Google Transit: mfe
Google Translate: TWS/0.9
Google Video: GFE/1.3
Google Reader: GFE/1.3
Google Ride Finder: Apache
Google Talk: GWS/2.1
Google Toolbar: GFE/1.3
Google Toolbar (PR Lookup): GWS/2.1
Google Web Accelerator: GFE/1.3
Google Web Alerts: PSFE/4.0

Blogger and Google Labs also gives a little diffrent “HTTP Header” reply than usual Apache gives. (version number missing).

Please do share if you know more about GWS

posted @ 2009-03-10 19:35 小马歌 阅读(688) | 评论 (1)编辑 收藏
 
April 24th, 2008

今天无意中看到老王的技术手册中对 unicode 字符串的转换方法。

才想起以前自己做的一个转换程序时,也碰到过这样的问题,几乎被遗忘了。避免忘记,与大家分享一下这两种方法。

老王掘出来的被遗忘的mb_convert_encoding方法:mb_convert_encoding(’醉爱’, ‘UTF-8′, ‘HTML-ENTITIES’);

我以前做的一个方法,对比上面的来说,很笨。不过在没有 mb 扩展的时候还是可以参考一下的。

function unescape($str){
$str = rawurldecode($str);
preg_match_all(”/&#(\d+);/U”,$str,$r);
$arr = $r[1];
$cstr = array();
foreach($arr as $number){
$cstr[] = iconv(”UCS-2″,”GBK”,pack(”n”,$number));
}
return join(”",$cstr);
}

unescape(’醉爱’);

posted @ 2009-03-10 19:31 小马歌 阅读(311) | 评论 (0)编辑 收藏
 
javascript:var%20a=document.all;for(var%20i=0;i<a.length;i++){a[i].onclick=function(){alert(this.innerHTML);event.cancelBubble=true;return%20false;};a[i].onmouseover=function(){this.style.border="1px%20solid%20#261CDC";event.cancelBubble=true;};a[i].onmouseout=function(){this.style.border="none";}};void(0);



把这段代码作为一个地址保存到收藏夹,想看哪个网页时,点一下 收藏夹的这个按钮,就可以了。
posted @ 2009-03-10 19:29 小马歌 阅读(109) | 评论 (0)编辑 收藏
 
from:http://www.php5x.com/

英文版权归Reinhold Weber所有,中译文作者yangyang(aka davidkoree)。双语版可用于非商业传播,但须注明英文版作者、版权信息,以及中译文作者。翻译水平有限,请广大PHPer指正。

1.如果一个方法可静态化,就对它做静态声明。速率可提升至4倍。

2.echo 比 print 快。

3.使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接。

4.在执行for循环之前确定最大循环数,不要每循环一次都计算最大值。

5.注销那些不用的变量尤其是大数组,以便释放内存。

6.尽量避免使用__get,__set,__autoload。

7.require_once()代价昂贵。

8.在包含文件时使用完整路径,解析操作系统路径所需的时间会更少。

9.如果你想知道脚本开始执行(译注:即服务器端收到客户端请求)的时刻,使用$_SERVER[‘REQUEST_TIME’]要好于time()。

10.函数代替正则表达式完成相同功能。

11.str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。

12.如果一个字符串替换函数,可接受数组或字符作为参数,并且参数长度不太长,那么可以考虑额外写一段替换代码,使得每次传递参数是一个字符,而不是只写一行代码接受数组作为查询和替换的参数。

13.使用选择分支语句(译注:即switch case)好于使用多个if,else if语句。

14.用@屏蔽错误消息的做法非常低效。

15.打开apache的mod_deflate模块。

16.数据库连接当使用完毕时应关掉。

17.$row[‘id’]的效率是$row[id]的7倍。

18.错误消息代价昂贵。

19.尽量不要在for循环中使用函数,比如for ($x=0; $x < count($array); $x)每循环一次都会调用count()函数。

20.在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。

21.递增一个全局变量要比递增一个局部变量慢2倍。

22.递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。

23.递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9至10倍。

24.仅定义一个局部变量而没在函数中调用它,同样会减慢速度(其程度相当于递增一个局部变量)。PHP大概会检查看是否存在全局变量。

25.方法调用看来与类中定义的方法的数量无关,因为我(在测试方法之前和之后都)添加了10个方法,但性能上没有变化。

26.派生类中的方法运行起来要快于在基类中定义的同样的方法。

27.调用带有一个参数的空函数,其花费的时间相当于执行7至8次的局部变量递增操作。类似的方法调用所花费的时间接近于15次的局部变量递增操作。

28.用单引号代替双引号来包含字符串,这样做会更快一些。因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会。当然,只有当你不需要在字符串中包含变量时才可以这么做。

29.输出多个字符串时,用逗号代替句点来分隔字符串,速度更快。注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加上了双引号)。

30.Apache解析一个PHP脚本的时间要比解析一个静态HTML页面慢2至10倍。尽量多用静态HTML页面,少用脚本。

31.除非脚本可以缓存,否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能,以免除编译开销。

32.尽量做缓存,可使用memcached。memcached是一款高性能的内存对象缓存系统,可用来加速动态Web应用程序,减轻数据库负载。对运算码 (OP code)的缓存很有用,使得脚本不必为每个请求做重新编译。

33.当操作字符串并需要检验其长度是否满足某种要求时,你想当然地会使用strlen()函数。此函数执行起来相当快,因为它不做任何计算,只返回在 zval 结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度。但是,由于strlen()是函数,多多少少会有些慢,因为函数调用会经过诸多步 骤,如字母小写化(译注:指函数名小写化,PHP不区分函数名大小写)、哈希查找,会跟随被调用的函数一起执行。在某些情况下,你可以使用isset() 技巧加速执行你的代码。

(举例如下)
if (strlen($foo) < 5) { echo “Foo is too short”$$ }
(与下面的技巧做比较)
if (!isset($foo{5})) { echo “Foo is too short”$$ }

调用isset()恰巧比strlen()快,因为与后者不同的是,isset()作为一种语言结构,意味着它的执行不需要函数查找和字母小写化。也就是说,实际上在检验字符串长度的顶层代码中你没有花太多开销。

34.当执行变量$i的递增或递减时,$i++会比++$i慢一些。这种差异是PHP特有的,并不适用于其他语言,所以请不要修改你的C或Java代码并 指望它们能立即变快,没用的。++$i更快是因为它只需要3条指令(opcodes),$i++则需要4条指令。后置递增实际上会产生一个临时变量,这个 临时变量随后被递增。而前置递增直接在原值上递增。这是最优化处理的一种,正如Zend的PHP优化器所作的那样。牢记这个优化处理不失为一个好主意,因为并不是所有的指令优化器都会做同样的优化处理,并且存在大量没有装配指令优化器的互联网服务提供商(ISPs)和服务器。

35.并不是事必面向对象(OOP),面向对象往往开销很大,每个方法和对象调用都会消耗很多内存。

36.并非要用类实现所有的数据结构,数组也很有用。

37.不要把方法细分得过多,仔细想想你真正打算重用的是哪些代码?

38.当你需要时,你总能把代码分解成方法。

39.尽量采用大量的PHP内置函数。

40.如果在代码中存在大量耗时的函数,你可以考虑用C扩展的方式实现它们。

41.评估检验(profile)你的代码。检验器会告诉你,代码的哪些部分消耗了多少时间。Xdebug调试器包含了检验程序,评估检验总体上可以显示出代码的瓶颈。

42.mod_zip可作为Apache模块,用来即时压缩你的数据,并可让数据传输量降低80%。

posted @ 2009-03-10 16:13 小马歌 阅读(91) | 评论 (0)编辑 收藏
 
用操作符"@"获取操作执行的句柄,然后判断这个句柄的boolean值。如果发生问题,自己抛出Exception.
比如下面一个解析xml可能遇到的运行时异常:
try{
 $doc = new DOMDocument();
 $aa = @$doc->load('C:/cinema_data.xml');
 echo $aa;
 if(!$aa){
  throw  new Exception('ocur excep');
 }
 echo 'ccc';
}catch(Exception $e){
 //echo $e->getTrace();
 echo 'bbb';
 exit;
}

可以看到,发生异常时,echo 'ccc'是没执行的。
posted @ 2009-03-10 16:08 小马歌 阅读(265) | 评论 (0)编辑 收藏
 

使用 DOM 库、SAX 解析器和正则表达式

developerWorks
文档选项

级别: 中级

Jack Herrington (jack_d_herrington@codegeneration.net), 高级软件工程师, "Code Generation Network"

2006 年 2 月 06 日

有许多技术可用于用 PHP 读取和编写 XML。本文提供了三种方法读取 XML:使用 DOM 库、使用 SAX 解析器和使用正则表达式。还介绍了使用 DOM 和 PHP 文本模板编写 XML。

用 PHP 读取和编写可扩展标记语言(XML)看起来可能有点恐怖。实际上,XML 和它的所有相关技术可能是恐怖的,但是用 PHP 读取和编写 XML 不一定是项恐怖的任务。首先,需要学习一点关于 XML 的知识 —— 它是什么,用它做什么。然后,需要学习如何用 PHP 读取和编写 XML,而有许多种方式可以做这件事。

本文提供了 XML 的简短入门,然后解释如何用 PHP 读取和编写 XML。

什么是 XML?

XML 是一种数据存储格式。它没有定义保存什么数据,也没有定义数据的格式。XML 只是定义了标记和这些标记的属性。格式良好的 XML 标记看起来像这样:

<name>Jack Herrington</name>

这个 <name> 标记包含一些文本:Jack Herrington。

不包含文本的 XML 标记看起来像这样:

<powerUp />

用 XML 对某件事进行编写的方式不止一种。例如,这个标记形成的输出与前一个标记相同:

<powerUp></powerUp>

也可以向 XML 标记添加属性。例如,这个 <name> 标记包含 firstlast 属性:

<name first="Jack" last="Herrington" />

也可以用 XML 对特殊字符进行编码。例如,& 符号可以像这样编码:

&

包含标记和属性的 XML 文件如果像示例一样格式化,就是格式良好的,这意味着标记是对称的,字符的编码正确。清单 1 是一份格式良好的 XML 的示例。


清单 1. XML 图书列表示例
  <books>
                        <book>
                        <author>Jack Herrington</author>
                        <title>PHP Hacks</title>
                        <publisher>O'Reilly</publisher>
                        </book>
                        <book>
                        <author>Jack Herrington</author>
                        <title>Podcasting Hacks</title>
                        <publisher>O'Reilly</publisher>
                        </book>
                        </books>
                        

清单 1 中的 XML 包含一个图书列表。父标记 <books> 包含一组 <book> 标记,每个 <book> 标记又包含 <author><title><publisher> 标记。

当 XML 文档的标记结构和内容得到外部模式文件的验证后,XML 文档就是正确的。模式文件可以用不同的格式指定。对于本文来说,所需要的只是格式良好的 XML。

如果觉得 XML 看起来很像超文本标记语言(HTML),那么就对了。XML 和 HTML 都是基于标记的语言,它们有许多相似之处。但是,要着重指出的是:虽然 XML 文档可能是格式良好的 HTML,但不是所有的 HTML 文档都是格式良好的 XML。换行标记(br)是 XML 和 HTML 之间区别的一个好例子。这个换行标记是格式良好的 HTML,但不是格式良好的 XML:

<p>This is a paragraph<br>
With a line break</p>

这个换行标记是格式良好的 XML 和 HTML:

<p>This is a paragraph<br />
With a line break</p>

如果要把 HTML 编写成同样是格式良好的 XML,请遵循 W3C 委员会的可扩展超文本标记语言(XHTML)标准(参见 参考资料)。所有现代的浏览器都能呈现 XHTML。而且,还可以用 XML 工具读取 XHTML 并找出文档中的数据,这比解析 HTML 容易得多。





回页首


使用 DOM 库读取 XML

读取格式良好的 XML 文件最容易的方式是使用编译成某些 PHP 安装的文档对象模型 (DOM)库。DOM 库把整个 XML 文档读入内存,并用节点树表示它,如图 1 所示。


图 1. 图书 XML 的 XML DOM 树
图书 XML 的 XML DOM 树

树顶部的 books 节点有两个 book 子标记。在每本书中,有 authorpublishertitle 几个节点。authorpublishertitle 节点分别有包含文本的文本子节点。

读取图书 XML 文件并用 DOM 显示内容的代码如清单 2 所示。


清单 2. 用 DOM 读取图书 XML
  <?php
                        $doc = new DOMDocument();
                        $doc->load( 'books.xml' );
                        $books = $doc->getElementsByTagName( "book" );
                        foreach( $books as $book )
                        {
                        $authors = $book->getElementsByTagName( "author" );
                        $author = $authors->item(0)->nodeValue;
                        $publishers = $book->getElementsByTagName( "publisher" );
                        $publisher = $publishers->item(0)->nodeValue;
                        $titles = $book->getElementsByTagName( "title" );
                        $title = $titles->item(0)->nodeValue;
                        echo "$title - $author - $publisher\n";
                        }
                        ?>
                        

脚本首先创建一个 new DOMdocument 对象,用 load 方法把图书 XML 装入这个对象。之后,脚本用 getElementsByName 方法得到指定名称下的所有元素的列表。

book 节点的循环中,脚本用 getElementsByName 方法获得 authorpublishertitle 标记的 nodeValuenodeValue 是节点中的文本。脚本然后显示这些值。

可以在命令行上像这样运行 PHP 脚本:

% php e1.php
PHP Hacks - Jack Herrington - O'Reilly
Podcasting Hacks - Jack Herrington - O'Reilly
%

可以看到,每个图书块输出一行。这是一个良好的开始。但是,如果不能访问 XML DOM 库该怎么办?





回页首


用 SAX 解析器读取 XML

读取 XML 的另一种方法是使用 XML Simple API(SAX)解析器。PHP 的大多数安装都包含 SAX 解析器。SAX 解析器运行在回调模型上。每次打开或关闭一个标记时,或者每次解析器看到文本时,就用节点或文本的信息回调用户定义的函数。

SAX 解析器的优点是,它是真正轻量级的。解析器不会在内存中长期保持内容,所以可以用于非常巨大的文件。缺点是编写 SAX 解析器回调是件非常麻烦的事。清单 3 显示了使用 SAX 读取图书 XML 文件并显示内容的代码。


清单 3. 用 SAX 解析器读取图书 XML
  <?php
                        $g_books = array();
                        $g_elem = null;
                        function startElement( $parser, $name, $attrs )
                        {
                        global $g_books, $g_elem;
                        if ( $name == 'BOOK' ) $g_books []= array();
                        $g_elem = $name;
                        }
                        function endElement( $parser, $name )
                        {
                        global $g_elem;
                        $g_elem = null;
                        }
                        function textData( $parser, $text )
                        {
                        global $g_books, $g_elem;
                        if ( $g_elem == 'AUTHOR' ||
                        $g_elem == 'PUBLISHER' ||
                        $g_elem == 'TITLE' )
                        {
                        $g_books[ count( $g_books ) - 1 ][ $g_elem ] = $text;
                        }
                        }
                        $parser = xml_parser_create();
                        xml_set_element_handler( $parser, "startElement", "endElement" );
                        xml_set_character_data_handler( $parser, "textData" );
                        $f = fopen( 'books.xml', 'r' );
                        while( $data = fread( $f, 4096 ) )
                        {
                        xml_parse( $parser, $data );
                        }
                        xml_parser_free( $parser );
                        foreach( $g_books as $book )
                        {
                        echo $book['TITLE']." - ".$book['AUTHOR']." - ";
                        echo $book['PUBLISHER']."\n";
                        }
                        ?>
                        

脚本首先设置 g_books 数组,它在内存中容纳所有图书和图书信息,g_elem 变量保存脚本目前正在处理的标记的名称。然后脚本定义回调函数。在这个示例中,回调函数是 startElementendElementtextData。在打开和关闭标记的时候,分别调用 startElementendElement 函数。在开始和结束标记之间的文本上面,调用 textData

在这个示例中,startElement 标记查找 book 标记,在 book 数组中开始一个新元素。然后,textData 函数查看当前元素,看它是不是 publishertitleauthor 标记。如果是,函数就把当前文本放入当前图书。

为了让解析继续,脚本用 xml_parser_create 函数创建解析器。然后,设置回调句柄。之后,脚本读取文件并把文件的大块内容发送到解析器。在文件读取之后,xml_parser_free 函数删除解析器。脚本的末尾输出 g_books 数组的内容。

可以看到,这比编写 DOM 的同样功能要困难得多。如果没有 DOM 库也没有 SAX 库该怎么办?还有替代方案么?





回页首


用正则表达式解析 XML

可以肯定,即使提到这个方法,有些工程师也会批评我,但是确实可以用正则表达式解析 XML。清单 4 显示了使用 preg_ 函数读取图书文件的示例。


清单 4. 用正则表达式读取 XML
  <?php
                        $xml = "";
                        $f = fopen( 'books.xml', 'r' );
                        while( $data = fread( $f, 4096 ) ) { $xml .= $data; }
                        fclose( $f );
                        preg_match_all( "/\<book\>(.*?)\<\/book\>/s",
                        $xml, $bookblocks );
                        foreach( $bookblocks[1] as $block )
                        {
                        preg_match_all( "/\<author\>(.*?)\<\/author\>/",
                        $block, $author );
                        preg_match_all( "/\<title\>(.*?)\<\/title\>/",
                        $block, $title );
                        preg_match_all( "/\<publisher\>(.*?)\<\/publisher\>/",
                        $block, $publisher );
                        echo( $title[1][0]." - ".$author[1][0]." - ".
                        $publisher[1][0]."\n" );
                        }
                        ?>
                        

请注意这个代码有多短。开始时,它把文件读进一个大的字符串。然后用一个 regex 函数读取每个图书项目。最后用 foreach 循环,在每个图书块间循环,并提取出 author、title 和 publisher。

那么,缺陷在哪呢?使用正则表达式代码读取 XML 的问题是,它并没先进行检查,确保 XML 的格式良好。这意味着在读取之前,无法知道 XML 是否格式良好。而且,有些格式正确的 XML 可能与正则表达式不匹配,所以日后必须修改它们。

我从不建议使用正则表达式读取 XML,但是有时它是兼容性最好的方式,因为正则表达式函数总是可用的。不要用正则表达式读取直接来自用户的 XML,因为无法控制这类 XML 的格式或结构。应当一直用 DOM 库或 SAX 解析器读取来自用户的 XML。





回页首


用 DOM 编写 XML

读取 XML 只是公式的一部分。该怎样编写 XML 呢?编写 XML 最好的方式就是用 DOM。清单 5 显示了 DOM 构建图书 XML 文件的方式。


清单 5. 用 DOM 编写图书 XML
  <?php
                        $books = array();
                        $books [] = array(
                        'title' => 'PHP Hacks',
                        'author' => 'Jack Herrington',
                        'publisher' => "O'Reilly"
                        );
                        $books [] = array(
                        'title' => 'Podcasting Hacks',
                        'author' => 'Jack Herrington',
                        'publisher' => "O'Reilly"
                        );
                        $doc = new DOMDocument();
                        $doc->formatOutput = true;
                        $r = $doc->createElement( "books" );
                        $doc->appendChild( $r );
                        foreach( $books as $book )
                        {
                        $b = $doc->createElement( "book" );
                        $author = $doc->createElement( "author" );
                        $author->appendChild(
                        $doc->createTextNode( $book['author'] )
                        );
                        $b->appendChild( $author );
                        $title = $doc->createElement( "title" );
                        $title->appendChild(
                        $doc->createTextNode( $book['title'] )
                        );
                        $b->appendChild( $title );
                        $publisher = $doc->createElement( "publisher" );
                        $publisher->appendChild(
                        $doc->createTextNode( $book['publisher'] )
                        );
                        $b->appendChild( $publisher );
                        $r->appendChild( $b );
                        }
                        echo $doc->saveXML();
                        ?>
                        

在脚本的顶部,用一些示例图书装入了 books 数组。这个数据可以来自用户也可以来自数据库。

示例图书装入之后,脚本创建一个 new DOMDocument,并把根节点 books 添加到它。然后脚本为每本书的 author、title 和 publisher 创建节点,并为每个节点添加文本节点。每个 book 节点的最后一步是重新把它添加到根节点 books

脚本的末尾用 saveXML 方法把 XML 输出到控制台。(也可以用 save 方法创建一个 XML 文件。)脚本的输出如清单 6 所示。


清单 6. DOM 构建脚本的输出
  % php e4.php
                        <?xml version="1.0"?>
                        <books>
                        <book>
                        <author>Jack Herrington</author>
                        <title>PHP Hacks</title>
                        <publisher>O'Reilly</publisher>
                        </book>
                        <book>
                        <author>Jack Herrington</author>
                        <title>Podcasting Hacks</title>
                        <publisher>O'Reilly</publisher>
                        </book>
                        </books>
                        %
                        

使用 DOM 的真正价值在于它创建的 XML 总是格式正确的。但是如果不能用 DOM 创建 XML 时该怎么办?





回页首


用 PHP 编写 XML

如果 DOM 不可用,可以用 PHP 的文本模板编写 XML。清单 7 显示了 PHP 如何构建图书 XML 文件。


清单 7. 用 PHP 编写图书 XML
  <?php
                        $books = array();
                        $books [] = array(
                        'title' => 'PHP Hacks',
                        'author' => 'Jack Herrington',
                        'publisher' => "O'Reilly"
                        );
                        $books [] = array(
                        'title' => 'Podcasting Hacks',
                        'author' => 'Jack Herrington',
                        'publisher' => "O'Reilly"
                        );
                        ?>
                        <books>
                        <?php
                        foreach( $books as $book )
                        {
                        ?>
                        <book>
                        <title><?php echo( $book['title'] ); ?></title>
                        <author><?php echo( $book['author'] ); ?>
                        </author>
                        <publisher><?php echo( $book['publisher'] ); ?>
                        </publisher>
                        </book>
                        <?php
                        }
                        ?>
                        </books>
                        

脚本的顶部与 DOM 脚本类似。脚本的底部打开 books 标记,然后在每个图书中迭代,创建 book 标记和所有的内部 titleauthorpublisher 标记。

这种方法的问题是对实体进行编码。为了确保实体编码正确,必须在每个项目上调用 htmlentities 函数,如清单 8 所示。


清单 8. 使用 htmlentities 函数对实体编码
                        <books>
                        <?php
                        foreach( $books as $book )
                        {
                        $title = htmlentities( $book['title'], ENT_QUOTES );
                        $author = htmlentities( $book['author'], ENT_QUOTES );
                        $publisher = htmlentities( $book['publisher'], ENT_QUOTES );
                        ?>
                        <book>
                        <title><?php echo( $title ); ?></title>
                        <author><?php echo( $author ); ?> </author>
                        <publisher><?php echo( $publisher ); ?>
                        </publisher>
                        </book>
                        <?php
                        }
                        ?>
                        </books>
                        

这就是用基本的 PHP 编写 XML 的烦人之处。您以为自己创建了完美的 XML,但是在试图使用数据的时候,马上就会发现某些元素的编码不正确。





回页首


结束语

XML 周围总有许多夸大之处和混淆之处。但是,并不像您想像的那么难 —— 特别是在 PHP 这样优秀的语言中。在理解并正确地实现了 XML 之后,就会发现有许多强大的工具可以使用。XPath 和 XSLT 就是这样两个值得研究的工具。



参考资料

学习

获得产品和技术
  • 请访问 PHP.net,了解关于 PHP 的最新新闻、找到下载,并向其他用户学习。

  • 了解 Expat XML Parser,这个解析器用来向 PHP 提供 SAX 解析器功能。

  • 利用 IBM 试用软件 改造您的下一个开放源码开发项目,可以下载也可以通过 DVD 得到。


讨论


关于作者

 

Jack D. Herrington 是有 20 多年经验的高级软件工程师。他是三本书的作者:Code Generation in ActionPodcasting Hacks 和即将发表的 PHP Hacks。他还撰写了 30 多篇文章。

posted @ 2009-03-09 14:43 小马歌 阅读(177) | 评论 (0)编辑 收藏
仅列出标题
共95页: First 上一页 69 70 71 72 73 74 75 76 77 下一页 Last