【问题标题】:PHP code to generate safe URL?生成安全 URL 的 PHP 代码?
【发布时间】:2013-10-31 20:20:29
【问题描述】:

我们需要从书名生成一个唯一的 URL - 书名可以包含任何字符。我们如何搜索替换所有“无效”字符,从而生成有效且整洁的 URL?

例如:

"The Great Book of PHP"

www.mysite.com/book/12345/the-great-book-of-php

"The Greatest !@#$ Book of PHP"

www.mysite.com/book/12345/the-greatest-book-of-php

"Funny title     "

www.mysite.com/book/12345/funny-title

【问题讨论】:

标签: php regex string url-rewriting sanitization


【解决方案1】:

啊,呆滞

// This function expects the input to be UTF-8 encoded.
function slugify($text)
{
    // Swap out Non "Letters" with a -
    $text = preg_replace('/[^\\pL\d]+/u', '-', $text); 

    // Trim out extra -'s
    $text = trim($text, '-');

    // Convert letters that we have left to the closest ASCII representation
    $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);

    // Make text lowercase
    $text = strtolower($text);

    // Strip out anything we haven't been able to convert
    $text = preg_replace('/[^-\w]+/', '', $text);

    return $text;
}

这很好用,因为它首先使用每个字符的 unicode 属性来确定它是否是一个字母(或 \d 对一个数字) - 然后它将那些不是 -'s - 然后它音译为ascii,对其他任何东西进行另一个替换,然后自行清理。 (Fabrik 的测试返回“arvizturo-tukorfurogep”)

我还倾向于添加停用词列表 - 以便将它们从 slug 中删除。 "the" "of" "or" "a" 等(但不要在长度上这样做,或者你去掉像 "php" 这样的东西)

【讨论】:

  • 简单而精彩! +++ ;)(现在想知道 WP 源中的那个骗局是什么:o)
  • Unicode 匹配仅适用于 5.1+ 并且 iconv 可能无法安装在某些服务器上 - 它们必须满足所有人的需求。
  • 如果我可以建议编辑,我在第一行添加了$text = utf8_encode($text);。如果没有这种转换,像Mon titre français 这样的字符串会返回空白,而现在它变成了mon-titre-francais
  • @PubliDesign 那么您的内部编码未设置为 UTF-8。您可以通过使用mb_internal_encoding('UTF-8') 或设置responsible INI values 来强制执行此操作。您的字符串可以与@Mez 的代码一起使用。
  • @althaus,原始代码不会强制字符串为 utf8,这可能会导致奇怪的不需要的字符(例如:黑色三角形中的 ?)。尝试了这个字符串加上$text = utf8_encode($text);,经过几次测试,我得到了很好的结果。
【解决方案2】:

如果“无效”表示非字母数字,您可以这样做:

function foo($str) {
    return trim(preg_replace('/[^a-z0-9]+/', '-', strtolower($str)), '-');
}

这会将$str 转换为小写,用一个连字符替换任何一个或多个非字母数字字符序列,然后删除前导和尾随连字符。

var_dump(foo("The Great Book of PHP") === 'the-great-book-of-php');
var_dump(foo("The Greatest !@#$ Book of PHP") === 'the-greatest-book-of-php');
var_dump(foo("Funny title     ") === 'funny-title');

【讨论】:

  • 也失败了。对不起。请阅读问题:“标题可以包含任何字符”
  • @fabrik:那怎么了?你没有测试例子吗?它们都产生真值。
  • @fabrik:“如果‘无效’表示非字母数字 […]”——matt_tm 没有说明无效的含义。我只是假设他的意思是非字母数字。
  • @Gumbo:谢谢你至少试图理解我在说什么。不仅是匈牙利人物,还有一本关于 Citroën 的书,然后就可以了。国际品牌名称中的重音字符。是的,OP 没有指定什么是无效的,什么不是,但正如他所说的“标题可以包含 any 字符”。 (而且,因为我们谈论的是书籍,所以有可能出现重音字符。)
  • 嗨 - 很抱歉打扰你的谈话,是的,非英文字符也应该考虑在内......“可见”标题与实际标题完全相同并不是一个可怕的要求标题,但它必须是有效的网址...
【解决方案3】:

您可以为此目的使用一个简单的正则表达式:

<?php
    function safeurl( $v )
    {
        $v = strtolower( $v );
        $v = preg_replace( "/[^a-z0-9]+/", "-", $v );
        $v = trim( $v, "-" );
        return $v;
    }
    echo "<br>www.mysite.com/book/12345/" . safeurl( "The Great Book of PHP" );
    echo "<br>www.mysite.com/book/12345/" . safeurl( "The Greatest !@#$ Book of PHP" );
    echo "<br>www.mysite.com/book/12345/" . safeurl( "  Funny title  " );
    echo "<br>www.mysite.com/book/12345/" . safeurl( "!!Even Funnier title!!" );
?>

【讨论】:

  • 对不起,萨尔曼。我已经用包含我们所有元音的匈牙利句子尝试了你的脚本,但它失败了:ideone.com/WDcV8
  • @fabrik:没有人提到匈牙利语。如果可以的话,我会 -1 你的评论。
  • 问题是否提到了匈牙利语?
  • 来自问题:“标题可以包含任何字符”。
  • 这会导致前导或尾随无效字符(空格除外)失败。
【解决方案4】:

如果您只想允许字母、数字和下划线(通常的单词字符),您可以这样做:

$str = strtolower(preg_replace(array('/\W/','/-+/','/^-|-$/'),array('-','-',''),$str));

它首先用- 替换任何非单词字符(\W)。
接下来,它将任何连续的- 替换为单个-
接下来它会删除任何前导或尾随 -

Working link

【讨论】:

【解决方案5】:

此代码来自CodeIgniter 的网址助手。它应该可以解决问题。

function url_title($str, $separator = 'dash', $lowercase = FALSE)
    {
        if ($separator == 'dash')
        {
            $search     = '_';
            $replace    = '-';
        }
        else
        {
            $search     = '-';
            $replace    = '_';
        }

        $trans = array(
                        '&\#\d+?;'              => '',
                        '&\S+?;'                => '',
                        '\s+'                   => $replace,
                        '[^a-z0-9\-\._]'        => '',
                        $replace.'+'            => $replace,
                        $replace.'$'            => $replace,
                        '^'.$replace            => $replace,
                        '\.+$'                  => ''
                      );

        $str = strip_tags($str);

        foreach ($trans as $key => $val)
        {
            $str = preg_replace("#".$key."#i", $val, $str);
        }

        if ($lowercase === TRUE)
        {
            $str = strtolower($str);
        }

        return trim(stripslashes($str));
    }

【讨论】:

    【解决方案6】:

    用特殊字符替换空格,然后用“-”替换空格。 str_replace?

    【讨论】:

    • 请解释一下您是如何定义特殊字符的?
    【解决方案7】:

    使用正则表达式替换删除所有非单词字符。例如:

    str_replace('[^a-zA-Z]+', '-', $input)

    【讨论】:

      【解决方案8】:
      <?php
      $input = "  The Great Book's of PHP  ";
      $output = trim(preg_replace(array("`'`", "`[^a-z]+`"),  array("", "-"), strtolower($input)), "-");
      echo $output; // the-great-books-of-php
      

      这会修剪尾随的破折号,并且不会像大多数解决方案那样做 "it's raining" -&gt; "it-s-raining" 之类的事情。

      【讨论】:

      • @Gumbo:我觉得它更可取。更容易阅读,不是吗?否则你读起来就像“下雨了”,这很奇怪。
      • “它的”和“它的”有不同的含义。更可取的变体是使用它的扩展(明确)变体,因此“它是”或“它有”。
      • @Gumbo:这是一个 URL。它应该简短明了..如果有的话,我也会去掉像“is”和“has”这样的词。没有人会在 URL 中寻找语法错误。如果他们无法弄清楚“下雨”实际上意味着“下雨”,因为没有撇号......那么......他们需要回到学校。
      • @Mark:像its-meaning这样含糊不清的词怎么办?
      • @Gumbo:你什么时候说过“这是有意义的”?谁在乎?他们可以访问该网站并阅读实际页面上的所有 unicode 荣耀中的实际标题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-18
      • 1970-01-01
      • 2018-06-15
      • 1970-01-01
      • 2011-04-17
      相关资源
      最近更新 更多