snoopy.class.php中_striplink方法的正则分析

上周提到老爷机坏了,昨天早上早早的抱去修理,维修工程师更换硬件排除法最后得知,故障出现在显卡,插入显卡,主板灯亮,按开关,没反映,或者CPU风扇抖动一下即停止。卸下显卡,开机正常。这位维修人员的结论是显卡坏了,建议更换显卡。我们有N卡9200,只要320元。我提出把显卡放到别的主机上试试,被拒绝了,好吧,那我也拒绝。最后,对方收我20元检测费。虽然我心里有点不情愿,他只是换了几个零件的简单排除法得出很有可能的结论而已,并没有告诉我准确的病因,是显卡的哪里出问题了?能否维修?他都没有告诉我。尽管这样,我还是给了,也没争论。

主机抱回来之后,自己卸下了显卡。开机,上网,打算到网上买块新的。老的显卡是我07年在学校买的。ATI RADEON X550,在当初,还算比较前卫的硬件。周五还赞扬其能勤奋工作到现在,而结果得知出问题的就是它。工作了3年多,不到四年,还能接收吧。主板换了华硕P5GC-MX/1333 ,作为硬件小白的我,也不知道换什么显卡较好。熟悉硬件的朋友,麻烦留言告诉一下,感谢了。现在打开网页,拉动浏览器滑动条的时候,卡的比较厉害,播放电影更是,像放映幻灯片一样。实在不能接受。遂网上搜了相关信息。价格在500左右。是有点贵了。遂暂时作罢。一整天心情都很低落,或者说,自从老爷机出问题了,心情一直很差。中午窝在家里,洗了洗衣服,趁太阳好,把冬天穿的衣服拿出来晒了晒。又挪动电脑附近的两个大桌子,打扫卫生,清理一番。一直忙到下午3点,头饿的晕忽忽的。匆忙到沙县小吃随便吃了点,下午,看会书,睡了会觉,早上送GF回家,起得太早了,困的厉害。睡醒之后,都7点多了,照照镜子,看看自己蓬松的发型,猥琐的样子,不禁笑了一笑。洗了把脸,到小区的理发店里剪了头发,由于是小区内,专门给老头老太太理发的,所以费用仅5元,在上海,应该没有比这还低了吧。晚上,把显示器接到电视盒上,看了会电视,差不多都是娱乐类的弱智脑残节目,我极为反感觉,又将显示器接回主机箱,开机到当当网上看了一番。因工作需要,要做个代码自动审计化的程序,我的想法是,不仅仅停留在对关键危险函数的正则匹配,而是做到语法分析,识别未初始化的变量、未过滤的富文本字段、SQL注入的方法等。想必,肯定的熟悉《编译原理》以及LEX、YACC之类相关知识,后悔大学没认真听,造成自己基础薄太弱了。当然,我也觉得大学的时候,直接教学生这么底层的知识没有循序渐进的引导学生去深入更好。可以从最简单的网页制作开始,然后,让学生对其感兴趣,再引导到动态,然后,联合数据库,然后效率优化,然后代码执行原理,然后编译原理类似这种步骤引导学生更好。比起现在的方式,可能更让学生感兴趣。(扯远了)东看西看,忙到了12点多才睡。

对于已经习惯8点左右起床上班的我来说,生物钟在早上8点左右,准时醒,有时候想赖床,但也无法再次入睡。起床洗漱,打开电脑,玩了两局web的三国杀,逛逛论坛,觉得饿了,才去煮点面条吃。回来继续,无意中打开PPC,看到一位网友“落叶人生”同学的帖子问一个正则问题,纠结了一下是否解释一下,以便给对方释疑解惑,也加固自己的知识。犹豫半天,觉得还是写下吧。下面正题:

PPC链接http://bbs.phpchina.com/thread-189797-1-1.html

  1. preg_match_all(“‘<\s*a\s.*?href\s*=\s*([\"\'])?(?(1)(.*?)\\1|([^\s\>]+))[^>]*>?(.*?)</a>’isx”,$document,$links);

对于一般的规范链 接能很好的使用,但不知道为什么对href=后面的网址不含引号的情况无法提取成功,哪个朋友帮分析下?谢谢!

其实,我没明白他的意思是想提取链接地址href后面的内容的,还是提取整个标签a中间的所有。

在下面的回帖中,他提到了这个正则来自snoopy.class.php的_striplink方法中的正则,遂到sf.net上下载一份原版到本地。

代码如下

	function _striplinks($document)
	{
		preg_match_all("'<\s*a\s.*?href\s*=\s*			# find <a href=
						([\"\'])?					# find single or double quote
						(?(1) (.*?)\\1 | ([^\s\>]+))		# if quote found, match up to next matching
													# quote, otherwise match up to next space
						'isx",$document,$links);

		// catenate the non-empty matches from the conditional subpattern

		while(list($key,$val) = each($links[2]))
		{
			if(!empty($val))
				$match[] = $val;
		}

		while(list($key,$val) = each($links[3]))
		{
			if(!empty($val))
				$match[] = $val;
		}

		// return the links
		return $match;
	}

先看下修饰符部分。【isx】,大家都知道【i】是不区分大小写;【s】是点号通配模式,也就是元字符【.】可以匹配换行符。在这里的作用是为了防止链接中出现换行的情况;
【x】宽松排列和注释模式,也就是空白字符不会被当成正则表达式的一部分,#后面的为注释,方便阅读的作用了。顺便说下括号后面的双引号后面的单引号,跟修饰符i前面的单引号,他们只是正则的起始标识,不是正则的一部分。其实,表达式里有单引号了,这里最好使用别的,比如斜杠,或者闭合的大括号等。
再看表达式【<\s*a\s.*?href\s*=\s*】,其后面也注释了,是匹配“<a href=”的,第一个【\s】匹配”<”到”a”之间的空白字符,不过一般都没的吧。都直接写”<a……”。后面的【\s】也是空白字符,不详细解释了。在后面的【.*?】是匹配“<a “到“href=”之间的内容,比如”title=”…..”、target=”….”等。【href=】中没有元字符,就是匹配【href=】.

再后面【([\"\'])?】这里的单引号,双引号是被PHP语法转义的,真正的表达式是【(["'])?】,匹配单引号和双音号,并且,用小括号分配了组(整个表达式的第一组),后面有【?】量词,意味这可有可无。

再后面很重要了。去掉PHP的转义字符之后【(?(1) (.*?)\1 | ([^\s>]+)】,这是一个正则表达式的高级用法,叫“条件判断”表达式。语法为【(? if then| else)】。这里的if部分为【(1)】也就是前面说的“整个表达式的第一组”的内容,如果为真,则使用表达式【(.*?)\1】来匹配(\1是引用捕获的第一个组的内容),如果【(1)】没匹配到,则使用【([^\s>]+)】来匹配。这样,就可以实现没有引号的情况下,也是可以匹配到了。(正则表达式的条件判断语法,【|else】可以不写,表示不用else部分的表达式)

对于楼主的问题。应该怎么改?我刚刚刷新了帖子,看到楼主的正则是可以匹配的呀。

汗,贴下PHP的代码吧。


if (preg_match('%<\s*a\s.*?href\s*=\s*(["\'])?(?(1)(.*?)\1|([^\s>]+))[^>]*>(.*?)</a>%si', $subject)) {
	# Successful match
} else {
	# Match attempt failed
}

文章标题跟内容有很大出入,见谅哈。

您可能喜欢下面几篇博文

发表评论

5 Comments.

  1. lonelybamboo

    上淘宝买二手的 ATI 9550 x1650都是当时代的神卡啊~日常用也够了

    • 哈,我对硬件基本不太懂。怕到淘宝上买到假货,不能用,又浪费钱。只好到京东商城上买了一个N卡9800GT 。。花了我600大洋。咬牙了,呵呵。 :grin:

  2. Air Max Trainer

    希望博主的老爷机早点修好,我也有一台03年的了,放在角落里好久了,电源换了2次,其他没什么大问题,就是太慢了,加了内存也无济于事…… :arrow:

  3. 呵呵,老爷机,是该退休了啊。

Leave a Reply



[ Ctrl + Enter ]

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

Trackbacks and Pingbacks:

CNXCT小组的博客 is Stephen Fry proof thanks to caching by WP Super Cache