2017-06-19 331 views
0

我有一個類登錄到咖啡機。我有一個laravel應用程序,可以「掃描」一系列IP地址中提供的所有咖啡機。PHP Curl在一些請求後停止

問題是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; 
} 
+0

多少IP地址是在那裏?你能計算腳本可以運行多少秒嗎? max_execution_time可能被設置爲60秒。 –

+0

@EdvardÅkerberg謝謝,max_execution_time是根據要發現的IP數量來計算的,例如255個IP * 5秒 –

回答

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成功地創建一個捲曲的資源,如果沒有,我拋出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,你可以很容易地確定哪些選項不能設置。

當調試卷發代碼時,總是設置CURLOPT_VERBOSE。 (hhb_curl總是這樣做,並給curl一個CURLOPT_STDERR tempfile()來放置詳細/錯誤日誌,並且通過$ hc-> getStdErr()給你提供日誌),你應該至少添加某種形式的CURLOPT_VERBOSE支持來調試。我的捲曲包裝hhb_curl可在此處獲得https://github.com/divinity76/hhb_.inc.php/blob/master/hhb_.inc.php

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 =)