Я хочу загрузить большие файлы на мой сервер. Я склеиваю эти файлы перед загрузкой в макс. 1 МБ кусков. Если один чанк загружен, этот чанк добавляется в файл.
На моем локальном сервере все работает хорошо, но если я тестирую этот скрипт на своем веб-сервере (размещенном в Strato -.-), процесс завершается с Внутренней ошибкой сервера каждый раз, когда размер добавляемого файла на сервере увеличивается до 64 МБ.
Я думаю, что это (конечно?) Вызвано ограничением Strato. Может быть, что-то с памятью, но я не могу объяснить себе, почему это происходит.
Это скрипт (версия PHP 5.6):
$file = $_FILES['chunk'];
$server_chunk = fopen($uploadDir.$_POST['file_id'], "ab");
$new_chunk = fopen($file['tmp_name'], "rb");
while(!feof($new_chunk)) //while-loop is optional
{
fwrite($server_chunk, fread($new_chunk, 1024));
};
fclose($new_chunk);
fclose($server_chunk);
По моему мнению, в этом коде нет строки, где файл загружается в память, чтобы вызвать эту ошибку, или что-то другое может вызвать эту ошибку?
Я проверил журналы сервера, но нет никакой записи, если эта ошибка происходит.
Я могу создать несколько 63MB файлов. Только если файлы превышают 64 МБ, сервер прерывает работу.
ОБНОВИТЬ:
Я написал следующий скрипт для объединения файловых блоков на сервере с cat.
Но я всегда получаю файл 8192B обратно.
Что-то не так с этим скриптом?
$ command — это что-то вроде:
/ bin / cat ../files/8_0 ../files/8_1 ../files/8_2 ../files/8_3
$command = '/bin/cat';
foreach($file_array AS $file_info)
{
$command = $command.' ../files/'.$file_info['file_id'].'_'.$file_info['server_chunkNumber'];
}
$handle1 = popen($command, "r");
$read = fread($handle1, $_GET['size']);
echo $read;
Я проверил результат. Байты в файле 8192B в точности совпадают с началом исходного файла. Так что, кажется, что-то работает …
Обновить:
я нашел этот.
Обновить:
$handle1 = popen($command, "r");
while(!feof($handle1))
{
$read = fread($handle1, 1024);
echo $read;
}
Это работает, я могу кусочно читать из ручки. Но, конечно, таким образом я сталкиваюсь с ограничениями по таймауту. Как я могу передать файл клиенту? Если на этот вопрос ответят все мои проблемы ушли;)
(см. обновление внизу)
Ошибка ограничения памяти выглядела бы иначе (но вы можете написать скрипт, который постоянно выделяет память, добавляя большие объекты в растущий массив, и смотрите, что происходит). Кроме того, ограничение памяти связано с ядром PHP, плюс сценарий, плюс структуры, плюс любой контент файла; даже если файл добавлен в должны были быть загружены или рассчитаны на ограничение памяти (может быть через mmap
, даже если это кажется странным), в лучшем случае маловероятно, чтобы предел составлял 64 мегабайта.
Так это выглядит ограничение файловой системы на один размер файла мне. Есть несколько облачных файловых систем, которые имеют такие ограничения; но я не знаю ни одного такого на локальном дисковом хранилище. Я попросил бы подсказки к технической поддержке хостинга.
Некоторые попытки, которые я сделал бы:
двойная проверка $uploadDir
если это не было назначено вами лично.
попробуйте создать файл по другому пути, чем $uploadDir
, если конечно не в одной файловой системе
попробуйте проверить на наличие ошибок:
if (!fwrite($server_chunk, fread($new_chunk, 1024))) {
die("Error writing: ");
}
параноидальная проверка на phpinfo (), чтобы убедиться, что нет странный странность, такая как переопределение функции. Вы можете расследовать по перечисляя функции и проверяя их (подделка, да, но вряд ли).
это действительно похоже на ограничение размера файла, не связанное с PHP. Ранее пользователи этого же хостинга сообщали о 32 Мб. Увидеть Вот а также Вот. Там люди не могут бежать mysqldump
, или же tar
резервное копирование. Это не имеет ничего общего с PHP напрямую.
Возможно, вы можете обойти эту проблему, сохранив файл порциями и загрузив его несколькими частями или передав Apache канал в cat
программа, если есть.
Что произойдет, если вы сохраните файл 123.0001, файл 1230002, …, а затем, после загрузки, проверьте все фрагменты и отправьте соответствующий Content-Length
создать командную строку для /bin/cat
(если доступно …) и подключить поток к серверу. Вы все еще можете столкнуться с временными ограничениями, но это стоит того.
Пример:
<?php
$pattern = "test/zot.*"; # BEWARE OF SHELL METACHARACTERS
$files = glob($pattern);
natsort($files);
$size = array_sum(array_map('filesize', $files));
ob_end_clean();
Header("Content-Disposition: attachment;filename=\"test.bin\";");
Header("Content-Type: application/octet-stream");
Header("Content-Length: {$size}");
passthru("/bin/cat {$pattern}");
Я проверил вышеупомянутое, и он загружает один файл размером 120 МБ из набора фрагментов по 10 МБ, упорядоченных как zot.1, zot.2, …, zot.10, zot.11, zot.12 (и да, я не использовал natsort
вначале). Если мне удастся найти время, я запусту его снова на виртуальной машине с дросселированной сетью, так что сценарий будет иметь ограничение по времени 10 с, а загрузка займет 20 с. Это возможный этот PHP не прервет сценарий, пока passthru не вернется, поскольку я заметил, что хронометраж PHP не очень интуитивно понятен.
Следующий код выполняется с ограничением по времени три секунды. Он запускает команду, которая принимает четыре секунд, затем отправляет вывод в браузер, продолжает работать, пока его время не будет исчерпано.
<pre>
<?php
print "It is now " . date("H:i:s") . "\n";
passthru("sleep 4; echo 'Qapla!'");
print "It is now " . date("H:i:s") . "\n";
$x = 0;
for ($i = 0; $i < 5; $i++) {
$t = microtime(true);
while (microtime(true) < $t + 1.0) {
$x++;
}
echo "OK so far. It is now " . date("H:i:s") . "\n";
}
Результат:
It is now 20:52:56
Qapla!
It is now 20:53:00
OK so far. It is now 20:53:01
OK so far. It is now 20:53:02
OK so far. It is now 20:53:03( ! ) Fatal error: Maximum execution time of 3 seconds exceeded in /srv/www/rumenta/htdocs/test.php on line 9
Call Stack
# Time Memory Function Location
1 0.0002 235384 {main}( ) ../test.php:0
2 7.0191 236152 microtime ( ) ../test.php:9
Конечно, вполне возможно, что Strato использует более строгую проверку времени выполнения скрипта. Также у меня установлен PHP как модуль; возможно, для CGI, которые работают как независимые процессы, применяются другие правила.
Других решений пока нет …