Запросы SSL, сделанные с помощью cURL, завершаются неудачно после разветвления процесса

Я столкнулся с довольно странным поведением с завитком

  1. Если я сделаю запрос SSL, используя curl в родительском процессе, а затем
    разорвать процесс и попытаться сделать еще один запрос SSL в дочернем
    процесс попытка завершается с ошибкой №. 35 (ошибка подключения SSL).
  2. Если я не сделаю запрос SSL в родительском, тот в дочернем процессе завершится успешно.
  3. Я могу сделать любое количество не SSL-запросов в родительском и SSL-запросов в дочернем успешно.

Похоже, что это ошибка в libcurl связанный вопрос и ответчик имеет обойти это.

Мои вопросы:

  1. Является curl_global_cleanup выставлено каким-то другим именем в PHP API?
  2. Если нет, есть ли какая-то другая работа вокруг?

$ch = curl_init('https://www.google.ca/');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$success = curl_exec($ch);
var_dump($success !== false); // true
curl_close($ch);

$pid = pcntl_fork();

if ($pid === 0) {
$ch = curl_init('http://www.google.ca/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$success = curl_exec($ch);
var_dump($success !== false); // true
curl_close($ch);

$ch = curl_init('https://www.google.ca/');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$success = curl_exec($ch);
var_dump($success !== false); // false

$errno = curl_errno($ch); // 35
$error = curl_error($ch); // SSL connect error
curl_close($ch);
} else if ($pid > 0) {
// wait for child process
pcntl_wait($status);
} else {
// handel fork error
}

Если это не ошибка в libcurl и я что-то не так делаю, пожалуйста, дайте мне знать.

2

Решение

Я просто решил это с помощью pcntl_exec функция. Таким образом, вы по существу удалили бы свой дочерний код и поместили его в другой php-файл, который затем выполнялся (и фактически заменял) дочерний процесс.

$ch = curl_init('https://www.google.ca/');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$success = curl_exec($ch);
var_dump($success !== false); // true
curl_close($ch);

$pid = pcntl_fork();

if ($pid === 0) {
pcntl_exec('child_curl.php');
} else if ($pid > 0) {
// wait for child process
pcntl_wait($status);
} else {
// handel fork error
}

Содержание child_curl.php:

$ch = curl_init('http://www.google.ca/');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$success = curl_exec($ch);
var_dump($success !== false); // true
curl_close($ch);

$ch = curl_init('https://www.google.ca/');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$success = curl_exec($ch);
var_dump($success !== false); // false

$errno = curl_errno($ch); // 35
$error = curl_error($ch); // SSL connect error
curl_close($ch);

После казни ребенка вы не увидите ошибки.

Эти другие вопросы помогли мне:

1

Другие решения

Другим обходным решением является использование сокетов.

function fetch_page($url) {
$socketPair = array();
if (socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $socketPair) === false) {
return false;
}
$pid = pcntl_fork();
if ($pid === 0) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);
socket_close($socketPair[1]);
socket_set_nonblock($socketPair[0]);
$exitStatus = $content ? 0 : 1;
if ($content) {
while ((strlen($content) > 0) && ($wrote = socket_write($socketPair[0], $content))) {
$content = substr($content, $wrote);
}
}
socket_close($socketPair[0]);
exit($exitStatus);
}
else if ($pid > 0) {
pcntl_wait($status);
socket_close($socketPair[0]);
$content = false;
if (pcntl_wexitstatus($status) === 0) {
$content = '';
while ($line = socket_read($socketPair[1], 4096)) {
$len = strlen($content);
$content .= $line;
}
}
socket_close($socketPair[1]);
return $content;
}
socket_close($socketPair[0]);
socket_close($socketPair[1]);
return false;
}
0

Я не нашел способа напрямую решить проблему, изложенную в вопросе. Тем не менее, я разработал пару обходных путей. И то, и другое решает проблему с форком процесса (угадайте, что) другим форком.

Пожалуйста, обратите внимание: Это не предназначено для улучшения производительности. Это просто обходной путь для проблемы, выделенной в вопросе.

function fetch_page($page) {
$tmp_file = tempnam(sys_get_temp_dir(), 'curl_tmp_file');
$pid = pcntl_fork();
if ($pid === 0) {
$ch = curl_init($page);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$content = curl_exec($ch);
curl_close($ch);
if ($content) {
file_put_contents($tmp_file, $content);
exit(0);
}
else {
exit(1);
}
}
else if ($pid > 0) {
pcntl_wait($status);
$content = false;
if (pcntl_wexitstatus($status) === 0) {
$content = file_get_contents($tmp_file);
}
unlink($tmp_file);
return $content;
}
else {
unlink($tmp_file);
return false;
}
}

Письмо о том, что я могу установить https-соединение в дочернем процессе.

fetch_page('https://www.google.ca/');

$pid = pcntl_fork();
if ($pid === 0) {
$ch = curl_init('https://www.google.ca/');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$success = curl_exec($ch);
var_dump($success !== false); // true
} else if ($pid > 0) {
// wait for child process
pcntl_wait($status);
} else {
// handel fork error
}
0
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector