我有一个登录咖啡机的课程。我有一个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;
}
答案 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 =)