Я столкнулся с довольно странным поведением с завитком
Похоже, что это ошибка в libcurl связанный вопрос и ответчик имеет обойти это.
Мои вопросы:
$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);
После казни ребенка вы не увидите ошибки.
Эти другие вопросы помогли мне:
Другим обходным решением является использование сокетов.
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;
}
Я не нашел способа напрямую решить проблему, изложенную в вопросе. Тем не менее, я разработал пару обходных путей. И то, и другое решает проблему с форком процесса (угадайте, что) другим форком.
Пожалуйста, обратите внимание: Это не предназначено для улучшения производительности. Это просто обходной путь для проблемы, выделенной в вопросе.
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
}