You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP开发分页SERP时urlencode参数错误及XSS防护函数用法咨询

报错原因

核心错误是变量覆盖:你最初从$_GET中获取的$col是字符串类型的查询列参数,后续执行数据库查询时,用$col = mysqli_fetch_array($result)将该变量覆盖为了查询结果数组,在构造分页参数时调用urlencode($col)传入了数组,因此触发类型错误警告。

安全函数使用错误修正

三个函数的使用场景和你的错误点如下:

  • urlencode():仅用于编码URL查询参数的值部分,你原本对$search/$tbl/$col参数值编码的逻辑是正确的,不要修改查询参数值之外的部分。
  • rawurlencode():用于编码URL的路径部分,你对当前文件名编码的逻辑符合使用场景,无需调整。
  • htmlentities():用于对输出到HTML页面的内容做转义,需要在内容最终输出到HTML标签/属性的时机调用,你提前对拼接中的查询字符串调用属于时机错误。另外所有用户可控的输出内容(搜索结果的标题、描述、URL等)都需要调用该函数转义,防范XSS注入。
其他存在的问题
  • 未对$_GET参数做存在性校验和类型转换,用户未传对应参数时会抛出Notice错误,$page/$max需要强制转为整数,避免运算和SQL拼接出错。
  • 搜索结果输出环节未做XSS转义,恶意内容被渲染时会触发注入风险。
  • LIMIT子句的参数直接拼接SQL,虽然是数值类型仍建议提前做强制类型转换。
修改后完整代码
<?php
//ERROR REPORTING FOR DEVMODE ONLY.
ini_set('display_errors','1');
ini_set('display_startup_errors','1');
error_reporting(E_ALL);


//MYSQLI CONNECTION.
mysqli_report(MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT);

$server = 'localhost';
$user = 'root';
$password = '';
$database = 'brute';

if(!$conn = mysqli_connect($server,$user,$password,$database))
{
    echo 'Mysqli Connection Error' .mysqli_connect_error($conn);
    echo 'Mysqli Connection Error Number' .mysqli_connect_errno($conn);
}

if(!mysqli_character_set_name($conn) == 'utf8mb4')
{
    echo 'Initial Character Set: ' .mysqli_character_set_name($conn);
    mysqli_set_charset($conn,'utf8mb4');
    echo 'Current Character Set: ' .mysqli_character_set_name($conn);
}


//PAGINATION SECTION. 增加默认值和类型转换
$search = isset($_GET['search']) ? trim($_GET['search']) : ''; //Keyword(s) to search.
$col = isset($_GET['col']) ? trim($_GET['col']) : ''; //MySql Tbl Col to search.
$tbl = isset($_GET['tbl']) ? trim($_GET['tbl']) : ''; //MySql Tbl to search.
$max = isset($_GET['max']) ? intval($_GET['max']) : 10; //Max Result per page.
$page = isset($_GET['page']) ? intval($_GET['page']) : 1; //Serp Number.
// 防止参数为负
$max = $max < 1 ? 10 : $max;
$page = $page < 1 ? 1 : $page;


//QUERY DATABASE FOR KEYWORD COUNT.
$query = "SELECT COUNT(id) From links WHERE keyword = ?";
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
    mysqli_stmt_bind_param($stmt,'s',$search);
    mysqli_stmt_execute($stmt);
    mysqli_stmt_bind_result($stmt,$row_count);
    if(mysqli_stmt_fetch($stmt))
    {
        echo 'Row Count: ' .$row_count; echo '<br>';    
    }
    else
    {
        echo 'Record fetching failed!';
        echo 'Error: ' .mysqli_stmt_error($conn);
        echo 'Error: ' .mysqli_stmt_errno($conn);
    }
    mysqli_stmt_close($stmt);
}
else
{
    echo 'Search Preparation Failed!';
}
echo '<b>'; echo __LINE__; echo '</b>'; echo '<br>';


//START KEYWORD SEARCH & OUTPUT RESULT
$offset = ($page*$max)-$max;
echo $offset; echo '<br>';
echo '<b>'; echo __LINE__; echo '</b>'; echo '<br>';
// LIMIT参数提前转int保证安全
$query = "SELECT id,date_and_time,domain,domain_email,ip,url,anchor,title,description,keyword,keyphrase From links WHERE keyword = ? LIMIT " . intval($offset) . "," . intval($max);
$stmt = mysqli_stmt_init($conn);
if(mysqli_stmt_prepare($stmt,$query))
{
    mysqli_stmt_bind_param($stmt,'s',$search);
    mysqli_stmt_execute($stmt);
    if($result = mysqli_stmt_get_result($stmt))
    {
        // 修改变量名为$row,避免覆盖原来的$col参数
        while($row = mysqli_fetch_array($result))
        {
            $id = $row['0']; //MYSQLI_NUM
            $date_and_time = $row['date_and_time']; //MYSQLI_ASSOC
            $domain = $row['2']; //MYSQLI_NUM
            $domain_email = $row['domain_email']; //MYSQLI_ASSOC
            $ip = $row['4']; //MYSQLI_NUM
            $url = $row['url']; //MYSQLI_ASSOC
            $anchor = $row['6']; //MYSQLI_NUM
            $title = $row['title']; //MYSQLI_ASSOC
            $description = $row['8']; //MYSQLI_NUM
            $keyword = $row['keyword']; //MYSQLI_ASSOC
            $keyphrase = $row['10']; //MYSQLI_NUM

            // 输出内容全部加htmlentities转义防范XSS
            echo 'Id: ' . htmlentities($id) ; echo '<br>';
            echo 'Date And Time: ' . htmlentities($date_and_time); echo '<br>';
            echo 'Domain: ' . htmlentities($domain); echo '<br>';
            echo 'Domain Email: ' . htmlentities($domain_email); echo '<br>';
            echo 'Ip: ' . htmlentities($ip); echo '<br>';
            echo 'Url: ' . htmlentities($url); echo '<br>';
            echo 'Anchor: ' . htmlentities($anchor); echo '<br>';
            echo 'Title: ' . htmlentities($title); echo '<br>';
            echo 'Description: ' . htmlentities($description); echo '<br>';
            echo 'Keyword: ' . htmlentities($keyword); echo '<br>';
            echo 'Keyphrase: ' . htmlentities($keyphrase); echo '<br>';        
        }
    }
    else
    {
        echo 'Record fetching failed!';
        echo 'Error: ' .mysqli_stmt_error($stmt);
        echo 'Error: ' .mysqli_stmt_errno($stmt);
    }
    mysqli_stmt_close($stmt);
}
mysqli_close($conn);
echo '<b>'; echo __LINE__; echo '</b>'; echo '<br>';


//PAGINATION SECTION TO NUMBER THE PAGES AND LINK THEM.
$total_pages = ceil($row_count/$max);
$i = 1; 

$selfpage = basename(__FILE__,'');
$path = rawurlencode($selfpage);
// 此时$col已经是原来的字符串参数,不会报错
$query_string_1 = '?search=' .urlencode($search) .'&tbl=' .urlencode($tbl) .'&col=' .urlencode($col) .'&max=' .intval($max);

while($i<=$total_pages)
{
    $query_string_2 = '&page=' .intval($i);
    // 先拼接完整URL,再在输出到href属性时做htmlentities转义
    $url = $path . $query_string_1 . $query_string_2;

    if($page == $i)
    {
        echo '<a href="' . htmlentities($url) . '"><b>' .intval($i) .'</b></a>';
    }
    else
    {
        echo '<a href="' . htmlentities($url) . '">' .intval($i) .'</a>';
    }
    $i++;
}
?>

内容的提问来源于stack exchange,提问作者I Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.15 12:15:05