PHP cUrl句柄资源被整数替换

问题描述 投票:0回答:2

我正在使用PHP curl向第三方服务器发送一系列请求,这需要登录,然后为该登录持久保存会话cookie。

所以我将curl操作包装到这个类中:

class SoapCli {
    private $ch;
    private $id;
    private $rc;

    function __construct() {
        $this->rc=0;
        $this->id=bin2hex(random_bytes(8));
        $this->ch = curl_init();
        $time=microtime(true);
        error_log(PHP_EOL.PHP_EOL."Instance id $this->id created ($time): \$this->ch = ".print_r($this->ch,true).PHP_EOL,3,"log.txt");
        curl_setopt($this->ch, CURLOPT_AUTOREFERER,1);
        curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($this->ch, CURLOPT_CONNECTTIMEOUT, 120);
        curl_setopt($this->ch, CURLOPT_COOKIEFILE, "");
        curl_setopt($this->ch, CURLOPT_ENCODING, "");
        curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($this->ch, CURLOPT_MAXREDIRS, 10);
        curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($this->ch, CURLOPT_VERBOSE, 1);
    }

    function Request(string $method, string $url, array $headers = array(), $postdata = "", $referer = null) {
        $resp = new stdClass();
        $resp->id = $this->id;
        $this->rc++;
        $time=microtime(true);
        error_log("Instance id $this->id before request $this->rc ($time): \$this->ch = ".print_r($this->ch,true).PHP_EOL,3,"log.txt");
        try {
            curl_setopt($this->ch, CURLOPT_CUSTOMREQUEST, $method);
            curl_setopt($this->ch, CURLOPT_URL, $url);
            curl_setopt($this->ch, CURLOPT_HTTPHEADER, $headers);
            if (isset($referer)) curl_setopt($this->ch, CURLOPT_REFERER, $referer);
            if (preg_match("/^POST$/i",$method)===1) curl_setopt($this->ch, CURLOPT_POSTFIELDS, $postdata);
            $resp->body = curl_exec($this->ch);
            $resp->err_message = curl_error($this->ch);
            $resp->err_number = curl_errno($this->ch);
            $resp->info = curl_getinfo($this->ch);
        }
        catch (Exception $exception) {
            $resp->err_message = $exception->getMessage();
            $resp->err_number = $exception->getCode();
            $resp->info = $exception->getTrace();
        }
        $time=microtime(true);
        error_log("Instance id $this->id before request $this->rc ($time): \$this->ch = ".print_r($this->ch,true).PHP_EOL,3,"log.txt");
        return $resp;
    }
}

但是,在第3次请求之后,存储curl句柄资源的受保护变量的内容被0(整数)的值替换,我真的无法弄清楚原因。我只能收集这个日志:

Instance id 1cb893bc5b7369bd created (1547852391.7976): $this->ch = Resource id #3
Instance id 1cb893bc5b7369bd before request 1 (1547852391.8025): $this->ch = Resource id #3
Instance id 1cb893bc5b7369bd before request 1 (1547852392.0723): $this->ch = Resource id #3
Instance id 1cb893bc5b7369bd before request 2 (1547852392.0778): $this->ch = Resource id #3
Instance id 1cb893bc5b7369bd before request 2 (1547852392.357): $this->ch = Resource id #3
Instance id 1cb893bc5b7369bd before request 3 (1547852392.3616): $this->ch = Resource id #3
Instance id 1cb893bc5b7369bd before request 3 (1547852392.6225): $this->ch = Resource id #3
Instance id 1cb893bc5b7369bd before request 4 (1547852393.0264): $this->ch = 0
Instance id 1cb893bc5b7369bd before request 4 (1547852393.0758): $this->ch = 0
Instance id 1cb893bc5b7369bd before request 5 (1547852394.8992): $this->ch = 0
Instance id 1cb893bc5b7369bd before request 5 (1547852394.9461): $this->ch = 0

编辑:这是消耗类qa​​zxswpoi的代码:

SoapCli

// index.php

$postdata = filter_input_array(INPUT_POST);
if ($_SESSION["logged_in"]===true) {
    echo file_get_contents("main.html");
} else if (isset($postdata) && isset($postdata["action"])) {
    $action = $postdata["action"];
    if ($action==="Login" && isset($postdata["usrcpf"]) && isset($postdata["usrpwd"])) {
        $username=$postdata["username"];
        $password=$postdata["password"];
        $sc=new SoapCli();   //instantiated here
        $_SESSION["sc"]=$sc;
        $login_response = $sc->Request(
            "GET",
            BASEURL."/login",
            array(
                "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0",
                "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
                "Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
                "Connection: keep-alive",
                "Upgrade-Insecure-Requests: 1",
                "Cache-Control: max-age=0"
                )
            );
        if ($login_response->err_number) {
            echo file_get_contents("login_server_error.html");
        } else {
            $dom = new DOMDocument;
            $dom->loadHTML($login_response->body);
            $xdom  = new DOMXPath($dom);
            $csrf_token_nodes = $xdom->query("//input[@name='_csrf_token']/@value");
            if ($csrf_token_nodes->length<1) {
                echo file_get_contents("login_server_error.html");
            } else {
                $csrf_token = $csrf_token_nodes->item(0)->textContent;
                $postdata = "_csrf_token=$csrf_token&_username=$username&_password=$password&_submit=Login";
                $login_check_response = $sc->Request(
                    "POST",
                    BASEURL."/login_check",
                    array(
                        "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0",
                        "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
                        "Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
                        "Content-Type: application/x-www-form-urlencoded",
                        "Connection: keep-alive",
                        "Upgrade-Insecure-Requests: 1"
                    ),
                    $postdata,
                    BASEURL."/login"
                    );
                if ($login_check_response->err_number) {
                    echo file_get_contents("login_server_error.html");
                } elseif (strpos($login_check_response->body, "api.js")) {
                    echo file_get_contents("login_auth_error.html");
                } else {
                    $route_userinfo = $sc->Request(
                        "POST",
                        BASEURL."/route",
                        array(
                             "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0",
                             "Accept: */*",
                             "Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3",
                             "Content-Type: application/json",
                             "X-Requested-With: XMLHttpRequest",
                             "Connection: keep-alive",
                             "Upgrade-Insecure-Requests: 1",
                         ),
                        USERINFO_JSON,
                        BASEURL."/"
                        );
                    if ($route_userinfo->err_number) {
                        echo file_get_contents("login_server_error.html");
                    } else {
                        $_SESSION["logged_in"]=true;
                        $_SESSION["user_info"]=json_decode($route_userinfo->body);
                        header("Location: ".$_SERVER["PHP_SELF"], true, 303);
                    }
                }
            }
        }
    } else {
        http_response_code(400);
    }
} else {
    echo file_get_contents("login.html");
}

由于变量// ajax.php (called by JS in main.html, which is loaded after login) if ($_SESSION["logged_in"]===true) { $postdata = filter_input_array(INPUT_POST); if (isset($postdata)) { if (isset($postdata["content"])) { if ($postdata["content"]==="tasks") { $sc=$_SESSION["sc"]; $route_tasks = $sc->Request( "POST", BASEURL."/route", array( "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0", "Accept: */*", "Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3", "Content-Type: application/json", "X-Requested-With: XMLHttpRequest", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", ), TAKS_JSON, BASEURL."/" ); if ($route_tasks->err_number) { echo file_get_contents("ajax_server_error.html"); } else { $tarefas=json_decode($route_tasks->body); if (isset($tarefas) && is_array($tarefas->records)) { foreach($tarefas->records as $i=>$tarefa){ echo "<p>".$tarefa->especieTarefa->nome."</p>"; } } else { http_response_code(500); } } } } else { http_response_code(400); } } else { http_response_code(400); } } else { http_response_code(403); } 不能在类中访问,我真的看不出如何在没有语句的情况下更改其内容。我也找不到任何关于一种会破坏句柄的http请求/响应的信息。

附加信息

无论它是什么,它都与请求无关,因为我试图重复请求#3,它是有效的并且收到有效的响应,并且由于句柄消失,它的重复失败。

另外,我正在尝试在PHP中实现的功能已经由一个功能齐全的.NET桌面(winforms)应用程序完成,所以它不能因为外部原因而无法完成。我只是想用PHP卷曲我用SoapCli::ch做的事情,并偶然发现了这篇文章中描述的问题。

只要我需要,我怎样才能保留手柄?

我在IIS Express / Windows 10上使用PHP 7.2。

php curl php-curl
2个回答
1
投票

简短的回答是:当您尝试在ajax.php中使用它时,句柄不存在

System.Net.HttpWebRequest内部,看看以下行:

ajax.php

然后你打电话:

                $sc=$_SESSION["sc"];

所以你在 $route_tasks = $sc->Request( ... ); 中调整了你的类,并在那里成功完成了所有3次调用,然后你将一个对象写入index.php变量,显然对象被php的会话处理程序正确编码和解码,这就是为什么你仍然可以调用该方法检索物体后,$_SESSION["sc"]内部的Request

当你确实在ajax.php中使用一个对象时,它与ajax.php创建的对象的实例不同,因为该实例属于index.php线程以及index.php句柄;从curl调用ajax.php会创建一个不同的线程来处理它,并且还需要一个新的index.php句柄。

curl更改为$sc=$_SESSION["sc"];,以便在使用之前创建$sc=new SoapCli();手柄。


0
投票

我发布这个答案只是为了说明我是如何解决@Solrac在他的回答中描述和解释的问题(这是正确的,我会接受):

curl
© www.soinside.com 2019 - 2024. All rights reserved.