

任意のURL(ファイルの種類は不明）からHTMLを取得するPHPプログラムを作成しています。  
取得したいのはHTMLのみですが、ファイルの種類が分からないためHTML以外の巨大なファイルを読み込む可能性があります。  
URLからcurl_execでファイルの内容を取得する際に、ファイルサイズが大きかった場合に以下のエラーでプログラムが落ちてしまいます。

[code]

    Allowed memory size of *** bytes exhausted
    
[/code]

プログラムの先頭にini_set("memory_limit", "-1");を追加しても駄目でした。  
ファイルサイズがはかり知れないためこの方法による回避はやめたいです。

次に考えたのが、curl_execの前にヘッダーのみ取得してヘッダーからContent-Lengthを取得する方法ですが、Content-
Lengthの記述があるとは限らないのでこの方法も駄目でした。

[code]

    $header = @shell_exec("curl -I {$url}")
    
[/code]

次に考えたのが、fopenでファイルの先頭だけ取得してHTMLかどうかを判別する方法です。

[code]

    $fp= @fopen($url, "r", false, $context);
    if ($fp) {
     $head = @fread($fp, 1000);
     fclose($fp);
    }
    
    if (preg_match("/^(<\!DOCTYPE|<html)/i", trim($head), $matches) > 0) {
     $html = curl_exec($url);
    }
    
[/code]

判別の仕方は良くないかも知れませんが、この方法ではある程度上手くいきました。  
ただしヘッダー取得の方法やこの方法だと2度URLにアクセスするため、全体の処理に時間がかかってしまいます。  
時間をかけずメモリエラーを出さずにHTMLを取得する方法はないでしょうか？


CC BY-SA 3.0
2015-10-02T01:17:10.753
17161
2015-11-01T07:46:51.000
12530
question
php
PHPのcURLでURLからファイルを取得する前にサイズを知る方法


HTTPで受信するデータサイズを事前に知るポータブルな方法はありません。したがって、任意のURLに対して確実に処理するには、データサイズによらず動作するよう考慮する必要があります。

簡便な方法としては、一旦ファイルに出力してしまって処理する方法が考えられます(`CURLOPT_FILE`)。しかし、大きなファイルに当たると受信と出力に時間がかかりますし、極端に大きなファイルの場合ディスクがあふれるかもしれません。

確実な方法は、受信したデータを逐次処理する方法です。cURLであれば`CURLOPT_WRITEFUCTION`というのが使えるようです。試してないですが何となくこんな感じで動くようです。

[code]

    curl_setopt($ch, CURLOPT_HEADER, 1);
    curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'callback');
    
    curl_exec($ch);
    curl_close($ch);
    
    function callback($res, $response){
        // なにかする
        return strlen($response); // return 0 とかするとそこで中断するようです
    }
    
[/code]

ヘッダもでてくるので、Conetnt-TypeやContent-Lengthも併せてチェックすれば良いでしょう。


CC BY-SA 3.0
2015-10-02T06:53:40.253
17176
2015-10-02T06:53:40.253
5793
17161
answer