Оптимизировать скорость file_put_contents

Я пытаюсь ускорить создание файла с моим видео. Моя проблема в том, что file_put_contents занимает слишком много времени для создания видеофайла размером в среднем 50 МБ. Мой код ниже сначала декодирует видео и помещает его в каталог. $ Видео - байтовый массив. Есть ли способ создать видеофайл без декодирования 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);

Дайте определение «занимает слишком много времени». Насколько велик создаваемый вами файл?

Dave 20.12.2018 15:53

средний размер файла 50 МБ @Dave

user10200885 20.12.2018 15:53

Скорость будет связана с оборудованием, на котором вы запускаете код. В любом случае, слишком долго - это очень субъективно.

Dave 20.12.2018 15:54

@ Дэйв, есть ли что-то, что я могу сделать в своем коде, чтобы хоть немного ускорить процесс?

user10200885 20.12.2018 15:55

@JonStirling, могу ли я использовать вместо этого fwrite ()? это быстрее?

user10200885 20.12.2018 15:58

И file_get_contents(), и file_put_contents() подразумевают загрузку всего видео в RAM. Использование таких функций бесполезно, старые добрые fopen() и fread() - единственный разумный механизм. (Почему вообще Base64?).

Álvaro González 20.12.2018 15:59

1) Вероятно, нет 2) Почему бы не попробовать и не посмотреть, а не спросить меня 3) Я не уверен, что вы читали мой комментарий.

Jonnix 20.12.2018 15:59

@ ÁlvaroGonzález, как я могу его использовать, вы можете показать мне, просто чтобы получить общее представление

user10200885 20.12.2018 16:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
0
8
434
1

Ответы 1

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

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

На данный момент у вас есть 4 копии видео, загруженные в RAM. Для мультимедийного файла размером 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

Можете ли вы направить меня с помощью кода, который я не знаю, как использовать fread () в цикле

user10200885 26.12.2018 10:10

Просто скопируйте и вставьте последний пример из документации.

Álvaro González 26.12.2018 10:12

кто может создавать видео по кускам?

user10200885 26.12.2018 10:59

Как создается видео путем обработки данных по частям?

user10200885 26.12.2018 11:16

@LawrenceAgulto Я только что обновил свой ответ. Если я все еще не могу объяснить себя, укажите, в чем именно у вас возникли трудности.

Álvaro González 26.12.2018 11:26

Я запутался в назначении $ input и $ output

user10200885 26.12.2018 11:37

Это стандартные термины в информатике (я уверен, что вы видели аббревиатуру I / O много раз). «Ввод» - это место, откуда вы читаете, а «выход» - это место, куда писать.

Álvaro González 26.12.2018 11:41

Итак, я буду использовать fopen () my $ Video, мой код будет $ input = fopen ($ Video, 'rb') или die (1);, это правильно?

user10200885 26.12.2018 11:50

Другие вопросы по теме