M3U плейлист на PHP: примеры и рекомендации
Основные подходы к созданию M3U плейлистов на PHP
Целевое решение: универсальная функция, которая из массива данных формирует корректный M3U файл с поддержкой расширенного формата EXTINF. Используется для быстрой генерации плейлиста из любых источников (БД, API, файлы конфигурации).
function generateM3U(array $items, string $filename = 'playlist.m3u'): bool {
$handle = fopen($filename, 'w');
if (!$handle) {
return false;
}
fwrite($handle, "#EXTM3U\n");
foreach ($items as $item) {
$duration = $item['duration'] ?? -1;
$title = $item['title'] ?? 'Unknown';
$path = $item['path'] ?? '';
fwrite($handle, "#EXTINF:{$duration},{$title}\n");
fwrite($handle, "{$path}\n");
}
fclose($handle);
return true;
}
преобразовать php (преобразование типов в php)
Пояснение: Функция принимает массив с элементами, каждый из которых содержит duration (в секундах), title (название) и path (URL или путь к файлу). Записывает заголовок #EXTM3U и для каждого элемента строку #EXTINF и сам путь. Возвращает true при успешной записи.
Типичные проблемы:
- Отсутствие символа новой строки в конце файла – некоторые плееры могут некорректно обрабатывать последнюю строку. Рекомендуется добавлять пустую строку в конце.
- Некорректная кодировка – если заголовки содержат не-ASCII символы, файл должен быть сохранён в UTF-8 без BOM. Для явной установки кодировки используйте
fwrite($handle, "\xEF\xBB\xBF");перед заголовком, если требуется BOM (для Windows-плееров). - Неэкранированные запятые в названии – в поле
titleзапятая может быть воспринята как разделитель. Рекомендуется заменять запятую на точку с запятой или экранировать.
Вариант 1: Генерация из базы данных MySQL
Как сформировать M3U на основе записей таблицы channels?
$db = new PDO('mysql:host=localhost;dbname=iptv', 'user', 'pass');
$stmt = $db->query('SELECT name, url, duration FROM channels WHERE active=1');
$items = [];
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$items[] = [
'title' => $row['name'],
'path' => $row['url'],
'duration' => $row['duration']
];
}
generateM3U($items, 'channels.m3u');
Php ai (искусственный интеллект на php)
Пояснение: Извлекаются активные каналы из БД, преобразуются в массив и передаются в ранее определённую функцию. Такой подход легко масштабируется для тысяч записей.
Возможные ошибки: Большое количество записей может исчерпать память – используйте прямое построчное добавление в файл внутри цикла, без промежуточного массива.
Вариант 2: Загрузка и модификация существующего M3U
Как добавить новые каналы в уже имеющийся плейлист?
$existing = file('old_playlist.m3u', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$newItems = [
['duration' => -1, 'title' => 'Новый канал', 'path' => 'http://example.com/stream']
];
$file = fopen('merged.m3u', 'w');
fwrite($file, "#EXTM3U\n");
foreach ($existing as $line) {
if (strpos($line, '#EXTM3U') !== 0) { // пропускаем дублирующий заголовок
fwrite($file, $line . "\n");
}
}
foreach ($newItems as $item) {
fwrite($file, "#EXTINF:{$item['duration']},{$item['title']}\n");
fwrite($file, "{$item['path']}\n");
}
fclose($file);
Click php url (обработка кликов по url в php)
Пояснение: Загружается старый файл, отбрасывается заголовок (если есть) и дописываются новые строки. Результат сохраняется в новый файл.
Вариант 3: Расширенный формат с группами и логотипами
Как добавить атрибуты tvg-id, tvg-logo, group-title для IPTV?
function generateM3UExtended(array $items, string $filename): bool {
$fp = fopen($filename, 'w');
if (!$fp) return false;
fwrite($fp, "#EXTM3U\n");
foreach ($items as $item) {
$extinf = sprintf("#EXTINF:%d tvg-id=\"%s\" tvg-logo=\"%s\" group-title=\"%s\",%s\n",
$item['duration'] ?? -1,
$item['tvg_id'] ?? '',
$item['tvg_logo'] ?? '',
$item['group_title'] ?? 'Без группы',
$item['title']
);
fwrite($fp, $extinf);
fwrite($fp, $item['path'] . "\n");
}
fclose($fp);
return true;
}
Php меньше (оператор меньше в php)
Пояснение: Добавлены нестандартные атрибуты в строку EXTINF. Это позволяет плеерам (например, IPTV Simple Client) группировать каналы и отображать логотипы.
Проблема: Синтаксис EXTINF зависит от версии M3U. Некоторые плееры игнорируют незнакомые атрибуты, другие могут сломаться. Проверяйте совместимость.
Вариант 4: Кэширование сгенерированного плейлиста
Как уменьшить нагрузку при каждом запросе плейлиста?
$cacheFile = 'cache/playlist.m3u';
$cacheTime = 3600; // 1 час
if (file_exists($cacheFile) && time() - filemtime($cacheFile) < $cacheTime) {
readfile($cacheFile);
exit;
}
// генерация нового плейлиста
$items = fetchChannelsFromDB();
generateM3U($items, $cacheFile);
readfile($cacheFile);
Пояснение: Перед генерацией проверяется время жизни кэша. Если кэш свежий, отдаётся готовый файл, иначе – пересоздаётся. Это значительно ускоряет отдачу для пользователей.
Расширенные примеры создания M3U плейлистов
1. Динамическая сортировка по категориям
Пример генерации плейлиста, где каналы группируются в блоки по group-title, с разделителями в виде комментариев.
function generateGroupedM3U(array $items, string $file): void {
$fp = fopen($file, 'w');
fwrite($fp, "#EXTM3U\n");
$groups = [];
foreach ($items as $item) {
$g = $item['group'] ?? 'Other';
$groups[$g][] = $item;
}
foreach ($groups as $groupName => $groupItems) {
fwrite($fp, "# ----- {$groupName} -----\n");
foreach ($groupItems as $item) {
fwrite($fp, "#EXTINF:{$item['duration']},{$item['title']}\n");
fwrite($fp, "{$item['url']}\n");
}
}
fclose($fp);
}
$data = [
['title' => 'Первый', 'duration' => -1, 'url' => 'http://a.com/1', 'group' => 'Новости'],
['title' => 'Второй', 'duration' => -1, 'url' => 'http://b.com/2', 'group' => 'Спорт'],
];
generateGroupedM3U($data, 'grouped.m3u');
Результат (grouped.m3u):
#EXTM3U # ----- Новости ----- #EXTINF:-1,Первый http://a.com/1 # ----- Спорт ----- #EXTINF:-1,Второй http://b.com/2
2. Интеграция с внешним API для получения метаданных
Загрузка списка каналов из JSON API и преобразование в M3U.
$json = file_get_contents('https://api.example.com/channels');
$channels = json_decode($json, true);
if (!$channels || !isset($channels['data'])) {
die('Ошибка получения данных');
}
$items = [];
foreach ($channels['data'] as $ch) {
$items[] = [
'title' => $ch['name'],
'path' => $ch['stream_url'],
'duration' => $ch['duration'] ?? -1,
'tvg_logo' => $ch['logo'] ?? ''
];
}
generateM3UExtended($items, 'api_playlist.m3u');
Результат: Файл M3U с расширенными атрибутами, готовый к использованию в любом плеере.
3. Потоковая запись большого плейлиста (список каналов 100000+)
Использование генератора для избежания хранения всех данных в памяти.
function channelGenerator(PDO $db): Generator {
$stmt = $db->query('SELECT name, url FROM channels');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
yield ['title' => $row['name'], 'path' => $row['url'], 'duration' => -1];
}
}
$fp = fopen('big_playlist.m3u', 'w');
fwrite($fp, "#EXTM3U\n");
foreach (channelGenerator($pdo) as $item) {
fwrite($fp, "#EXTINF:{$item['duration']},{$item['title']}\n");
fwrite($fp, "{$item['path']}\n");
}
fclose($fp);
Пояснение: Генератор построчно читает из БД и сразу пишет в файл, не создавая промежуточного массива.
4. Поддержка разных протоколов и автоматическое определение формата
Если источник предоставляет потоки http, rtmp, mms, можно автоматически проставить соответствующий префикс в EXTINF.
foreach ($items as &$item) {
$protocol = parse_url($item['path'], PHP_URL_SCHEME);
$item['type'] = ($protocol === 'rtmp') ? 'rtmp' : 'hls';
}
// в EXTINF можно добавить атрибут radio="true" или protocol
Применение: Позволяет плееру правильно выбирать декодер.
5. Генерация M3U с аутентификацией (токен в URL)
Добавление временного токена к ссылкам для ограниченного доступа.
$token = generateToken(); // допустим, md5(time())
$items = array_map(function($item) use ($token) {
$separator = (strpos($item['path'], '?') !== false) ? '&' : '?';
$item['path'] .= $separator . 'token=' . $token;
return $item;
}, $items);
generateM3U($items, 'secure_playlist.m3u');
Результат: Все URL в плейлисте содержат параметр token, который можно проверить на стороне сервера.