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

PHP Curl提交学生ID与CSRF令牌至考勤系统失败求助

解决PHP Curl提交Django考勤系统数据失败的问题

我希望实现本校考勤系统的自动化操作,该网站需要提交student_id(学生ID)和csrfmiddlewaretoken两个数据字段,但使用PHP Curl提交数据时始终失败,尝试了以下两种方法均未成功,现寻求解决方案。

原始方法1

<?php

    $url = "http://x.com";
    $username = "111";

    $csrf_token_field_name = "csrfmiddlewaretoken";
    $params = array(
                    "student_id" => $username
                    );

    $token_cookie= realpath("test.txt");

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/32.0.1700.107 Chrome/32.0.1700.107 Safari/537.36');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_COOKIEJAR, $token_cookie);
    curl_setopt($ch, CURLOPT_COOKIEFILE, $token_cookie);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    $response = curl_exec($ch);


    if (curl_errno($ch)) die(curl_error($ch));
    libxml_use_internal_errors(true);
    $dom = new DomDocument();
    $dom->loadHTML($response);
    libxml_use_internal_errors(false);
    $tokens = $dom->getElementsByTagName("input");
    for ($i = 0; $i < $tokens->length; $i++)
    {
        $meta = $tokens->item($i);
        if($meta->getAttribute('name') == 'csrfmiddlewaretoken')
            $t = $meta->getAttribute('value');
    }
    if($t) {
        $csrf_token = file_get_contents(realpath("another-cookie.txt"));
        $postinfo = "";
        foreach($params as $param_key => $param_value)
        {
            $postinfo .= $param_key ."=". $param_value . "&";
        }
        $postinfo .= $csrf_token_field_name ."=". $t;

        $headers = array();

        $header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,";
        $header[] = "Cache-Control: max-age=0";
        $header[] = "Connection: keep-alive";
        $header[] = "Keep-Alive: 300";
        $header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
        $header[] = "Accept-Language: en-us,en;q=0.5";
        $header[] = "Pragma: ";
        $headers[] = "X-CSRF-Token: $t";
        $headers[] = "Cookie: $token_cookie";

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6");
        curl_setopt($ch, CURLOPT_COOKIEJAR, $token_cookie);
        curl_setopt($ch, CURLOPT_COOKIEFILE, $token_cookie);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postinfo);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_REFERER, $url);
        curl_setopt($ch, CURLOPT_ENCODING, "gzip,deflate");
        curl_setopt($ch, CURLOPT_AUTOREFERER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 260);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_VERBOSE, true);

        ob_start();
        $html = curl_exec($ch);
        $result = curl_getinfo($ch);
        ob_get_clean();

        echo "<pre>";
        print_r($result);
        echo "</pre>";
        print($html);

        if (curl_errno($ch)) print curl_error($ch);
        curl_close($ch);
    }

?>

原始方法2

<?php

    include "simple_html_dom.php";

$ch = curl_init("http://x.com");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
$response = curl_exec($ch);

$dom = new DOMDocument;
$dom->loadHTML($response);
$tags = $dom->getElementsByTagName('input');
for($i = 0; $i < $tags->length; $i++){
    $grab = $tags->item($i);
    if($grab->getAttribute('name') === 'csrfmiddlewaretoken'){
        $token = $grab->getAttribute('value');
    }
}
echo $token;
$data = array(
    "csrfmiddlewaretoken"=> $token,
    "student_id"=> '123'

);

curl_setopt($ch, CURLOPT_URL, "http://x.com");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$response = curl_exec($ch);
echo $response;

?>

核心问题分析

方法1的错误点

  • 手动拼接POST数据未做urlencode处理,若student_id含特殊字符会导致参数解析失败
  • 错误将Cookie文件路径写入Cookie请求头,Curl会自动通过CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE管理Cookie,无需手动设置该头
  • 额外添加的X-CSRF-Token头不符合Django校验逻辑,Django优先通过表单字段或Cookie中的csrftoken验证,该头属于冗余操作
  • 读取another-cookie.txt的操作完全多余,Cookie已由Curl自动维护

方法2的错误点

  • 未设置CURLOPT_COOKIEFILE,导致第二次POST请求无法携带第一次GET请求获取的Cookie(Django需要Cookie中的csrftoken与表单字段配合验证)
  • 未设置User-Agent请求头,部分网站会拦截无UA的请求
  • 未设置Referer头,Django可能会校验请求来源
  • 引入simple_html_dom.php但未使用,属于冗余代码

修正后的可行代码

<?php
$url = "http://x.com";
$student_id = "123"; // 替换为实际学生ID
$cookie_file = realpath("cookie.txt");

// 第一步:获取页面和CSRF Token,同时保存Cookie
$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
    CURLOPT_COOKIEJAR => $cookie_file,
    CURLOPT_COOKIEFILE => $cookie_file,
    CURLOPT_SSL_VERIFYHOST => 0,
    CURLOPT_SSL_VERIFYPEER => 0,
]);
$response = curl_exec($ch);
if (curl_errno($ch)) {
    die("请求失败:" . curl_error($ch));
}

// 解析CSRF Token
libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML($response);
libxml_use_internal_errors(false);
$csrf_token = null;
$inputs = $dom->getElementsByTagName("input");
foreach ($inputs as $input) {
    if ($input->getAttribute("name") === "csrfmiddlewaretoken") {
        $csrf_token = $input->getAttribute("value");
        break;
    }
}
if (!$csrf_token) {
    die("未找到CSRF Token");
}

// 第二步:提交POST请求
$post_data = [
    "csrfmiddlewaretoken" => $csrf_token,
    "student_id" => $student_id
];
curl_setopt_array($ch, [
    CURLOPT_URL => $url,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => http_build_query($post_data), // 自动处理URL编码
    CURLOPT_REFERER => $url, // 设置来源页面
    CURLOPT_FOLLOWLOCATION => true, // 跟随跳转
]);
$submit_response = curl_exec($ch);
if (curl_errno($ch)) {
    die("提交失败:" . curl_error($ch));
}

// 输出结果
echo "<pre>";
print_r(curl_getinfo($ch));
echo "</pre>";
echo $submit_response;

curl_close($ch);
?>

关键优化点

  • 使用curl_setopt_array批量设置参数,代码更简洁易维护
  • 用http_build_query处理POST数据,自动完成URL编码,避免手动拼接的错误
  • 同时设置CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE,确保Cookie在两次请求间正确传递
  • 添加标准的User-Agent和Referer头,模拟正常浏览器请求
  • 简化CSRF Token的解析逻辑,提前终止循环提升效率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 20:05:55