Creating an ID3 Tags Reader with PHP

Date: 26th Aug 2011 Author: admin 15 Comments
Posted in: PHP

ID3 Tags Reader with PHP

ID3 Tags Reader with PHP

Today we will work with PHP again. Today I will show you how you can use PHP to obtain ID3 meta info from music files (mp3). Most easy way to store id3 info – winamp software. So you will able to test our result script with your music files. We will extract next fields: Title, Album, Author, Discription, Genre, Publisher, OriginalArtist, URL etc.

Live Demo
download in package

Now – download the example files and lets start coding !


Step 1. HTML

As usual, we start with the HTML. This is source of demo page layout:

main_page.html

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <title>ID3 Tags Reader with PHP | Script-tutorials</title>
    <link rel="stylesheet" href="css/main.css" type="text/css" media="all" />
</head>
<body>
    <div class="example" id="main">
        <table style="width:100%">
            <thead>
                <td><b>Title</b></td>
                <td><b>Album</b></td>
                <td><b>Author</b></td>
                <td><b>AlbumAuthor</b></td>
                <td><b>Track</b></td>
                <td><b>Year</b></td>
                <td><b>Lenght</b></td>
                <td><b>Lyric</b></td>
                <td><b>Desc</b></td>
                <td><b>Genre</b></td>
            </thead>
            __list__
        </table>

        <hr /><h3>Extra info</h3>
        <table style="width:100%">
            <thead>
                <td><b>Title</b></td>
                <td><b>Encoded</b></td>
                <td><b>Copyright</b></td>
                <td><b>Publisher</b></td>
                <td><b>OriginalArtist</b></td>
                <td><b>URL</b></td>
                <td><b>Comments</b></td>
                <td><b>Composer</b></td>
            </thead>
            __list2__
        </table>

    </div>
</body>
</html>

I prepared 2 tables to display ID3 infos of each enumerated file

Step 2. CSS

Here are used CSS styles:

css/main.css

body{background-color:#ddd;margin:0;padding:0}
.example{position:relative;background-color:#fff;width:980px;height:700px;border:1px #000 solid;margin:20px auto;padding:20px;-moz-border-radius:3px;-webkit-border-radius:3px}

Step 3. PHP

Our most important part of project – PHP.

index.php

<?php

// set error reporting level
if (version_compare(phpversion(), '5.3.0', '>=') == 1)
  error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
else
  error_reporting(E_ALL & ~E_NOTICE);

// gathering all mp3 files in 'mp3' folder into array
$sDir = 'mp3/';
$aFiles = array();
$rDir = opendir($sDir);
if ($rDir) {
    while ($sFile = readdir($rDir)) {
        if ($sFile == '.' or $sFile == '..' or !is_file($sDir . $sFile))
            continue;

        $aPathInfo = pathinfo($sFile);
        $sExt = strtolower($aPathInfo['extension']);
        if ($sExt == 'mp3') {
            $aFiles[] = $sDir . $sFile;
        }
    }
    closedir( $rDir );
}

// new object of our ID3TagsReader class
$oReader = new ID3TagsReader();

// passing through located files ..
$sList = $sList2 = '';
foreach ($aFiles as $sSingleFile) {
    $aTags = $oReader->getTagsInfo($sSingleFile); // obtaining ID3 tags info
    $sList .= '<tr><td>'.$aTags['Title'].'</td><td>'.$aTags['Album'].'</td><td>'.$aTags['Author'].'</td>
                    <td>'.$aTags['AlbumAuthor'].'</td><td>'.$aTags['Track'].'</td><td>'.$aTags['Year'].'</td>
                    <td>'.$aTags['Lenght'].'</td><td>'.$aTags['Lyric'].'</td><td>'.$aTags['Desc'].'</td>
                    <td>'.$aTags['Genre'].'</td></tr>';

    $sList2 .= '<tr><td>'.$aTags['Title'].'</td><td>'.$aTags['Encoded'].'</td><td>'.$aTags['Copyright'].'</td>
                    <td>'.$aTags['Publisher'].'</td><td>'.$aTags['OriginalArtist'].'</td><td>'.$aTags['URL'].'</td>
                    <td>'.$aTags['Comments'].'</td><td>'.$aTags['Composer'].'</td></tr>';
}

// main output
echo strtr(file_get_contents('main_page.html'), array('__list__' => $sList, '__list2__' => $sList2));

// class ID3TagsReader
class ID3TagsReader {

    // variables
    var $aTV23 = array( // array of possible sys tags (for last version of ID3)
        'TIT2',
        'TALB',
        'TPE1',
        'TPE2',
        'TRCK',
        'TYER',
        'TLEN',
        'USLT',
        'TPOS',
        'TCON',
        'TENC',
        'TCOP',
        'TPUB',
        'TOPE',
        'WXXX',
        'COMM',
        'TCOM'
    );
    var $aTV23t = array( // array of titles for sys tags
        'Title',
        'Album',
        'Author',
        'AlbumAuthor',
        'Track',
        'Year',
        'Lenght',
        'Lyric',
        'Desc',
        'Genre',
        'Encoded',
        'Copyright',
        'Publisher',
        'OriginalArtist',
        'URL',
        'Comments',
        'Composer'
    );
    var $aTV22 = array( // array of possible sys tags (for old version of ID3)
        'TT2',
        'TAL',
        'TP1',
        'TRK',
        'TYE',
        'TLE',
        'ULT'
    );
    var $aTV22t = array( // array of titles for sys tags
        'Title',
        'Album',
        'Author',
        'Track',
        'Year',
        'Lenght',
        'Lyric'
    );

    // constructor
    function ID3TagsReader() {}

    // functions
    function getTagsInfo($sFilepath) {
        // read source file
        $iFSize = filesize($sFilepath);
        $vFD = fopen($sFilepath,'r');
        $sSrc = fread($vFD,$iFSize);
        fclose($vFD);

        // obtain base info
        if (substr($sSrc,0,3) == 'ID3') {
            $aInfo['FileName'] = $sFilepath;
            $aInfo['Version'] = hexdec(bin2hex(substr($sSrc,3,1))).'.'.hexdec(bin2hex(substr($sSrc,4,1)));
        }

        // passing through possible tags of idv2 (v3 and v4)
        if ($aInfo['Version'] == '4.0' || $aInfo['Version'] == '3.0') {
            for ($i = 0; $i < count($this->aTV23); $i++) {
                if (strpos($sSrc, $this->aTV23[$i].chr(0)) != FALSE) {

                    $s = '';
                    $iPos = strpos($sSrc, $this->aTV23[$i].chr(0));
                    $iLen = hexdec(bin2hex(substr($sSrc,($iPos + 5),3)));

                    $data = substr($sSrc, $iPos, 9 + $iLen);
                    for ($a = 0; $a < strlen($data); $a++) {
                        $char = substr($data, $a, 1);
                        if ($char >= ' ' && $char <= '~')
                            $s .= $char;
                    }
                    if (substr($s, 0, 4) == $this->aTV23[$i]) {
                        $iSL = 4;
                        if ($this->aTV23[$i] == 'USLT') {
                            $iSL = 7;
                        } elseif ($this->aTV23[$i] == 'TALB') {
                            $iSL = 5;
                        } elseif ($this->aTV23[$i] == 'TENC') {
                            $iSL = 6;
                        }
                        $aInfo[$this->aTV23t[$i]] = substr($s, $iSL);
                    }
                }
            }
        }

        // passing through possible tags of idv2 (v2)
        if($aInfo['Version'] == '2.0') {
            for ($i = 0; $i < count($this->aTV22); $i++) {
                if (strpos($sSrc, $this->aTV22[$i].chr(0)) != FALSE) {

                    $s = '';
                    $iPos = strpos($sSrc, $this->aTV22[$i].chr(0));
                    $iLen = hexdec(bin2hex(substr($sSrc,($iPos + 3),3)));

                    $data = substr($sSrc, $iPos, 6 + $iLen);
                    for ($a = 0; $a < strlen($data); $a++) {
                        $char = substr($data, $a, 1);
                        if ($char >= ' ' && $char <= '~')
                            $s .= $char;
                    }

                    if (substr($s, 0, 3) == $this->aTV22[$i]) {
                        $iSL = 3;
                        if ($this->aTV22[$i] == 'ULT') {
                            $iSL = 6;
                        }
                        $aInfo[$this->aTV22t[$i]] = substr($s, $iSL);
                    }
                }
            }
        }
        return $aInfo;
    }
}

?>

After put your mp3 files near these code files thats all. Yes, there are a lot of code, but everything is close. Commonly – you can check code in beginning (before defining of class), and class itself. First half is very easy – passing through files of folder, and generating output. So about class itself (ID3TagsReader) – this is more difficult. We will read hex code of each MP3 file and looking for inner information (ID3). I will try to pick all ID3 tags which can be available in Winamp (mp3 player). But I can say that the total of all possible tags is much more.


Live Demo
download in archive

Conclusion

I hope today’s article was very interesting for you. This material can be of great interest for projects that work with the music. This will help you get a variety of information from music files without including another large libraries. Good luck in your work!

Enjoyed this Post?

    Tweet
   
   

Stay connected with us:

If you enjoyed this article, feel free to share our tutorial with your friends.

15 Comments

    • John More's Gravatar
    • Hello there, while trying to implement your ID3CLASSREADER class I came upon some things I wanted to share with you so that you can maybe help me out. So first thing I love using ezsql when working with php + sql, however it seems that your class turns ezsql useless lol which is nothing really serious but just so you know. The second thing I came across is the fact that a lot of mp3′s get they’re titles or albums chopped up by exactly one letter at the end, or at the begining, and sometimes both! Also some characters like “(” or “/” appear sometimes in the titles, artists or album titles. I was trying to use your class to get all the id3 of 1000 mp3′s inside a folder while retrieving them to a sql database. Just by “echo”ing it all I came up with those small bugs.

      I’ve been using other scripts but none was able to read as much id3 as yours, without those small bugs it would render this script perfect for me.

      Could you help me out?

      John More

    • sam's Gravatar
    • Hi,

      Can it read Id3 info from link?
      Eg. http://www.djpreet.net/dj/songs/Hindi/Movie album/B/Breathing Under Water (hindi-Ost) ( Feb 2k8)/Breathing Under Water – 04 – Sea Dreamer.mp3

      ??

    • Shubham Sharma's Gravatar
    • Shubham SharmaDecember 2, 2011 7:00 am

      Thank u..

      yoyr script is working correctly.

      but i also want to fetch the thumbnail of that mp3 file..

      can u help me in this…?

    • Shubham Sharma's Gravatar
    • Shubham SharmaDecember 2, 2011 1:28 pm

      can u tell me how can i read all this information for an video file as well…?

    • kosta's Gravatar
    • Hey Admin,
      This is what I have been looking for. Though I need more. Namely, make url clickable, reading ID3 info from icecast stream. Do you have ideas or could you direct me to the right place? Thank you.

    • Chris's Gravatar
    • Hello! I don’t know if anyone is still around for this but I’ll try anyway. I am really liking this code. I want to use it to organize a batch of mp3s that have somehow gathered in my webspace. I have created a header page for the “jukebox” then kick off a loading screen in an iframe just to let folks know something is going on while they wait which then kicks of the code I downloaded here as “example128.” First thing I guess is the wait… does this code load the whole mp3 file or just the beginning of the file with the ID3 tag? The next “problem” I had was that it SEEMS to work best with ID3v2.3. I have been playing with this for a week or so now and as far as I can recall it was missing some output fields with ID3v2.4 (so I just converted all tags to ID3v2.3). It sometimes appends extra bytes at the front of fields sometimes (looks like the field character counter, truncating an equal number off of the end). The thing I can’t figure out at all is sometimes bytes are missing on both ends of a field. I would LOVE to make this thing work but am just now starting to learn how to write a little PHP code with no previous knowledge before looking at your tutorials. Any ideas or pointers? The website so far lives at http://clubbogart.com/CaptainJukebox/
      Thanks,
      Chris

    • Edu's Gravatar
    • Don's Gravatar
    • Nice tutorial and wonderful code.

      I have a small issue. I want to be really fliexible. Can this work with only one mp3 file. Maybe just specify the location and file name in a variable, and not the total contents in a directory? Thanks.

Leave a Reply to Shubham Sharma Cancel reply

Your email address will not be published. Required fields are marked *

*

CAPTCHA Image
Refresh Image

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>