@artem-dainov
Php, java, js. Boot spring, jquery, git

Как правильно отдать медиа файлы для веб проигрывателей и ссылок с других разделов компьютера/сервера?

Доброго времени суток!
Пожалуйста простите за то, что этот топик такой длинный, но у меня имеется две проблемы и в двух словах не описать их.

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

1. Какие нужно использовать заголовки для передачи media контента на веб страницу?
У меня компьютер с windows. Использую Open server. На диске D: имеется каталог Music. В нем есть несколько музыкальных файлов. Я хочу их воспроизвести на локальном сайте. В Html audio player я вставляю такую ссылку.
<audio src='http://my-site.local/music/123' controls></audio>


Адрес, /music/123, ведет на страницу audio.php и в ней есть такой код.
<?php
function download($file) {
if (file_exists($file)) {
// сбрасываем буфер вывода PHP, чтобы избежать переполнения памяти выделенной под скрипт
// если этого не сделать файл будет читаться в память полностью!
if (ob_get_level()) {
ob_end_clean();
}
// заставляем браузер показать окно сохранения файла
// header('Content-Description: File Transfer');
// header('Content-Type: application/octet-stream');
header("content-type: audio/mpeg");
header('Accept-Ranges: bytes');
header('Content-Length: ' . filesize($file));
// читаем файл и отправляем его пользователю
if ($fd = fopen($file, 'rb')) {
while (!feof($fd)) {
print fread($fd, 1024);
}
fclose($fd);
}
exit;
}
}
download("D:/music/".$_GET['filename'].".mp3"); // Из адреса, где есть /music/123
?>

В таком варианте музыка воспроизводится корректно, но очень редко бывает так, что проигрыватель затыкается, как будто что-то докачивает, и может через минуту играть дальше.
Это дико раздражает и я подумал, что у меня может с заголовками что-то не так. Кто знает, в чем может быть причина?
Ведь, файлы, которые будут лежать у меня на сайте и будут доступны по ссылке, my-site.local/file.mp3, будет работать без всяких проблем.

2. Файлы могут содержать знак & и из-за этого могут сломаться get параметры.
По этой причине я обращаюсь к audio.php через POST. Однако, я не могу понять, как правильно получить данные, чтобы вставить их в проигрыватель.
Вод код.
$(document).ready(function(){
$.post("/audio.php",{file: 'm&m.mp3'},audioPlay);
function audioPlay(data) {
// А вот как дальше вставить это в проигрыватель, я не знаю.
audio.src = data; // Так браузер зависает.
}
});

Спасибо, что вы дочитали это до конца и надеюсь на вашу помощь в решении двух моих проблем.
С уважением - Автор топика!
  • Вопрос задан
  • 311 просмотров
Решения вопроса 1
Compolomus
@Compolomus Куратор тега PHP
Комполом-быдлокодер
возможно поможет
// index.php

function download(string $filePath): void
{
    if (!headers_sent()) {
        ob_end_clean();
    }

    if (!file_exists($filePath)) {
        throw new InvalidArgumentException('File not exists');
    }

    $filesize = filesize($filePath);
    $fileObject = new SplFileObject($filePath, 'rb');

    header('content-type: audio/mpeg');

    $range = 0;

    if (isset($_SERVER['HTTP_RANGE'])) {
        $range = $_SERVER['HTTP_RANGE'];
        $range = str_replace('bytes=', '', $range);
        [$range] = explode('-', $range);

        if (!empty($range)) {
            $fileObject->fseek($range);
        }
    }

    if ($range) {
        header($_SERVER['SERVER_PROTOCOL'] . ' 206 Partial Content');
    } else {
        header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK');
    }

    header('Accept-Ranges: bytes');
    header('Content-Description: inline; File Transfer');
    header('Content-Disposition: attachment; filename="' . basename($fileObject->getBasename()) . '";', false);
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . ($filesize - $range));

    if ($range) {
        header('Content-Range: bytes ' . $range . '-' . ($filesize - 1) . '/' . $filesize);
    }

    header('Connection: close');

    $speed = 100;

    while (!$fileObject->eof() && connection_status() === 0) {
        echo $fileObject->fread(1024 * $speed);
        flush();
        #sleep(1);  // разкоментирование приведет к ограничению скорости в 100 kb
    }
}

download('./1.mp3');


<span class="green"><audio controls><source src="http://localhost/dnl/index.php"></audio></span>


spoiler

Request URL: http://localhost/dnl/index.php
Request Method: GET
Status Code: 206 Partial Content
Remote Address: 127.0.0.1:80
Referrer Policy: strict-origin-when-cross-origin
Accept-Ranges: bytes
Connection: close
Content-Description: inline; File Transfer
Content-Disposition: attachment; filename="1.mp3";
Content-Length: 168977156
Content-Range: bytes 2097152-171074307/171074308
Content-Transfer-Encoding: binary
Content-Type: audio/mpeg
Date: Sat, 15 Apr 2023 19:03:29 GMT
Server: Apache
X-Content-Type-Options: nosniff
Accept: */*
Accept-Encoding: identity;q=1, *;q=0
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7,nb;q=0.6
Connection: keep-alive
DNT: 1
Host: localhost
Range: bytes=2097152-
Referer: http://localhost/dnl/index.html
sec-ch-ua: "Google Chrome";v="111", "Not(A:Brand";v="8", "Chromium";v="111"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Sec-Fetch-Dest: video
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36

Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@pantsarny
А зачем тут php?
Если у вас nginx - используйте alias или root для папки с контентом
Ответ написан
Stalker_RED
@Stalker_RED
1. Вы можете в конфиге nginx указать что при запросе mysite.loc надо искаьт файлы в d:\music
2. вы можете на уровне операционной системы сделать симлинк
mklink /d c:\work'mysite\music d:\music
3. вы можете вот ака как у вас сейчас выдавать через PHP.
Плюсы - легко можно добавить дополнительного кода - проверки прав доступа, статистику собрать, биллинг прикрутить.
Минус один, но очень заметный при большом количестве пользователей - грузите процессор лишний раз.

знак & и из-за этого могут сломаться get параметры
экранирование? не, не слышал.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы