12 ноября 2008 г. ID3 PHP

Получаем ID3-теги с помощью PHP

ID3 (от англ. Identify an MP3) — формат метаданных, наиболее часто используемый в MP3 файлах. ID3 подпись содержит данные о названии трека, альбома, имени исполнителя и т. д. Именно эти данные использует Winamp и все остальные проигрыватели при воспроизведении файла, показывая, какая песня сейчас играет.

http://ru.wikipedia.org/wiki/ID3_(метаданные)

php_id3

http://ru2.php.net/manual/ru/book.id3.php

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

GetID3

http://getid3.sourceforge.net/

В поисках решения получше, я наткнулся на проект GetID3 и скачал самую последнюю версию данной библиотеки (Latest 2.x beta version: 2.0.0-b4).

Поддерживает следующие форматы тегов:

  • ID3v1 (v1.0 & v1.1)
  • ID3v2 (v2.2, v2.3 & v2.4)
  • APE tags (v1 & v2)
  • (Ogg) VorbisComment
  • Lyrics3 (v1 & v2)

Более подробное описание возможностей можно посмотреть на странице проекта, а мы пойдем дальше - посмотрим поближе саму библиотеку, так сказать в работе.

Добавил в проект данную библиотеку, открыл свою любимую IDE - Eclipse, и она меня сразу оповестила о ошибке в 403 строке файла write.id3v2.php, оказываеться, разработчики забыли открыть блок после else. Грубо конечно, но спишем все на бета-версию :)

Едем дальше, теперь все работает, скорость обработки достаточно быстрая!

Пример использования:

$getid3 = new getID3();
$getid3->encoding = 'UTF-8'; //указываем output-кодировку
$getid3->Analyze($filename); //путь до файла
var_dump($getid3->info['comments']); //посмотрим результаты работы

Боремся с обрезанием крайнего символа

Ещё одна проблема, крайние символы обрезаются на один символ больше. То есть, например "Алиса" будет "Алис". Итак, заходим в module.tag.id3v2.php (338) и заменяем

$parsed_frame['data'] = substr($frame_data, 0, $frame_size);

на

$parsed_frame['data'] = substr($frame_data, 0, $frame_size +1);

Ещё есть проблема с определением кодировки

Проблема состоит в том, что кодировку корректно данная библиотека не может определить, из-за этого все беды... Например, теги у нас в windows-1251, а библиотека определяет ее как iso-8859-1.

А беда в том, что в самом начале мы устанавливаем кодировку для вывода (UTF-8) и она конвертирует строку в кодировке windows-1251 в utf-8, при этом с параметрами iso-8859-1 и utf-8, соответственно. Поэтому приходиться конвертить из utf-8 в iso-8859-1, а потом из windows-1251 в utf-8 снова :)

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

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

Комментарии

Полезно однако.
(: В закладки.

И снова я тестирую твою антиспам машину адворд. Когда же она заработает нормально?

Кстати по поводу кодировки, можно её автоматически определить, например с помощью библиотеки http://popoff.donetsk.ua/text/work/libs/a/charset/

Кодировку ещё умеет определять mb_detect_encoding().

После некоторых танцев вокруг кодировок получилось что-то вроде:


    /**
     * Получить параметры записи
     * @param  string $filename путь к файлу
     * @return array  параметры или false при какой-нибудь ошибке
     *     "title"  - название
     *     "artist" - исполнитель
     *     "length" - длина в секундах
     */
    public static function getMP3Params($filename)
    {
        require_once(dirname(__FILE__).'/getid3/getid3/getid3.php');
        try {
            $g = new getID3();
            //$g->encoding = 'UTF-8'; // В примере было, ни на что не влияет
            @$g->analyze($filename); // Куча Strict Standarts
        } catch (Exception $e) {
            /* Не знаю, что за исключения, но в примере был try-catch */
            return false;
        }
        if (!isset($g->info)) {
            return false;
        }
        $info = $g->info;
        if (isset($info['error'])) {
            return false;
        }
        if ($info['fileformat'] != 'mp3') {
            return false;
        }
        $length = intval(
                (($info['avdataend'] - $info['avdataoffset']) * 8) / 
                $info['audio']['bitrate']
        );
        $result = Array(
            'title'  => '',
            'artist' => '',
            'length' => $length,
        );
        if (isset($info['id3v2'])) {
            $info = $info['id3v2'];
        } elseif (isset($info['id3v1'])) {
            $info = $info['id3v1'];
        } else {
            return $result;
        }
        if (!isset($info['comments'])) {
            return $result;
        }
        $info = $info['comments'];
        if (isset($info['artist'])) {
            $artist = $info['artist'][0];
            /* Танцы с бубном */
            $ar     = mb_convert_encoding($artist, 'iso-8859-1', 'utf-8');
            $artist = $ar ? $ar : $artist;
            $artist = mb_convert_encoding($artist, 'utf-8', 'windows-1251');
            $result['artist'] = $artist;
        }
        if (isset($info['title'])) {
            $title = $info['title'][0];
            $tl    = mb_convert_encoding($title, 'iso-8859-1', 'utf-8');
            $title = $tl ? $tl : $title;
            $title = mb_convert_encoding($title, 'utf-8', 'windows-1251');
            $result['title'] = $title;
        }
        return $result;
    }

if (isset($info['id3v2'])) {
    $info = $info['id3v2'];
} elseif (isset($info['id3v1'])) {
    $info = $info['id3v1'];
} else {
    return $result;
}

$info['id3v1'] и $info['id3v2'] - массивы? Просто ты эту $info переопределяешь много где... А код вообще проверял?

да, массивы.
Обрати внимание, что иногда хватает windows-1251 --> utf-8.
Так что извращения utf8->iso(utf)->win иногда излишни. А иногда нет.
Плюс длину в секундах вычислил как

intval((($info['avdataend'] - $info['avdataoffset']) * 8) /$info['audio']['bitrate']);

. Кажется, работает.

ElectroInjector 28 июня 2009 г. 17:18

Лагин под вордпресс на основе этого кода пользовался бы популярностью ;)

ElectroInjector, и какова аудитория?)

А чем не нравится MP3_Id?
http://pear.php.net/package/MP3_Id/download

2 vasa_c
Кажется, Вы ненавидите сами себя :) Код ужасен.

flegg, не пользовался

flegg, мне похуй ;

дайте код которым можно изменить ID3v2 теги в MP3 файле с помощю PHP

У меня нет такого кода, я никогда не менял через PHP теги.
Может это поможет http://www.php.su/articles/?cat=others&page=013

в последней od3 ест ошибка изза которой я както раз потерял часов 6. когда делаешь save() (или что там, writetags() ли)

они пытаются создать темповый файл, а если стоит ограничение open_basedir, то их обработчик ошибок не пишет ошибку, хотя до этог овсе ошики которые он смог найти гладко шлет в обработчик, а вот эту злую нет :D

это я к слову, если при записи вы видите что файл не перезаписывается - ид тоже не без ошибок, ищите :)

эдво - ты ахуенен

правда - правда, ты ахуенен! :)

phpdude, да ну нафиг, это ты ахуенен! :)

Вобщем с долгими мучениями и поисками сделал то что хотел, а именно изменение ID3v2 тегов в MP3 файле, вот мануал http://ua2.php.net/manual/en/book.id3.php может кому пригодиться.

У меня раньше с этим модулем были траблы, я об этом в статье писал... Хотя может сейчас все наладили уже

adw0rd, огромное тебе спасибо!!! Потратил уйму времени, чё тока не делал, искал везде, находил много чего, но низера не подходило или не работало!
СПС ЗА ЭТОТ КОД!!!

Спасибо! )

intval((($info['avdataend'] - $info['avdataoffset']) * 8) /$info['audio']['bitrate']);

а можно и проще)
$length = intval($info['playtime_seconds']);

Александр 4 ноября 2013 г. 1:12

Автору спасибо за статью. Но объясните пожалуйста как подключить данную библиотеку. Куча файлов и теряешься как то сразу.

Александр 4 ноября 2013 г. 9:16

Уже ненадо разобрался.

Оставьте свой комментарий

Markdown