Php正则表达式在不同的服务器上工作不同

时间:2013-03-25 22:48:19

标签: php regex expression regex-greedy

我正在使用正则表达式从网页上获取网址。

在localhost上(PHP 5.3.15与Suhosin-Patch(cli)(内置:2012年8月24日17:45:44))代码:

$file = file_get_contents("http://www.etech.haw-hamburg.de/Stundenplan/");
$pattern = "/<a href=\"([^\"]*.pdf)\">(.*)<\/a>/iU";
preg_match_all($pattern, $file, $matches);
echo "<pre>";
print_r($matches);
echo "</pre>";

给出:

=> Array
(
        [0] => Sem_IuE_E1a.pdf
        [1] => Sem_IuE_E2a.pdf
        [2] => Sem_IuE_E3a.pdf
        [3] => Sem_IuE_E4a.pdf
        [4] => Sem_IuE_E6AT.pdf
        [5] => Sem_IuE_E7.pdf
        [6] => Sem_IuE_E1b.pdf
        [7] => Sem_IuE_E2b.pdf
        [8] => Sem_IuE_E3b.pdf
        [9] => Sem_IuE_E4b.pdf
        [10] => Sem_IuE_E6II.pdf
        [11] => Sem_IuE_E6KT.pdf
        [12] => Sem_IuE_BMT1.pdf
        [13] => Laborplan%20BMT1%20KoP%201.pdf
        [14] => Sem_IuE_BMT2.pdf
        [15] => Sem_IuE_BMT3.pdf
        [16] => Sem_IuE_BMT4.pdf
        [17] => Sem_IuE_BMT5.pdf
        [18] => Sem_IuE_BMT6.pdf
        [19] => Sem_IuE_IE2.pdf
        [20] => Sem_IuE_IE4.pdf
        [21] => Sem_IuE_IE6.pdf
        [22] => Sem_IuE_AM.pdf
        [23] => Sem_IuE_IKM1.pdf
        [24] => Legende_Stud.pdf
        [25] => Kalender.pdf
        [26] => Doz.pdf
        [27] => Doz.pdf
    )

而在远程服务器上(PHP 5.3.3(cli)(内置:2013年2月22日02:51:11)),相同的代码给出:

=> Array
    (
        [0] => Sem_IuE_E2a.pdf
        [1] => Sem_IuE_E7.pdf
        [2] => Sem_IuE_E1b.pdf
        [3] => Sem_IuE_E2b.pdf
        [4] => Sem_IuE_E3b.pdf
        [5] => Sem_IuE_E6II.pdf
        [6] => Sem_IuE_E6KT.pdf
        [7] => Sem_IuE_BMT1.pdf
        [8] => Laborplan%20BMT1%20KoP%201.pdf
        [9] => Sem_IuE_BMT2.pdf
        [10] => Sem_IuE_BMT3.pdf
        [11] => Sem_IuE_BMT4.pdf
        [12] => Sem_IuE_BMT5.pdf
        [13] => Sem_IuE_BMT6.pdf
        [14] => Sem_IuE_IE2.pdf
        [15] => Sem_IuE_IE4.pdf
        [16] => Sem_IuE_IE6.pdf
        [17] => Sem_IuE_AM.pdf
        [18] => Doz.pdf
        [19] => Doz.pdf
    )

有什么问题?

2 个答案:

答案 0 :(得分:1)

我没有确切的答案。但是在你的问题中,你提到使用PHP 5.3.3和PHP 5.3.15会得到不同的结果。

我看了PHP5 ChangeLog,答案可能就在哪里,并看到了以下可能的解释。

  

将捆绑的PCRE升级到版本8.11。 (IIIa)的

  

将捆绑的PCRE升级到版本8.12。上(Scott)

我阅读了两个PCRE版本的发行说明,我不确定在您的情况下哪些会影响匹配,除了一些提及UTF8编码的更正。

但是,在查看U修饰符时,我在PCRE Configuration Options中注意到:

  

PCRE的回溯限制。 PHP&lt;默认为100000 5.3.7。

我的猜测是U(PCRE_UNGREEDY)修饰符中的某些修正更改了<a>之间的部分匹配方式。这是有道理的,因为通过查看您正在抓取的页面的来源,在早期PHP版本中匹配的唯一一个是不包含内部HTML的<a>标记。

示例,这个匹配:

<a href="Sem_IuE_E2a.pdf">E2a</a>

这个没有:

<a href="Sem_IuE_E4a.pdf"><span lang=IT style='mso-ansi-language:IT'>E4a</span></a>

非常有趣,但如何解决?

我无法访问早期的PHP版本,因此我无法对其进行测试,但我会说删除正则表达式中的贪婪部分,因为您不需要匹配<a></a>中的部分标签,因为该值已包含在PDF文件名中:

$pattern = "/<a href=\"([^\"]*.pdf)\">/i";

使用DOM Parser

答案 1 :(得分:1)

我想出了一个解决方法。如果您打开页面,请删除标签,然后解析您应获得更一致的答案。来自Microsoft应用程序(目标页面)的代码非常糟糕。

<?php
$file = file_get_contents("http://www.etech.haw-hamburg.de/Stundenplan/");
$file = strip_tags($file,'<a>');
$pattern = "!\<a href=[\"|']([^.]+\.pdf)[\"|']\>([^\<]+)\<\/a\>!iU";
preg_match_all($pattern, $file, $matches);
echo "<pre>";
print_r($matches);
echo "</pre>";
?>