如果PHP超过5mb,则停止远程文件下载

时间:2012-12-19 23:51:06

标签: php

如果文件超过5mb,如何停止下载文件?如果我在转移时停止它,文件是否会保存在某个其他临时目录或内存中?我怎么会知道?这是我目前的代码:

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

4 个答案:

答案 0 :(得分: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变量才能跟踪下载的内容长度,这两者都不可接受(恕我直言)。

答案 1 :(得分:2)

至于获取网址并限制尺寸,这并不太难......但file_get_contents不会这样做。您可以fopen该网址,并在流上使用stream_get_meta_data来获取有关该流的信息数组。如果我正在阅读example权限(如果传输编码不是“分块”),您会在那里找到Content-Length标题,它会告诉您文件大小。如果该值已设置且超出限制,则保释。

如果流元数据没有该信息,或者信息表明文件足够小,那么您仍然拥有该流本身;您仍然可以fread从远程文件fwrite到本地的文件,直到您全部读取或达到限制。当然,如果你到达那一点,一旦达到极限,文件仍然存在;你必须自己删除它。

答案 2 :(得分: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

答案 3 :(得分: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
}