program tip

전체 URL을 사용할 때 PHP file_get_contents 매우 느림

radiobox 2020. 11. 29. 10:10
반응형

전체 URL을 사용할 때 PHP file_get_contents 매우 느림


HTML 페이지에서 pdf 파일을 생성하는 스크립트 (원래 만들지 않은 스크립트)로 작업하고 있습니다. 문제는 처리하는 데 1 ~ 2 분처럼 매우 오랜 시간이 걸린다는 것입니다. 아마도 이것은 원래 잘 작동했지만 지난 몇 주 동안 느려졌습니다.

스크립트 file_get_contents는 php 스크립트를 호출 한 다음 결과를 서버의 HTML 파일로 출력하고 해당 파일에서 pdf 생성기 앱을 실행합니다.

file_get_contents로컬 경로가 아닌 전체 URL에 대한 호출로 문제를 좁힌 것 같습니다 .

내가 사용할 때

$content = file_get_contents('test.txt');

거의 즉시 처리됩니다. 그러나 전체 URL을 사용하면

$content = file_get_contents('http://example.com/test.txt');

처리하는 데 30-90 초가 걸립니다.

Google 서버에 국한되지 않고 http://www.google.com 과 같은 외부 URL에 액세스 할 때 느립니다 . 파일을 로컬로 호출하면 작동하지 않는 쿼리 문자열 변수가 필요하기 때문에 스크립트가 전체 URL을 호출한다고 생각합니다.

나는 또한 시도 fopen, readfile그리고 curl, 그들은 모두 유사하게 느린했다. 이 문제를 해결할 위치에 대한 아이디어가 있습니까?


참고 : 이 문제는 PHP 5.6.14에서 수정되었습니다. Connection: close헤더는 자동으로 1.0 요청 /도 HTTP에 대한 전송됩니다. commit을 참조하십시오4b1dff6 .

file_get_contents 스크립트의 느린 원인을 파악하는 데 어려움을 겪었습니다.

Wireshark를 사용하여 분석 한 결과 원격 웹 서버가 15 초까지 TCP 연결을 닫지 않았다는 문제가있었습니다 (예 : "keep-alive").

실제로 file_get_contents는 "연결"HTTP 헤더를 보내지 않으므로 원격 웹 서버는 기본적으로 연결 유지 연결로 간주하고 15 초까지 TCP 스트림을 닫지 않습니다 (표준 값이 아닐 수 있음-상황에 따라 다름). 서버 conf에서).

일반 브라우저는 HTTP 페이로드 길이가 응답 Content-Length HTTP 헤더에 지정된 길이에 도달하면 페이지가 완전히로드 된 것으로 간주합니다. File_get_contents는 이것을하지 않으며 그것은 부끄러운 일입니다.

해결책

따라서 솔루션을 알고 싶다면 여기에 있습니다.

$context = stream_context_create(array('http' => array('header'=>'Connection: close\r\n')));
file_get_contents("http://www.something.com/somepage.html",false,$context);

문제는 바로하는 것입니다 다운로드가 완료되면 연결을 종료하기 위해 원격 웹 서버에게 file_get_contents는 응답 콘텐츠 길이 HTTP 헤더를 사용하여 스스로 그것을 할 수있는 지능형 충분이 아니므로.


방법 보다 훨씬 빠르기 때문에 curl ()사용 하여 외부 콘텐츠를 가져옵니다 file_get_contents. 이것이 문제를 해결할지 확실하지 않지만 한 번 시도해 볼 가치가 있습니다.

또한 서버 속도는 파일을 검색하는 데 걸리는 시간에 영향을 미칩니다.

다음은 사용 예입니다.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com/test.txt');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);

때로는 DNS가 서버에서 너무 느리기 때문에 다음을 시도하십시오.

바꾸다

echo file_get_contents('http://www.google.com');

같이

$context=stream_context_create(array('http' => array('header'=>"Host: www.google.com\r\n")));
echo file_get_contents('http://74.125.71.103', false, $context);

나는 같은 문제가 있었다.

나를 위해 일한 유일한 것은 $options배열 에서 시간 제한을 설정하는 것입니다 .

$options = array(
    'http' => array(
        'header'  => implode($headers, "\r\n"),
        'method'  => 'POST',
        'content' => '',
        'timeout' => .5
    ),
);

서버의 명령 줄에서 해당 URL을 가져 오실 수 있습니까? 컬 또는 wget이 떠 오릅니다. 그들이 정상적인 속도로 URL을 검색한다면 네트워크 문제가 아니며 아마도 apache / php 설정에있는 것입니다.


$context = stream_context_create(array('http' => array('header'=>'Connection: close\r\n')));
$string = file_get_contents("http://localhost/testcall/request.php",false,$context);

시간 : 50976 밀리 초 (총 5 개 시도에서 avaerage 시간)

$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, "http://localhost/testcall/request.php");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
echo $data = curl_exec($ch);
curl_close($ch);

시간 : 46679ms (총 5 회 시도시 사용 시간)

참고 : request.php는 mysql 데이터베이스에서 일부 데이터를 가져 오는 데 사용됩니다.


API에 의해 전달 된 엄청난 데이터가 있는데 데이터 file_get_contents를 읽는 데 사용하고 있지만 약 60 초가 걸렸습니다 . 그러나 KrisWebDev의 솔루션을 사용하면 약 25 초가 소요되었습니다 .

$context = stream_context_create(array('https' => array('header'=>'Connection: close\r\n')));
file_get_contents($url,false,$context);

What I would also consider with Curl is that you can "thread" the requests. This has helped me immensely as I do not have access to a version of PHP that allows threading at the moment .

For example, I was getting 7 images from a remote server using file_get_contents and it was taking 2-5 seconds per request. This process alone was adding 30seconds or something to the process, while the user waited for the PDF to be generated.

This literally reduced the time to about 1 image. Another example, I verify 36 urls in the time it took before to do one. I think you get the point. :-)

    $timeout = 30;
    $retTxfr = 1;
    $user = '';
    $pass = '';

    $master = curl_multi_init();
    $node_count = count($curlList);
    $keys = array("url");

    for ($i = 0; $i < $node_count; $i++) {
        foreach ($keys as $key) {
            if (empty($curlList[$i][$key])) continue;
            $ch[$i][$key] = curl_init($curlList[$i][$key]);
            curl_setopt($ch[$i][$key], CURLOPT_TIMEOUT, $timeout); // -- timeout after X seconds
            curl_setopt($ch[$i][$key], CURLOPT_RETURNTRANSFER, $retTxfr);
            curl_setopt($ch[$i][$key], CURLOPT_HTTPAUTH, CURLAUTH_ANY);
            curl_setopt($ch[$i][$key], CURLOPT_USERPWD, "{$user}:{$pass}");
            curl_setopt($ch[$i][$key], CURLOPT_RETURNTRANSFER, true);
            curl_multi_add_handle($master, $ch[$i][$key]);
        }
    }

    // -- get all requests at once, finish when done or timeout met --
    do {  curl_multi_exec($master, $running);  }
    while ($running > 0);

Then check over the results:

            if ((int)curl_getinfo($ch[$i][$key], CURLINFO_HTTP_CODE) > 399 || empty($results[$i][$key])) {
                unset($results[$i][$key]);
            } else {
                $results[$i]["options"] = $curlList[$i]["options"];
            }
            curl_multi_remove_handle($master, $ch[$i][$key]);
            curl_close($ch[$i][$key]);

then close file:

    curl_multi_close($master);

I know that is old question but I found it today and answers didn't work for me. I didn't see anyone saying that max connections per IP may be set to 1. That way you are doing API request and API is doing another request because you use full url. That's why loading directly from disc works. For me that fixed a problem:

if (strpos($file->url, env('APP_URL')) === 0) {
    $url = substr($file->url, strlen(env('APP_URL')));
} else {
    $url = $file->url;
}
return file_get_contents($url);

참고URL : https://stackoverflow.com/questions/3629504/php-file-get-contents-very-slow-when-using-full-url

반응형