正则表达式验证URL在PHP中无法正常工作

时间:2012-04-24 11:18:32

标签: php regex codeigniter

我正在使用正则表达式来验证URL。这个表达式在JavaScript中非常有效,但在PHP中它给了我这个错误

A PHP Error was encountered

Severity: Warning

Message: preg_match() [function.preg-match]: Unknown modifier '('

Filename: home/auth.php

Line Number: 1596
A PHP Error was encountered

Severity: Warning

Message: preg_match() [function.preg-match]: Unknown modifier '('

Filename: home/auth.php

Line Number: 1601

这是我的表达

$pattern ="/^(http|https|ftp)\:\/\/www\.([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*(\.){1}((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$/";

这是php函数

public function valid_url($data)
{
    $data = trim($data);

    if(!$data)
    {
        return TRUE;            
    }

    $pattern ="/^(http|https|ftp)\:\/\/www\.([a-zA-Z0-9\.\-]+(\:[a-zA-Z0-9\.&%\$\-]+)*@)*(\.){1}((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(\:[0-9]+)*(/($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$/";
    $valid = preg_match($pattern,$data);

    if(!$valid)
    {
        $data = "http://".$data;
        $valid = preg_match($pattern,$data);
    }

    if(!$valid)
    {
        $this->form_validation->set_message('valid_url', 'Please enter a valid URL.');
        return FALSE;           
    }
    else
    {
        return TRUE;
    }       
}

我对正则表达式不是很擅长,所以我无法弄清楚这个问题,请帮我纠正正则表达式。

3 个答案:

答案 0 :(得分:6)

哇,这是一个很大的表达。我发现了几个错误,我希望能向你解释。让我们分开吧:

$pattern ="/

这是你的第一个错误。由于正斜杠用于URL的多个部分,因此应使用不同的分隔符。我建议使用代字号~,因为这不常用于网址。这意味着您不必在\/的每个位置都保持转义正斜杠。

^(http|https|ftp)\:\/\/www\.([a-zA-Z0-9\.\-]+

此字符类包含下一个错误。在字符类中,点只表示一个点。没有必要逃脱它。此外,将仪表放在末端,它也不需要转义,因为它不可能意味着范围。字符类可以缩短为[a-zA-Z0-9.-]+

(\:[a-zA-Z0-9\.&%\$\-]+

这里我们在字符类中有下一个错误&。这将匹配&或a或a或m或a;,而不仅仅是&amp ;.您不需要将其转换为html代码,因为这样做意味着匹配代码包含的任何字符。使用以前的知识,你不需要逃避点,或者如果它在最后,则不需要破折号。你也不需要逃避美元符号,因为在角色类中它只是意味着一美元。请记住,在字符类中,除了插入符^,反斜杠\,结束方括号],短划线-之外,所有元字符都只是标准字符(但是这可以留下,如果它在最后),以及你选择什么作为你的分隔符,例如代替~。然后,此角色类可以变为[a-zA-Z0-9.&%$-]+

)*@)*(\.){1}

部分可能是错误,可能不是。基本上,有没有必要在这里捕捉点?如果不需要捕获它,请单独留下支架。但是,重复中存在明确的错误。 {1}完全绝对是多余的。那里的一切都必须至少重复一次。这只是让代码变得混乱。以上内容可缩短为)*@)*\.

((25[0-5]|2[0-4][0-9]|[0-1]{1}

同样,不需要{1}。删除它,((25[0-5]|2[0-4][0-9]|[0-1]

[0-9]{2}|[1-9]{1}[0-9]{1}

再次两次,这变为[0-9]{2}|[1-9][0-9] 你继续这样做,你可以缩短下一段代码:

|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9])

|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])

这并不是特别好,但每一点都有帮助。下一个:

|([a-zA-Z0-9\-]+\.)*[a-zA-Z0-9\-]+

可以优化两个字符类|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+

\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2})

这是非常严格的限制,但我认为你有这样的理由,所以我会留下它。

)(\:[0-9]+)*(/

以下是导致错误的原因。您没有逃脱正斜杠。但是,我将保留它,因为使用不同的分隔符可以避免这种情况并整理你的模式。

($|[a-zA-Z0-9\.\,\?\'\\\+&%\$#\=~_\-]+))*$/";

现在知道我们不需要逃避其中的所有内容,这个角色类可以大大缩短。它可以成为($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/";

使用我们现在知道的所有内容,您的模式可以变得更漂亮,更容易处理。

它可以成为:

$pattern = "~^(http|https|ftp)://www\.([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[0-9])|([a-zA-Z0-9-]+\.)+(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(/($|[a-zA-Z0-9.,?'\\+&%$#=\~_-]+))*$~";

现在您的表达式较小,找到错误和更多自定义应该会更容易一些。

只是快速说明
我一直注意到您在某些分组的开头(\:使用了以下语法。我删除了反斜杠,因为它不需要冒号。但是,你是否试图让它成为未被捕获的群体?如果是这样,那么语法是(?:

编辑:: 您还可以通过使用字符类

进一步优化模式

\ d = [0-9]
\ w = [a-zA-Z0-9 _]

将i添加到最后一个模式分隔符的末尾也会导致不区分大小写。这意味着,您可以只写[a-zA-Z]而不是写[a-z]

此外,http|https可以成为https?

所以你的模式也可以进一步缩短:

$pattern = "~^(https?|ftp)://www\.([a-z\d.-]+(:[a-z\d.&%$-]+)*@)*((25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]\d|[1-9])\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]\d|[1-9]|0)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]\d|[1-9]|0)\.(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]\d|\d)|([a-z\d-]+\.)+(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-z]{2}))(:\d+)*(/($|[\w.,?'\\+&%$#=\~-]+))*$~i";

答案 1 :(得分:1)

我看到一个错误:

[0-9]+)*(/($

[0-9]+)*(\/($

[0-9]+)*(($

如果/应该是一个ender,它不应该是。

但严重的是,你有没有办法实现这一目标?这个字符串很难排除故障。

答案 2 :(得分:0)

为什么不使用标准的php函数filter_var?

http://lv.php.net/manual/ru/function.filter-var.php