WordPress函数:wp_parse_str 解析查询字符串
编辑文章简介
wp_parse_str 函数将 URL 格式的查询字符串解析并转换为一个 PHP 关联数组,常用于处理 URL 参数或表单序列化数据。
语法
此函数定义于 WordPress 核心文件 wp-includes/formatting.php 中。它内部封装了 PHP 的原生 parse_str() 函数,但额外处理了 WordPress 历史版本中的“魔术引号”问题,确保了在不同服务器环境下的解析一致性。
wp_parse_str( string $input_string, array &$output_array ): void
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
$input_string |
string | 是 | 需要被解析的查询字符串(例如:'name=John&age=25')。 |
&$output_array |
array | 是 | 解析后的参数将被填充到这个变量中。注意这是一个引用传递的参数。 |
| 返回值 | void | 此函数无返回值,结果通过修改第二个参数 &$output_array 来传递。 |
重要历史提示:在 WordPress 3.4 之前,wp_parse_str() 的参数顺序与 PHP 原生的 parse_str() 相反。现在的顺序(字符串在前,数组在后)与 PHP 保持一致。了解这一点有助于阅读遗留代码。
用法
基础用法
最基础的场景是解析一个格式良好的查询字符串,并将其转换为一个关联数组,便于在代码中访问各个参数。
// 示例:解析一个简单的查询字符串
$query_string = 'post_type=page&posts_per_page=5&orderby=date';
$args = array(); // 必须先声明一个数组变量
wp_parse_str( $query_string, $args );
// 现在 $args 数组包含了解析后的参数
var_dump( $args );
/*
输出:
array(3) {
["post_type"]=>
string(4) "page"
["posts_per_page"]=>
string(1) "5"
["orderby"]=>
string(4) "date"
}
*/
// 你可以像使用普通数组一样使用这些值
if ( isset( $args['post_type'] ) ) {
echo '查询的文章类型是:' . esc_html( $args['post_type'] );
}
进阶用法
一个典型的进阶场景是从当前页面的 URL 中获取查询参数,并将其用于构建自定义查询。这在创建自定义筛选功能或处理插件设置页面时非常有用。
// 示例:从当前URL获取参数,并用于 WP_Query
// 假设当前URL是:https://example.com/?category=news&featured=1
// 获取当前URL中的查询字符串部分
$current_query_string = $_SERVER['QUERY_STRING']; // ‘category=news&featured=1’
$query_args = array(); // 初始化数组,用于存放解析后的参数
wp_parse_str( $current_query_string, $query_args );
// 现在将解析出的参数安全地合并到 WP_Query 参数中
$custom_query = new WP_Query(
array(
'post_type' => 'post',
'posts_per_page' => 10,
'category_name' => isset( $query_args['category'] ) ? sanitize_title( $query_args['category'] ) : '',
'meta_query' => array(
// 注意:这里仅作示例,实际中需要更严格地验证 ‘featured’ 的值
array(
'key' => '_featured',
'value' => isset( $query_args['featured'] ) ? '1' : '',
),
),
)
);
// ... 使用 $custom_query 进行循环输出 ...
易错点
混淆参数顺序
这是最常见的错误。错误地将数组作为第一个参数传入,导致期望解析的字符串未被处理,而传入的数组却被清空。
// 错误示例
$my_array = array( 'some_data' => 'value' );
wp_parse_str( $my_array, $query_string ); // 参数顺序错误!
// 正确顺序
wp_parse_str( $query_string, $my_array );
误解返回值
试图直接获取函数的返回值会导致错误,因为此函数没有返回值。必须通过第二个参数(引用)来获取结果。
// 错误示例
$result = wp_parse_str( 'key=value', $array ); // $result 为 null
// 正确做法
$array = array();
wp_parse_str( 'key=value', $array );
// 现在 $array 是 array( 'key' => 'value' )
忽略输入来源的安全性
wp_parse_str 本身只负责解析字符串结构,并不对解析出的内容进行任何安全过滤或验证。直接使用来自用户(如 $_GET, $_POST)的原始字符串是极其危险的,可能导致安全漏洞。
// 危险示例:直接解析不可信的输入
wp_parse_str( $_GET['user_input'], $params );
// 如果 $_GET['user_input'] 是 `evil_code=<script>alert('xss')</script>`,
// 那么 $params['evil_code'] 就包含恶意脚本。
// 相对安全的做法是,在特定、受控的上下文中使用,或先对输入字符串进行初步验证。
// 更好的做法见下方‘最佳实践’。
最佳实践
安全地使用解析结果
鉴于 wp_parse_str 不处理数据安全,对解析后得到的数据进行验证、清理和转义是开发者的责任。永远不要信任解析后的数据,尤其是在进行数据库操作或前端输出时。
// 示例:安全地处理并输出解析后的数据
$raw_input = $_SERVER['QUERY_STRING']; // 来自URL,不可信
$params = array();
wp_parse_str( $raw_input, $params );
// 1. 验证:检查必须的参数是否存在、类型是否正确
$user_id = isset( $params['user_id'] ) ? absint( $params['user_id'] ) : 0; // 转换为非负整数
if ( ! $user_id ) {
wp_die( '无效的用户ID' );
}
// 2. 清理:用于数据库查询时,使用 prepare 语句
global $wpdb;
$user = $wpdb->get_row(
$wpdb->prepare(
"SELECT * FROM {$wpdb->users} WHERE ID = %d",
$user_id
)
);
// 3. 转义:在HTML上下文中输出前,必须转义
if ( $user ) {
echo '<h2>用户:' . esc_html( $user->display_name ) . '</h2>'; // 输出时转义
}
预处理输入字符串
在调用 wp_parse_str 之前,可以先对输入字符串进行一些预处理,例如使用 sanitize_text_field 移除不必要的空格和非法字符,或者使用 wp_strip_all_tags 剥离所有HTML/PHP标签,这能为后续处理提供一个更干净的基础。
// 示例:在解析前清理输入字符串
$dirty_string = $_POST['form_data']; // 可能包含多余空格或换行
$clean_string = sanitize_text_field( $dirty_string ); // 清理字符串
$form_data = array();
wp_parse_str( $clean_string, $form_data );
// 现在 $form_data 中的数据已经过初步清理
保持代码清晰与可维护
当解析的字符串结构复杂,或解析逻辑在多处使用时,应将逻辑封装成有明确命名和注释的函数或方法。这有助于其他开发者(或未来的你)理解代码意图。
// 示例:封装解析逻辑
function my_plugin_parse_filter_params( $query_string ) {
$params = array();
wp_parse_str( $query_string, $params );
// 定义我们期望并允许的参数及其默认值、清理方式
$allowed = array(
'category' => array(
'default' => '',
'sanitize' => 'sanitize_title',
),
'page' => array(
'default' => 1,
'sanitize' => 'absint',
),
// ... 更多参数
);
$clean_params = array();
foreach ( $allowed as $key => $rules ) {
$value = isset( $params[ $key ] ) ? $params[ $key ] : $rules['default'];
$clean_params[ $key ] = call_user_func( $rules['sanitize'], $value );
}
return $clean_params;
}
// 在代码中使用
$filters = my_plugin_parse_filter_params( $_SERVER['QUERY_STRING'] );
// $filters 现在是一个完全验证和清理过的安全数组