【问题标题】:Generate unique url slug with PHP使用 PHP 生成唯一的 url slug
【发布时间】:2015-12-19 15:56:25
【问题描述】:

我正在开发一个小型 CMS 系统。目前在尝试生成唯一网址时脑死亡。我从页面标题生成 url。有一个很好的脚本来实现这一点,但我无法解决重复的问题。

类似问题here,但得到了准确的输出。

我设法做到以下几点;

this-is-the-slug
this-is-the-slug-2

但如果我第三次创建相同的帖子,它只会重复:this-is-the-slug-2

$i = 1;
$baseurl = $url;
//$check database here
if($thereisamatch){
$url = $baseurl . "-" . $i++;  
}

我无法绕过它,非常感谢您的帮助。

if(isset($_POST['save'])) {
    $title = mysqli_real_escape_string($db, $_POST['title']);
    $url = toAscii($title);
    // check url
    $content = $_POST['content'];
    $author = $_SESSION['thelab_username'];
    $type = $_POST['type'];
    $showtitle = $_POST['showtitle'];
    $saveas = $_POST['status'];

    $insert = $connection->query(" INSERT INTO lab_pages (title, permalink, content, author, status, type, showtitle)
    VALUES ('$title', '$newslug', '$content', '$author', '$saveas', '$type', '$showtitle') ");

    if($insert === TRUE) {
        echo '<div id="success">Page added. <button id="close">Close</button></div>';
    }

    else {
        echo '<div id="error">Failed. Try again. <button id="failed">Close</button></div>';
        printf("Errormessage: %s\n", $db->error);
    }
}

function toAscii($str, $replace=array(), $delimiter='-') {
 if( !empty($replace) ) {
  $str = str_replace((array)$replace, ' ', $str);
 }

 $clean = iconv('UTF-8', 'ASCII//TRANSLIT', $str);
 $clean = preg_replace("/[^a-zA-Z0-9\/_|+ -]/", '', $clean);
 $clean = strtolower(trim($clean, '-'));
 $clean = preg_replace("/[\/_|+ -]+/", $delimiter, $clean);

 return $clean;
}

【问题讨论】:

  • 匹配缺少 $ 只是一个错字吗?
  • 另外,您应该执行类似 while([此 url 存在于数据库中]){ $url = $baseurl."-".$i++;} 的操作。即使这很危险,如果 $i 失控,您也应该有一些触发的东西;
  • @Jim_M 只是用“匹配”进行演示。
  • @Devrim $connection 是这个 PDO 连接吗?
  • @OlegSamorai 不,它是一个 mysqli 连接。

标签: php mysql


【解决方案1】:

此代码不安全,无法用于生产!(sql 注入)

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

function get_one_value($con,$query) {
    $result = mysqli_query($con,$query);
    $row = mysqli_fetch_row($result);
    return($row[0]);
}
$slug = slug($input_without_trailing_number);
$exists = get_one_value("select count(id) from table where slug = '$slug'"); 

if ($exists > 0)
{
    $new_number = $exists + 1;
    $newslug = $slug."-".$new_number;
}
echo $newslug;

加入我自己的 slug 函数,因为我发现它非常有用,我希望其他人也会这样做。

【讨论】:

  • @Devrim 尝试将“select count(id) from table where slug = '$slug'”更改为“select count(id) from table where slug LIKE '$slug%'”
  • @Devrim 你能给出你的完整代码吗?
  • @OlegSamorai 我在问题中添加了我的代码(删除了建议的答案)。
【解决方案2】:

我也遇到了永久链接的问题。特别是当我想从网址中删除俄语、中文和除英语之外的任何其他字符时。试试下面的功能。我用过 PDO,但差别不大。

        function FilterPermalink($link){
            $db = new Connect;
            $link = strtolower(trim($link));
            $link = preg_replace('/[^a-z0-9-]/', '-', $link);
            $link = preg_replace('/-+/', "-", $link);
            $link = rtrim($link, '-');
            $link = preg_replace('/\s+/', '-', $link);
            if(strlen($link) > 30)
                $link = substr($link, 0, 30);
            $existing_lnk = $db->prepare("SELECT id FROM posts WHERE permalink = :permalink");
            $existing_lnk->execute(array('permalink' => $link));
            $num = $existing_lnk->fetchAll(PDO::FETCH_COLUMN);
            $first_total = count($num);
            for($i=0;$first_total != 0;$i++){
                if($i == 0){
                    $new_number = $first_total + 1;
                    $newlink = $link."-".$new_number;
                }
                $check_lnk = $db->prepare("SELECT id FROM posts WHERE permalink = :permalink");
                $check_lnk->execute(array('permalink' => $newlink));
                $other = $check_lnk->fetchAll(PDO::FETCH_COLUMN);
                $other_total = count($other);
                if($other_total != 0){
                    $first_total = $first_total + $other_total;
                    $new_number = $first_total;
                    $newlink = $link."-".$new_number;
                }elseif($other_total == 0){
                    $first_total = 0;
                }           
            }
            if($i > 0)
                return $newlink;
            else
                return $link;
        }

它对我很有效。

【讨论】:

    【解决方案3】:

    你可以通过两种方式解决它。

    1. 将检查数据库移入函数并使用循环。

    像这样:

    function check_into_database($url){
        //if isset - return true else false
    }
    $i = 1; $baseurl = $url;
    while(check_into_database($url)){
        $url = $baseurl . "-" . $i++;        
    }
    

    第二种方式

    使用带有 count(id) 的查询来检查所有 url。

    查询应该是这样的:

    SELECT COUNT(id) FROM tbl_name WHERE url LIKE "$url%"
    

    此查询将返回类似 this-is-the-slug% 的 url 计数。

    【讨论】:

    • 我使用您在此处编写的确切查询(您想要一个示例)。
    【解决方案4】:

    使用数据库匹配的值(SELECT COUNT(*))并增加它以获得新的后缀。

    PHP 脚本不相互通信,因此$i 在开始时将始终设置为1,然后增加1,因此2

    感谢源代码。因此,您的代码的开头应该是:

    if(isset($_POST['save'])) {
        $title = mysqli_real_escape_string($db, $_POST['title']);
        $url = toAscii($title);
        // check url
        $content = $_POST['content'];
        $author = $_SESSION['thelab_username'];
        $type = $_POST['type'];
        $showtitle = $_POST['showtitle'];
        $saveas = $_POST['status']; // no modifications until here
    
        // count entries with permalink like our slug
        $urlmask = $url.'%';
        $sql = 'SELECT COUNT(*) FROM lab_pages WHERE permalink LIKE ?';
        $stst =  $db->stmt_init();
        $stst->bind_param('s', $urlmask);
        $stst->execute();
        $stst->store_result();
        $stst->bind_result($count);
        $stst->fetch();
        $stst->free_result();
        $newslug = sprintf('%s-%d', $url, $count+1);
    
        $insert = $connection->query(" INSERT INTO lab_pages (title, permalink, content, author, status, type, showtitle)
        VALUES ('$title', '$newslug', '$content', '$author', '$saveas', '$type', '$showtitle') ");
        :
    

    重要的是使用像SELECT COUNT(*) FROM lab_pages WHERE permalink LIKE "$url%" 这样的 SQL 语句来获取当前 slug 的数量。然后你可以增加它并创造一个新的独特的蛞蝓。由于性能原因,应为列永久链接编制索引。

    但是,我宁愿使用uniqid() 来处理类似的事情。

    为了演示,我使用了准备好的语句,但您当然可以通过正常的 query-fetch_array-free_result 序列运行查询。

    【讨论】:

    • 我也试过这个方法。但是,即使我进行“喜欢”查询,它也不会超过 2。我想如果我找不到解决方案,我只会在 slug 末尾添加唯一 ID。
    • @Devrim 你能举一个你使用的查询示例吗?
    • 由于我不熟悉 PDO,我很难理解这里发生了什么,因为它给了我一个致命的错误“无法通过引用传递参数”。 $stst-&gt;bind_param('s', $url.'%');
    • 不是PDO,而是mysqli的语句对象。我纠正了错误。
    【解决方案5】:

    试试这个代码,这对我有用。

    // 检查slug是否已经存在

    $post_slug = preg_replace('/[^a-z0-9]+/i', '-', trim(strtolower($_POST['post_title'])));
    
    $query = "SELECT * FROM `posts` WHERE post_slug = '$post_slug'";
    $result = mysqli_query($conn, $query) or die(mysql_error());
    $ifExist = mysqli_num_rows($result);
    if ($ifExist >= 1) {
    
        $post_slug = $post_slug . '-' . $ifExist++;
    } else {
        $post_slug = $post_slug;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-08
      • 2014-12-09
      • 2013-09-11
      • 1970-01-01
      • 1970-01-01
      • 2012-03-28
      • 2010-12-11
      • 2014-05-26
      • 1970-01-01
      相关资源
      最近更新 更多