|
|
|
| Долго мучался с веб интерфейсом для работы с фтп. Даю пользователю возможность скачать файлы mp3.
Файлы лежат на удаленном фтп-сервере. Скрипт соединяется с сервером читает содержимое и выдает его пользователю (pop-up открыть/сохранить), предварительно отправив необходимые хеды.
Я поставил в своем php.ini мемори сайз 16М - этого вполне хватало.
Но! Когда дело дошло до 80-минутных ДиДжейских сетов размером 130-170 Мб..... :(
Естесственно увеличивать размер выделяемой памяти в php.ini не является рациональным)
Подскажите, может эту проблему можно решить используя Output Control Functions?
Никогда ранее с буффером вывода не приходилось работать.
Спасибо.
Fatal error: Allowed memory size of
16777216 bytes exhausted (tried to allocate
4097 bytes) in /var/www/html/meloman/libs/FTP.class.php on
line 999
|
| |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 13:30)
| | Вы их что - в память читаете?! | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 14:14)
| | ммм.....ну да :-[
Очень быстро работает :)
Есстесно если файл небольшой :)
вот кусок моего download.php
if(!$contents = $ftp->read($filename)) throw new Exception($error);
header("Content-Disposition: attachment; filename=$name");
header("Accept-Ranges: bytes");
header("Content-type: application/octet-stream");
echo $contents;
|
| |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 14:16)
| | [поправлено модератором] | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 14:27)
| | Какой же выход?
PS я и не смеялся
если читать в файл - немзвестно сколько придется ждать завершения работы скрипта.
К тому же на сервере включен безопаный режим. И set_time_limit(0) не сработает.
Скрипт просто умрет недокачав файл | |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 14:32)
| | В файл сохранять. Килобайта по 64.
64К занимает в 256 раз меньше чем 16М, а прироста скорости Вы не ощутите.
Всё равно львиную долю времени займет FTP-обмен | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 14:27)
| | Особенно, если учесть, что вы ЯВНО заявляете "Принимаю диапазонные запросы! Поддерживаю докачку!"
А потом тупо шлете весь контент. | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 14:32)
| | Я не совсем понял - в файл писать по 64К а потом выдать весь файл? Или это должно происходить асинхронно?
Можете показать на примере?
Как и где мне резать контент по 64 К? | |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 14:43)
| | Может Вы покажете скрипт, которым файл из FTP вытягиваете?
Размер блока может быть и другим, не в нем дело, а в том, что целиком файл в память класть нельзя. Да и не нужно совершенно. | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 15:17)
| |
<?php
...
try {
$ftp = new FTP();
if(!$ftp->connect($cfg['ftp']['host'])) throw new Exception($error);
$ftp->login($cfg['ftp']['user'], $cfg['ftp']['pass']);
...........
if(!$contents = $ftp->read($filename)) throw new Exception($error);
header("Content-Disposition: attachment; filename=$name");
header("Accept-Ranges: bytes");
header("Content-type: application/octet-stream");
echo $contents;
exit();
}
?>
|
И метод read класса FTP
<?php
public function read($remoteFile,$localFile=NULL)
{
$fp=null;
if(!$this->_ready)
{
$this->_error="Please login to FTP server first.";
return false;
}
preg_match("/\..+/",$remoteFile,$matches);
$ext=strtolower(substr($matches[0],1));
if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array($ext,$this->AutoAsciiExt)))
$mode=FTP_ASCII;
else
$mode=FTP_BINARY;
$mode=FTP_BINARY;
$this->_mode($mode);
if(!$this->_listen())
{
$this->sendMsg("Failed to listen to server.");
return false;
}
if($localFile==true)
$localFile=$remoteFile;
if(@file_exists($localFile))
$this->sendMsg("$localFile will be overwritten.");
if(!empty($localFile))
{
$fp=fopen($localFile,"w");
if(!$fp)
{
$this->_error="Couldn't open $localFile to write.";
return false;
}
}
if(!$this->_put("RETR $remoteFile"))
{
$this->_error="Failed to send command to FTP Server.";
@fclose($fp);
$this->_data_close();
return false;
}
$msg=$this->_read();
if(!$this->_checkReply())
{
$this->_error=$msg;
@fclose($fp);
$this->_data_close();
return false;
}
$this->sendMsg($msg);
$out=$this->_read_data($mode,$fp);
@fclose($fp);
$this->_data_close();
$msg=$this->_read();
if(!$this->_checkReply())
{
$this->_error=$msg;
return false;
}
$this->sendMsg($msg);
$this->sendMsg("File successfuly read.");
return $out;
}
?>
|
| |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 15:30)
| | толку то... он упирается в _read_data
прикрепите архивом весь класс. | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 15:17)
| | Дык я вот и спрашиваю как это сделать? | |
|
|
|
|
 4.6 Кб |
|
|
для: hammet
(25.05.2007 в 15:38)
| | ok | |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 15:56)
| | Второй параметр метода read - имя файла, куда класть .
Всё уже реализовано в классе. | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 16:07)
| | Все таже ошибка - при сохранении файла размером в 180 Мб - имеем файл размером 100 Байт с контентом Fatal
error: Allowed memory size..........
Хотя я пишу на винчестер а потом выдаю пользователю.
$tmp_file = 'tpl_cache/download_file'.md5(microtime());
if(!$contents = $ftp->read($filename, $tmp_file)) throw new Exception($error);
header("Content-Disposition: attachment; filename=$name");
header("Accept-Ranges: bytes");
header("Content-type: application/octet-stream");
echo file_get_contents($tmp_file);
exit();
|
хотя в кэше лежит нужный файл нужного размера и с нужным контентом. Значит он с фтп скачался быстро и вся проблема в другом.
Может хеды неправильные? | |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 16:27)
| | строку echo file_get_contents($tmp_file);
замените на fpassthru(fopen($tmp_file, 'rb'))
file_get_contents читает файл в память. целиком. | |
|
|
|
|
|
|
|
для: Trianon
(25.05.2007 в 17:17)
| | Спасибо большое, Trianon, Вы как всегда меня выручили :)
Все работает.
Нашел также 2 вариант загрузки по частям:
<?php
function readfile_chunked ($filename) {
$chunksize = 1*(1024*1024);
$buffer = '';
$handle = fopen($filename, 'rb');
if ($handle === false) {
return false;
}
while (!feof($handle)) {
$buffer = fread($handle, $chunksize);
print $buffer;
}
return fclose($handle);
}
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=$name");
header('Content-Length: '.filesize($tmp_file));
$b = readfile_chunked($tmp_file);
?>
|
тоже работает как надо!
Так же, кому интересно, почитайте эту статью.
http://webmastak.com/article.aspx?id=322 | |
|
|
|
|
|
|
|
для: hammet
(25.05.2007 в 17:36)
| | Это не вариант загрузки по частям.
Загрузка по частям - вот:
http://softtime.ru/forum/read.php?id_forum=1&id_theme=37589 | |
|
|
|