PHP卷曲在一些请求后停止

时间:2017-06-19 20:07:41

标签: php laravel curl

我有一个登录咖啡机的课程。我有一个laravel应用程序"扫描"所有咖啡机都在一系列IP地址中给出。

问题是Curl在39,128甚至90个请求后停止。所以,我不知道是什么问题,或者是否是内存泄漏,因为PHP和Curl没有显示任何错误。

我需要有关如何解决此类问题的建议或提示。以下是我的代码。

CoffeeMachine课程

<?php 
namespace Starbucks\CoffeeMachine;
class CoffeeMachine
{
private $url = '';
private $username = '';
private $password = '';

private $session;
private $response;
private $responses;

private $lastMessage = '';
private $lastStatus = FALSE;
private $authenticated = FALSE;

private function setFailStatus($message = '')
{
    $this->lastStatus = FALSE;
    $this->lastMessage = $message;
    return FALSE;
}

private function setSuccessStatus($message = '')
{
    $this->lastStatus = TRUE;
    $this->lastMessage = $message;
    return TRUE;
}

public function __construct($url = '', $username = 'admin', $password = 'admin')
{
    $this->boot();

    $this->url = $url;
    $this->username = $username;
    $this->password = $password;
    $this->session = curl_init();

    curl_setopt($this->session, CURLOPT_CONNECTTIMEOUT, 5);
    curl_setopt($this->session, CURLOPT_FAILONERROR, 1);
    curl_setopt($this->session, CURLOPT_FORBID_REUSE, 1);
    curl_setopt($this->session, CURLOPT_FRESH_CONNECT, 1);
}

public function getResponse()
{
    return $this->response;
}

public function login()
{
    curl_setopt($this->session, CURLOPT_URL, $this->url . '/cgi-bin/dologin');
    curl_setopt($this->session, CURLOPT_POST, 1);
    curl_setopt($this->session, CURLOPT_POSTFIELDS, array(
            'username' => $this->username,
            'password' => $this->password
        )
    );
    curl_setopt($this->session, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($this->session, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($this->session, CURLOPT_HEADER, 0);

    $response = curl_exec($this->session);
    $response = json_decode($response, 1);

    if (!isset($response['response'])) return $this->setFailStatus('Auth with no data...');

    if ($response['response'] != 'success') return $this->setFailStatus('Access denied...');

    $this->response = $response;
    $this->lastStatus = TRUE;
    $this->lastMessage = 'OK';
    $this->authenticated = TRUE;

    return TRUE;
}

public function getDeviceInfo()
{

}

public function logout()
{
    curl_close($this->session);
}
}

在IP范围内发现方法

<?php
public function discover(Request $request)
{
    $from = ip2long($request->input('from', '0.0.0.0'));
    $to = ip2long($request->input('to', '255.255.255.255'));
    $ips = array();

    // CHUNK IN GROUPS OF 10 FOR WAIT 60 SECONDS, BUT NOT WORK
    for($i = $from; $i < $to; $i++) $ips[] = long2ip($i);
    $group_of_ips = array_chunk($ips, 10);

    // TESTED THIS AND NOT WORK
    $default_max_execution_time = ini_get('max_execution_time');
    ini_set('max_execution_time', ((abs($from - $to) * 5) + (count($group_of_ips) * 60)) );

    $machine_ips = array();
    foreach($group_of_ips as $index => $row) {
        foreach($row as $ip) {
            $gs = new CoffeeMachine($ip, 'admin', 'admin');
            if ($gs->login()) {
                $machine_ips[] = $ip;
            }
            $gs->logout();
        }
        sleep(60); // TESTED THIS AND NOT WORK
    }

    ini_set('max_execution_time', $default_max_execution_time);

    /* RETURN THE COFFEE MACHINE IP ADDRESS */
    return $machine_ips;
}

2 个答案:

答案 0 :(得分:0)

添加更多错误检查。来自我的卷曲包装的一些片段,hhb_curl:

    $this->curlh = curl_init ( '' ); // why empty string? PHP Fatal error: Uncaught TypeError: curl_init() expects parameter 1 to be string, null given
    if (! $this->curlh) {
        throw new RuntimeException ( 'curl_init failed!' );
    }

这里我验证curl_init设法创建了一个curl资源,如果没有,我抛出一个RuntimeException。你也应该这样做。

    $ret = curl_exec ( $this->curlh );
    if ($this->errno ()) {
        throw new RuntimeException ( 'curl_exec failed. errno: ' . var_export ( $this->errno (), true ) . ' error: ' . var_export ( $this->error (), true ) );
    }

这里,我验证curl_exec没有注册任何错误,否则我抛出RuntimeException。你也应该这样做。 (它使用curl_errno($ ch))

function setopt_array(array $options): bool {
    foreach ( $options as $option => $value ) {
        $this->setopt ( $option, $value );
    }
    return true;
}

这里我确保我的setopt_array实际上并没有使用curl_setopt_array,而是我自己的curl_setopt包装器,你应该这样做,原因如下所示。

private function _setopt(int $option, $value): bool {
    $ret = curl_setopt ( $this->curlh, $option, $value );
    if (! $ret) {
        throw new InvalidArgumentException ( 'curl_setopt failed. errno: ' . $this->errno () . '. error: ' . $this->error () . '. option: ' . var_export ( $this->_curlopt_name ( $option ), true ) . ' (' . var_export ( $option, true ) . '). value: ' . var_export ( $value, true ) );
    }
    $this->curloptions [$option] = $value;
    return $ret; // true...
}

这里我验证curl_setopt成功,如果没有,我抛出一个InvalidArgumentException,你应该做同样的事情(或者至少抛出某种异常,而不是忽略你当前的代码。),不像curl_setopt_array,您实际上可以轻松确定无法设置哪个选项。

并且在调试curl代码时,始终设置CURLOPT_VERBOSE。 (hhb_curl总是这样做,并给curl一个CURLOPT_STDERR tempfile()来放入详细/错误日志,并通过$ hc-&gt; getStdErr()提供日志,你应该至少添加一些形式的CURLOPT_VERBOSE支持调试。我的curl包装器hhb_curl可以在这里找到https://github.com/divinity76/hhb_.inc.php/blob/master/hhb_.inc.php

答案 1 :(得分:0)

为curl执行添加超时解决了问题。您需要监控要访问的每个设备的响应时间。对我来说,CONNECTTIMEOUT和TIMEOUT的工作时间可以正常工作10秒。

<?php 
namespace Starbucks\CoffeeMachine;
class CoffeeMachine
{
private $url = '';
private $username = '';
private $password = '';

private $session;
private $response;
private $responses;

private $lastMessage = '';
private $lastStatus = FALSE;
private $authenticated = FALSE;

private function setFailStatus($message = '')
{
    $this->lastStatus = FALSE;
    $this->lastMessage = $message;
    return FALSE;
}

private function setSuccessStatus($message = '')
{
    $this->lastStatus = TRUE;
    $this->lastMessage = $message;
    return TRUE;
}

public function __construct($url = '', $username = 'admin', $password = 'admin')
{
    $this->boot();

    $this->url = $url;
    $this->username = $username;
    $this->password = $password;
    $this->session = curl_init();

    curl_setopt($this->session, CURLOPT_CONNECTTIMEOUT, 10);
    curl_setopt($this->session, CURLOPT_TIMEOUT, 10);
    curl_setopt($this->session, CURLOPT_FAILONERROR, 1);
    curl_setopt($this->session, CURLOPT_FORBID_REUSE, 1);
    curl_setopt($this->session, CURLOPT_FRESH_CONNECT, 1);
}

public function getResponse()
{
    return $this->response;
}

public function login()
{
    curl_setopt($this->session, CURLOPT_URL, $this->url . '/cgi-bin/dologin');
    curl_setopt($this->session, CURLOPT_POST, 1);
    curl_setopt($this->session, CURLOPT_POSTFIELDS, array(
            'username' => $this->username,
            'password' => $this->password
        )
    );
    curl_setopt($this->session, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($this->session, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($this->session, CURLOPT_HEADER, 0);

    $response = curl_exec($this->session);

    if (curl_errno($this->session)) {
        $msg = $this->url . "\n" . curl_errno($this->session) . "\n" . curl_error($this->session);
        return $this->setFailStatus($msg);
    }

    $response = json_decode($response, 1);

    if (!isset($response['response'])) return $this->setFailStatus('Auth with no data...');

    if ($response['response'] != 'success') return $this->setFailStatus('Access denied...');

    $this->response = $response;
    $this->lastStatus = TRUE;
    $this->lastMessage = 'OK';
    $this->authenticated = TRUE;

    return TRUE;
}

public function getDeviceInfo()
{

}

public function logout()
{
    curl_close($this->session);
}
}

现在我可以循环并到达CoffeeMachines =)