curl로 https 접속시 SSL connect error (errno=35) 발생.
여기저기 찾아보면서 nss 업데이트도 해보고 해도 해결이 안됨.
좀 더 자세히 알아보기 위해 단순 curl_error()가 아닌 디버깅 정보를 출력해보기로 함 (=curl -v)
얻은 결과는 아래와 같음.
에러는 NSS error -8023
* About to connect() to DOMAIN port 443 (#0)
* Trying IP_ADDR... * connected
* Connected to DOMAIN (IP_ADDR) port 443 (#0)
* warning: ignoring value of ssl.verifyhost
* NSS error -8023
* Closing connection #0
* SSL connect error
이 정보를 바탕으로 뒤져본 결과 에러발생 요건은 아래와 같음.
1. openssl이 아닌 nss와 연결된 libCurl 사용
2. parent process에서 curl 한 번 호출
3. 이후 fork()로 생성된 child process에서 curl 호출
위 3가지 조합이 전부 맞물려야 발생하는 에러임.
PHP 코드로 보자면 아래와 같음.
<?PHP
// curl 호출 함수
function curlGet($procType)
{
$verboseStream = fopen('php://temp', 'w+');
$c = curl_init();
curl_setopt_array($c, array(
CURLOPT_URL => 'https://www.google.com',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_VERBOSE => true,
CURLOPT_STDERR => $verboseStream
));
$r = curl_exec($c);
rewind($verboseStream);
$verbose = stream_get_contents($verboseStream);
printf("[%s]\n%s\n%s\n", $procType, str_repeat('-', 120), $verbose);
}
// 1. parent에서 curl 호출 (성공)
curlGet('PARENT');
// 2. fork
$pid = pcntl_fork();
if ($pid === 0) {
// 3. child에서 curl 호출 (에러 발생!!!!!!!!!!!!!!!!)
curlGet('CHILD');
}
else if ($pid > 0) {
// parent. child process 실행완료까지 대기
pcntl_waitpid(0, $status);
}
else {
// error
}
해결방법은 fork() 전에 curl_global_cleanup() 을 호출해주고 fork() 후에 curl_global_init() 를 호출해주는 것인 듯 한데,
PHP에선 어떻게 제어할 방법이 없다.
하지만 저걸 다른식으로 해주는 방법이 존재함.
fork() 후 child process에서 curl을 곧바로 호출하지 않고 pcntl_exec()를 이용해 다른 php 파일을 불러와서 실행하면 에러가 안남.
위의 예제를 기준으로 하자면 아래처럼 하면 됨.
우선 curlGet() 함수를 func.php 파일로 분리하고,
<?PHP
function curlGet($procType)
{
$verboseStream = fopen('php://temp', 'w+');
$c = curl_init();
curl_setopt_array($c, array(
CURLOPT_URL => 'https://www.google.com',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_VERBOSE => true,
CURLOPT_STDERR => $verboseStream
));
$r = curl_exec($c);
rewind($verboseStream);
$verbose = stream_get_contents($verboseStream);
printf("[%s]\n%s\n%s\n", $procType, str_repeat('-', 120), $verbose);
}
child process에서 실행될 파일도 child.php로 분리하고, (파일명 호출로 실행될 수 있도록 permission도 조정하고 인터프리터도 추가)
#!/PATH/TO/php -q
<?PHP
require_once __DIR__.'/func.php';
curlGet('CHILD');
parent process는 아래처럼.
<?PHP
require_once __DIR__.'/func.php';
// 1. parent에서 curl 호출 (성공)
curlGet('PARENT');
// 2. fork
$pid = pcntl_fork();
if ($pid === 0) {
// 3. child에서 curl 호출 (성공)
pcntl_exec(__DIR__.'/child.php');
}
else if ($pid > 0) {
pcntl_waitpid(0, $status);
}
else {
// error
}
이제 에러가 안나고 정상동작 함.
.
'PHP' 카테고리의 다른 글
[PHP] 문자열 조합해서 상수 읽어오기 (use string concatenation to read constant) (0) | 2021.01.27 |
---|---|
[PHP] curl 여러 url 비동기 호출 (curl, async, non-blocking, curl_multi) (2) | 2020.08.20 |
[PHP] curl -v(verbose) 옵션 세팅 및 결과 확인하기 (0) | 2020.08.11 |
[PHP] heredoc 내부에서 함수 호출하기 (calling function inside heredoc) (0) | 2020.07.14 |
[PHP] timezone 적용 date() (0) | 2020.06.02 |