Чтение ID3 тегов и другой информации из mp3 файлов средствами phpВсе ID3 теги (ID3 tag) хранятся в последних 128-ми байтах mp3 файла. Это означает, что их можно читать без специальных компонентов. Распределение информации следующее:
Для определения тегов достаточно отформатировать распаковку из бинарной строки в соответствии с выше приведенной последовательностью: 01 $f = fopen ( 'test.mp3' , 'rb' ); 02 rewind ( $f ); 03 fseek ( $f , -128, SEEK_END); 04 $tmp = fread ( $f ,128); 05 if ( $tmp [125] == Chr (0) and $tmp [126] != Chr (0)) { 06 // ID3 v1.1 07 $format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a28COMMENT/x1/C1TRACK/C1GENRENO' ; 08 } else { 09 // ID3 v1 10 $format = 'a3TAG/a30NAME/a30ARTISTS/a30ALBUM/a4YEAR/a30COMMENT/C1GENRENO' ; 11 } 12 13 $id3tag = unpack( $format , $tmp ); Результат работы скрипта: Иногда бывает необходимо кроме ID3 tag 'ов узнать и другую инфу об mp3 файле (частоту, bitrate, длительность и др.), я взял за основу библиотекуhttp://pear.php.net/package/MP3_ID и написал следующую функцию, которая позволяет это сделать. Я не буду ее комментировать, потому что здесь мало программирования, а в основном знание структуры mp3 файла, кто захочет - разберется. 001 function readframe( $file ) { 002 if (! ( $f = fopen ( $file , 'rb' )) ) die ( "Unable to open " . $file ); 003 $res [ 'filesize' ] = filesize ( $file ); 004 do { 005 while ( fread ( $f ,1) != Chr (255)) { // Find the first frame 006 if ( feof ( $f )) die ( "No mpeg frame found" ) ; 007 } 008 fseek ( $f , ftell ( $f ) - 1); // back up one byte 009 010 $frameoffset = ftell ( $f ); 011 012 $r = fread ( $f , 4); 013 014 $bits = sprintf( "%'08b%'08b%'08b%'08b" , ord( $r {0}), ord( $r {1}), ord( $r {2}), ord( $r {3})); 015 } 016 while (! $bits [8] and ! $bits [9] and ! $bits [10]); // 1st 8 bits true from the while 017 018 // Detect VBR header 019 if ( $bits [11] == 0) { 020 if (( $bits [24] == 1) && ( $bits [25] == 1)) { 021 $vbroffset = 9; // MPEG 2.5 Mono 022 } else { 023 $vbroffset = 17; // MPEG 2.5 Stereo 024 } 025 } else if ( $bits [12] == 0) { 026 if (( $bits [24] == 1) && ( $bits [25] == 1)) { 027 $vbroffset = 9; // MPEG 2 Mono 028 } else { 029 $vbroffset = 17; // MPEG 2 Stereo 030 } 031 } else { 032 if (( $bits [24] == 1) && ( $bits [25] == 1)) { 033 $vbroffset = 17; // MPEG 1 Mono 034 } else { 035 $vbroffset = 32; // MPEG 1 Stereo 036 } 037 } 038 039 fseek ( $f , ftell ( $f ) + $vbroffset ); 040 $r = fread ( $f , 4); 041 042 switch ( $r ) { 043 case 'Xing' : 044 $res [ 'encoding_type' ] = 'VBR' ; 045 case 'VBRI' : 046 default : 047 if ( $vbroffset != 32) { 048 // VBRI Header is fixed after 32 bytes, so maybe we are looking at the wrong place. 049 fseek ( $f , ftell ( $f ) + 32 - $vbroffset ); 050 $r = fread ( $f , 4); 051 052 if ( $r != 'VBRI' ) { 053 $res [ 'encoding_type' ] = 'CBR' ; 054 break ; 055 } 056 } else { 057 $res [ 'encoding_type' ] = 'CBR' ; 058 break ; 059 } 060 061 $res [ 'encoding_type' ] = 'VBR' ; 062 } 063 064 fclose( $f ); 065 066 if ( $bits [11] == 0) { 067 $res [ 'mpeg_ver' ] = "2.5" ; 068 $bitrates = array ( 069 '1' => array (0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0), 070 '2' => array (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), 071 '3' => array (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), 072 ); 073 } else if ( $bits [12] == 0) { 074 $res [ 'mpeg_ver' ] = "2" ; 075 $bitrates = array ( 076 '1' => array (0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0), 077 '2' => array (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), 078 '3' => array (0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0), 079 ); 080 } else { 081 $res [ 'mpeg_ver' ] = "1" ; 082 $bitrates = array ( 083 '1' => array (0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0), 084 '2' => array (0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0), 085 '3' => array (0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0), 086 ); 087 } 088 089 $layer = array ( 090 array (0,3), 091 array (2,1), 092 ); 093 $res [ 'layer' ] = $layer [ $bits [13]][ $bits [14]]; 094 095 if ( $bits [15] == 0) { 096 // It's backwards, if the bit is not set then it is protected. 097 $res [ 'crc' ] = true; 098 } 099 100 $bitrate = 0; 101 if ( $bits [16] == 1) $bitrate += 8; 102 if ( $bits [17] == 1) $bitrate += 4; 103 if ( $bits [18] == 1) $bitrate += 2; 104 if ( $bits [19] == 1) $bitrate += 1; 105 $res [ 'bitrate' ] = $bitrates [ $res [ 'layer' ]][ $bitrate ]; 106 107 $frequency = array ( 108 '1' => array ( 109 '0' => array (44100, 48000), 110 '1' => array (32000, 0), 111 ), 112 '2' => array ( 113 '0' => array (22050, 24000), 114 '1' => array (16000, 0), 115 ), 116 '2.5' => array ( 117 '0' => array (11025, 12000), 118 '1' => array (8000, 0), 119 ), 120 ); 121 $res [ 'frequency' ] = $frequency [ $res [ 'mpeg_ver' ]][ $bits [20]][ $bits [21]]; 122 123 $mode = array ( 124 array ( 'Stereo' , 'Joint Stereo' ), 125 array ( 'Dual Channel' , 'Mono' ), 126 ); 127 $res [ 'mode' ] = $mode [ $bits [24]][ $bits [25]]; 128 129 $samplesperframe = array ( 130 '1' => array ( 131 '1' => 384, 132 '2' => 1152, 133 '3' => 1152 134 ), 135 '2' => array ( 136 '1' => 384, 137 '2' => 1152, 138 '3' => 576 139 ), 140 '2.5' => array ( 141 '1' => 384, 142 '2' => 1152, 143 '3' => 576 144 ), 145 ); 146 $res [ 'samples_per_frame' ] = $samplesperframe [ $res [ 'mpeg_ver' ]][ $res [ 'layer' ]]; 147 148 if ( $res [ 'encoding_type' ] != 'VBR' ) { 149 if ( $res [ 'bitrate' ] == 0) { 150 $s = -1; 151 } else { 152 $s = ((8* filesize ( $file ))/1000) / $res [ 'bitrate' ]; 153 } 154 $res [ 'length' ] = sprintf( '%02d:%02d' , floor ( $s /60), floor ( $s -( floor ( $s /60)*60))); 155 $res [ 'lengthh' ] = sprintf( '%02d:%02d:%02d' , floor ( $s /3600), floor ( $s /60), floor ( $s -( floor ( $s /60)*60))); 156 $res [ 'lengths' ] = (int) $s ; 157 158 $res [ 'samples' ] = ceil ( $res [ 'lengths' ] * $res [ 'frequency' ]); 159 if (0 != $res [ 'samples_per_frame' ]) { 160 $res [ 'frames' ] = ceil ( $res [ 'samples' ] / $res [ 'samples_per_frame' ]); 161 } else { 162 $res [ 'frames' ] = 0; 163 } 164 $res [ 'musicsize' ] = ceil ( $res [ 'lengths' ] * $res [ 'bitrate' ] * 1000 / 8); 165 } else { 166 $res [ 'samples' ] = $res [ 'samples_per_frame' ] * $res [ 'frames' ]; 167 $s = $res [ 'samples' ] / $res [ 'frequency' ]; 168 169 $res [ 'length' ] = sprintf( '%02d:%02d' , floor ( $s /60), floor ( $s -( floor ( $s /60)*60))); 170 $res [ 'lengthh' ] = sprintf( '%02d:%02d:%02d' , floor ( $s /3600), floor ( $s /60), floor ( $s -( floor ( $s /60)*60))); 171 $res [ 'lengths' ] = (int) $s ; 172 173 $res [ 'bitrate' ] = (int)(( $res [ 'musicsize' ] / $s ) * 8 / 1000); 174 } 175 176 return $res ; 177 } Результат работы скрипта:
|