阐述 WordPress `wp_get_current_commenter()` 函数的源码:如何从 `Cookie` 中获取评论者信息。

WordPress 评论者身份之谜:wp_get_current_commenter() 函数源码深度剖析

各位观众,欢迎来到今天的“WordPress 源码解密”讲座!今天我们要聊的是一个非常重要,但又常常被忽视的函数:wp_get_current_commenter()。 它负责从用户的 Cookie 中提取评论者的信息,对于评论功能来说,绝对是幕后英雄般的存在。 那么,让我们一起扒开它的源代码,看看它到底是如何工作的,顺便也学习一些 Cookie 操作的小技巧。

1. 开场白:Cookie 的前世今生

在深入源码之前,先简单回顾一下 Cookie 的概念。 Cookie 就像网站发给浏览器的小纸条,上面记录着一些信息,比如用户的登录状态、偏好设置等等。 当用户再次访问网站时,浏览器会把这些小纸条(Cookie)带上,网站就能“认出”用户了。 是不是有点像暗号接头?

评论功能也需要 Cookie 来记住用户的身份。 如果用户之前发表过评论,我们就可以通过 Cookie 自动填充他们的姓名、邮箱等信息,省去重复输入的麻烦。 而 wp_get_current_commenter() 函数,正是负责从 Cookie 中读取这些信息的关键角色。

2. 源码探秘:wp_get_current_commenter() 的真面目

好了,废话不多说,直接上代码! wp-includes/comment.php 文件里,我们可以找到 wp_get_current_commenter() 函数的定义:

function wp_get_current_commenter() {
    static $commenter = null;

    if ( null !== $commenter ) {
        return $commenter;
    }

    $comment_cookie_domain = '';

    if ( defined( 'COOKIE_DOMAIN' ) && COOKIE_DOMAIN ) {
        $comment_cookie_domain = COOKIE_DOMAIN;
    }

    $commenter = wp_parse_args(
        wp_unslash( $_COOKIE ),
        array(
            'comment_author_' . sanitize_title( get_option( 'blogname' ) ) => '',
            'comment_author_email_' . sanitize_title( get_option( 'blogname' ) ) => '',
            'comment_author_url_' . sanitize_title( get_option( 'blogname' ) ) => '',
        )
    );

    $commenter = (object) array(
        'comment_author'       => isset( $commenter[ 'comment_author_' . sanitize_title( get_option( 'blogname' ) ) ] ) ? trim( $commenter[ 'comment_author_' . sanitize_title( get_option( 'blogname' ) ) ] ) : '',
        'comment_author_email' => isset( $commenter[ 'comment_author_email_' . sanitize_title( get_option( 'blogname' ) ) ] ) ? trim( $commenter[ 'comment_author_email_' . sanitize_title( get_option( 'blogname' ) ) ] ) : '',
        'comment_author_url'   => isset( $commenter[ 'comment_author_url_' . sanitize_title( get_option( 'blogname' ) ) ] ) ? trim( $commenter[ 'comment_author_url_' . sanitize_title( get_option( 'blogname' ) ) ] ) : '',
        'comment_author_domain' => $comment_cookie_domain,
    );

    return $commenter;
}

别被这一堆代码吓到,我们一步一步来分析。

2.1. 静态变量缓存:提高效率的小技巧

static $commenter = null;

if ( null !== $commenter ) {
    return $commenter;
}

这段代码使用了静态变量 $commenter。 静态变量的特点是,函数每次被调用时,它只会被初始化一次。 也就是说,如果 $commenter 已经被赋值过了,函数就会直接返回它的值,而不会重复执行后面的代码。 这样做的好处是,可以提高函数的执行效率,避免重复读取 Cookie。 毕竟,Cookie 的读取也是需要消耗资源的。

2.2. 获取 Cookie 域名:决定 Cookie 的作用范围

$comment_cookie_domain = '';

if ( defined( 'COOKIE_DOMAIN' ) && COOKIE_DOMAIN ) {
    $comment_cookie_domain = COOKIE_DOMAIN;
}

这段代码尝试获取 COOKIE_DOMAIN 常量的值。 这个常量定义了 Cookie 的作用域,也就是 Cookie 对哪些域名有效。 如果 COOKIE_DOMAIN 没有定义,或者为空字符串,那么 Cookie 的作用域就是当前域名。 这个参数在设置 Cookie 的时候非常重要,错误的域名可能导致 Cookie 无法被正确读取。

2.3. 读取 Cookie 数据:核心逻辑

$commenter = wp_parse_args(
    wp_unslash( $_COOKIE ),
    array(
        'comment_author_' . sanitize_title( get_option( 'blogname' ) ) => '',
        'comment_author_email_' . sanitize_title( get_option( 'blogname' ) ) => '',
        'comment_author_url_' . sanitize_title( get_option( 'blogname' ) ) => '',
    )
);

这部分代码是整个函数的关键。 它主要做了两件事:

  1. wp_unslash( $_COOKIE ): 首先,它使用 wp_unslash() 函数对 $_COOKIE 超全局数组进行处理。 wp_unslash() 函数的作用是移除由 magic_quotes_gpc 自动添加的反斜杠。 虽然 magic_quotes_gpc 在 PHP 5.4 中已经被移除,但 WordPress 为了兼容性,仍然保留了这个函数。 目的是确保从 Cookie 中读取的数据是原始的,没有被转义。

  2. wp_parse_args(): 然后,它使用 wp_parse_args() 函数将 $_COOKIE 数组与一个默认的参数数组进行合并。 wp_parse_args() 函数的作用类似于 array_merge(),但是它有一些额外的特性,比如可以处理对象。 在这里,它将 $_COOKIE 数组作为用户提供的参数,将一个包含默认值的数组作为默认参数。

    默认参数数组定义了三个 Cookie 的名称:

    • comment_author_{blogname}
    • comment_author_email_{blogname}
    • comment_author_url_{blogname}

    其中,{blogname} 会被替换为博客名称的 sanitize_title() 结果。 sanitize_title() 函数会将博客名称转换为一个 URL 友好的字符串,比如将 "My Awesome Blog" 转换为 "my-awesome-blog"。 这样做的好处是可以避免 Cookie 名称冲突,特别是当你的网站使用了多个 WordPress 站点时。

    wp_parse_args() 函数会将 $_COOKIE 数组中与默认参数数组中键名相同的元素的值,赋值给 $commenter 数组。 如果 $_COOKIE 数组中没有相应的键名,那么 $commenter 数组中对应的元素的值就会使用默认值(空字符串)。

2.4. 创建对象并赋值:整理数据

$commenter = (object) array(
    'comment_author'       => isset( $commenter[ 'comment_author_' . sanitize_title( get_option( 'blogname' ) ) ] ) ? trim( $commenter[ 'comment_author_' . sanitize_title( get_option( 'blogname' ) ) ] ) : '',
    'comment_author_email' => isset( $commenter[ 'comment_author_email_' . sanitize_title( get_option( 'blogname' ) ) ] ) ? trim( $commenter[ 'comment_author_email_' . sanitize_title( get_option( 'blogname' ) ) ] ) : '',
    'comment_author_url'   => isset( $commenter[ 'comment_author_url_' . sanitize_title( get_option( 'blogname' ) ) ] ) ? trim( $commenter[ 'comment_author_url_' . sanitize_title( get_option( 'blogname' ) ) ] ) : '',
    'comment_author_domain' => $comment_cookie_domain,
);

这段代码将 $commenter 数组转换为一个对象,并对其中的值进行处理。 具体来说,它做了以下几件事:

  1. 数组转对象: 使用 (object) array() 将数组转换为对象。 这样做的好处是可以更方便地访问对象属性,比如可以使用 $commenter->comment_author 来获取评论者的姓名。

  2. isset() 判断: 使用 isset() 函数判断 $commenter 数组中是否存在相应的键名。 这样做可以避免访问不存在的键名时出现错误。

  3. trim() 函数: 使用 trim() 函数去除字符串两端的空格。 这样做可以确保评论者的姓名、邮箱等信息没有多余的空格。

  4. 赋值: 将处理后的值赋值给对象的相应属性。

  5. 设置 comment_author_domain: 将之前获取的 Cookie 域名赋值给 comment_author_domain 属性。

2.5. 返回结果:大功告成

return $commenter;

最后,函数返回 $commenter 对象,其中包含了从 Cookie 中读取的评论者信息。

3. 案例分析:模拟 Cookie 设置与读取

为了更好地理解 wp_get_current_commenter() 函数的工作原理,我们可以模拟一下 Cookie 的设置与读取过程。

3.1. 设置 Cookie

假设我们要在用户发表评论后,设置 Cookie 来保存他们的姓名、邮箱和网址。 可以使用 setcookie() 函数来实现:

$comment_author = '张三';
$comment_author_email = '[email protected]';
$comment_author_url = 'https://example.com';

$blogname = get_option( 'blogname' );
$cookie_name_author = 'comment_author_' . sanitize_title( $blogname );
$cookie_name_email = 'comment_author_email_' . sanitize_title( $blogname );
$cookie_name_url = 'comment_author_url_' . sanitize_title( $blogname );

$cookie_domain = defined( 'COOKIE_DOMAIN' ) && COOKIE_DOMAIN ? COOKIE_DOMAIN : '';

setcookie( $cookie_name_author, $comment_author, time() + 3600 * 24 * 30, COOKIEPATH, $cookie_domain );
setcookie( $cookie_name_email, $comment_author_email, time() + 3600 * 24 * 30, COOKIEPATH, $cookie_domain );
setcookie( $cookie_name_url, $comment_author_url, time() + 3600 * 24 * 30, COOKIEPATH, $cookie_domain );

这段代码首先定义了评论者的姓名、邮箱和网址。 然后,它使用 get_option( 'blogname' ) 函数获取博客名称,并使用 sanitize_title() 函数将其转换为 URL 友好的字符串。 接着,它根据博客名称生成 Cookie 的名称。 最后,它使用 setcookie() 函数设置 Cookie

setcookie() 函数的参数如下:

  • name: Cookie 的名称。
  • value: Cookie 的值。
  • expire: Cookie 的过期时间,Unix 时间戳。 这里设置为 30 天后过期。
  • path: Cookie 的有效路径。 COOKIEPATH 常量定义了 WordPress 的 Cookie 路径,通常是网站的根目录。
  • domain: Cookie 的有效域名。 COOKIE_DOMAIN 常量定义了 WordPress 的 Cookie 域名。

3.2. 读取 Cookie

现在,我们可以使用 wp_get_current_commenter() 函数来读取 Cookie 中的信息:

$commenter = wp_get_current_commenter();

echo '姓名:' . $commenter->comment_author . '<br>';
echo '邮箱:' . $commenter->comment_author_email . '<br>';
echo '网址:' . $commenter->comment_author_url . '<br>';

这段代码首先调用 wp_get_current_commenter() 函数获取 $commenter 对象。 然后,它使用 echo 语句将 $commenter 对象的属性值输出到页面上。

如果 Cookie 设置成功,并且 wp_get_current_commenter() 函数能够正确读取 Cookie 中的信息,那么页面上将会显示评论者的姓名、邮箱和网址。

4. 常见问题与注意事项

在使用 wp_get_current_commenter() 函数时,需要注意以下几点:

  • Cookie 禁用: 如果用户禁用了 Cookie,那么 wp_get_current_commenter() 函数将无法读取任何信息。 因此,在评论表单中,需要提供一个选项,让用户手动输入他们的姓名、邮箱和网址。

  • Cookie 过期: Cookie 有过期时间。 如果 Cookie 已经过期,那么 wp_get_current_commenter() 函数将无法读取任何信息。 因此,需要定期更新 Cookie 的过期时间。

  • Cookie 安全: Cookie 可能会被恶意用户篡改。 因此,需要对 Cookie 进行加密处理,以防止 Cookie 中的信息被泄露。

  • 多站点环境: 在多站点环境中,需要确保每个站点的 Cookie 名称是唯一的,以避免 Cookie 冲突。 可以使用 sanitize_title( get_option( 'blogname' ) ) 函数来生成唯一的 Cookie 名称。

  • COOKIE_DOMAIN 常量: 正确配置 COOKIE_DOMAIN 常量至关重要。 错误的配置可能导致 Cookie 在不同的子域名之间无法共享,或者根本无法被读取。

  • 缓存问题: 由于 wp_get_current_commenter() 使用了静态变量进行缓存,如果 Cookie 被修改,缓存可能不会立即更新。 可以考虑在某些情况下手动清除缓存。

5. 总结

wp_get_current_commenter() 函数虽然看起来简单,但它在 WordPress 的评论功能中扮演着重要的角色。 它负责从 Cookie 中读取评论者的信息,为用户提供更好的评论体验。 通过深入分析它的源码,我们可以更好地理解 Cookie 的工作原理,以及 WordPress 如何处理 Cookie 数据。 希望今天的讲座能帮助大家更好地掌握 WordPress 开发技巧!

功能 描述
读取 Cookie $_COOKIE 超全局数组中读取评论者的姓名、邮箱和网址等信息。
缓存数据 使用静态变量缓存读取到的评论者信息,避免重复读取 Cookie,提高效率。
处理数据 使用 wp_unslash() 函数移除反斜杠,使用 trim() 函数去除字符串两端的空格,确保数据的准确性。
安全性 通过 sanitize_title() 函数对博客名称进行处理,生成唯一的 Cookie 名称,避免 Cookie 冲突。
对象化 将读取到的评论者信息转换为对象,方便访问对象属性。
配置域名 获取 COOKIE_DOMAIN 常量的值,用于设置 Cookie 的作用域。

今天的分享就到这里,谢谢大家!希望大家能从这次源码剖析中学到一些实用的技巧,并在实际开发中灵活运用。 记住,理解代码背后的逻辑,才能更好地驾驭它! 下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注