[2016风云杯]web01(正则匹配)

<?php 
highlight_file('2.php');
$key='KEY{********************************}';
$IsMatch= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IsMatch ){ 
  die('key: '.$key);
}
?>

打开就是一个php源码,核心就是正则,因为之前一直对正则很生疏,这次单独摘出来这个题,写完顺带做个扩展。

对正则表达式进行分析:

"/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i"

第一个key是直接给出的直接利用 //?id=key

第二个 . 代表了任意字符,所以使用任意的字符暂用 a 代替 //?id=keya

第三个 * 代表匹配前面的表达式任意次数,因为前面的 keya 中 key 为表达式而 a 为字符所以在这后边添加key来进行匹配,但是我真的懒,所以就让他匹配0次 //?id=keya

第四个又是一个key的表达式直接加上就好了 //?id=keyakey

第五个紧接着又是一个 . 那就再加一个a //?id=keyakeya

第六个是 {4,7} 就是匹配前面的字符4-7次,结合前面的“.”,就是匹配任意字符4-7次 //?id=keyakeyaaaa

第七个 还是直接给出的 key //?id=keyakeyaaaakey

第八个 : 也是表达式直接写出来的字符串,我们直接利用 //?id=keyakeyaaaakey:

第九个是一个 / 而多的 是为了防止转义 //?id=keyakeyaaaakey:/

第十个还是 . 还用a //?id=keyakeyaaaakey:/a

第十一个是 / //?id=keyakeyaaaakey:/a/

第十二个 (.*key) 这里我们输入key就行 //?id=keyakeyaaaakey:/a/key

第十三个 [a-z] 代表a-z中的任意一个字符,继续用a //?id=keyakeyaaaakey:/a/keya

第十四个 [[:punct:]] 代表任意一个符号,输入标点符号即可,这里我们用个啥都行 //?id=keyakeyaaaakey:/a/keya;

第十五个 /i 代表大小写不敏感

到此,我们就写出了一个符合要求的表达式,传入id参数就得到了flag。

php正则

正则表达式组成

/正则表达式/ - - - 模糊查询

/^正则表达式$/ - - - 精准匹配

通用原子和元字符

\d匹配一个数字字符。等价于 [0-9]

\D匹配一个非数字字符。等价于 [^0-9]

\f匹配一个换页符。等价于 \x0c\cL

\n匹配一个换行符。等价于 \x0a\cJ

\r匹配一个回车符。等价于 \x0d\cM

\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]

\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]

\t匹配一个制表符。等价于 \x09\cI

\v匹配一个垂直制表符。等价于 \x0b\cK

\w匹配包括下划线的任何单词字符。等价于[A-Za-z0-9_]

\W匹配任何非单词字符。等价于 [^A-Za-z0-9_]

\b词边界,就是指必须要在最前或者最后。例如,“erb”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。

\B非边界,就是不能在一个正则表达式的最前或者最后。例如:“erB”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。

\xn匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,\x41 匹配 “A”。\x041 则等价于 \x04 & “1”。正则表达式中可以使用 ASCII 编码。

\nm标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。

\nml如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。

\un十六进制数字表示的 Unicode 字符。例如, u00A9 匹配版权符号(?)。

. 匹配除 “n” 之外的任何单个字符

^ 匹配输入字符串的开始位置。在字符域[]中表示取反,如'1'等于'w';而^w表示以单词字符开头。

$ 匹配输入字符串的结束位置。例'w$'表示以单词字符结尾。

? 匹配前面的子表达式零次或一次 等价于 {0,1},例如,"do(es)?" 可以匹配 "do" 或 "does"。

* 匹配前面的子表达式零次或多次,等价于{0,}。例如,zo* 能匹配 "z" 、 "zo"、'zoo'。

+ 匹配前面的子表达式一次或多次,等价于{1,}例如,'zo+' 能匹配 "zo" 以及 "zoo"。

{n} n 为非负整数,匹配确定的 n 次。例如,o{2} 不能匹配 "Bob" 或‘Booob’,但是能匹配 "food" 中的两个 o。

{n,} n 为非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o*'。

{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格。

[] 字符集合(字符域)。匹配所包含的任意一个字符。例如, '[abc]' 可以匹配 "plain" 中的 'a'。

() 匹配 ()内的内容 并获取这一匹配。搭配\n(n为大于1的整数),http://baidu.com若表达式:‘(\w+)(:)\/\/.*\1则匹配http://baidu.comhttp,\1表示http。

(?:) 匹 配 但不获取匹配结果,不进行存储供以后使用。这在使用 "或" 字符 (|) 来组合一个模式的各个部分是很有用。例如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。上面表达式若改为(?:\w+)(:)\/\/.*\1,则\1表示为:

| x|y,匹配 x 或 y。例如,'z|food' 能匹配 "z" 或 "food"。(z|f)ood'则匹配 "zood" 或 "food"。

[-] 字符范围。匹配指定范围内的任意字符。例如,[a-z] 可以匹配 'a' 到 'z' 范围内的任意小写字母字符。

(?=pattern) 向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,'Windows (?=95|98|NT|2000)' 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

(?!pattern) 向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是,该匹配不需要获取供以后使用。例如'Windows (?!95|98|NT|2000)' 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始

有时候定界符后会有一个字母,即模式修正符,有以下几种:

i表示匹配不区分大小写

m将模式视为多行,使用^和$表示任何一行都可以以正则表达式开始或结束

s如果没有使用这个模式修正符号,元字符中的"."默认不能表示换行符号,字符串将视为单行

x表示模式中的空白忽略不计

e正则表达式必须使用在preg_replace替换字符串的函数中时才可以使用(讲这个函数时再说)

A以模式字符串开头,相当于元字符^

Z以模式字符串结尾,相当于元字符$

U正则表达式的特点:就是比较“贪婪”,使用该模式修正符可以取消贪婪模式

php常用正则函数

1.preg_match($pattern , $str  , $arr );(正则表达式,匹配的字符串,匹配到的结果)
var_dump($arr) --------匹配到的结果
2.preg_grep() 返回模式匹配的数组单元 -------筛选 过滤
3.preg_match_all();执行多次匹配
进行全局正则表达式匹配   返回共计匹配的人数
//匹配所有的a标签   $a = '/<a.*?  href="(.*?)">(.*?)</a>/';
4.preg_replace()    ---执行正则表达式的搜索和替换
类似于  str_replace()         (要替换的,替换的,原字符串)
例子: $str = 'a?b?c';
var_dump(str_replace(' ? '  ,  ' : ' , $str));   => a:b:c
5.preg_split()  --- 分割     
类似于  explode();
$str = "09/24/2015"          转换成  2014-09-24
var_dump(preg_replace('/(\d{2}\/(\d){2}\/(\d){4})/'),'\\3-\\1-\\2',$str);

  1. w
最后修改:2020 年 08 月 12 日 10 : 29 AM
请作者喝杯奶茶吧~