7

ファイルが 5 MB を超える場合、リモート ファイルがファイルをダウンロードしないようにするにはどうすればよいですか? 転送中に停止すると、ファイルは他の一時ディレクトリまたはメモリのどこかに保持されますか? どうすればわかりますか?これが私の現在のコードです:

$url = 'http://www.spacetelescope.org/static/archives/images/large/heic0601a.jpg';
$file = '../temp/test.jpg';
file_put_contents($file, file_get_contents($url));
4

4 に答える 4

8

これを行う方法はいくつかありますが、現在 を使用しているため、次のfile_get_contents()ようにします。

  • を使用してリモートファイルを開きますfopen()
  • ファイルを読み取り、次を使用して段階的に保存しますfread()。これにより、現在のサイズを追跡し、しきい値を超えたときのスローとエラーを追跡できます。

このようなもの:

$url = 'http://www.spacetelescope.org/static/archives/images/large/heic0601a.jpg';
$file = '../temp/test.jpg';
$limit = 5 * 1024 * 1024; // 5MB

if (!$rfp = fopen($url, 'r')) {
  // error, could not open remote file
}
if (!$lfp = fopen($file, 'w')) {
  // error, could not open local file
}

// Check the content-length for exceeding the limit
foreach ($http_response_header as $header) {
  if (preg_match('/^\s*content-length\s*:\s*(\d+)\s*$/', $header, $matches)) {
    if ($matches[1] > $limit) {
      // error, file too large
    }
  }
}

$downloaded = 0;

while (!feof($rfp) && $downloaded < $limit) {
  $chunk = fread($rfp, 8192);
  fwrite($lfp, $chunk);
  $downloaded += strlen($chunk);
}

if ($downloaded > $limit) {
  // error, file too large
  unlink($file); // delete local data
} else {
  // success
}

注意:Content-Length:ファイルを受信する前にヘッダーを検査して、ファイルが大きすぎるかどうかを確認したくなるかもしれません。必要に応じてこれを行うこともできますが、値を信頼しないでください。ヘッダーは本質的に任意の値であり、ファイルのサイズと一致しないコンテンツの長さを使用することはプロトコル違反になりますが、システムをだましてルールに違反するファイルをダウンロードさせるために使用される可能性があります。この値を確認したとしても、バイトを数える必要があります。

データ コールバックを介して curl を使用してこれを行うこともできますが、主に curl には標準のジェネリックcallable型ではなく文字列関数名が必要であるという事実のため、これはあまり満足のいく解決策ではないと考えています。staticダウンロードされたコンテンツの長さを追跡するためのグローバル変数または変数ですが、どちらもこれには受け入れられません(IMHO)。

于 2012-12-20T00:04:35.693 に答える
2

URL の取得とサイズの制限については、それほど難しくはありませんが、file_get_contentsできません。fopenURL をストリームで使用stream_get_meta_dataして、ストリームに関する情報の配列を取得できます。私がContent-Lengthを正しく読んでいる場合 (そして転送エンコーディングが「チャンク」されていない場合)、そこにヘッダーがあり、ファイルサイズがわかります。値が設定されていて、制限を超えている場合は、保釈します。

ストリーム メタデータにその情報がない場合、またはファイルが十分に小さいことが情報に示されている場合でも、ストリーム自体は存在します。すべてを読み取るか、制限に達するまでfread、リモートファイルからチャンクでローカルファイルに移動できます。fwriteもちろん、その時点に達した場合、制限に達してもファイルは引き続き存在します。自分で削除する必要があります。

于 2012-12-20T00:06:01.050 に答える
1

これは不可能file_get_contentsです。ファイル サイズを取得するには、PHP cURL 拡張機能を使用する必要があります。

<?php
$max_length = 5 * 1024 * 1024;
$url = 'http://www.spacetelescope.org/static/archives/images/large/heic0601a.jpg';
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);
curl_close($ch);
if ($data === false) {
  echo 'cURL failed';
  exit;
}
$contentLength = 'unknown';
if (preg_match('/Content-Length: (\d+)/', $data, $matches)) {
  $contentLength = (int)$matches[1];
}
echo "Content-Length: $contentLength\n";

if ($contentLength > $max_length) {
    echo "File is too large\n";
} else {
    echo "File size is ok\n";
}

これを関数にまとめて、URL のチェックに使用します。大きすぎるものはスキップできます。

欠点:

このメソッドは、Content-Lengthヘッダーがサーバーから返された場合にのみ機能します。すべてのサーバーが適切に動作しているわけではなく、すべてのサーバーが正しい長さを返すわけではありません。

利点:

ダウンロードして$max_lengthバイト単位で書き込む必要はありません。この方法はより高速で、リソースの消費が少なくなります。

変更元:

http://php.net/filesize#92462

于 2012-12-20T00:06:05.943 に答える
1

これは、同じ行に沿った DaveRandom のソリューションのバリエーションですが、完全にロードされるまでファイルを書き込みません。

<?php
define('MAXMB', 5);
define('BYTESPERMB', 1048576);

$maxsize = MAXMB * BYTESPERMB;

$handle = fopen("http://www.example.com/", "rb");
$contents = '';
$completed = true;
while (!feof($handle)) {
  $chunk = fread($handle, 8192);

  $size += strlen($chunk);
  if ($size > $maxsize) {
      $completed = false;
      break;
  }
  $contents .= $chunk;
}
fclose($handle);

if ($completed) {
  // File appears to be completely downloaded so write it --
  file_put_contents('path/to/localfile', $contents);

} else {
  // It was too big
}
于 2012-12-20T00:08:54.960 に答える