Get ID3 Tags with PHP

July 7, 2011
All over the internet, there are different ways of extracting the ID3 Tags from MP3 files. Some are exotic OOP objects using several scripts, some are just plain functions, and some require the PECL extension.

Of course, if you're anything like me, you're not really interested in spending days upon days on something that you're probably not going to use that much.

So, I bring you the getID3() function (BETA)... Why Beta? Because it doesn't work exactly like I want it to, but it does pretty good.

Download Original
  1. function getID3($filename=NULL)
  2. {
  3. $FrameData = array('AENC'=>'Audio encryption', 'APIC'=>'Attached picture', 'COMM'=>'Comments', 'COMR'=>'Commercial frame', 'ENCR'=>'Encryption method registration', 'EQUA'=>'Equalization', 'ETCO'=>'Event timing codes', 'GEOB'=>'General encapsulated object', 'GRID'=>'Group identification registration', 'IPLS'=>'Involved people list', 'LINK'=>'Linked information', 'MCDI'=>'Music CD identifier', 'MLLT'=>'MPEG location lookup table', 'OWNE'=>'Ownership frame', 'PRIV'=>'Private frame', 'PCNT'=>'Play counter', 'POPM'=>'Popularimeter', 'POSS'=>'Position synchronisation frame', 'RBUF'=>'Recommended buffer size', 'RVAD'=>'Relative volume adjustment', 'RVRB'=>'Reverb', 'SYLT'=>'Synchronized lyric/text', 'SYTC'=>'Synchronized tempo codes', 'TALB'=>'Album/Movie/Show title', 'TBPM'=>'BPM (beats per minute)', 'TCOM'=>'Composer', 'TCON'=>'Content type', 'TCOP'=>'Copyright message', 'TDAT'=>'Date', 'TDLY'=>'Playlist delay', 'TENC'=>'Encoded by', 'TEXT'=>'Lyricist/Text writer', 'TFLT'=>'File type', 'TIME'=>'Time', 'TIT1'=>'Content group description', 'TIT2'=>'Title/songname/content description', 'TIT3'=>'Subtitle/Description refinement', 'TKEY'=>'Initial key', 'TLAN'=>'Language(s)', 'TLEN'=>'Length', 'TMED'=>'Media type', 'TOAL'=>'Original album/movie/show title', 'TOFN'=>'Original filename', 'TOLY'=>'Original lyricist(s)/text writer(s)', 'TOPE'=>'Original artist(s)/performer(s)', 'TORY'=>'Original release year', 'TOWN'=>'File owner/licensee', 'TPE1'=>'Lead performer(s)/Soloist(s)', 'TPE2'=>'Band/orchestra/accompaniment', 'TPE3'=>'Conductor/performer refinement', 'TPE4'=>'Interpreted, remixed, or otherwise modified by', 'TPOS'=>'Part of a set', 'TPUB'=>'Publisher', 'TRCK'=>'Track number/Position in set', 'TRDA'=>'Recording dates', 'TRSN'=>'Internet radio station name', 'TRSO'=>'Internet radio station owner', 'TSIZ'=>'Size', 'TSRC'=>'ISRC (international standard recording code)', 'TSSE'=>'Software/Hardware and settings used for encoding', 'TYER'=>'Year', 'TXXX'=>'User defined text information frame', 'UFID'=>'Unique file identifier', 'USER'=>'Terms of use', 'USLT'=>'Unsychronized lyric/text transcription', 'WCOM'=>'Commercial information', 'WCOP'=>'Copyright/Legal information', 'WOAF'=>'Official audio file webpage', 'WOAR'=>'Official artist/performer webpage', 'WOAS'=>'Official audio source webpage', 'WORS'=>'Official internet radio station homepage', 'WPAY'=>'Payment', 'WPUB'=>'Publishers official webpage', 'WXXX'=>'User defined URL link frame');
  4. $Genres = array(0 => 'Blues', 1 => 'Classic Rock', 2 => 'Country', 3 => 'Dance', 4 => 'Disco', 5 => 'Funk', 6 => 'Grunge', 7 => 'Hip-Hop', 8 => 'Jazz', 9 => 'Metal', 10 => 'New Age', 11 => 'Oldies', 12 => 'Other', 13 => 'Pop', 14 => 'R&B', 15 => 'Rap', 16 => 'Reggae', 17 => 'Rock', 18 => 'Techno', 19 => 'Industrial', 20 => 'Alternative', 21 => 'Ska', 22 => 'Death Metal', 23 => 'Pranks', 24 => 'Soundtrack', 25 => 'Euro-Techno', 26 => 'Ambient', 27 => 'Trip-Hop', 28 => 'Vocal', 29 => 'Jazz+Funk', 30 => 'Fusion', 31 => 'Trance', 32 => 'Classical', 33 => 'Instrumental', 34 => 'Acid', 35 => 'House', 36 => 'Game', 37 => 'Sound Clip', 38 => 'Gospel', 39 => 'Noise', 40 => 'Alternative Rock', 41 => 'Bass', 42 => 'Soul', 43 => 'Punk', 44 => 'Space', 45 => 'Meditative', 46 => 'Instrumental Pop', 47 => 'Instrumental Rock', 48 => 'Ethnic', 49 => 'Gothic', 50 => 'Darkwave', 51 => 'Techno-Industrial', 52 => 'Electronic', 53 => 'Pop-Folk', 54 => 'Eurodance', 55 => 'Dream', 56 => 'Southern Rock', 57 => 'Comedy', 58 => 'Cult', 59 => 'Gangsta', 60 => 'Top 40', 61 => 'Christian Rap', 62 => 'Pop/Funk', 63 => 'Jungle', 64 => 'Native US', 65 => 'Cabaret', 66 => 'New Wave', 67 => 'Psychadelic', 68 => 'Rave', 69 => 'Showtunes', 70 => 'Trailer', 71 => 'Lo-Fi', 72 => 'Tribal', 73 => 'Acid Punk', 74 => 'Acid Jazz', 75 => 'Polka', 76 => 'Retro', 77 => 'Musical', 78 => 'Rock & Roll', 79 => 'Hard Rock', 80 => 'Folk', 81 => 'Folk-Rock', 82 => 'National Folk', 83 => 'Swing', 84 => 'Fast Fusion', 85 => 'Bebob', 86 => 'Latin', 87 => 'Revival', 88 => 'Celtic', 89 => 'Bluegrass', 90 => 'Avantgarde', 91 => 'Gothic Rock', 92 => 'Progressive Rock', 93 => 'Psychedelic Rock', 94 => 'Symphonic Rock', 95 => 'Slow Rock', 96 => 'Big Band', 97 => 'Chorus', 98 => 'Easy Listening', 99 => 'Acoustic', 100 => 'Humour', 101 => 'Speech', 102 => 'Chanson', 103 => 'Opera', 104 => 'Chamber Music', 105 => 'Sonata', 106 => 'Symphony', 107 => 'Booty Bass', 108 => 'Primus', 109 => 'Porn Groove', 110 => 'Satire', 111 => 'Slow Jam', 112 => 'Club', 113 => 'Tango', 114 => 'Samba', 115 => 'Folklore', 116 => 'Ballad', 117 => 'Power Ballad', 118 => 'Rhytmic Soul', 119 => 'Freestyle', 120 => 'Duet', 121 => 'Punk Rock', 122 => 'Drum Solo', 123 => 'Acapella', 124 => 'Euro-House', 125 => 'Dance Hall', 126 => 'Goa', 127 => 'Drum & Bass', 128 => 'Club-House', 129 => 'Hardcore', 130 => 'Terror', 131 => 'Indie', 132 => 'BritPop', 133 => 'Negerpunk', 134 => 'Polsk Punk', 135 => 'Beat', 136 => 'Christian Gangsta', 137 => 'Heavy Metal', 138 => 'Black Metal', 139 => 'Crossover', 140 => 'Contemporary C', 141 => 'Christian Rock', 142 => 'Merengue', 143 => 'Salsa', 144 => 'Thrash Metal', 145 => 'Anime', 146 => 'JPop', 147 => 'SynthPop');
  5.  
  6. if (strtoupper($filename)=="GETFRAMES")
  7. RETURN $FrameData;
  8. if (strtoupper($filename)=="GETGENRES")
  9. RETURN $Genres;
  10.  
  11. if (!$ID3Header = file_get_contents($filename,NULL,NULL,0,5000))
  12. trigger_error("File not found in getID3",E_USER_ERROR);
  13.  
  14. $OutChar = $OutNum = $Explode = $ASCII = NULL;
  15. for ($i=0;$i<=strlen($ID3Header);$i++)
  16. {
  17. $ThisChar = substr($ID3Header,$i,1);
  18. if (ord($ThisChar)>31 && ord($ThisChar)<127)
  19. $ASCII .= $ThisChar;
  20. }
  21. //Detect the frame's start
  22. foreach($FrameData as $k => $v)
  23. {
  24. $FrameStart[$k] = stripos($ASCII,$k)+strlen($k);
  25. if ($FrameStart[$k]==4)
  26. unset($FrameStart[$k]);
  27. }
  28. //Detect conflicting frame to find end of frame
  29. foreach($FrameStart as $FSKey => $FSValue)
  30. {
  31. $ThisFrame = substr($ASCII,$FSValue,80);
  32. $LastCheck=80;
  33.  
  34. foreach($FrameData as $k => $v)
  35. {
  36. if (stripos($ThisFrame,$k)<=$LastCheck && stripos($ThisFrame,$k)>0)
  37. $LastCheck = stripos($ThisFrame,$k);
  38. }
  39. $FrameLength[$FSKey] = $LastCheck;
  40. }
  41. foreach($FrameStart as $k => $v)
  42. {
  43. $FrameOut[$FrameData[$k]] = trim(substr($ASCII,$v,$FrameLength[$k]));
  44. $FrameOut[$k] = trim(substr($ASCII,$v,$FrameLength[$k]));
  45. }
  46. RETURN $FrameOut;
  47. }


Get ID3 Tag Function Examples


Download Original
  1. <?PHP
  2.  
  3. echo "<pre>";
  4. //Example 1
  5. $ID3 = getID3("c:/ala.mp3");
  6. print_r($ID3);
  7.  
  8. //Example2
  9. $ID3 = getID3("getframes");
  10. print_r($ID3);
  11.  
  12. //Example 3
  13. $ID3 = getID3("getgenres");
  14. print_r($ID3);
  15.  
  16. ?>


In these examples, note the following:

Example 1 - Retrieving ID3 Tags from the MP3 file with PHP
This will return an array with the 4-character ID3 Tag identifiers that are present in the MP3, as well as the ID3 descriptions... See below for an example:

Array
(
    [Commercial frame] => on Rogers
    [COMR] => on Rogers
    [Private frame] => 'WM/MediaClassPrimaryID}`#KH*(D
    [PRIV] => 'WM/MediaClassPrimaryID}`#KH*(D
    [Popularimeter] => Windows Media Player 9 Series
    [POPM] => Windows Media Player 9 Series
    [Album/Movie/Show title] => Greatest Hits, Vol. 2
    [TALB] => Greatest Hits, Vol. 2
    [Composer] => Ron Rogers
    [TCOM] => Ron Rogers
    [Content type] => (2)
    [TCON] => (2)
    [Title/songname/content description] => Dixieland Delight
    [TIT2] => Dixieland Delight
    [Lead performer(s)/Soloist(s)] => Alabamalll
    [TPE1] => Alabamalll
    [Band/orchestra/accompaniment] => Alabama
    [TPE2] => Alabama
    [Publisher] => RCA
    [TPUB] => RCA
    [Track number/Position in set] => 3
    [TRCK] => 3
    [Year] => 1991
    [TYER] => 1991
)


Take the last two lines for example... "TYER" is the ID3 code for the MP3's year, whereas "Year" is the description. Both values are returned for ease of use.

Be cautious using the returned values... run any escaping or filtering you would on user-provided data on these, as the data returned is raw. You may get errorneous data from this function, as it is a BETA function. It's in the works on my free time.

Example 2 -- Getting the ID3 4-character codes and the ID3 descriptions in an array
This will return the entire frames array used to find the comparisons:

Array
(
    [AENC] => Audio encryption
    [APIC] => Attached picture
    [COMM] => Comments
    [COMR] => Commercial frame
    [ENCR] => Encryption method registration
    [EQUA] => Equalization
... ... ... ...


Example 3 -- Getting the genre integers and titles per the ID3 Specification
Alright, 0-79 are the standard, 80-125 are WinAmp, and the rest? I don't know where they came from... But you'll need this to use the CONTENT (TCON) returned value.

The Genre is provided as follows:
[TCON] = "(X)YYYYY^";

The (X) part contains the integer which you'd match up with this data, and the YYYYY^ part is used in certain versions to allow custom genres to be specified inside the ID3 tag, while outside the 147 already provided.

Array
(
    [0] => Blues
    [1] => Classic Rock
    [2] => Country
    [3] => Dance
    [4] => Disco
    [5] => Funk
... ... ... ...


Name:

No comments yet! Be the first!