17

リモートファイルに接続して、リモートファイルからの出力をローカルファイルに書き込みたいのですが、これが私の関数です。

function get_remote_file_to_cache()
{

    $the_site="http://facebook.com";

    $curl = curl_init();
    $fp = fopen("cache/temp_file.txt", "w");
    curl_setopt ($curl, CURLOPT_URL, $the_site);
    curl_setopt($curl, CURLOPT_FILE, $fp);

    curl_setopt($curl,  CURLOPT_RETURNTRANSFER, TRUE);

    curl_exec ($curl);

    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if($httpCode == 404) {
        touch('cache/404_err.txt');
    }else
    {
        touch('cache/'.rand(0, 99999).'--all_good.txt');
    }

    curl_close ($curl);
}

「cache」ディレクトリに2つのファイルを作成しますが、問題は「temp_file.txt」にデータが書き込まれないことです。これはなぜですか。

4

6 に答える 6

28

実際、fwriteの使用は部分的に正しいです。大きなファイルでのメモリオーバーフローの問題(PHPの最大メモリ制限を超えた)を回避するには、ファイルに書き込むためのコールバック関数を設定する必要があります。

注:グローバル変数を使用するのではなく、ファイルのダウンロードやファイルハンドルなどを処理するためのクラスを作成することをお勧めしますが、この例の目的のために、以下に設定を実行する方法を示します。

したがって、次のようにします。

# setup a global file pointer
$GlobalFileHandle = null;

function saveRemoteFile($url, $filename) {
  global $GlobalFileHandle;

  set_time_limit(0);

  # Open the file for writing...
  $GlobalFileHandle = fopen($filename, 'w+');

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_FILE, $GlobalFileHandle);
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_USERAGENT, "MY+USER+AGENT"); //Make this valid if possible
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); # optional
  curl_setopt($ch, CURLOPT_TIMEOUT, -1); # optional: -1 = unlimited, 3600 = 1 hour
  curl_setopt($ch, CURLOPT_VERBOSE, false); # Set to true to see all the innards

  # Only if you need to bypass SSL certificate validation
  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

  # Assign a callback function to the CURL Write-Function
  curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'curlWriteFile');

  # Exceute the download - note we DO NOT put the result into a variable!
  curl_exec($ch);

  # Close CURL
  curl_close($ch);

  # Close the file pointer
  fclose($GlobalFileHandle);
}

function curlWriteFile($cp, $data) {
  global $GlobalFileHandle;
  $len = fwrite($GlobalFileHandle, $data);
  return $len;
}

進行状況のコールバックを作成して、ダウンロードの量/速度を表示することもできますが、CLIに出力するときに複雑になる可能性があるため、これは別の例です。

基本的に、これにより、ダウンロードされたデータの各ブロックが取得され、最初にファイル全体がメモリにダウンロードされるのではなく、すぐにファイルにダンプされます。

それを行うためのはるかに安全な方法!もちろん、URLが正しいこと(スペースを%20に変換するなど)と、ローカルファイルが書き込み可能であることを確認する必要があります。

乾杯、ジェームズ。

于 2014-06-18T05:24:26.867 に答える
17

GETリクエストをに送信してみましょうhttp://facebook.com

$ curl -v http://facebook.com
* URLを再構築:http://facebook.com/
*ホスト名がDNSキャッシュに見つかりませんでした
*69.171.230.5を試してみてください...
* facebook.com(69.171.230.5)ポート80(#0)に接続
> GET / HTTP / 1.1
>ユーザーエージェント:curl / 7.35.0
>ホスト:facebook.com
>受け入れる:* / *
>>
<HTTP /1.1302が見つかりました
<場所:https://facebook.com/
<変更:Accept-エンコーディング
<コンテンツタイプ:text / html
<日付:2015年9月3日木曜日16:26:34 GMT
<接続:キープアライブ
<コンテンツの長さ:0
<
*ホストfacebook.comへの接続#0はそのまま残されました

どうしたの?Facebookが私たちをhttp://facebook.comからセキュリティで保護するようにリダイレクトしたようhttps://facebook.com/です。応答本体の長さに注意してください。

コンテンツの長さ:0

これは、ゼロバイトがに書き込まれることを意味しますxxxx--all_good.txt。これが、ファイルが空のままである理由です。

あなたの解決策は絶対に正しいです:

$fp = fopen('file.txt', 'w');
curl_setopt($handle, CURLOPT_FILE, $fp);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);

URLをに変更するだけですhttps://facebook.com/

その他の回答について:

  • fwrite()@JonGauthier:いいえ、後で使用する必要はありませんcurl_exec()
  • CURLOPT_WRITEFUNCTION@doublehelix:いいえ、内容をファイルにコピーするような単純な操作は必要ありません。
  • @ScottSaunders:touch()空のファイルが存在しない場合は作成します。OPの意図だったと思います。

真剣に、3つの答えとすべてが無効ですか?

于 2015-02-19T13:17:03.550 に答える
11

を使用してファイルに明示的に書き込み、fwrite前に作成したファイルハンドルを渡す必要があります。

if ( $httpCode == 404 ) {
    ...
} else {
    $contents = curl_exec($curl);
    fwrite($fp, $contents);
}

curl_close($curl);
fclose($fp);
于 2011-11-01T13:57:48.670 に答える
5

あなたの質問ではあなたは

    curl_setopt($curl, CURLOPT_FILE, $fp);

    curl_setopt($curl,  CURLOPT_RETURNTRANSFER, TRUE);

しかし、PHPのcurl_setoptドキュメントノートから...

It appears that setting CURLOPT_FILE before setting CURLOPT_RETURNTRANSFER doesn't work, presumably because CURLOPT_FILE depends on CURLOPT_RETURNTRANSFER being set.

So do this:

<?php
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FILE, $fp);
?>

not this:

<?php
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
?>

...「 CURLOPT_FILEは、設定されているCURLOPT_RETURNTRANSFERに依存します」と述べています。

参照:https ://www.php.net/manual/en/function.curl-setopt.php#99082

于 2020-06-28T02:55:24.030 に答える
3

メモリリークの問題を回避するには:

私もこの問題に直面しました。言うのは本当にばかげていますが、解決策はCURLOPT_FILEの前にCURLOPT_RETURNTRANSFERを設定することです!

CURLOPT_FILEはCURLOPT_RETURNTRANSFERに依存しているようです。

$curl = curl_init();
$fp = fopen("cache/temp_file.txt", "w+");
curl_setopt($curl,  CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_FILE, $fp);
curl_setopt($curl, CURLOPT_URL, $url);
curl_exec ($curl);
curl_close($curl);
fclose($fp);
于 2019-06-10T16:27:16.670 に答える
2

このtouch()関数は、ファイルの内容に対して何もしません。変更時刻を更新するだけです。を見てくださいfile_put_contents() function

于 2011-11-01T13:59:30.273 に答える