curl_multi_exec():提供的资源不是有效的 cURL 句柄资源



我最近更新了PHP 7.2(从5.x开始(,我的一个Opencart插件开始表现得很奇怪。我认为当 curl 尝试连接到 404 链接时会发生这种情况。在日志中,我看到:

curl_multi_exec((:提供的资源不是有效的 cURL 句柄 资源在

我认为这是一个无限循环,因为它不会停止自己。代码如下:

public function uploadMultipleImages($images, $importer, &$parent)
{
set_error_handler('error_handler_for_export', E_ALL);
register_shutdown_function('fatal_error_shutdown_handler_for_export');
if (count($images) == 0)
return true;
//ini_set('memory_limit', '512M');
ini_set('memory_limit', '-1');
try {
$img = array();
$directory = rtrim(DIR_IMAGE . 'data/' . str_replace('../', '', $importer), '/');
if (!is_dir($directory))
if (!mkdir($directory, 0777, true))
die('Failed to create folders...');
$pack = 30;
$chs = array();
$cmh = curl_multi_init();
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP xml Image: Images to download: ' . count($images));
}
for ($t = 0; $t < $pack && $t < count($images); $t++) {
$chs[$t] = curl_init();
curl_setopt($chs[$t], CURLOPT_URL, $images[$t]['image']);
curl_setopt($chs[$t], CURLOPT_RETURNTRANSFER, 1);
curl_setopt($chs[$t], CURLOPT_CONNECTTIMEOUT, 100);
curl_setopt($chs[$t], CURLOPT_TIMEOUT, 100);
curl_multi_add_handle($cmh, $chs[$t]);
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Added to queue image 51: ' . $images[$t]['image'] . ' CNT: ' . count($chs));
}
}
do {
while (($execrun = curl_multi_exec($cmh, $running)) == CURLM_CALL_MULTI_PERFORM) ;
if ($execrun != CURLM_OK)
break;
//usleep(200000); 
// Block for data in / output; error handling is done by curl_multi_exec
curl_multi_select($cmh);
// a request was just completed -- find out which one
while ($done = curl_multi_info_read($cmh)) {
$info = curl_getinfo($done['handle']);
if ($info['http_code'] > 199 && $info['http_code'] < 300) {
$file = curl_multi_getcontent($done['handle']);

// handle the done request
if ($file != null && $file != '' && !empty($file) && $file != 'null') {
$parts = parse_url($info['url']);
$filename = basename($parts['path']);
$path_to_file = $directory . '/' . $filename;
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Image extension: ' . $ext);
}
$ok = TRUE;
if ($ext == 'jpg' || $ext == 'jpeg' || $ext == 'png' || $ext == 'gif') {
$path_to_file = $directory . '/' . $this->clean_filename($filename);
$theFileName = $this->clean_filename($filename);
} else {
$path_to_file = $directory . '/' . $this->clean_filename($filename . $parts['query']);
$theFileName = $this->clean_filename($filename . $parts['query']) . ".jpg";
switch ($info['content_type']) {
case 'image/jpeg':
$path_to_file = $path_to_file . '.jpg';
$theFileName = $theFileName . '.jpg';
$ok = TRUE;
break;
case 'image/gif':
$path_to_file = $path_to_file . '.gif';
$theFileName = $theFileName . '.gif';
$ok = TRUE;
break;
case 'image/png':
$path_to_file = $path_to_file . '.png';
$theFileName = $theFileName . '.png';
$ok = TRUE;
break;
default:
$ok = FALSE;
break;
}
}
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Image type: ' . $info['content_type']);
}
if ($ok === TRUE)
if (file_put_contents($path_to_file, $file) > 0) {
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Image saved image: ' . $info['url']);
}
$parent->nr_images_imported++;
}
}
unset($file);
} else {
// request failed.  add error handling.
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Failed downloading image: ' . $info['url']);
}
}
// start a new request (it's important to do this before removing the old one)
if ($t + 1 < count($images)) {
$t++;
$chs[$t] = curl_init();
curl_setopt($chs[$t], CURLOPT_URL, $images[$t]['image']);
curl_setopt($chs[$t], CURLOPT_RETURNTRANSFER, 1);
curl_setopt($chs[$t], CURLOPT_CONNECTTIMEOUT, 100);
curl_setopt($chs[$t], CURLOPT_TIMEOUT, 100);
curl_multi_add_handle($cmh, $chs[$t]);
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Added to queue image: 147' . $images[$t]['image'] . ' CNT: ' . count($chs));
}
}
// remove the curl handle that just completed
curl_close($done['handle']);
curl_multi_remove_handle($cmh, $done['handle']);
if (($key = array_search($done['handle'], $chs)) !== false) {
unset($chs[$key]);
}
unset($done);
clearstatcache();
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Removed from queue image 160: ' . $info['url'] . ' CNT: ' . count($chs));
}
if ($t % 50 == 0) {
$parent->db->query("SELECT 1");
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: PING - MYSQL! 165 ');
}
}
}
} while ($running);
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Before images m_CURL_CLOSE !');
}
curl_multi_close($cmh);
//PING
$parent->db->query("SELECT 1");
return TRUE;
} catch (Exception $e) {
$errstr = $e->getMessage();
$errline = $e->getLine();
$errfile = $e->getFile();
$errno = $e->getCode();
$parent->session->data['export_error'] = array('errstr' => $errstr, 'errno' => $errno, 'errfile' => $errfile, 'errline' => $errline);
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP ' . get_class($e) . ':  ' . $errstr . ' in ' . $errfile . ' on line ' . $errline);
}
return false;
}
}

我建议您首先采取一些措施来确保一切正常:

(1(- 通过替换以下内容,确保为 cUrl 提供的图像 URL 是有效(格式正确(的 URL:

curl_setopt($chs[$t], CURLOPT_URL, $images[$t]['image']);

为此(添加 urlencode(:

curl_setopt($chs[$t], CURLOPT_URL, urlencode($images[$t]['image']));

为了防止URL格式不正确的可能错误,更多信息在这里:https://forum.ait-pro.com/forums/topic/after-curl-site-is-slow/

(2(- 然后,根据官方手册(此处(,您应该致电:

curl_init()curl_multi_init()

这样,您应该移动:

$cmh = curl_multi_init();

for元素之后,例如:

for ($t = 0; $t < $pack && $t < count($images) ; $t++)
{
$chs[$t] = curl_init();
curl_setopt($chs[$t], CURLOPT_URL, $images[$t]['image']);
curl_setopt($chs[$t], CURLOPT_RETURNTRANSFER, 1);
curl_setopt($chs[$t], CURLOPT_CONNECTTIMEOUT, 100);
curl_setopt($chs[$t], CURLOPT_TIMEOUT, 100);
curl_multi_add_handle($cmh, $chs[$t]);    // <-- DELETE THIS LINE
if ($parent->config->get('config_error_log')) {
$parent->log->write('PHP Importer Images: Added to queue image 51: ' . $images[$t]['image'] . ' CNT: '. count($chs));
}
}
//AND MOVE IT HERE (remember deleting the first $cmh = curl_multi_init();
$cmh = curl_multi_init();
for ($t = 0; $t < $pack && $t < count($images) ; $t++) {
curl_multi_add_handle($cmh, $chs[$t]);
}
do {
...

并记住删除第一个$cmh = curl_multi_init();. 您可以在此处查看类似问题的更多信息。

最后,如果您有无限循环,请检查do{ ... } while()的条件/状态并while()调用,例如$running以确保循环完成。

您的代码在实践中禁用了 cURL 中的重定向限制。因此,如果被调用的页面向您发送特定类型的重定向(就像某些 404 页面一样(,您可能会发现自己处于无限循环中。

您可以通过让每个 curl 请求打印其目标 URL 来轻松检查这一点。

解决问题,并不理想,它可能会破坏其他一些代码,但是......如果无法从 curl 句柄显式检查重定向状态(这是正确的方法(,请尝试将CURLOPT_FOLLOWLOCATION选项设置为 0。

最新更新