因恐惧而耗尽内存

时间:2018-04-05 09:28:58

标签: php curl fread b2

我正在使用Backblaze B2存储文件,并使用他们的文档代码通过他们的API上传。但是,他们的代码使用fread来读取文件,这会导致大于100MB的文件出现问题,因为它会尝试将整个文件加载到内存中。有没有更好的方法可以将整个文件加载到RAM中?

$file_name = "file.txt";
$my_file = "<path-to-file>" . $file_name;
$handle = fopen($my_file, 'r');
$read_file = fread($handle,filesize($my_file));

$upload_url = ""; // Provided by b2_get_upload_url
$upload_auth_token = ""; // Provided by b2_get_upload_url
$bucket_id = "";  // The ID of the bucket
$content_type = "text/plain";
$sha1_of_file_data = sha1_file($my_file);

$session = curl_init($upload_url);

// Add read file as post field
curl_setopt($session, CURLOPT_POSTFIELDS, $read_file); 

// Add headers
$headers = array();
$headers[] = "Authorization: " . $upload_auth_token;
$headers[] = "X-Bz-File-Name: " . $file_name;
$headers[] = "Content-Type: " . $content_type;
$headers[] = "X-Bz-Content-Sha1: " . $sha1_of_file_data;
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); 

curl_setopt($session, CURLOPT_POST, true); // HTTP POST
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);  // Receive server response
$server_output = curl_exec($session); // Let's do this!
curl_close ($session); // Clean up
echo ($server_output); // Tell me about the rabbits, George!

我尝试过使用:

curl_setopt($session, CURLOPT_POSTFIELDS, array('file' => '@'.realpath('file.txt')));

但是我收到错误响应:读取上传数据时出错:SocketTimeoutException(读取超时)

编辑:使用CURL流式传输文件名似乎也不起作用。

1 个答案:

答案 0 :(得分:2)

您遇到的问题与此有关。

fread($handle,filesize($my_file));

使用文件大小,你可以做file_get_contents。使用fget

一次读取1行是更好的记忆
$handle = fopen($myfile, 'r');

while(!feof($handle)){
     $line = fgets($handle);
} 

这样你只需要在内存中读取一行,但如果你需要完整的文件内容,你仍然会遇到瓶颈。

唯一真正的方法是流式上传。

我做了一个快速搜索,似乎CURL的默认设置是流式文件,如果你给它文件名

 $post_data['file'] = 'myfile.csv';

 curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);

您可以查看上一个答案以获取更多详细信息

Is it possible to use cURL to stream upload a file using POST?

所以只要你能超越sha1_file看起来你可以只传输文件,这应该避免内存问题。但是可能存在时间限制问题。如果失败,我也无法想到获取哈希的方法。

仅供参考,我个人从未尝试过,通常我只是使用sFTP进行大型文件传输。所以我不知道是否必须特别post_data['file']我只是从另一个答案中复制了它。

祝你好运......

<强>更新

看到流媒体似乎失败了(见评论)。

您可能需要测试流式传输以确保其正常运行。我不知道会涉及到什么,可能会将文件流式传输到您自己的服务器?此外,我不确定为什么它不会像“广告宣传”一样工作,你可能已经测试过了。但是,测试某些东西永远不会伤害,在你确定之前永远不要假设有些东西可行。尝试新的解决方案很容易,只是错过设置或错误的路径,然后根据原始问题回过头来思考它。

我花了很多时间把事情分开才意识到我有拼写错误。这些天我非常擅长编程,所以我通常也会忽略这些错误。我的观点是,在继续前进之前,请确保这不是一个简单的错误。

假设一切设置正确,我会尝试file_get_contents。我不知道它会不会更好但是更多的意思是打开整个文件。它在代码中似乎也更易读,因为很明显需要整个文件。如果没别的话,它似乎在语义上更正确。

您还可以使用

增加PHP可以访问的RAM
ini_set('memory_limit', '512M')

根据您的服务器,您甚至可以更高。之前我去过的最高点是3G,但我使用的服务器有54GB ram,这是一次性的事情(我们从MySql向MongoDB迁移了1.3亿行,innodb索引正在吃掉30 + GB)。通常,我使用512M运行,并且有一些常规需要1G的脚本。但是,我不会毫不犹豫地追寻记忆。在优化和测试之后,这通常是我的最后手段。我们做了很多繁重的处理,这就是为什么我们有这么大的服务器,我们还有2个奴隶服务器(除此之外),每个服务器运行16GB。

至于要放置的大小,通常我会将其增加128M告诉它有效,然后添加额外的128M以确保,但您可能希望采用较小的步骤。通常人们总是使用8的倍数,但我不知道这些日子是否会产生很大差异。

再次,祝你好运。