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

使用PHP爬取议会网站遭遇‘Invalid Checksum format’错误求助

解决Oracle APEX表单提交的Checksum格式错误问题

我在做一个爬取当地议会网站垃圾收集日期的业余项目,用PHP+Curl模拟表单提交,但遇到了头疼的问题:把代码里打印出的变量手动复制到Postman里提交能成功,但直接跑PHP代码就返回Checksum format error。我怀疑是$protected变量的问题,因为把它换成手动复制的静态值代码就能正常运行。

原代码

<?php 
function curlResponseHeaderCallback($ch, $headerLine) {
    global $cookies;
    if (preg_match('/^Set-Cookie:\s*([^;]*)/mi', $headerLine, $cookie) == 1)
        $cookies[] = $cookie;
    return strlen($headerLine); // Needed by curl
}

function get_string_between($string, $start, $end){
    $string = ' ' . $string;
    $ini = strpos($string, $start);
    if ($ini == 0) return '';
    $ini += strlen($start);
    $len = strpos($string, $end, $ini) - $ini;
    return substr($string, $ini, $len);
}

$cookies = Array();
$ch = curl_init('https://iweb.itouchvision.com/portal/f?p=customer:BIN_DAYS:::NO:RP:UID:625C791B4D9301137723E9095361401AE8C03934');
// Ask for the callback.
curl_setopt($ch, CURLOPT_HEADERFUNCTION, "curlResponseHeaderCallback");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
$result = curl_exec($ch);
curl_close($ch);

$protected = get_string_between($result, 'id="pPageItemsProtected" value="', '"');
$arr = explode('set-cookie: ORA_WWV_APP_1030=', $cookies[0][0]);
$cookie = $arr[1];
$p_flow_id = get_string_between($result, 'name="p_flow_id" value="', '" id="pFlowId"');
$p_flow_step_id = get_string_between($result, 'name="p_flow_step_id" value="', '" id="pFlowStepId" ');
$p_instance = get_string_between($result, 'name="p_instance" value="', '" id="pInstance"');
$p_page_submission_id = get_string_between($result, '<input type="hidden" name="p_page_submission_id" value="', '" id="pPage');
$P0_PWD_POLICY_LONG = get_string_between($result, 'data-for="P0_PWD_POLICY_LONG" value="', '">');
$P0_PWD_POLICY_NO_SPACE = get_string_between($result, 'data-for="P0_PWD_POLICY_NO_SPACE" value="', '">');
$P0_PWD_POLICY_VALID_PUNCT = get_string_between($result, 'data-for="P0_PWD_POLICY_VALID_PUNCT" value="', '">');
$P0_PWD_POLICY_REPEAT_CHAR = get_string_between($result, 'data-for="P0_PWD_POLICY_REPEAT_CHAR" value="', '">');
$P0_PWD_POLICY_USERNAME = get_string_between($result, 'data-for="P0_PWD_POLICY_USERNAME" value="', '">');
$P0_PWD_POLICY_ALPHANUM = get_string_between($result, 'data-for="P0_PWD_POLICY_ALPHANUM" value="', '">');
$P153_CAL_MSG = get_string_between($result, 'data-for="P153_CAL_MSG" value="', '">');
$P153_ZABY = get_string_between($result, 'data-for="P153_ZABY" value="', '">');
$P153_USER_AGENT = get_string_between($result, 'data-for="P153_USER_AGENT" value="', '">');
$P153_SYSDATE = get_string_between($result, 'name="P153_SYSDATE" maxlength="" size="30" value="', '" autocomplete="off">');

echo 'p_flow_id' . $p_flow_id . ' </br> ';
echo 'p_flow_step_id' . $p_flow_step_id  . ' </br> ';
echo 'p_instance' . $p_instance . ' </br> ';
echo 'p_page_submission_id' . $p_page_submission_id . ' </br>';
echo 'cookie' . $cookie . '</br>';
echo '$protected' . $protected . '</br>';

$p_json = '{"salt":"'.$p_page_submission_id.'","pageItems":{"itemsToSubmit":[{"n":"P0_LANGUAGE","v":"EN"},{"n":"P0_PWD_POLICY_LONG","v":"","ck":"'.$P0_PWD_POLICY_LONG.'"},{"n":"P0_PWD_POLICY_NO_SPACE","v":"","ck":"'.$P0_PWD_POLICY_NO_SPACE.'"},{"n":"P0_PWD_POLICY_VALID_PUNCT","v":"","ck":"'.$P0_PWD_POLICY_VALID_PUNCT.'"},{"n":"P0_PWD_POLICY_REPEAT_CHAR","v":"","ck":"'.$P0_PWD_POLICY_REPEAT_CHAR.'"},{"n":"P0_PWD_POLICY_USERNAME","v":"","ck":"'.$P0_PWD_POLICY_USERNAME.'"},{"n":"P0_PWD_POLICY_ALPHANUM","v":"","ck":"'.$P0_PWD_POLICY_ALPHANUM.'"},{"n":"P153_POST_CODE","v":"ta1 1aa"},{"n":"P153_CAL_MSG","v":"","ck":"'.$P153_CAL_MSG.'"},{"n":"P153_ZABY","v":"","ck":"'.$P153_ZABY.'"},{"n":"P153_TEMP","v":""},{"n":"P153_USER_AGENT","v":"","ck":"'.$P153_USER_AGENT.'"},{"n":"P153_SYSDATE","v":"'.$P153_SYSDATE.'"}],"protected":"'.$protected.'","rowVersion":"","formRegionChecksums":[]}}';
echo $p_json;

$url = 'https://iweb.itouchvision.com/portal/wwv_flow.accept';
$data = array('p_json' => $p_json, 'p_flow_id' => $p_flow_id, 'p_flow_step_id' => $p_flow_step_id, 'p_instance' => $p_instance, 'p_page_submission_id' => $p_page_submission_id, 'p_request' => 'SEARCH', 'p_reload_on_submit' => 'A');

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Cookie: ORA_WWV_APP_1030=" . $cookie));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
echo $response;
curl_close($ch);

问题根源

你的get_string_between函数在提取变量时,可能带回了不可见的空白字符(比如换行、制表符、首尾空格),或者变量在手动拼接JSON时出现了转义错误。尤其是$protected这类校验值,哪怕多一个不可见字符,都会导致校验失败。

修复步骤

  1. 清理提取的变量:对所有从HTML中提取的变量做trim()处理,去除首尾空白字符:
$protected = trim(get_string_between($result, 'id="pPageItemsProtected" value="', '"'));
$p_flow_id = trim(get_string_between($result, 'name="p_flow_id" value="', '" id="pFlowId"'));
$p_flow_step_id = trim(get_string_between($result, 'name="p_flow_step_id" value="', '" id="pFlowStepId" '));
$p_instance = trim(get_string_between($result, 'name="p_instance" value="', '" id="pInstance"'));
$p_page_submission_id = trim(get_string_between($result, '<input type="hidden" name="p_page_submission_id" value="', '" id="pPage'));
// 其他所有提取的变量都加上trim()
  1. 修复Curl的HTTP头设置:连续两次调用CURLOPT_HTTPHEADER会覆盖前一次的设置,导致Content-Type头丢失,合并HTTP头:
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/x-www-form-urlencoded',
    "Cookie: ORA_WWV_APP_1030=" . $cookie
));
  1. 避免手动拼接JSON:手动拼接容易出现转义错误,改用json_encode生成标准JSON:
$pageItems = [
    ["n"=>"P0_LANGUAGE","v"=>"EN"],
    ["n"=>"P0_PWD_POLICY_LONG","v"=>"","ck"=>$P0_PWD_POLICY_LONG],
    ["n"=>"P0_PWD_POLICY_NO_SPACE","v"=>"","ck"=>$P0_PWD_POLICY_NO_SPACE],
    ["n"=>"P0_PWD_POLICY_VALID_PUNCT","v"=>"","ck"=>$P0_PWD_POLICY_VALID_PUNCT],
    ["n"=>"P0_PWD_POLICY_REPEAT_CHAR","v"=>"","ck"=>$P0_PWD_POLICY_REPEAT_CHAR],
    ["n"=>"P0_PWD_POLICY_USERNAME","v"=>"","ck"=>$P0_PWD_POLICY_USERNAME],
    ["n"=>"P0_PWD_POLICY_ALPHANUM","v"=>"","ck"=>$P0_PWD_POLICY_ALPHANUM],
    ["n"=>"P153_POST_CODE","v"=>"ta1 1aa"],
    ["n"=>"P153_CAL_MSG","v"=>"","ck"=>$P153_CAL_MSG],
    ["n"=>"P153_ZABY","v"=>"","ck"=>$P153_ZABY],
    ["n"=>"P153_TEMP","v"=>""],
    ["n"=>"P153_USER_AGENT","v"=>"","ck"=>$P153_USER_AGENT],
    ["n"=>"P153_SYSDATE","v"=>$P153_SYSDATE]
];

$p_json_data = [
    "salt" => $p_page_submission_id,
    "pageItems" => [
        "itemsToSubmit" => $pageItems,
        "protected" => $protected,
        "rowVersion" => "",
        "formRegionChecksums" => []
    ]
];

$p_json = json_encode($p_json_data);
  1. 优化Cookie管理:手动解析Cookie容易出错,改用Curl的CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE自动管理:
// 第一次请求保存Cookie到临时文件
$cookie_file = tempnam(sys_get_temp_dir(), 'cookie');
$ch = curl_init('https://iweb.itouchvision.com/portal/f?p=customer:BIN_DAYS:::NO:RP:UID:625C791B4D9301137723E9095361401AE8C03934');
curl_setopt($ch, CURLOPT_HEADERFUNCTION, "curlResponseHeaderCallback");
curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_file);
$result = curl_exec($ch);
curl_close($ch);

// 第二次请求加载Cookie
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_file);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);
unlink($cookie_file); // 用完删除临时文件

验证方法

每次提取变量后,用var_dump($protected)查看变量的实际内容和长度,对比手动复制的静态值,确保完全一致(包括字符数、不可见字符)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:49:54