分析 WordPress `is_admin()` 函数的源码:如何通过 `$_SERVER[‘REQUEST_URI’]` 判断是否为后台请求。

大家好,今天咱们来扒一扒 WordPress 后台的“守门神”—— is_admin() 函数。别看它名字简单,背后的逻辑可有点意思。它就像一个尽职尽责的保安,负责判断当前的请求是不是要进入 WordPress 的后台“禁地”。

开场白:后台的“结界”

想象一下,WordPress 后台就像一个神秘的魔法学院,只有拥有通行证的人才能进入学习魔法。这个通行证就是 is_admin() 函数返回的 true。如果它返回 false,那对不起,你只能在学院外面溜达溜达。

那么,这个“保安” is_admin() 究竟是如何辨别请求的呢?关键就在于它仔细检查了 $_SERVER['REQUEST_URI'] 这个“线索”。

一、$_SERVER['REQUEST_URI'] 是什么?

$_SERVER 是一个 PHP 超全局变量,它包含了服务器和执行环境的信息。$_SERVER['REQUEST_URI'] 里面存储的是用户在浏览器地址栏中输入的请求 URI,也就是从域名之后到问号(如果有的话)之前的部分。

举个例子:

  • 如果用户访问 https://example.com/wp-admin/index.php,那么 $_SERVER['REQUEST_URI'] 的值就是 /wp-admin/index.php
  • 如果用户访问 https://example.com/wp-admin/post.php?post=123,那么 $_SERVER['REQUEST_URI'] 的值就是 /wp-admin/post.php?post=123
  • 如果用户访问 https://example.com/some-page,那么 $_SERVER['REQUEST_URI'] 的值就是 /some-page

简单来说,$_SERVER['REQUEST_URI'] 就是用户在浏览器地址栏中输入的内容中,域名之后的部分。

二、is_admin() 的源码剖析

现在,让我们深入到 is_admin() 的源码中,看看它是如何利用 $_SERVER['REQUEST_URI'] 来判断是否为后台请求的。

function is_admin() {
    if ( isset( $GLOBALS['is_admin'] ) ) {
        return $GLOBALS['is_admin'];
    }

    if ( defined( 'WP_ADMIN' ) ) {
        $GLOBALS['is_admin'] = WP_ADMIN;
        return $GLOBALS['is_admin'];
    }

    $current_file = basename( $_SERVER['SCRIPT_FILENAME'] );

    // Check if install.php is being run.
    if ( 'install.php' === $current_file ) {
        $GLOBALS['is_admin'] = false;
        return $GLOBALS['is_admin'];
    }

    $admin_base_path = rtrim( str_replace( basename( ABSPATH ), '', str_replace( '\', '/', ABSPATH ) ), '/' );

    $is_admin = false;
    if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
        $admin_url_slug = untrailingslashit( str_replace( $admin_base_path, '', admin_url() ) );
        $is_admin       = false !== strpos( $_SERVER['REQUEST_URI'], $admin_url_slug );
    }

    /**
     * Filters whether the current request is for an administrative interface page.
     *
     * @since 2.0.0
     *
     * @param bool $is_admin Whether the request is for an administrative interface page.
     */
    $GLOBALS['is_admin'] = (bool) apply_filters( 'admin_init', $is_admin );

    return $GLOBALS['is_admin'];
}

让我们一步一步地解读这段代码:

  1. 检查全局变量 $GLOBALS['is_admin'] 和常量 WP_ADMIN

    if ( isset( $GLOBALS['is_admin'] ) ) {
        return $GLOBALS['is_admin'];
    }
    
    if ( defined( 'WP_ADMIN' ) ) {
        $GLOBALS['is_admin'] = WP_ADMIN;
        return $GLOBALS['is_admin'];
    }

    这段代码首先检查是否已经设置了全局变量 $GLOBALS['is_admin']。如果已经设置,就直接返回它的值。这是一种缓存机制,避免重复计算。

    然后,它检查是否定义了常量 WP_ADMIN。如果定义了,就把它的值赋给 $GLOBALS['is_admin'] 并返回。WP_ADMIN 常量通常在 wp-config.php 文件中定义,用于强制指定是否为后台请求。

  2. 检查是否是 install.php

    $current_file = basename( $_SERVER['SCRIPT_FILENAME'] );
    
    // Check if install.php is being run.
    if ( 'install.php' === $current_file ) {
        $GLOBALS['is_admin'] = false;
        return $GLOBALS['is_admin'];
    }

    这段代码获取当前执行的 PHP 文件的文件名,并检查是否是 install.php。如果是,就将 $GLOBALS['is_admin'] 设置为 false 并返回。这是因为在安装 WordPress 的过程中,不应该被认为是后台请求。

  3. 计算后台 URL 的 Slug:

    $admin_base_path = rtrim( str_replace( basename( ABSPATH ), '', str_replace( '\', '/', ABSPATH ) ), '/' );
    
    $is_admin = false;
    if ( ! empty( $_SERVER['REQUEST_URI'] ) ) {
        $admin_url_slug = untrailingslashit( str_replace( $admin_base_path, '', admin_url() ) );
        $is_admin       = false !== strpos( $_SERVER['REQUEST_URI'], $admin_url_slug );
    }

    这段代码是 is_admin() 函数的核心部分。它首先计算后台 URL 的 Slug。

    • $admin_base_path 获取 WordPress 安装目录的路径。
    • admin_url() 返回 WordPress 后台的 URL,例如 https://example.com/wp-admin/
    • str_replace( $admin_base_path, '', admin_url() ) 从后台 URL 中移除 WordPress 安装目录的路径,得到类似于 /wp-admin/ 的字符串。
    • untrailingslashit() 移除字符串末尾的斜杠,得到 /wp-admin

    然后,它使用 strpos() 函数来检查 $_SERVER['REQUEST_URI'] 中是否包含后台 URL 的 Slug。如果包含,就将 $is_admin 设置为 true

  4. 应用过滤器 admin_init

    /**
     * Filters whether the current request is for an administrative interface page.
     *
     * @since 2.0.0
     *
     * @param bool $is_admin Whether the request is for an administrative interface page.
     */
    $GLOBALS['is_admin'] = (bool) apply_filters( 'admin_init', $is_admin );
    
    return $GLOBALS['is_admin'];

    这段代码使用 apply_filters() 函数来应用 admin_init 过滤器。这个过滤器允许开发者自定义是否为后台请求。

    最后,它将 $is_admin 的值赋给全局变量 $GLOBALS['is_admin'] 并返回。

三、is_admin() 的判断逻辑总结

用表格总结一下 is_admin() 的判断逻辑:

步骤 描述 依赖的变量/函数
1 检查 $GLOBALS['is_admin'] 是否已设置,如果已设置则直接返回。 $GLOBALS['is_admin']
2 检查 WP_ADMIN 常量是否已定义,如果已定义则将其值赋给 $GLOBALS['is_admin'] 并返回。 WP_ADMIN
3 检查当前执行的文件是否为 install.php,如果是则返回 false $_SERVER['SCRIPT_FILENAME']
4 计算后台 URL 的 Slug。 ABSPATH, admin_url()
5 检查 $_SERVER['REQUEST_URI'] 中是否包含后台 URL 的 Slug,如果包含则返回 true $_SERVER['REQUEST_URI']
6 应用 admin_init 过滤器,允许开发者自定义判断结果。 apply_filters('admin_init', $is_admin)

四、代码示例:模拟 is_admin() 的行为

为了更好地理解 is_admin() 的工作原理,我们可以编写一个简单的代码示例来模拟它的行为。

<?php

function simulate_is_admin() {
    // 模拟 $_SERVER['REQUEST_URI']
    $_SERVER['REQUEST_URI'] = '/wp-admin/index.php'; // 或者 '/wp-admin/post.php?post=123' 或者 '/some-page'

    // 模拟 ABSPATH 和 admin_url()
    define( 'ABSPATH', '/var/www/html/wordpress/' ); // 你的 WordPress 安装目录
    function admin_url() {
        return 'https://example.com/wp-admin/'; // 你的 WordPress 后台 URL
    }

    $admin_base_path = rtrim( str_replace( basename( ABSPATH ), '', str_replace( '\', '/', ABSPATH ) ), '/' );
    $admin_url_slug = untrailingslashit( str_replace( $admin_base_path, '', admin_url() ) );

    $is_admin = false !== strpos( $_SERVER['REQUEST_URI'], $admin_url_slug );

    return $is_admin;
}

// 调用模拟函数并输出结果
$is_admin = simulate_is_admin();
if ( $is_admin ) {
    echo "这是一个后台请求!";
} else {
    echo "这不是一个后台请求。";
}

?>

在这个示例中,我们手动设置了 $_SERVER['REQUEST_URI']ABSPATHadmin_url() 的值,然后模拟了 is_admin() 函数的核心逻辑。你可以修改 $_SERVER['REQUEST_URI'] 的值来测试不同的情况。

五、注意事项和常见问题

  • $_SERVER['REQUEST_URI'] 的可靠性: 理论上,$_SERVER['REQUEST_URI'] 的值是由客户端提供的,因此存在被篡改的风险。但是,在实际应用中,这种风险很小。
  • 使用 is_admin() 的时机: is_admin() 函数应该在 admin_init 动作之后调用,以确保 WordPress 已经完成了初始化。
  • is_admin()is_admin_bar_showing() 的区别: is_admin() 用于判断是否为后台请求,而 is_admin_bar_showing() 用于判断是否显示管理栏。它们是不同的概念。

六、高级应用:自定义 admin_init 过滤器

通过 admin_init 过滤器,我们可以自定义 is_admin() 函数的返回值。这在某些特殊情况下非常有用。

例如,我们可以根据用户的 IP 地址来判断是否为后台请求:

add_filter( 'admin_init', 'my_custom_is_admin' );

function my_custom_is_admin( $is_admin ) {
    $allowed_ips = array( '127.0.0.1', '192.168.1.100' ); // 允许访问后台的 IP 地址

    if ( in_array( $_SERVER['REMOTE_ADDR'], $allowed_ips ) ) {
        return true;
    } else {
        return $is_admin; // 保持原来的判断结果
    }
}

在这个示例中,我们创建了一个名为 my_custom_is_admin() 的函数,并将其添加到 admin_init 过滤器中。这个函数检查用户的 IP 地址是否在允许的 IP 地址列表中。如果在列表中,就返回 true,否则返回原来的判断结果。

七、总结:is_admin() 的价值

is_admin() 函数是 WordPress 安全机制的重要组成部分。它通过检查 $_SERVER['REQUEST_URI'] 和应用 admin_init 过滤器,有效地判断当前的请求是否要进入后台。了解 is_admin() 的工作原理,可以帮助我们更好地理解 WordPress 的安全机制,并编写更安全的代码。

希望今天的讲座能够帮助大家更好地理解 is_admin() 函数。下次再见!

发表回复

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