【问题标题】:Creating a canonical with PHP使用 PHP 创建规范
【发布时间】:2011-01-29 16:03:02
【问题描述】:

我需要 PHP 代码在 <link /> 标记内生成动态规范 URL,如下所示:

<link rel="canonical" href="php goes here" />

我的网站使用PHP生成变量如下:

http://www.mysite.com/script.php?var1=blue&var2=large&pointlessvar=narrow

我希望能够返回删除 &amp;pointlessvar=narrow 的规范 URL

并以我认为合适的方式重新排列变量,如下所示:

<link rel="canonical" href="http://www.mysite.com/script.php?var2=large&var1=blue" />

我想这样做是出于 SEO 的目的,因为我的网站包含许多不同顺序的变量,这些变量为基本相同的内容提供不同的 URL(以防止 SERPS 中的重复并集中链接汁)

谁能推荐一些我可以放在&lt;link /&gt;标签中的PHP代码?

【问题讨论】:

  • &amp;pointlessvar=narrow根据什么标准被视为无用?
  • 你应该从使用 url-rewriting / seo-friendly url开始。这样做是值得的,它会避免你不得不如此规范。
  • @zerkms 也许称它为无意义变量有点误导 - 我的错。它并非完全没用 - 它允许我的访问者缩小他们的搜索结果,但它可能会导致我不希望搜索引擎索引的重复内容,因此我需要生成一个规范的 URL 以将其从 SERPS 中删除。
  • @Boris Guéry - 我不想重新编写实际的 URL,因为我的网站是实时的并且在 SERPS 中有数千个索引页面。重写 URL 听起来像是重定向的噩梦 :)
  • @Matt:我仍然无法获得选择标准,哪些变量应该出现在“规范 URL”中,哪些不应该出现。

标签: php html xhtml seo


【解决方案1】:

要创建一个规范的 url,您实际上应该确保您只获得了您需要的参数,并将它们也按固定顺序放置。这段代码就是这样做的。它过滤 _GET 参数列表并构建一个仅包含所需参数的新 url。我把它放了一些 cmets,所以您可以轻松地调整此代码以满足您的需求。

我使用array_filter,因为我不确定如果在数组的foreach 中取消设置数组元素会发生什么。

function params()
{
    return array('b', 'c', 'a', 'z');
}

function checkParam($a)
{
    // Checks if key $a is in array of valid parameters
    return in_array($a, params());
}

function compare($a, $b)
{
    return array_search($a, params()) - array_search($b, params());
}

function getCanonicalUrl()
{
    $querystring = '';

    // Copy and flip the array to allow filtering by key.
    $params = array_flip($_GET);

    // Filter out any params that are not wanted.
    $params = array_filter($params, 'checkParam'); 

    // If none remain, we're done.
    if (count($params) !== 0)
    {
        // Sort the rest in given order
        uasort($params, 'compare');
        // Create a query string. Mind, name and value are still flipped.
        $querystring = '?'.http_build_query(array_flip($params));
    }

    return 
        'http://'.
        // $_SERVER['HTTP_HOST'] .
        $_SERVER['SCRIPT_NAME'] .
        $querystring;
}

print getCanonicalUrl();

【讨论】:

  • 嗨 GolezTrol,这太棒了!感谢您的帮助 - 除了 2 个问题之外,它几乎可以满足我的所有需求。 1) 代码似乎生成了一个与域名重复且缺少 http:// 前缀的 URL,例如它返回以下 URL:www.mysite.com/www.mysite.com/script.php?var2=large&amp;var1=blue 2) 我如何在返回的 URL 中排列变量,以便它们是否按照我在 funtion checkParam($a) 中指定的确切顺序?再次感谢您的时间 - 快到了!
  • 它不应该那样做,但也许该域已经包含在 SCRIPT_NAME 中。如果是这样,只需跳过 HTTP_HOST。您需要自己添加“http://”。在 $_SERVER 中找不到实际的协议前缀。如果您跳过带有asort 的行,您的变量将不会被排序。
  • 您好 GolezTrol,感谢您的回复。添加 http:// 前缀完美地解决了问题:)。我仍然对变量的排序顺序有疑问,删除asort 没有帮助,变量现在只是以随机顺序出现。我希望它们按照我在funtion checkParam($a) 中指定的确切顺序排列,很抱歉!
  • 澄清一下,删除了asort后,变量现在按照它们出现在实际URL中的顺序返回,而不是它们在funtion checkParam($a)中列出的顺序
  • 我又做了一个修改。添加了 compare() 函数,该函数通过参数数组中的索引比较两个键。我现在使用uasort 而不是asort,它以与array_filter 相同的方式接受回调。它允许您指定自定义比较函数。我还将数组移到了一个单独的函数中,因此您不必声明它两次。它也可以是一个全球性的,尽管您已经到了可以将所有内容都放在特定类中的地步。 (但那是另一章。:))
【解决方案2】:
$path = "http://www.mysite.com/script.php?var1=blue&var2=large&pointlessvar=narrow";
$url = parse_url($path, PHP_URL_QUERY); // Fetch the query component of a url

// Put the query into an array with the var name as the key
parse_str($url, $query=array()); 

foreach ($query as $name=>$val) {
    // Check for pointless vars and unset() them here
}

krsort ($query); // Sort by array keys in reverse order.

$pathex = explode('?', $path, 2);
$npath = $pathex[0] . '?' . http_build_query($query);

php 提供了更多的排序功能。
它们甚至允许您编写自己的custom sort function

【讨论】:

  • 不知道 PHP_URL_QUERY 常量参数,谢谢
  • @Boris Guéry 是的,直到我看到这里的其他人在使用它,我才知道它哈哈
【解决方案3】:

您可以混合使用parse_url(); 函数和http_build_query() 来重建您的网址。

$url = 'http://www.mysite.com/script.php?var1=blue&var2=large&pointlessvar=narrow';
$url = parse_url($url);

$params = array();
$tmpParams = explode('&',$url['query']);

foreach ($tmpParams as $param) {
    $tmp = explode('=', $param);
    $params[$tmp[0]] = (!empty($tmp[1])) ? $tmp[1] : null;
}

然后遍历 $params 以取消设置无用的变量,然后使用 http_build_query 重建。

【讨论】:

  • http_build_query() 在某些情况下可能会丢失数据。
  • @zerkms,你能指出这方面的任何来源吗?我以前从来没有遇到过问题。
  • 哎呀,错过了parse_str() 及其点问题
【解决方案4】:

您可以使用 $_SERVER 超全局和 $_GET 超全局来获取 url 的各个部分。您可以随意重新排列和过滤它们。

【讨论】: