改善我的功能:生成SEO友好的标题

时间:2009-05-19 21:14:58

标签: php optimization

我正在使用此功能生成SEO友好的标题,但我认为它可以改进,任何人都想尝试?它做了一些事情:清除常见的重音字母,检查“禁止”数组,并选择性地检查正在使用的标题数据库。

    /**
    * Recursive function that generates a unique "this-is-the-title123" string for use in URL.
    * Checks optionally against $table and $field and the array $forbidden to make sure it's unique.
    * Usage: the resulting string should be saved in the db with the object. 
    */
    function seo_titleinurl_generate($title, $forbidden = FALSE, $table = FALSE, $field = FALSE)
    {
        ## 1. parse $title
        $title = clean($title, "oneline"); // remove tags and such

        $title = ereg_replace(" ", "-", $title); // replace spaces by "-"
        $title = ereg_replace("á", "a", $title); // replace special chars
        $title = ereg_replace("í", "i", $title); // replace special chars
        $title = ereg_replace("ó", "o", $title); // replace special chars
        $title = ereg_replace("ú", "u", $title); // replace special chars
        $title = ereg_replace("ñ", "n", $title); // replace special chars
        $title = ereg_replace("Ñ", "n", $title); // replace special chars

        $title = strtolower(trim($title)); // lowercase
        $title = preg_replace("/([^a-zA-Z0-9_-])/",'',$title); // only keep standard latin letters and numbers, hyphens and dashes

        ## 2. check against db (optional)
        if ($table AND $field)
        {
            $sql = "SELECT * FROM $table WHERE $field = '" . addslashes($title) . "'";
            $res = mysql_debug_query($sql);
            if (mysql_num_rows($res) > 0)
            {
                // already taken. So recursively adjust $title and try again.
                $title = append_increasing_number($title);
                $title = seo_titleinurl_generate($title, $forbidden, $table, $field);
            }
        }

        ## 3. check against $forbidden array
        if ($forbidden)
        {
            while (list ($key, $val) = each($forbidden))
            {
                // $val is the forbidden string
                if ($title == $val)
                {
                    $title = append_increasing_number($title);
                    $title = seo_titleinurl_generate($title, $forbidden, $table, $field);
                }
            }
        }
        return $title;
    }
    /**
    * Function that appends an increasing number to a string, for example "peter" becomes "peter1" and "peter129" becomes "peter130".
    * (To improve, this function could be made recursive to deal with numbers over 99999.)
    */
    function append_increasing_number($title)
    {
        ##. 1. Find number at end of string.
        $last1 = substr($title, strlen($title)-1, 1);
        $last2 = substr($title, strlen($title)-2, 2);
        $last3 = substr($title, strlen($title)-3, 3);
        $last4 = substr($title, strlen($title)-4, 4);
        $last5 = substr($title, strlen($title)-5, 5); // up to 5 numbers (ie. 99999)

        if (is_numeric($last5))
        {
            $last5++; // +1
            $title = substr($title, 0, strlen($title)-5) . $last5;
        } elseif (is_numeric($last4))
        {
            $last4++; // +1
            $title = substr($title, 0, strlen($title)-4) . $last4;
        } elseif (is_numeric($last3))
        {
            $last3++; // +1
            $title = substr($title, 0, strlen($title)-3) . $last3;
        } elseif (is_numeric($last2))
        {
            $last2++; // +1
            $title = substr($title, 0, strlen($title)-2) . $last2;
        } elseif (is_numeric($last1))
        {
            $last1++; // +1
            $title = substr($title, 0, strlen($title)-1) . $last1;
        } else 
        {
            $title = $title . "1"; // append '1'    
        }

        return $title;
    }

6 个答案:

答案 0 :(得分:4)

似乎存在竞争条件,因为您正在执行SELECT以查看之前是否已使用过标题,如果没有则返回它(可能是调用代码然后将其插入到DB中)。如果另一个进程执行相同的操作,但它插入SELECT和INSERT之间怎么办?您的插入将失败。你可能应该为URL添加一些保证唯一的令牌(可能是比SEO友好名称高一级的路径中的“目录”,类似于StackOverflow的做法),以避免SEO友好的URL需要的问题是独一无二的。

我还要重写append_increasing_number()函数以使其更具可读性......让它以编程方式确定最终有多少数字并且正常工作,而不是一个巨大的if / else来解决它。代码将更清晰,更简单,甚至可能更快。

答案 1 :(得分:4)

上面的str_replace建议非常好。此外,您可以用一行替换最后一个函数:

function append_increasing_number($title) {
  return preg_replace('@([0-9]+)$@e', '\1+1', $title);
}

您可以做得更好并完全删除循环查询,并执行类似

的操作
"SELECT MAX($field) + 1 FROM $table WHERE $field LIKE '" . mysql_escape_string(preg_replace('@[0-9]+$@', '', $title)) . "%'";

在这样的循环中运行SELECT只是丑陋。

答案 2 :(得分:3)

看起来其他人已经达到了大部分重点(特别是关于递增后缀和递归/循环执行SQL查询),但我仍然看到了一些可以做出的重大改进。

首先,不要试图想出你自己的变音符号到ASCII的替代品;你永远不会抓住它们,而且存在更好的工具。特别是,我将注意力转向iconv的“翻译”功能。您可以将UTF-8(或用于标题的任何编码)转换为普通的旧7位ASCII,如下所示:

$title = strtolower(strip(clean($title)));
$title = iconv('UTF-8', 'ASCII//TRANSLIT', $title);
$title = str_replace("'", "", $title);
$title = preg_replace(array("/\W+/", "/^\W+|\W+$/"), array("-", ""), $title);

请注意,这也修复了原始代码中的错误,其中在trim()之前调用了空格到破折号的替换,并用单个破折号替换了所有非字母/数字/破坏程序的运行。例如," Héllo, world's peoples!"变为"hello-worlds-peoples"。这将取代整个第1部分。

其次,可以重写$forbidden循环以提高效率并消除递归:

if ($forbidden)
{
    while (in_array($title, $forbidden))
    {
        $title = append_increasing_number($title);
    }
}

这取代了第3节。

答案 3 :(得分:2)

你可能会失去:

$title = ereg_replace(" ", "-", $title);

用更快的str_replace()

替换这些行
$title = str_replace(" ", "-", $title);

来自str_replace()的PHP手册页:

  

如果你不需要花哨的替换   规则(如正则表达式),你   应始终使用此功能   而不是ereg_replace()或   preg_replace()

编辑:

我增强了你的append_increasing_number($title)功能,它完全相同,只是对结尾的位数没有限制(而且它更漂亮:):

function append_increasing_number($title)
{
    $counter = strlen($title);
    while(is_numeric(substr($title, $counter - 1, 1))) {
        $counter--;
    }
    $numberPart = (int) substr($title,$counter,strlen($title) - 1);
    $incrementedNumberPart = $numberPart + 1;
    return str_replace($numberPart, $incrementedNumberPart, $title);
}

答案 4 :(得分:2)

按照karim79的回答,第一部分可以更易读,更容易维护:

替换

$title = ereg_replace(" ", "-", $title); // replace spaces by "-"
$title = ereg_replace("á", "a", $title); // replace special chars
$title = ereg_replace("í", "i", $title); // replace special chars

$replacements = array(
  ' ' => '-',
  'á' => 'a',
  'í' => 'i'
);
$title = str_replace(array_keys($replacements, array_values($replacements), $title);

使用append_increasing_number()的最后一部分看起来很糟糕。您可以删除整个功能,只需执行类似

的操作
while ($i < 99999){
//check for existance of $title . $i; if doesn't exist - insert!
}

答案 5 :(得分:1)

你也可以使用带有str_replace()的数组,这样就可以了

$replace = array(' ', 'á');
$with = array('-', 'a');

数组中的位置必须对应。

那应该刮几行,还有几个毫秒。

你还要考虑所有的标点符号,经常会有不同的引号和!等等进入网址。我会在\ W(不是单词)上做一个preg_replace

preg_replace('/\w/', '', $title);

这应该对你有所帮助。

菲尔