Intereting Posts

Запросы SSL, сделанные с ошибкой cURL после процесса fork

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

  1. Если я сделаю запрос SSL, используя curl в родительском процессе, а затем разветвит процесс и попытаюсь сделать еще один запрос SSL в дочернем процессе, попытка будет неудачной с ошибкой no. 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, и это то, что я делаю неправильно, пожалуйста, дайте мне знать.

Я просто решил это, используя функцию 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); 

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

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

  • Ошибка libCurl SSL после fork ()
  • Curl и pcntl_fork ()

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

 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; } 

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

Обратите внимание: это не предназначено для какого-либо улучшения производительности. Это просто обходное решение проблемы, выделенной в вопросе.

 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 }