Оптимизировать скорость file_put_contents - PullRequest
0 голосов
/ 20 декабря 2018

Я пытаюсь ускорить создание файла моего видео.Моя проблема заключается в том, что file_put_contents занимает много времени для создания видеофайла в среднем 50 МБ.Мой код ниже сначала декодирует видео и помещает его в каталог. $ Video - это байтовый массив.Есть ли способ создать видеофайл без декодирования base64 и что я могу сделать, чтобы ускорить создание файла?

$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);

$CAFNo = $json_obj->CAFNo;
$Date = $json_obj->CAFDate;
$Video = $json_obj->Video;
$CafDate = date("Y-m-d", strtotime($Date));

$video_decode = base64_decode($Video);
$video_filename = __DIR__ . '/uploads/'. $CAFNo . '_'.$CafDate.'_VID.mp4';
$save_video = file_put_contents($video_filename, $video_decode);

$video_dbfilename = './uploads/'. $CAFNo . '_'.$CafDate.'_VID.mp4';

$sql = "UPDATE tblCaf SET Video = '$video_dbfilename' WHERE CAFNo = '$CAFNo'";
mysqli_query ($conn, $sql);

1 Ответ

0 голосов
/ 22 декабря 2018

Медиа-файл может быть огромным, поэтому вы не можете обработать его с помощью методов, которые включают загрузку всего файла в ОЗУ, не говоря уже о нескольких копиях данных одновременно.Ваш код делает это несколько раз.

$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
$Video = $json_obj->Video;
$video_decode = base64_decode($Video);

На данный момент у вас есть 4 копии видео, загруженные в ОЗУ.Для медиа-файла 50 МБ это означает, что $video_decode содержит 50 МБ данных, а другие переменные еще больше.Вам также необходимо добавить внутреннюю память, используемую такими функциями, как json_decode().Чтобы получить представление об используемой оперативной памяти, вы можете вставить ее между каждой операцией:

var_dump(memory_get_usage(true));

Кроме того, современные видеокодеки представляют собой высоко оптимизированные двоичные потоки.Если вы преобразуете эти двоичные данные в обычный текст, размер будет расти.Base64 увеличивает объем данных на 4/3 .JSON добавляет немного накладных расходов, хотя на данный момент ничего серьезного.


Если бы мне пришлось разработать это с нуля, я бы использовал POST-запрос с двоичным форматом (либо multipart/form-data или пользовательскую кодировку, может быть, просто файл как есть), а затем просто прочитайте ввод в виде кусков:

Если вы предпочитаете или должны придерживаться текущего дизайна, вам нужноадресация всех операций чтения и декодирования файла в чанках:

И последнее, но не менее важное: никогда не создавайте код SQL путем внедренияненадежный внешний ввод:

$sql = "UPDATE tblCaf SET Video = '$video_dbfilename' WHERE CAFNo = '$CAFNo'";

Вместо этого используйте подготовленные операторы .Орды учебных пособий, которые предлагают иначе, должны были быть сожжены давно.


Обновление: Кажется, что концепция обработки данных небольшими порциями (вместо загрузки всего в памяти)Это не так просто, как я думал, поэтому я приведу исполняемый код, чтобы проиллюстрировать разницу.

Прежде всего, давайте создадим файл размером 100 МБ для проверки:

$test = __DIR__ . '/test.txt';
$fp = fopen($test, 'wb') or die(1);
for ($i = 0; $i < 1839607; $i++) {
    fwrite($fp, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n") or die(2);
}
fclose($fp);

Если выприбегнуть к простым в использовании вспомогательным функциям с одним вкладышем:

ini_set('memory_limit', '300M');
$test = __DIR__ . '/test.txt';
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
$data = file_get_contents($test);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
file_put_contents(__DIR__ . '/copy.txt', $data);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
printf("Maximum memory usage: %d MB\n", memory_get_peak_usage(true) / 1024 / 1024);

... это связано с ценой, требующей потенциально большого объема памяти (бесплатной еды не бывает):

Current memory usage: 0 MB
Current memory usage: 100 MB
Current memory usage: 100 MB
Maximum memory usage: 201 MB

Если вы разбили файл на маленькие кусочки:

$test = __DIR__ . '/test.txt';
$chunk_size = 1024 * 1024;
$input = fopen($test, 'rb') or die(1);
$output = fopen(__DIR__ . '/copy.txt', 'wb') or die(2);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
while (!feof($input)) {
    $chunk = fread($input, $chunk_size) or die(3);
    fwrite($output, $chunk) or die(4);
}
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
fclose($input);
fclose($output);
printf("Current memory usage: %d MB\n", memory_get_usage(true) / 1024 / 1024);
printf("Maximum memory usage: %d MB\n", memory_get_peak_usage(true) / 1024 / 1024);

... вы можете использовать фиксированный объем памяти для файлов любого размера:

Current memory usage: 0 MB
Current memory usage: 1 MB
Current memory usage: 1 MB
Maximum memory usage: 3 MB
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...