我在卷曲中遇到了一些非常奇怪的行为
- 如果我在父进程中使用curl发出SSL请求,然后分叉进程并尝试在子进程中发出另一个SSL请求处理尝试失败,错误编号为35(SSL连接错误)
- 如果我没有在父进程中发出SSL请求,则子进程中的请求会成功
- 我可以使父级中任意数量的非SSL请求和子级中的SSL请求成功
看来这是一个与libcurl相关的问题中的错误,回答者对此有解决办法
我的问题是:
- curl_global_cleanup是否由PHP API中的其他名称公开
- 如果没有,周围还有其他工作吗
$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);
在执行子项之后,您将不会看到错误。
这些其他问题帮助了我:
- fork()后出现libCurl SSL错误
- 卷曲和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;
}
我还没有找到直接处理问题的方法。然而,我已经制定了一些变通办法。两者都用(猜测是什么)另一个分叉来解决流程分叉问题
请注意:这不是为了提高性能。这只是问题中突出显示的问题的一种变通方法。
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
}