├── @ ├── assets │ ├── css │ │ ├── bootstrap.min.css │ │ ├── main.css │ │ └── material-kit.css │ └── js │ │ ├── bootstrap-datetimepicker.js │ │ ├── bootstrap-selectpicker.js │ │ ├── bootstrap-tagsinput.js │ │ ├── bootstrap.min.js │ │ ├── jasny-bootstrap.min.js │ │ ├── jquery.flexisel.js │ │ ├── jquery.min.js │ │ ├── material-kit.js │ │ ├── material.min.js │ │ ├── moment.min.js │ │ └── nouislider.min.js ├── dj.php └── php-getid3 │ ├── README.md │ ├── changelog.txt │ ├── dependencies.txt │ ├── getid3 │ ├── extension.cache.dbm.php │ ├── extension.cache.mysql.php │ ├── extension.cache.mysqli.php │ ├── extension.cache.sqlite3.php │ ├── getid3.lib.php │ ├── getid3.php │ ├── module.archive.gzip.php │ ├── module.archive.hpk.php │ ├── module.archive.rar.php │ ├── module.archive.szip.php │ ├── module.archive.tar.php │ ├── module.archive.xz.php │ ├── module.archive.zip.php │ ├── module.audio-video.asf.php │ ├── module.audio-video.bink.php │ ├── module.audio-video.flv.php │ ├── module.audio-video.ivf.php │ ├── module.audio-video.matroska.php │ ├── module.audio-video.mpeg.php │ ├── module.audio-video.nsv.php │ ├── module.audio-video.quicktime.php │ ├── module.audio-video.real.php │ ├── module.audio-video.riff.php │ ├── module.audio-video.swf.php │ ├── module.audio-video.ts.php │ ├── module.audio-video.wtv.php │ ├── module.audio.aa.php │ ├── module.audio.aac.php │ ├── module.audio.ac3.php │ ├── module.audio.amr.php │ ├── module.audio.au.php │ ├── module.audio.avr.php │ ├── module.audio.bonk.php │ ├── module.audio.dsf.php │ ├── module.audio.dss.php │ ├── module.audio.dts.php │ ├── module.audio.flac.php │ ├── module.audio.la.php │ ├── module.audio.lpac.php │ ├── module.audio.midi.php │ ├── module.audio.mod.php │ ├── module.audio.monkey.php │ ├── module.audio.mp3.php │ ├── module.audio.mpc.php │ ├── module.audio.ogg.php │ ├── module.audio.optimfrog.php │ ├── module.audio.rkau.php │ ├── module.audio.shorten.php │ ├── module.audio.tak.php │ ├── module.audio.tta.php │ ├── module.audio.voc.php │ ├── module.audio.vqf.php │ ├── module.audio.wavpack.php │ ├── module.graphic.bmp.php │ ├── module.graphic.efax.php │ ├── module.graphic.gif.php │ ├── module.graphic.jpg.php │ ├── module.graphic.pcd.php │ ├── module.graphic.png.php │ ├── module.graphic.svg.php │ ├── module.graphic.tiff.php │ ├── module.misc.cue.php │ ├── module.misc.exe.php │ ├── module.misc.iso.php │ ├── module.misc.msoffice.php │ ├── module.misc.par2.php │ ├── module.misc.pdf.php │ ├── module.tag.apetag.php │ ├── module.tag.id3v1.php │ ├── module.tag.id3v2.php │ ├── module.tag.lyrics3.php │ ├── module.tag.xmp.php │ ├── write.apetag.php │ ├── write.id3v1.php │ ├── write.id3v2.php │ ├── write.lyrics3.php │ ├── write.metaflac.php │ ├── write.php │ ├── write.real.php │ └── write.vorbiscomment.php │ ├── license.txt │ ├── licenses │ ├── license.commercial.txt │ ├── license.gpl-10.txt │ ├── license.gpl-20.txt │ ├── license.gpl-30.txt │ ├── license.lgpl-30.txt │ └── license.mpl-20.txt │ ├── readme.txt │ └── structure.txt ├── CHANGELOG.md ├── LICENSE ├── _config.yml ├── index.php ├── media └── .not_delete_ThisFolder ├── readme.md └── up ├── index.php └── tmp └── .not_delete_ThisFolder /@/assets/css/main.css: -------------------------------------------------------------------------------- 1 | .fixed_player { 2 | z-index: 3; 3 | position: fixed; 4 | bottom: 0; 5 | left: 0; 6 | right: 0; 7 | height: auto; 8 | padding-top: 10px; 9 | padding-bottom: 20px; 10 | background-color: rgb(19,19,19); 11 | } 12 | .track_title{ 13 | color: black; 14 | } 15 | .active { 16 | cursor: default; 17 | } 18 | .track { 19 | cursor: pointer; 20 | } 21 | 22 | .track.active { 23 | cursor: default; 24 | } 25 | 26 | .plyr--audio .plyr__controls { 27 | background-color:transparent; 28 | border:none; 29 | color:#fff; 30 | padding:20px 0px 20px 0px; 31 | width:100%; 32 | } 33 | 34 | a.plyr__controls__item.plyr__control:hover, 35 | .plyr--audio .plyr__controls button:hover, 36 | .plyr--audio .plyr__controls button.tab-focus:focus, 37 | .plyr__play-large { 38 | background-color:rgba(0,0,0,.1); 39 | } 40 | 41 | .plyr__progress--played, 42 | .plyr__volume--display { 43 | color:rgba(0,0,0,.1); 44 | } 45 | 46 | .plyr--audio .plyr__progress--buffer, 47 | .plyr--audio .plyr__volume--display { 48 | background:rgba(0,0,0,.1); 49 | } 50 | 51 | .plyr--audio .plyr__progress--buffer { 52 | color:rgba(0,0,0,.1); 53 | } 54 | 55 | .plLength { 56 | padding-top: 12px; 57 | padding-left:21px; 58 | position:absolute; 59 | right:21px; 60 | } -------------------------------------------------------------------------------- /@/dj.php: -------------------------------------------------------------------------------- 1 | user_credentials_file)){ 33 | die("NOT PERMITTED!"); 34 | }else{ 35 | $hashed_password = password_hash($password, PASSWORD_DEFAULT); 36 | $udata = fopen($this->user_credentials_file, "w") or die("Unable to write file!
Check permission"); 37 | fwrite($udata, ""); 38 | fclose($udata); 39 | $is_new = 1; 40 | } 41 | } 42 | public function login($username, $password){ 43 | global $_SESSION; 44 | include($this->user_credentials_file); 45 | if(htmlspecialchars($username) == $real_username && password_verify($password, $real_password)){ 46 | $_SESSION['logged'] = true; 47 | return true; 48 | }else{ 49 | return false; 50 | } 51 | } 52 | } 53 | $access = new ACCESS(); 54 | 55 | class getAudio{ 56 | public $getid3_folder = "../@/php-getid3/"; 57 | public function info($file){ 58 | if(!include($this->getid3_folder.'getid3/getid3.php')){ 59 | return die("Error Basic library not included [lib: getid3]"); 60 | } 61 | // Initialize getID3 engine 62 | $getID3 = new getID3; 63 | // Analyze file 64 | $FileInfo = $getID3->analyze($file); 65 | return array( 66 | "title" => $FileInfo['tags']['id3v2']['title'][0], 67 | "duration" => $FileInfo['playtime_string'], 68 | "ext" => $FileInfo['fileformat'], 69 | "file_name" => $FileInfo['filename'], 70 | "file_path" => $FileInfo['filepath'], 71 | "file_size" => $FileInfo['filesize'], 72 | "mime" => $FileInfo['mime_type'], 73 | "artist" => $getID3->analyze($file)['id3v1']['artist'] 74 | ); 75 | 76 | } 77 | } 78 | 79 | class GR3Manager{ 80 | public $media_dir = "../media/"; 81 | public $tmp_folder = "../up/tmp/"; 82 | public $playlist_file = "../up/playlist.gr3"; 83 | public $allow_duplicate = true; 84 | public $up_exts = array(".mp3", ".ogg", ".m4a", ".webm"); 85 | public $max_audio_size = 39097152; 86 | 87 | public function playlistToArray($playlist){ 88 | if(empty($playlist)){ 89 | $playlist = $this->playlist_file; 90 | } 91 | $array = json_decode(file_get_contents($playlist), true); 92 | if(is_null($array) or empty($array)){ 93 | return array(); 94 | }else{ 95 | return $array; 96 | } 97 | } 98 | public function arrayToPlaylist($array){ 99 | return json_encode(array_values($array)); 100 | } 101 | public function rewritePlaylist($data){ 102 | $f=fopen($this->playlist_file,'w'); 103 | fwrite($f,$data); 104 | fclose($f); 105 | return true; 106 | } 107 | public function add_in_playlist($track_num, $track_name, $track_duration, $file_name, $ext, $mime, $artist){ 108 | $asx = $this->playlistToArray(""); 109 | array_unshift($asx , array("track"=>$track_num,"name"=>$track_name,"duration"=>$track_duration,"file"=>$file_name,"ext"=>$ext,"mime"=>$mime,"artist"=>$artist)); 110 | $this->rewritePlaylist($this->arrayToPlaylist($asx)); 111 | return true; 112 | } 113 | public function clearTMP(){ 114 | $dirPath = ($this->tmp_folder); 115 | if (! is_dir($dirPath)) { 116 | throw new InvalidArgumentException("$dirPath must be a directory"); 117 | } 118 | if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') { 119 | $dirPath .= '/'; 120 | } 121 | $files = glob($dirPath . '*', GLOB_MARK); 122 | foreach ($files as $file) { 123 | if (is_dir($file)) { 124 | self::deleteDir($file); 125 | } else { 126 | unlink($file); 127 | } 128 | } 129 | return true; 130 | } 131 | public function genName($ext = ""){ // numTracks 132 | $time = time(); 133 | return array("oci-".$time.".".$ext, "oci-".$time); 134 | } 135 | public function totalTracks(){ 136 | $files = glob($this->media_dir . "*"); 137 | if ($files){ 138 | return $this->playlistToArray("")[0]['track']; 139 | }else{ 140 | return 0; 141 | } 142 | } 143 | public function uploadTrack_1(){ 144 | global $_FILES, $up_2; 145 | $this->clearTMP(); // clear tmp folder 146 | $file_name = $_FILES['audio']['name']; 147 | $file_size = $_FILES['audio']['size']; 148 | $file_tmp = $_FILES['audio']['tmp_name']; 149 | $file_ext = strtolower(end(explode('.',$file_name))); 150 | if(in_array(".".$file_ext,$this->up_exts)=== false){ 151 | return array(false, "Extension not allowed."); 152 | exit(); 153 | } 154 | if($file_size > $this->max_audio_size) { 155 | return array(false, "File size error"); 156 | exit(); 157 | } 158 | $new_name = $this->genName($file_ext); 159 | move_uploaded_file($file_tmp,$this->tmp_folder.$new_name[0]); 160 | $up_2 = true; 161 | $getAudio = new getAudio; 162 | $audio_info = $getAudio->info($this->tmp_folder.$new_name[0]); 163 | $track_name = $audio_info['title']; 164 | $track_duration = $audio_info['duration']; 165 | if(empty($track_name)){ $track_name = basename($file_name, ".".$file_ext); } 166 | if($track_name == "mp4"){ $track_name = "m4a"; } 167 | $track_mime = $audio_info['mime']; 168 | $track_artist =$audio_info['artist']; 169 | return array(true, array($this->tmp_folder.$new_name[0], $track_name, $file_ext, htmlspecialchars($track_duration), base64_encode($new_name[1]), $track_mime, $track_artist)); 170 | } 171 | public function uploadTrack_2(){ 172 | global $_POST, $up_2; 173 | $up_2 = false; 174 | 175 | $track_num = $this->totalTracks() + 1; 176 | if(empty($_POST['name'])){ 177 | $track_name = "Track ".$track_num; 178 | }else{ 179 | $track_name = htmlspecialchars($_POST['name']); 180 | } 181 | $track_artist = htmlspecialchars($_POST['track_artist']); 182 | if(is_null($track_artist) or empty($track_artist) or $track_artist == "" or $track_artist == "1" or $track_artist == 1 or $track_artist == "true"){ 183 | $track_artist = "Unknown Artist"; 184 | } 185 | $track_duration = htmlspecialchars_decode($_POST['duration']); 186 | $track_file = base64_decode($_POST['track_id_info']); 187 | $track_mime = base64_decode($_POST['track_mime']); 188 | // update playlist 189 | $this->add_in_playlist($track_num, $track_name, $track_duration, $track_file, htmlspecialchars($_POST['ext']), $track_mime, $track_artist); 190 | // moving file from tmp folder to media folder 191 | $name = scandir($this->tmp_folder, 1)[0]; 192 | rename($this->tmp_folder.$name, $this->media_dir.$name); 193 | 194 | $this->clearTMP(); // clear tmp folder 195 | return array(true, $track_name); 196 | } 197 | public function removeTrack($track_id){ 198 | $tracks = $this->playlistToArray(""); 199 | $index = 0; 200 | foreach ($tracks as $track) { 201 | if($track['track'] == $track_id){ 202 | $name_saved = $track['name']; 203 | $file_saved = $track['file']; 204 | unlink($this->media_dir.$file_saved.".".$track['ext']); 205 | unset($tracks[$index]); 206 | break; 207 | } 208 | $index++; 209 | } 210 | $this->rewritePlaylist($this->arrayToPlaylist($tracks)); 211 | return array(true, $name_saved); 212 | } 213 | public function check_duplicate($file){ 214 | $tracks = $this->playlistToArray(""); 215 | if(!is_null($tracks) or $tracks != ""){ 216 | foreach($tracks as $track){ 217 | if(md5_file($file) == md5_file($this->media_dir.$track['file'].".".$track['ext'])){ 218 | return array(true, $track['name']); 219 | } 220 | } 221 | } 222 | return array(false, false); 223 | } 224 | } 225 | $gr3manager = new GR3Manager(); 226 | ?> 227 | -------------------------------------------------------------------------------- /@/php-getid3/dependencies.txt: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////// 2 | /// getID3() by James Heinrich // 3 | // available at http://getid3.sourceforge.net // 4 | // or https://www.getid3.org // 5 | // also https://github.com/JamesHeinrich/getID3 // 6 | ///////////////////////////////////////////////////////////////// 7 | // // 8 | // dependencies.txt - part of getID3() // 9 | // See readme.txt for more details // 10 | // /// 11 | ///////////////////////////////////////////////////////////////// 12 | 13 | lyrics3 depends on apetag (optional) 14 | ogg depends on flac 15 | id3v2 depends on id3v1 16 | apetag depends on id3v1 (optional, writing only) 17 | bonk depends on id3v2 (optional) 18 | riff depends on mp3 19 | mpeg depends on mp3 20 | quicktime depends on mp3 21 | flac depends on ogg 22 | optimfrog depends on riff 23 | la depends on riff 24 | lpac depends on riff 25 | asf depends on riff, id3v1 (optional) 26 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/extension.cache.dbm.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // // 9 | // extension.cache.dbm.php - part of getID3() // 10 | // Please see readme.txt for more information // 11 | // /// 12 | ///////////////////////////////////////////////////////////////// 13 | // // 14 | // This extension written by Allan Hansen // 15 | // /// 16 | ///////////////////////////////////////////////////////////////// 17 | 18 | 19 | /** 20 | * This is a caching extension for getID3(). It works the exact same 21 | * way as the getID3 class, but return cached information very fast 22 | * 23 | * Example: 24 | * 25 | * Normal getID3 usage (example): 26 | * 27 | * require_once 'getid3/getid3.php'; 28 | * $getID3 = new getID3; 29 | * $getID3->encoding = 'UTF-8'; 30 | * $info1 = $getID3->analyze('file1.flac'); 31 | * $info2 = $getID3->analyze('file2.wv'); 32 | * 33 | * getID3_cached usage: 34 | * 35 | * require_once 'getid3/getid3.php'; 36 | * require_once 'getid3/getid3/extension.cache.dbm.php'; 37 | * $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm', 38 | * '/tmp/getid3_cache.lock'); 39 | * $getID3->encoding = 'UTF-8'; 40 | * $info1 = $getID3->analyze('file1.flac'); 41 | * $info2 = $getID3->analyze('file2.wv'); 42 | * 43 | * 44 | * Supported Cache Types 45 | * 46 | * SQL Databases: (use extension.cache.mysql) 47 | * 48 | * cache_type cache_options 49 | * ------------------------------------------------------------------- 50 | * mysql host, database, username, password 51 | * 52 | * 53 | * DBM-Style Databases: (this extension) 54 | * 55 | * cache_type cache_options 56 | * ------------------------------------------------------------------- 57 | * gdbm dbm_filename, lock_filename 58 | * ndbm dbm_filename, lock_filename 59 | * db2 dbm_filename, lock_filename 60 | * db3 dbm_filename, lock_filename 61 | * db4 dbm_filename, lock_filename (PHP5 required) 62 | * 63 | * PHP must have write access to both dbm_filename and lock_filename. 64 | * 65 | * 66 | * Recommended Cache Types 67 | * 68 | * Infrequent updates, many reads any DBM 69 | * Frequent updates mysql 70 | */ 71 | 72 | 73 | class getID3_cached_dbm extends getID3 74 | { 75 | /** 76 | * @var resource 77 | */ 78 | private $dba; 79 | 80 | /** 81 | * @var resource|bool 82 | */ 83 | private $lock; 84 | 85 | /** 86 | * @var string 87 | */ 88 | private $cache_type; 89 | 90 | /** 91 | * @var string 92 | */ 93 | private $dbm_filename; 94 | 95 | /** 96 | * constructor - see top of this file for cache type and cache_options 97 | * 98 | * @param string $cache_type 99 | * @param string $dbm_filename 100 | * @param string $lock_filename 101 | * 102 | * @throws Exception 103 | * @throws getid3_exception 104 | */ 105 | public function __construct($cache_type, $dbm_filename, $lock_filename) { 106 | 107 | // Check for dba extension 108 | if (!extension_loaded('dba')) { 109 | throw new Exception('PHP is not compiled with dba support, required to use DBM style cache.'); 110 | } 111 | 112 | // Check for specific dba driver 113 | if (!function_exists('dba_handlers') || !in_array($cache_type, dba_handlers())) { 114 | throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.'); 115 | } 116 | 117 | // Create lock file if needed 118 | if (!file_exists($lock_filename)) { 119 | if (!touch($lock_filename)) { 120 | throw new Exception('failed to create lock file: '.$lock_filename); 121 | } 122 | } 123 | 124 | // Open lock file for writing 125 | if (!is_writeable($lock_filename)) { 126 | throw new Exception('lock file: '.$lock_filename.' is not writable'); 127 | } 128 | $this->lock = fopen($lock_filename, 'w'); 129 | 130 | // Acquire exclusive write lock to lock file 131 | flock($this->lock, LOCK_EX); 132 | 133 | // Create dbm-file if needed 134 | if (!file_exists($dbm_filename)) { 135 | if (!touch($dbm_filename)) { 136 | throw new Exception('failed to create dbm file: '.$dbm_filename); 137 | } 138 | } 139 | 140 | // Try to open dbm file for writing 141 | $this->dba = dba_open($dbm_filename, 'w', $cache_type); 142 | if (!$this->dba) { 143 | 144 | // Failed - create new dbm file 145 | $this->dba = dba_open($dbm_filename, 'n', $cache_type); 146 | 147 | if (!$this->dba) { 148 | throw new Exception('failed to create dbm file: '.$dbm_filename); 149 | } 150 | 151 | // Insert getID3 version number 152 | dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); 153 | } 154 | 155 | // Init misc values 156 | $this->cache_type = $cache_type; 157 | $this->dbm_filename = $dbm_filename; 158 | 159 | // Register destructor 160 | register_shutdown_function(array($this, '__destruct')); 161 | 162 | // Check version number and clear cache if changed 163 | if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) { 164 | $this->clear_cache(); 165 | } 166 | 167 | parent::__construct(); 168 | } 169 | 170 | 171 | 172 | /** 173 | * destructor 174 | */ 175 | public function __destruct() { 176 | 177 | // Close dbm file 178 | dba_close($this->dba); 179 | 180 | // Release exclusive lock 181 | flock($this->lock, LOCK_UN); 182 | 183 | // Close lock file 184 | fclose($this->lock); 185 | } 186 | 187 | 188 | 189 | /** 190 | * clear cache 191 | * 192 | * @throws Exception 193 | */ 194 | public function clear_cache() { 195 | 196 | // Close dbm file 197 | dba_close($this->dba); 198 | 199 | // Create new dbm file 200 | $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type); 201 | 202 | if (!$this->dba) { 203 | throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename); 204 | } 205 | 206 | // Insert getID3 version number 207 | dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); 208 | 209 | // Re-register shutdown function 210 | register_shutdown_function(array($this, '__destruct')); 211 | } 212 | 213 | 214 | 215 | /** 216 | * clear cache 217 | * 218 | * @param string $filename 219 | * @param int $filesize 220 | * @param string $original_filename 221 | * @param resource $fp 222 | * 223 | * @return mixed 224 | */ 225 | public function analyze($filename, $filesize=null, $original_filename='', $fp=null) { 226 | 227 | if (file_exists($filename)) { 228 | 229 | // Calc key filename::mod_time::size - should be unique 230 | $key = $filename.'::'.filemtime($filename).'::'.filesize($filename); 231 | 232 | // Loopup key 233 | $result = dba_fetch($key, $this->dba); 234 | 235 | // Hit 236 | if ($result !== false) { 237 | return unserialize($result); 238 | } 239 | } 240 | 241 | // Miss 242 | $result = parent::analyze($filename, $filesize, $original_filename, $fp); 243 | 244 | // Save result 245 | if (isset($key) && file_exists($filename)) { 246 | dba_insert($key, serialize($result), $this->dba); 247 | } 248 | 249 | return $result; 250 | } 251 | 252 | } 253 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/extension.cache.mysql.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // // 9 | // extension.cache.mysql.php - part of getID3() // 10 | // Please see readme.txt for more information // 11 | // /// 12 | ///////////////////////////////////////////////////////////////// 13 | // // 14 | // This extension written by Allan Hansen // 15 | // Table name mod by Carlo Capocasa // 16 | // /// 17 | ///////////////////////////////////////////////////////////////// 18 | 19 | 20 | /** 21 | * This is a caching extension for getID3(). It works the exact same 22 | * way as the getID3 class, but return cached information very fast 23 | * 24 | * Example: (see also demo.cache.mysql.php in /demo/) 25 | * 26 | * Normal getID3 usage (example): 27 | * 28 | * require_once 'getid3/getid3.php'; 29 | * $getID3 = new getID3; 30 | * $getID3->encoding = 'UTF-8'; 31 | * $info1 = $getID3->analyze('file1.flac'); 32 | * $info2 = $getID3->analyze('file2.wv'); 33 | * 34 | * getID3_cached usage: 35 | * 36 | * require_once 'getid3/getid3.php'; 37 | * require_once 'getid3/getid3/extension.cache.mysql.php'; 38 | * // 5th parameter (tablename) is optional, default is 'getid3_cache' 39 | * $getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password', 'tablename'); 40 | * $getID3->encoding = 'UTF-8'; 41 | * $info1 = $getID3->analyze('file1.flac'); 42 | * $info2 = $getID3->analyze('file2.wv'); 43 | * 44 | * 45 | * Supported Cache Types (this extension) 46 | * 47 | * SQL Databases: 48 | * 49 | * cache_type cache_options 50 | * ------------------------------------------------------------------- 51 | * mysql host, database, username, password 52 | * 53 | * 54 | * DBM-Style Databases: (use extension.cache.dbm) 55 | * 56 | * cache_type cache_options 57 | * ------------------------------------------------------------------- 58 | * gdbm dbm_filename, lock_filename 59 | * ndbm dbm_filename, lock_filename 60 | * db2 dbm_filename, lock_filename 61 | * db3 dbm_filename, lock_filename 62 | * db4 dbm_filename, lock_filename (PHP5 required) 63 | * 64 | * PHP must have write access to both dbm_filename and lock_filename. 65 | * 66 | * 67 | * Recommended Cache Types 68 | * 69 | * Infrequent updates, many reads any DBM 70 | * Frequent updates mysql 71 | */ 72 | 73 | 74 | class getID3_cached_mysql extends getID3 75 | { 76 | /** 77 | * @var resource 78 | */ 79 | private $cursor; 80 | 81 | /** 82 | * @var resource 83 | */ 84 | private $connection; 85 | 86 | /** 87 | * @var string 88 | */ 89 | private $table; 90 | 91 | 92 | /** 93 | * constructor - see top of this file for cache type and cache_options 94 | * 95 | * @param string $host 96 | * @param string $database 97 | * @param string $username 98 | * @param string $password 99 | * @param string $table 100 | * 101 | * @throws Exception 102 | * @throws getid3_exception 103 | */ 104 | public function __construct($host, $database, $username, $password, $table='getid3_cache') { 105 | 106 | // Check for mysql support 107 | if (!function_exists('mysql_pconnect')) { 108 | throw new Exception('PHP not compiled with mysql support.'); 109 | } 110 | 111 | // Connect to database 112 | $this->connection = mysql_pconnect($host, $username, $password); 113 | if (!$this->connection) { 114 | throw new Exception('mysql_pconnect() failed - check permissions and spelling.'); 115 | } 116 | 117 | // Select database 118 | if (!mysql_select_db($database, $this->connection)) { 119 | throw new Exception('Cannot use database '.$database); 120 | } 121 | 122 | // Set table 123 | $this->table = $table; 124 | 125 | // Create cache table if not exists 126 | $this->create_table(); 127 | 128 | // Check version number and clear cache if changed 129 | $version = ''; 130 | $SQLquery = 'SELECT `value`'; 131 | $SQLquery .= ' FROM `'.mysql_real_escape_string($this->table).'`'; 132 | $SQLquery .= ' WHERE (`filename` = \''.mysql_real_escape_string(getID3::VERSION).'\')'; 133 | $SQLquery .= ' AND (`filesize` = -1)'; 134 | $SQLquery .= ' AND (`filetime` = -1)'; 135 | $SQLquery .= ' AND (`analyzetime` = -1)'; 136 | if ($this->cursor = mysql_query($SQLquery, $this->connection)) { 137 | list($version) = mysql_fetch_array($this->cursor); 138 | } 139 | if ($version != getID3::VERSION) { 140 | $this->clear_cache(); 141 | } 142 | 143 | parent::__construct(); 144 | } 145 | 146 | 147 | 148 | /** 149 | * clear cache 150 | */ 151 | public function clear_cache() { 152 | 153 | $this->cursor = mysql_query('DELETE FROM `'.mysql_real_escape_string($this->table).'`', $this->connection); 154 | $this->cursor = mysql_query('INSERT INTO `'.mysql_real_escape_string($this->table).'` VALUES (\''.getID3::VERSION.'\', -1, -1, -1, \''.getID3::VERSION.'\')', $this->connection); 155 | } 156 | 157 | 158 | 159 | /** 160 | * analyze file 161 | * 162 | * @param string $filename 163 | * @param int $filesize 164 | * @param string $original_filename 165 | * @param resource $fp 166 | * 167 | * @return mixed 168 | */ 169 | public function analyze($filename, $filesize=null, $original_filename='', $fp=null) { 170 | 171 | $filetime = 0; 172 | if (file_exists($filename)) { 173 | 174 | // Short-hands 175 | $filetime = filemtime($filename); 176 | $filesize = filesize($filename); 177 | 178 | // Lookup file 179 | $SQLquery = 'SELECT `value`'; 180 | $SQLquery .= ' FROM `'.mysql_real_escape_string($this->table).'`'; 181 | $SQLquery .= ' WHERE (`filename` = \''.mysql_real_escape_string($filename).'\')'; 182 | $SQLquery .= ' AND (`filesize` = \''.mysql_real_escape_string($filesize).'\')'; 183 | $SQLquery .= ' AND (`filetime` = \''.mysql_real_escape_string($filetime).'\')'; 184 | $this->cursor = mysql_query($SQLquery, $this->connection); 185 | if (mysql_num_rows($this->cursor) > 0) { 186 | // Hit 187 | list($result) = mysql_fetch_array($this->cursor); 188 | return unserialize(base64_decode($result)); 189 | } 190 | } 191 | 192 | // Miss 193 | $analysis = parent::analyze($filename, $filesize, $original_filename, $fp); 194 | 195 | // Save result 196 | if (file_exists($filename)) { 197 | $SQLquery = 'INSERT INTO `'.mysql_real_escape_string($this->table).'` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('; 198 | $SQLquery .= '\''.mysql_real_escape_string($filename).'\''; 199 | $SQLquery .= ', \''.mysql_real_escape_string($filesize).'\''; 200 | $SQLquery .= ', \''.mysql_real_escape_string($filetime).'\''; 201 | $SQLquery .= ', \''.mysql_real_escape_string(time() ).'\''; 202 | $SQLquery .= ', \''.mysql_real_escape_string(base64_encode(serialize($analysis))).'\')'; 203 | $this->cursor = mysql_query($SQLquery, $this->connection); 204 | } 205 | return $analysis; 206 | } 207 | 208 | 209 | 210 | /** 211 | * (re)create sql table 212 | * 213 | * @param bool $drop 214 | */ 215 | private function create_table($drop=false) { 216 | 217 | $SQLquery = 'CREATE TABLE IF NOT EXISTS `'.mysql_real_escape_string($this->table).'` ('; 218 | $SQLquery .= '`filename` VARCHAR(990) NOT NULL DEFAULT \'\''; 219 | $SQLquery .= ', `filesize` INT(11) NOT NULL DEFAULT \'0\''; 220 | $SQLquery .= ', `filetime` INT(11) NOT NULL DEFAULT \'0\''; 221 | $SQLquery .= ', `analyzetime` INT(11) NOT NULL DEFAULT \'0\''; 222 | $SQLquery .= ', `value` LONGTEXT NOT NULL'; 223 | $SQLquery .= ', PRIMARY KEY (`filename`, `filesize`, `filetime`))'; 224 | $this->cursor = mysql_query($SQLquery, $this->connection); 225 | echo mysql_error($this->connection); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.archive.hpk.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.archive.hpk.php // 12 | // module for analyzing HPK files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_hpk extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $info['fileformat'] = 'hpk'; 30 | 31 | $this->fseek($info['avdataoffset']); 32 | $HPKheader = $this->fread(36); 33 | 34 | if (substr($HPKheader, 0, 4) == 'BPUL') { 35 | 36 | $info['hpk']['header']['signature'] = substr($HPKheader, 0, 4); 37 | $info['hpk']['header']['data_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 4, 4)); 38 | $info['hpk']['header']['fragments_per_file'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 8, 4)); 39 | //$info['hpk']['header']['unknown1'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 12, 4)); 40 | $info['hpk']['header']['fragments_residual_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 16, 4)); 41 | $info['hpk']['header']['fragments_residual_count'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 20, 4)); 42 | //$info['hpk']['header']['unknown2'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 24, 4)); 43 | $info['hpk']['header']['fragmented_filesystem_offset'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 28, 4)); 44 | $info['hpk']['header']['fragmented_filesystem_length'] = getid3_lib::LittleEndian2Int(substr($HPKheader, 32, 4)); 45 | 46 | $info['hpk']['header']['filesystem_entries'] = $info['hpk']['header']['fragmented_filesystem_length'] / ($info['hpk']['header']['fragments_per_file'] * 8); 47 | $this->fseek($info['hpk']['header']['fragmented_filesystem_offset']); 48 | for ($i = 0; $i < $info['hpk']['header']['filesystem_entries']; $i++) { 49 | $offset = getid3_lib::LittleEndian2Int($this->fread(4)); 50 | $length = getid3_lib::LittleEndian2Int($this->fread(4)); 51 | $info['hpk']['filesystem'][$i] = array('offset' => $offset, 'length' => $length); 52 | } 53 | 54 | $this->error('HPK parsing incomplete (and mostly broken) in this version of getID3() ['.$this->getid3->version().']'); 55 | 56 | /* 57 | $filename = ''; 58 | $dirs = array(); 59 | foreach ($info['hpk']['filesystem'] as $key => $filesystemdata) { 60 | $this->fseek($filesystemdata['offset']); 61 | $first4 = $this->fread(4); 62 | if (($first4 == 'LZ4 ') || ($first4 == 'ZLIB')) { 63 | // actual data, ignore 64 | $info['hpk']['toc'][$key] = array( 65 | 'filename' => ltrim(implode('/', $dirs).'/'.$filename, '/'), 66 | 'offset' => $filesystemdata['offset'], 67 | 'length' => $filesystemdata['length'], 68 | ); 69 | $filename = ''; 70 | $dirs = array(); 71 | } else { 72 | $fragment_index = getid3_lib::LittleEndian2Int($first4); 73 | $fragment_type = getid3_lib::LittleEndian2Int($this->fread(4)); // file = 0, directory = 1 74 | $name_length = getid3_lib::LittleEndian2Int($this->fread(2)); 75 | if ($fragment_type == 1) { 76 | $dirs[] = $this->fread($name_length); 77 | } else { 78 | $filename = $this->fread($name_length); 79 | } 80 | } 81 | } 82 | */ 83 | 84 | } else { 85 | $this->error('Expecting "BPUL" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($HPKheader, 0, 4)).'"'); 86 | return false; 87 | } 88 | 89 | return true; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.archive.rar.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.archive.rar.php // 12 | // module for analyzing RAR files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_rar extends getid3_handler 22 | { 23 | /** 24 | * @var bool 25 | */ 26 | public $option_use_rar_extension = false; 27 | 28 | /** 29 | * @return bool 30 | */ 31 | public function Analyze() { 32 | $info = &$this->getid3->info; 33 | 34 | $info['fileformat'] = 'rar'; 35 | 36 | if ($this->option_use_rar_extension === true) { 37 | if (function_exists('rar_open')) { 38 | if ($rp = rar_open($info['filenamepath'])) { 39 | $info['rar']['files'] = array(); 40 | $entries = rar_list($rp); 41 | foreach ($entries as $entry) { 42 | $info['rar']['files'] = getid3_lib::array_merge_clobber($info['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize())); 43 | } 44 | rar_close($rp); 45 | return true; 46 | } else { 47 | $this->error('failed to rar_open('.$info['filename'].')'); 48 | } 49 | } else { 50 | $this->error('RAR support does not appear to be available in this PHP installation'); 51 | } 52 | } else { 53 | $this->error('PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)'); 54 | } 55 | return false; 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.archive.szip.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.archive.szip.php // 12 | // module for analyzing SZIP compressed files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_szip extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $SZIPHeader = $this->fread(6); 31 | if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") { 32 | $this->error('Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"'); 33 | return false; 34 | } 35 | $info['fileformat'] = 'szip'; 36 | $info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1)); 37 | $info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1)); 38 | $this->error('SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 39 | return false; 40 | 41 | while (!$this->feof()) { 42 | $NextBlockID = $this->fread(2); 43 | switch ($NextBlockID) { 44 | case 'SZ': 45 | // Note that szip files can be concatenated, this has the same effect as 46 | // concatenating the files. this also means that global header blocks 47 | // might be present between directory/data blocks. 48 | $this->fseek(4, SEEK_CUR); 49 | break; 50 | 51 | case 'BH': 52 | $BHheaderbytes = getid3_lib::BigEndian2Int($this->fread(3)); 53 | $BHheaderdata = $this->fread($BHheaderbytes); 54 | $BHheaderoffset = 0; 55 | while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) { 56 | //filename as \0 terminated string (empty string indicates end) 57 | //owner as \0 terminated string (empty is same as last file) 58 | //group as \0 terminated string (empty is same as last file) 59 | //3 byte filelength in this block 60 | //2 byte access flags 61 | //4 byte creation time (like in unix) 62 | //4 byte modification time (like in unix) 63 | //4 byte access time (like in unix) 64 | 65 | $BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); 66 | $BHheaderoffset += (strlen($BHdataArray['filename']) + 1); 67 | 68 | $BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); 69 | $BHheaderoffset += (strlen($BHdataArray['owner']) + 1); 70 | 71 | $BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); 72 | $BHheaderoffset += (strlen($BHdataArray['group']) + 1); 73 | 74 | $BHdataArray['filelength'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3)); 75 | $BHheaderoffset += 3; 76 | 77 | $BHdataArray['access_flags'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2)); 78 | $BHheaderoffset += 2; 79 | 80 | $BHdataArray['creation_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); 81 | $BHheaderoffset += 4; 82 | 83 | $BHdataArray['modification_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); 84 | $BHheaderoffset += 4; 85 | 86 | $BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); 87 | $BHheaderoffset += 4; 88 | 89 | $info['szip']['BH'][] = $BHdataArray; 90 | } 91 | break; 92 | 93 | default: 94 | break 2; 95 | } 96 | } 97 | 98 | return true; 99 | 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.archive.tar.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.archive.tar.php // 12 | // module for analyzing TAR files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | // // 17 | // Module originally written by // 18 | // Mike Mozolin // 19 | // // 20 | ///////////////////////////////////////////////////////////////// 21 | 22 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 23 | exit; 24 | } 25 | 26 | class getid3_tar extends getid3_handler 27 | { 28 | /** 29 | * @return bool 30 | */ 31 | public function Analyze() { 32 | $info = &$this->getid3->info; 33 | 34 | $info['fileformat'] = 'tar'; 35 | $info['tar']['files'] = array(); 36 | 37 | $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix'; 38 | $null_512k = str_repeat("\x00", 512); // end-of-file marker 39 | 40 | $this->fseek(0); 41 | while (!feof($this->getid3->fp)) { 42 | $buffer = $this->fread(512); 43 | if (strlen($buffer) < 512) { 44 | break; 45 | } 46 | 47 | // check the block 48 | $checksum = 0; 49 | for ($i = 0; $i < 148; $i++) { 50 | $checksum += ord($buffer[$i]); 51 | } 52 | for ($i = 148; $i < 156; $i++) { 53 | $checksum += ord(' '); 54 | } 55 | for ($i = 156; $i < 512; $i++) { 56 | $checksum += ord($buffer[$i]); 57 | } 58 | $attr = unpack($unpack_header, $buffer); 59 | $name = (isset($attr['fname'] ) ? trim($attr['fname'] ) : ''); 60 | $mode = octdec(isset($attr['mode'] ) ? trim($attr['mode'] ) : ''); 61 | $uid = octdec(isset($attr['uid'] ) ? trim($attr['uid'] ) : ''); 62 | $gid = octdec(isset($attr['gid'] ) ? trim($attr['gid'] ) : ''); 63 | $size = octdec(isset($attr['size'] ) ? trim($attr['size'] ) : ''); 64 | $mtime = octdec(isset($attr['mtime'] ) ? trim($attr['mtime'] ) : ''); 65 | $chksum = octdec(isset($attr['chksum'] ) ? trim($attr['chksum'] ) : ''); 66 | $typflag = (isset($attr['typflag']) ? trim($attr['typflag']) : ''); 67 | $lnkname = (isset($attr['lnkname']) ? trim($attr['lnkname']) : ''); 68 | $magic = (isset($attr['magic'] ) ? trim($attr['magic'] ) : ''); 69 | $ver = (isset($attr['ver'] ) ? trim($attr['ver'] ) : ''); 70 | $uname = (isset($attr['uname'] ) ? trim($attr['uname'] ) : ''); 71 | $gname = (isset($attr['gname'] ) ? trim($attr['gname'] ) : ''); 72 | $devmaj = octdec(isset($attr['devmaj'] ) ? trim($attr['devmaj'] ) : ''); 73 | $devmin = octdec(isset($attr['devmin'] ) ? trim($attr['devmin'] ) : ''); 74 | $prefix = (isset($attr['prefix'] ) ? trim($attr['prefix'] ) : ''); 75 | if (($checksum == 256) && ($chksum == 0)) { 76 | // EOF Found 77 | break; 78 | } 79 | if ($prefix) { 80 | $name = $prefix.'/'.$name; 81 | } 82 | if ((preg_match('#/$#', $name)) && !$name) { 83 | $typeflag = 5; 84 | } 85 | if ($buffer == $null_512k) { 86 | // it's the end of the tar-file... 87 | break; 88 | } 89 | 90 | // Read to the next chunk 91 | $this->fseek($size, SEEK_CUR); 92 | 93 | $diff = $size % 512; 94 | if ($diff != 0) { 95 | // Padding, throw away 96 | $this->fseek((512 - $diff), SEEK_CUR); 97 | } 98 | // Protect against tar-files with garbage at the end 99 | if ($name == '') { 100 | break; 101 | } 102 | $info['tar']['file_details'][$name] = array ( 103 | 'name' => $name, 104 | 'mode_raw' => $mode, 105 | 'mode' => self::display_perms($mode), 106 | 'uid' => $uid, 107 | 'gid' => $gid, 108 | 'size' => $size, 109 | 'mtime' => $mtime, 110 | 'chksum' => $chksum, 111 | 'typeflag' => self::get_flag_type($typflag), 112 | 'linkname' => $lnkname, 113 | 'magic' => $magic, 114 | 'version' => $ver, 115 | 'uname' => $uname, 116 | 'gname' => $gname, 117 | 'devmajor' => $devmaj, 118 | 'devminor' => $devmin 119 | ); 120 | $info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size)); 121 | } 122 | return true; 123 | } 124 | 125 | /** 126 | * Parses the file mode to file permissions. 127 | * 128 | * @param int $mode 129 | * 130 | * @return string 131 | */ 132 | public function display_perms($mode) { 133 | // Determine Type 134 | if ($mode & 0x1000) $type='p'; // FIFO pipe 135 | elseif ($mode & 0x2000) $type='c'; // Character special 136 | elseif ($mode & 0x4000) $type='d'; // Directory 137 | elseif ($mode & 0x6000) $type='b'; // Block special 138 | elseif ($mode & 0x8000) $type='-'; // Regular 139 | elseif ($mode & 0xA000) $type='l'; // Symbolic Link 140 | elseif ($mode & 0xC000) $type='s'; // Socket 141 | else $type='u'; // UNKNOWN 142 | 143 | // Determine permissions 144 | $owner['read'] = (($mode & 00400) ? 'r' : '-'); 145 | $owner['write'] = (($mode & 00200) ? 'w' : '-'); 146 | $owner['execute'] = (($mode & 00100) ? 'x' : '-'); 147 | $group['read'] = (($mode & 00040) ? 'r' : '-'); 148 | $group['write'] = (($mode & 00020) ? 'w' : '-'); 149 | $group['execute'] = (($mode & 00010) ? 'x' : '-'); 150 | $world['read'] = (($mode & 00004) ? 'r' : '-'); 151 | $world['write'] = (($mode & 00002) ? 'w' : '-'); 152 | $world['execute'] = (($mode & 00001) ? 'x' : '-'); 153 | 154 | // Adjust for SUID, SGID and sticky bit 155 | if ($mode & 0x800) $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S'; 156 | if ($mode & 0x400) $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S'; 157 | if ($mode & 0x200) $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T'; 158 | 159 | $s = sprintf('%1s', $type); 160 | $s .= sprintf('%1s%1s%1s', $owner['read'], $owner['write'], $owner['execute']); 161 | $s .= sprintf('%1s%1s%1s', $group['read'], $group['write'], $group['execute']); 162 | $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']); 163 | return $s; 164 | } 165 | 166 | /** 167 | * Converts the file type. 168 | * 169 | * @param string $typflag 170 | * 171 | * @return mixed|string 172 | */ 173 | public function get_flag_type($typflag) { 174 | static $flag_types = array( 175 | '0' => 'LF_NORMAL', 176 | '1' => 'LF_LINK', 177 | '2' => 'LF_SYNLINK', 178 | '3' => 'LF_CHR', 179 | '4' => 'LF_BLK', 180 | '5' => 'LF_DIR', 181 | '6' => 'LF_FIFO', 182 | '7' => 'LF_CONFIG', 183 | 'D' => 'LF_DUMPDIR', 184 | 'K' => 'LF_LONGLINK', 185 | 'L' => 'LF_LONGNAME', 186 | 'M' => 'LF_MULTIVOL', 187 | 'N' => 'LF_NAMES', 188 | 'S' => 'LF_SPARSE', 189 | 'V' => 'LF_VOLHDR' 190 | ); 191 | return (isset($flag_types[$typflag]) ? $flag_types[$typflag] : ''); 192 | } 193 | 194 | } 195 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.archive.xz.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.archive.xz.php // 12 | // module for analyzing XZ files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_xz extends getid3_handler 22 | { 23 | 24 | /** 25 | * @return bool 26 | */ 27 | public function Analyze() { 28 | $info = &$this->getid3->info; 29 | 30 | $this->fseek($info['avdataoffset']); 31 | $xzheader = $this->fread(6); 32 | 33 | // https://tukaani.org/xz/xz-file-format-1.0.4.txt 34 | $info['xz']['stream_header']['magic'] = substr($xzheader, 0, 6); 35 | if ($info['xz']['stream_header']['magic'] != "\xFD".'7zXZ'."\x00") { 36 | $this->error('Invalid XZ stream header magic (expecting FD 37 7A 58 5A 00, found '.getid3_lib::PrintHexBytes($info['xz']['stream_header']['magic']).') at offset '.$info['avdataoffset']); 37 | return false; 38 | } 39 | $info['fileformat'] = 'xz'; 40 | $this->error('XZ parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 41 | return false; 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio-video.bink.php: -------------------------------------------------------------------------------- 1 | // 4 | // available at https://github.com/JamesHeinrich/getID3 // 5 | // or https://www.getid3.org // 6 | // or http://getid3.sourceforge.net // 7 | // see readme.txt for more details // 8 | ///////////////////////////////////////////////////////////////// 9 | // // 10 | // module.audio.bink.php // 11 | // module for analyzing Bink or Smacker audio-video files // 12 | // dependencies: NONE // 13 | // /// 14 | ///////////////////////////////////////////////////////////////// 15 | 16 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 17 | exit; 18 | } 19 | 20 | class getid3_bink extends getid3_handler 21 | { 22 | /** 23 | * @return bool 24 | */ 25 | public function Analyze() { 26 | $info = &$this->getid3->info; 27 | 28 | $this->error('Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']'); 29 | 30 | $this->fseek($info['avdataoffset']); 31 | $fileTypeID = $this->fread(3); 32 | switch ($fileTypeID) { 33 | case 'BIK': 34 | return $this->ParseBink(); 35 | 36 | case 'SMK': 37 | return $this->ParseSmacker(); 38 | 39 | default: 40 | $this->error('Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"'); 41 | return false; 42 | } 43 | } 44 | 45 | /** 46 | * @return bool 47 | */ 48 | public function ParseBink() { 49 | $info = &$this->getid3->info; 50 | $info['fileformat'] = 'bink'; 51 | $info['video']['dataformat'] = 'bink'; 52 | 53 | $fileData = 'BIK'.$this->fread(13); 54 | 55 | $info['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4)); 56 | $info['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2)); 57 | 58 | if (($info['avdataend'] - $info['avdataoffset']) != ($info['bink']['data_size'] + 8)) { 59 | $this->error('Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset'])); 60 | } 61 | 62 | return true; 63 | } 64 | 65 | /** 66 | * @return bool 67 | */ 68 | public function ParseSmacker() { 69 | $info = &$this->getid3->info; 70 | $info['fileformat'] = 'smacker'; 71 | $info['video']['dataformat'] = 'smacker'; 72 | 73 | return true; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio-video.ivf.php: -------------------------------------------------------------------------------- 1 | // 4 | // available at https://github.com/JamesHeinrich/getID3 // 5 | // or https://www.getid3.org // 6 | // or http://getid3.sourceforge.net // 7 | // see readme.txt for more details // 8 | ///////////////////////////////////////////////////////////////// 9 | // // 10 | // module.audio.ivf.php // 11 | // module for analyzing IVF audio-video files // 12 | // dependencies: NONE // 13 | // /// 14 | ///////////////////////////////////////////////////////////////// 15 | 16 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 17 | exit; 18 | } 19 | 20 | class getid3_ivf extends getid3_handler 21 | { 22 | /** 23 | * @return bool 24 | */ 25 | public function Analyze() { 26 | $info = &$this->getid3->info; 27 | 28 | $info['fileformat'] = 'ivf'; 29 | $info['video']['dataformat'] = 'ivf'; 30 | 31 | $this->fseek($info['avdataoffset']); 32 | $IVFheader = $this->fread(32); 33 | 34 | if (substr($IVFheader, 0, 4) == 'DKIF') { 35 | 36 | // https://wiki.multimedia.cx/index.php/IVF 37 | $info['ivf']['header']['signature'] = substr($IVFheader, 0, 4); 38 | $info['ivf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 4, 2)); // should be 0 39 | $info['ivf']['header']['headersize'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 6, 2)); 40 | $info['ivf']['header']['fourcc'] = substr($IVFheader, 8, 4); 41 | $info['ivf']['header']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 12, 2)); 42 | $info['ivf']['header']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 14, 2)); 43 | $info['ivf']['header']['timebase_numerator'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 16, 4)); 44 | $info['ivf']['header']['timebase_denominator'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 20, 4)); 45 | $info['ivf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($IVFheader, 24, 4)); 46 | //$info['ivf']['header']['reserved'] = substr($IVFheader, 28, 4); 47 | 48 | $info['ivf']['header']['frame_rate'] = (float) $info['ivf']['header']['timebase_numerator'] / $info['ivf']['header']['timebase_denominator']; 49 | 50 | if ($info['ivf']['header']['version'] > 0) { 51 | $this->warning('Expecting IVF header version 0, found version '.$info['ivf']['header']['version'].', results may not be accurate'); 52 | } 53 | 54 | $info['video']['resolution_x'] = $info['ivf']['header']['resolution_x']; 55 | $info['video']['resolution_y'] = $info['ivf']['header']['resolution_y']; 56 | $info['video']['codec'] = $info['ivf']['header']['fourcc']; 57 | 58 | $info['ivf']['frame_count'] = 0; 59 | while (!$this->feof()) { 60 | if ($frameheader = $this->fread(12)) { 61 | $framesize = getid3_lib::LittleEndian2Int(substr($frameheader, 0, 4)); // size of frame in bytes (not including the 12-byte header) 62 | $timestamp = getid3_lib::LittleEndian2Int(substr($frameheader, 4, 8)); // 64-bit presentation timestamp 63 | $this->fseek($framesize, SEEK_CUR); 64 | $info['ivf']['frame_count']++; 65 | } 66 | } 67 | if ($info['ivf']['frame_count']) { 68 | $info['playtime_seconds'] = $timestamp / 100000; 69 | $info['video']['frame_rate'] = (float) $info['ivf']['frame_count'] / $info['playtime_seconds']; 70 | } 71 | 72 | } else { 73 | $this->error('Expecting "DKIF" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($IVFheader, 0, 4)).'"'); 74 | return false; 75 | } 76 | 77 | return true; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio-video.swf.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio-video.swf.php // 12 | // module for analyzing Shockwave Flash files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_swf extends getid3_handler 22 | { 23 | public $ReturnAllTagData = false; 24 | 25 | /** 26 | * @return bool 27 | */ 28 | public function Analyze() { 29 | $info = &$this->getid3->info; 30 | 31 | $info['fileformat'] = 'swf'; 32 | $info['video']['dataformat'] = 'swf'; 33 | 34 | // http://www.openswf.org/spec/SWFfileformat.html 35 | 36 | $this->fseek($info['avdataoffset']); 37 | 38 | $SWFfileData = $this->fread($info['avdataend'] - $info['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data 39 | 40 | $info['swf']['header']['signature'] = substr($SWFfileData, 0, 3); 41 | switch ($info['swf']['header']['signature']) { 42 | case 'FWS': 43 | $info['swf']['header']['compressed'] = false; 44 | break; 45 | 46 | case 'CWS': 47 | $info['swf']['header']['compressed'] = true; 48 | break; 49 | 50 | default: 51 | $this->error('Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"'); 52 | unset($info['swf']); 53 | unset($info['fileformat']); 54 | return false; 55 | } 56 | $info['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1)); 57 | $info['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4)); 58 | 59 | if ($info['swf']['header']['compressed']) { 60 | $SWFHead = substr($SWFfileData, 0, 8); 61 | $SWFfileData = substr($SWFfileData, 8); 62 | if ($decompressed = @gzuncompress($SWFfileData)) { 63 | $SWFfileData = $SWFHead.$decompressed; 64 | } else { 65 | $this->error('Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)'); 66 | return false; 67 | } 68 | } 69 | 70 | $FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xF8) >> 3; 71 | $FrameSizeDataLength = ceil((5 + (4 * $FrameSizeBitsPerValue)) / 8); 72 | $FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x07), 3, '0', STR_PAD_LEFT); 73 | for ($i = 1; $i < $FrameSizeDataLength; $i++) { 74 | $FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT); 75 | } 76 | list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1)); 77 | $info['swf']['header']['frame_width'] = getid3_lib::Bin2Dec($X2); 78 | $info['swf']['header']['frame_height'] = getid3_lib::Bin2Dec($Y2); 79 | 80 | // http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm 81 | // Next in the header is the frame rate, which is kind of weird. 82 | // It is supposed to be stored as a 16bit integer, but the first byte 83 | // (or last depending on how you look at it) is completely ignored. 84 | // Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps. 85 | 86 | // Byte at (8 + $FrameSizeDataLength) is always zero and ignored 87 | $info['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1)); 88 | $info['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2)); 89 | 90 | $info['video']['frame_rate'] = $info['swf']['header']['frame_rate']; 91 | $info['video']['resolution_x'] = intval(round($info['swf']['header']['frame_width'] / 20)); 92 | $info['video']['resolution_y'] = intval(round($info['swf']['header']['frame_height'] / 20)); 93 | $info['video']['pixel_aspect_ratio'] = (float) 1; 94 | 95 | if (($info['swf']['header']['frame_count'] > 0) && ($info['swf']['header']['frame_rate'] > 0)) { 96 | $info['playtime_seconds'] = $info['swf']['header']['frame_count'] / $info['swf']['header']['frame_rate']; 97 | } 98 | //echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'
'; 99 | 100 | 101 | // SWF tags 102 | 103 | $CurrentOffset = 12 + $FrameSizeDataLength; 104 | $SWFdataLength = strlen($SWFfileData); 105 | 106 | while ($CurrentOffset < $SWFdataLength) { 107 | //echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'
'; 108 | 109 | $TagIDTagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2)); 110 | $TagID = ($TagIDTagLength & 0xFFFC) >> 6; 111 | $TagLength = ($TagIDTagLength & 0x003F); 112 | $CurrentOffset += 2; 113 | if ($TagLength == 0x3F) { 114 | $TagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4)); 115 | $CurrentOffset += 4; 116 | } 117 | 118 | unset($TagData); 119 | $TagData['offset'] = $CurrentOffset; 120 | $TagData['size'] = $TagLength; 121 | $TagData['id'] = $TagID; 122 | $TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength); 123 | switch ($TagID) { 124 | case 0: // end of movie 125 | break 2; 126 | 127 | case 9: // Set background color 128 | //$info['swf']['tags'][] = $TagData; 129 | $info['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT)); 130 | break; 131 | 132 | default: 133 | if ($this->ReturnAllTagData) { 134 | $info['swf']['tags'][] = $TagData; 135 | } 136 | break; 137 | } 138 | 139 | $CurrentOffset += $TagLength; 140 | } 141 | 142 | return true; 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio-video.ts.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio-video.ts.php // 12 | // module for analyzing MPEG Transport Stream (.ts) files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_ts extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $TSheader = $this->fread(19); 31 | $magic = "\x47"; 32 | if (substr($TSheader, 0, 1) != $magic) { 33 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.'); 34 | return false; 35 | } 36 | $info['fileformat'] = 'ts'; 37 | 38 | // http://en.wikipedia.org/wiki/.ts 39 | 40 | $offset = 0; 41 | $info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1; 42 | $pid_flags_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2; 43 | $SAC_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1; 44 | $info['ts']['packet']['flags']['transport_error_indicator'] = (bool) ($pid_flags_raw & 0x8000); // Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error 45 | $info['ts']['packet']['flags']['payload_unit_start_indicator'] = (bool) ($pid_flags_raw & 0x4000); // 1 means start of PES data or PSI otherwise zero only. 46 | $info['ts']['packet']['flags']['transport_high_priority'] = (bool) ($pid_flags_raw & 0x2000); // 1 means higher priority than other packets with the same PID. 47 | $info['ts']['packet']['packet_id'] = ($pid_flags_raw & 0x1FFF) >> 0; 48 | 49 | $info['ts']['packet']['raw']['scrambling_control'] = ($SAC_raw & 0xC0) >> 6; 50 | $info['ts']['packet']['flags']['adaption_field_exists'] = (bool) ($SAC_raw & 0x20); 51 | $info['ts']['packet']['flags']['payload_exists'] = (bool) ($SAC_raw & 0x10); 52 | $info['ts']['packet']['continuity_counter'] = ($SAC_raw & 0x0F) >> 0; // Incremented only when a payload is present 53 | $info['ts']['packet']['scrambling_control'] = $this->TSscramblingControlLookup($info['ts']['packet']['raw']['scrambling_control']); 54 | 55 | if ($info['ts']['packet']['flags']['adaption_field_exists']) { 56 | $AdaptionField_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2; 57 | $info['ts']['packet']['adaption']['field_length'] = ($AdaptionField_raw & 0xFF00) >> 8; // Number of bytes in the adaptation field immediately following this byte 58 | $info['ts']['packet']['adaption']['flags']['discontinuity'] = (bool) ($AdaptionField_raw & 0x0080); // Set to 1 if current TS packet is in a discontinuity state with respect to either the continuity counter or the program clock reference 59 | $info['ts']['packet']['adaption']['flags']['random_access'] = (bool) ($AdaptionField_raw & 0x0040); // Set to 1 if the PES packet in this TS packet starts a video/audio sequence 60 | $info['ts']['packet']['adaption']['flags']['high_priority'] = (bool) ($AdaptionField_raw & 0x0020); // 1 = higher priority 61 | $info['ts']['packet']['adaption']['flags']['pcr'] = (bool) ($AdaptionField_raw & 0x0010); // 1 means adaptation field does contain a PCR field 62 | $info['ts']['packet']['adaption']['flags']['opcr'] = (bool) ($AdaptionField_raw & 0x0008); // 1 means adaptation field does contain an OPCR field 63 | $info['ts']['packet']['adaption']['flags']['splice_point'] = (bool) ($AdaptionField_raw & 0x0004); // 1 means presence of splice countdown field in adaptation field 64 | $info['ts']['packet']['adaption']['flags']['private_data'] = (bool) ($AdaptionField_raw & 0x0002); // 1 means presence of private data bytes in adaptation field 65 | $info['ts']['packet']['adaption']['flags']['extension'] = (bool) ($AdaptionField_raw & 0x0001); // 1 means presence of adaptation field extension 66 | if ($info['ts']['packet']['adaption']['flags']['pcr']) { 67 | $info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6; 68 | } 69 | if ($info['ts']['packet']['adaption']['flags']['opcr']) { 70 | $info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6; 71 | } 72 | } 73 | 74 | $this->error('MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 75 | return false; 76 | 77 | } 78 | 79 | /** 80 | * @param int $raw 81 | * 82 | * @return string 83 | */ 84 | public function TSscramblingControlLookup($raw) { 85 | $TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key'); 86 | return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid'); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio-video.wtv.php: -------------------------------------------------------------------------------- 1 | // 4 | // available at https://github.com/JamesHeinrich/getID3 // 5 | // or https://www.getid3.org // 6 | // or http://getid3.sourceforge.net // 7 | // see readme.txt for more details // 8 | ///////////////////////////////////////////////////////////////// 9 | // // 10 | // module.audio.wtv.php // 11 | // module for analyzing WTV (Windows Recorded TV Show) // 12 | // audio-video files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_wtv extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $info['fileformat'] = 'wtv'; 30 | $info['video']['dataformat'] = 'wtv'; 31 | 32 | $this->error('WTV (Windows Recorded TV Show) files not properly processed by this version of getID3() ['.$this->getid3->version().']'); 33 | 34 | return true; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.aa.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.aa.php // 12 | // module for analyzing Audible Audiobook files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_aa extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $AAheader = $this->fread(8); 31 | 32 | $magic = "\x57\x90\x75\x36"; 33 | if (substr($AAheader, 4, 4) != $magic) { 34 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"'); 35 | return false; 36 | } 37 | 38 | // shortcut 39 | $info['aa'] = array(); 40 | $thisfile_aa = &$info['aa']; 41 | 42 | $info['fileformat'] = 'aa'; 43 | $info['audio']['dataformat'] = 'aa'; 44 | $this->error('Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 45 | return false; 46 | $info['audio']['bitrate_mode'] = 'cbr'; // is it? 47 | $thisfile_aa['encoding'] = 'ISO-8859-1'; 48 | 49 | $thisfile_aa['filesize'] = getid3_lib::BigEndian2Int(substr($AAheader, 0, 4)); 50 | if ($thisfile_aa['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) { 51 | $this->warning('Possible truncated file - expecting "'.$thisfile_aa['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'); 52 | } 53 | 54 | $info['audio']['bits_per_sample'] = 16; // is it? 55 | $info['audio']['sample_rate'] = $thisfile_aa['sample_rate']; 56 | $info['audio']['channels'] = $thisfile_aa['channels']; 57 | 58 | //$info['playtime_seconds'] = 0; 59 | //$info['audio']['bitrate'] = 0; 60 | 61 | return true; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.amr.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.aa.php // 12 | // module for analyzing Audible Audiobook files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_amr extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $AMRheader = $this->fread(6); 31 | 32 | $magic = '#!AMR'."\x0A"; 33 | if (substr($AMRheader, 0, 6) != $magic) { 34 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AMRheader, 0, 6)).'"'); 35 | return false; 36 | } 37 | 38 | // shortcut 39 | $info['amr'] = array(); 40 | $thisfile_amr = &$info['amr']; 41 | 42 | $info['fileformat'] = 'amr'; 43 | $info['audio']['dataformat'] = 'amr'; 44 | $info['audio']['bitrate_mode'] = 'vbr'; // within a small predefined range: 4.75kbps to 12.2kbps 45 | $info['audio']['bits_per_sample'] = 13; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz" 46 | $info['audio']['sample_rate'] = 8000; // http://en.wikipedia.org/wiki/Adaptive_Multi-Rate_audio_codec: "Sampling frequency 8 kHz/13-bit (160 samples for 20 ms frames), filtered to 200–3400 Hz" 47 | $info['audio']['channels'] = 1; 48 | $thisfile_amr['frame_mode_count'] = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0); 49 | 50 | $buffer = ''; 51 | do { 52 | if ((strlen($buffer) < $this->getid3->fread_buffer_size()) && !feof($this->getid3->fp)) { 53 | $buffer .= $this->fread($this->getid3->fread_buffer_size() * 2); 54 | } 55 | $AMR_frame_header = ord(substr($buffer, 0, 1)); 56 | $codec_mode_request = ($AMR_frame_header & 0x78) >> 3; // The 2nd bit through 5th bit (counting the most significant bit as the first bit) comprise the CMR (Codec Mode Request), values 0-7 being valid for AMR. The top bit of the CMR can actually be ignored, though it is used when AMR forms RTP payloads. The lower 3-bits of the header are reserved and are not used. Viewing the header from most significant bit to least significant bit, the encoding is XCCCCXXX, where Xs are reserved (typically 0) and the Cs are the CMR. 57 | if ($codec_mode_request > 7) { 58 | break; 59 | } 60 | $thisfile_amr['frame_mode_count'][$codec_mode_request]++; 61 | $buffer = substr($buffer, $this->amr_mode_bytes_per_frame($codec_mode_request)); 62 | } while (strlen($buffer) > 0); 63 | 64 | $info['playtime_seconds'] = array_sum($thisfile_amr['frame_mode_count']) * 0.020; // each frame contain 160 samples and is 20 milliseconds long 65 | $info['audio']['bitrate'] = (8 * ($info['avdataend'] - $info['avdataoffset'])) / $info['playtime_seconds']; // bitrate could be calculated from average bitrate by distributation of frame types. That would give effective audio bitrate, this gives overall file bitrate which will be a little bit higher since every frame will waste 8 bits for header, plus a few bits for octet padding 66 | $info['bitrate'] = $info['audio']['bitrate']; 67 | 68 | return true; 69 | } 70 | 71 | /** 72 | * @param int $key 73 | * 74 | * @return int|false 75 | */ 76 | public function amr_mode_bitrate($key) { 77 | static $amr_mode_bitrate = array( 78 | 0 => 4750, 79 | 1 => 5150, 80 | 2 => 5900, 81 | 3 => 6700, 82 | 4 => 7400, 83 | 5 => 7950, 84 | 6 => 10200, 85 | 7 => 12200, 86 | ); 87 | return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false); 88 | } 89 | 90 | /** 91 | * @param int $key 92 | * 93 | * @return int|false 94 | */ 95 | public function amr_mode_bytes_per_frame($key) { 96 | static $amr_mode_bitrate = array( 97 | 0 => 13, // 1-byte frame header + 95 bits [padded to: 12 bytes] audio data 98 | 1 => 14, // 1-byte frame header + 103 bits [padded to: 13 bytes] audio data 99 | 2 => 16, // 1-byte frame header + 118 bits [padded to: 15 bytes] audio data 100 | 3 => 18, // 1-byte frame header + 134 bits [padded to: 17 bytes] audio data 101 | 4 => 20, // 1-byte frame header + 148 bits [padded to: 19 bytes] audio data 102 | 5 => 21, // 1-byte frame header + 159 bits [padded to: 20 bytes] audio data 103 | 6 => 27, // 1-byte frame header + 204 bits [padded to: 26 bytes] audio data 104 | 7 => 32, // 1-byte frame header + 244 bits [padded to: 31 bytes] audio data 105 | ); 106 | return (isset($amr_mode_bitrate[$key]) ? $amr_mode_bitrate[$key] : false); 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.au.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.au.php // 12 | // module for analyzing AU files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_au extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $AUheader = $this->fread(8); 31 | 32 | $magic = '.snd'; 33 | if (substr($AUheader, 0, 4) != $magic) { 34 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"'); 35 | return false; 36 | } 37 | 38 | // shortcut 39 | $info['au'] = array(); 40 | $thisfile_au = &$info['au']; 41 | 42 | $info['fileformat'] = 'au'; 43 | $info['audio']['dataformat'] = 'au'; 44 | $info['audio']['bitrate_mode'] = 'cbr'; 45 | $thisfile_au['encoding'] = 'ISO-8859-1'; 46 | 47 | $thisfile_au['header_length'] = getid3_lib::BigEndian2Int(substr($AUheader, 4, 4)); 48 | $AUheader .= $this->fread($thisfile_au['header_length'] - 8); 49 | $info['avdataoffset'] += $thisfile_au['header_length']; 50 | 51 | $thisfile_au['data_size'] = getid3_lib::BigEndian2Int(substr($AUheader, 8, 4)); 52 | $thisfile_au['data_format_id'] = getid3_lib::BigEndian2Int(substr($AUheader, 12, 4)); 53 | $thisfile_au['sample_rate'] = getid3_lib::BigEndian2Int(substr($AUheader, 16, 4)); 54 | $thisfile_au['channels'] = getid3_lib::BigEndian2Int(substr($AUheader, 20, 4)); 55 | $thisfile_au['comments']['comment'][] = trim(substr($AUheader, 24)); 56 | 57 | $thisfile_au['data_format'] = $this->AUdataFormatNameLookup($thisfile_au['data_format_id']); 58 | $thisfile_au['used_bits_per_sample'] = $this->AUdataFormatUsedBitsPerSampleLookup($thisfile_au['data_format_id']); 59 | if ($thisfile_au['bits_per_sample'] = $this->AUdataFormatBitsPerSampleLookup($thisfile_au['data_format_id'])) { 60 | $info['audio']['bits_per_sample'] = $thisfile_au['bits_per_sample']; 61 | } else { 62 | unset($thisfile_au['bits_per_sample']); 63 | } 64 | 65 | $info['audio']['sample_rate'] = $thisfile_au['sample_rate']; 66 | $info['audio']['channels'] = $thisfile_au['channels']; 67 | 68 | if (($info['avdataoffset'] + $thisfile_au['data_size']) > $info['avdataend']) { 69 | $this->warning('Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'); 70 | } 71 | 72 | $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8)); 73 | $info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds']; 74 | 75 | return true; 76 | } 77 | 78 | /** 79 | * @param int $id 80 | * 81 | * @return string|false 82 | */ 83 | public function AUdataFormatNameLookup($id) { 84 | static $AUdataFormatNameLookup = array( 85 | 0 => 'unspecified format', 86 | 1 => '8-bit mu-law', 87 | 2 => '8-bit linear', 88 | 3 => '16-bit linear', 89 | 4 => '24-bit linear', 90 | 5 => '32-bit linear', 91 | 6 => 'floating-point', 92 | 7 => 'double-precision float', 93 | 8 => 'fragmented sampled data', 94 | 9 => 'SUN_FORMAT_NESTED', 95 | 10 => 'DSP program', 96 | 11 => '8-bit fixed-point', 97 | 12 => '16-bit fixed-point', 98 | 13 => '24-bit fixed-point', 99 | 14 => '32-bit fixed-point', 100 | 101 | 16 => 'non-audio display data', 102 | 17 => 'SND_FORMAT_MULAW_SQUELCH', 103 | 18 => '16-bit linear with emphasis', 104 | 19 => '16-bit linear with compression', 105 | 20 => '16-bit linear with emphasis + compression', 106 | 21 => 'Music Kit DSP commands', 107 | 22 => 'SND_FORMAT_DSP_COMMANDS_SAMPLES', 108 | 23 => 'CCITT g.721 4-bit ADPCM', 109 | 24 => 'CCITT g.722 ADPCM', 110 | 25 => 'CCITT g.723 3-bit ADPCM', 111 | 26 => 'CCITT g.723 5-bit ADPCM', 112 | 27 => 'A-Law 8-bit' 113 | ); 114 | return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false); 115 | } 116 | 117 | /** 118 | * @param int $id 119 | * 120 | * @return int|false 121 | */ 122 | public function AUdataFormatBitsPerSampleLookup($id) { 123 | static $AUdataFormatBitsPerSampleLookup = array( 124 | 1 => 8, 125 | 2 => 8, 126 | 3 => 16, 127 | 4 => 24, 128 | 5 => 32, 129 | 6 => 32, 130 | 7 => 64, 131 | 132 | 11 => 8, 133 | 12 => 16, 134 | 13 => 24, 135 | 14 => 32, 136 | 137 | 18 => 16, 138 | 19 => 16, 139 | 20 => 16, 140 | 141 | 23 => 16, 142 | 143 | 25 => 16, 144 | 26 => 16, 145 | 27 => 8 146 | ); 147 | return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false); 148 | } 149 | 150 | /** 151 | * @param int $id 152 | * 153 | * @return int|false 154 | */ 155 | public function AUdataFormatUsedBitsPerSampleLookup($id) { 156 | static $AUdataFormatUsedBitsPerSampleLookup = array( 157 | 1 => 8, 158 | 2 => 8, 159 | 3 => 16, 160 | 4 => 24, 161 | 5 => 32, 162 | 6 => 32, 163 | 7 => 64, 164 | 165 | 11 => 8, 166 | 12 => 16, 167 | 13 => 24, 168 | 14 => 32, 169 | 170 | 18 => 16, 171 | 19 => 16, 172 | 20 => 16, 173 | 174 | 23 => 4, 175 | 176 | 25 => 3, 177 | 26 => 5, 178 | 27 => 8, 179 | ); 180 | return (isset($AUdataFormatUsedBitsPerSampleLookup[$id]) ? $AUdataFormatUsedBitsPerSampleLookup[$id] : false); 181 | } 182 | 183 | } 184 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.avr.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.avr.php // 12 | // module for analyzing AVR Audio files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_avr extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | // http://cui.unige.ch/OSG/info/AudioFormats/ap11.html 30 | // http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html 31 | // offset type length name comments 32 | // --------------------------------------------------------------------- 33 | // 0 char 4 ID format ID == "2BIT" 34 | // 4 char 8 name sample name (unused space filled with 0) 35 | // 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo 36 | // With stereo, samples are alternated, 37 | // the first voice is the left : 38 | // (LRLRLRLRLRLRLRLRLR...) 39 | // 14 short 1 resolution 8, 12 or 16 (bits) 40 | // 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed 41 | // 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on 42 | // 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127 43 | // 0xFFFF means "no MIDI note defined" 44 | // 22 byte 1 Replay speed Frequence in the Replay software 45 | // 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz, 46 | // 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz 47 | // 6=43.885 Khz, 7=47.261 Khz 48 | // -1 (0xFF)=no defined Frequence 49 | // 23 byte 3 sample rate in Hertz 50 | // 26 long 1 size in bytes (2 * bytes in stereo) 51 | // 30 long 1 loop begin 0 for no loop 52 | // 34 long 1 loop size equal to 'size' for no loop 53 | // 38 short 2 Reserved, MIDI keyboard split */ 54 | // 40 short 2 Reserved, sample compression */ 55 | // 42 short 2 Reserved */ 56 | // 44 char 20; Additional filename space, used if (name[7] != 0) 57 | // 64 byte 64 user data 58 | // 128 bytes ? sample data (12 bits samples are coded on 16 bits: 59 | // 0000 xxxx xxxx xxxx) 60 | // --------------------------------------------------------------------- 61 | 62 | // Note that all values are in motorola (big-endian) format, and that long is 63 | // assumed to be 4 bytes, and short 2 bytes. 64 | // When reading the samples, you should handle both signed and unsigned data, 65 | // and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert 66 | // 8-bit data between signed/unsigned just add 127 to the sample values. 67 | // Simularly for 16-bit data you should add 32769 68 | 69 | $info['fileformat'] = 'avr'; 70 | 71 | $this->fseek($info['avdataoffset']); 72 | $AVRheader = $this->fread(128); 73 | 74 | $info['avr']['raw']['magic'] = substr($AVRheader, 0, 4); 75 | $magic = '2BIT'; 76 | if ($info['avr']['raw']['magic'] != $magic) { 77 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"'); 78 | unset($info['fileformat']); 79 | unset($info['avr']); 80 | return false; 81 | } 82 | $info['avdataoffset'] += 128; 83 | 84 | $info['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8)); 85 | $info['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2)); 86 | $info['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2)); 87 | $info['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2)); 88 | $info['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2)); 89 | $info['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2)); 90 | $info['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1)); 91 | $info['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3)); 92 | $info['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4)); 93 | $info['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4)); 94 | $info['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4)); 95 | $info['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2)); 96 | $info['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2)); 97 | $info['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2)); 98 | $info['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20)); 99 | $info['avr']['comment'] = rtrim(substr($AVRheader, 64, 64)); 100 | 101 | $info['avr']['flags']['stereo'] = (($info['avr']['raw']['mono'] == 0) ? false : true); 102 | $info['avr']['flags']['signed'] = (($info['avr']['raw']['signed'] == 0) ? false : true); 103 | $info['avr']['flags']['loop'] = (($info['avr']['raw']['loop'] == 0) ? false : true); 104 | 105 | $info['avr']['midi_notes'] = array(); 106 | if (($info['avr']['raw']['midi'] & 0xFF00) != 0xFF00) { 107 | $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xFF00) >> 8; 108 | } 109 | if (($info['avr']['raw']['midi'] & 0x00FF) != 0x00FF) { 110 | $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0x00FF); 111 | } 112 | 113 | if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) { 114 | $this->warning('Probable truncated file: expecting '.($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset'])); 115 | } 116 | 117 | $info['audio']['dataformat'] = 'avr'; 118 | $info['audio']['lossless'] = true; 119 | $info['audio']['bitrate_mode'] = 'cbr'; 120 | $info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample']; 121 | $info['audio']['sample_rate'] = $info['avr']['sample_rate']; 122 | $info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1); 123 | $info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate']; 124 | $info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds']; 125 | 126 | 127 | return true; 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.dsf.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.dsf.php // 12 | // module for analyzing dsf/DSF Audio files // 13 | // dependencies: module.tag.id3v2.php // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); 21 | 22 | class getid3_dsf extends getid3_handler 23 | { 24 | /** 25 | * @return bool 26 | */ 27 | public function Analyze() { 28 | $info = &$this->getid3->info; 29 | 30 | $info['fileformat'] = 'dsf'; 31 | $info['audio']['dataformat'] = 'dsf'; 32 | $info['audio']['lossless'] = true; 33 | $info['audio']['bitrate_mode'] = 'cbr'; 34 | 35 | $this->fseek($info['avdataoffset']); 36 | $dsfheader = $this->fread(28 + 12); 37 | 38 | $headeroffset = 0; 39 | $info['dsf']['dsd']['magic'] = substr($dsfheader, $headeroffset, 4); 40 | $headeroffset += 4; 41 | $magic = 'DSD '; 42 | if ($info['dsf']['dsd']['magic'] != $magic) { 43 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['dsf']['dsd']['magic']).'"'); 44 | unset($info['fileformat']); 45 | unset($info['audio']); 46 | unset($info['dsf']); 47 | return false; 48 | } 49 | $info['dsf']['dsd']['dsd_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // should be 28 50 | $headeroffset += 8; 51 | $info['dsf']['dsd']['dsf_file_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); 52 | $headeroffset += 8; 53 | $info['dsf']['dsd']['meta_chunk_offset'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); 54 | $headeroffset += 8; 55 | 56 | 57 | $info['dsf']['fmt']['magic'] = substr($dsfheader, $headeroffset, 4); 58 | $headeroffset += 4; 59 | $magic = 'fmt '; 60 | if ($info['dsf']['fmt']['magic'] != $magic) { 61 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['fmt']['magic']).'"'); 62 | return false; 63 | } 64 | $info['dsf']['fmt']['fmt_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); // usually 52 bytes 65 | $headeroffset += 8; 66 | $dsfheader .= $this->fread($info['dsf']['fmt']['fmt_chunk_size'] - 12 + 12); // we have already read the entire DSD chunk, plus 12 bytes of FMT. We now want to read the size of FMT, plus 12 bytes into the next chunk to get magic and size. 67 | if (strlen($dsfheader) != ($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size'] + 12)) { 68 | $this->error('Expecting '.($info['dsf']['dsd']['dsd_chunk_size'] + $info['dsf']['fmt']['fmt_chunk_size']).' bytes header, found '.strlen($dsfheader).' bytes'); 69 | return false; 70 | } 71 | $info['dsf']['fmt']['format_version'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "1" 72 | $headeroffset += 4; 73 | $info['dsf']['fmt']['format_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // usually "0" = "DSD Raw" 74 | $headeroffset += 4; 75 | $info['dsf']['fmt']['channel_type_id'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); 76 | $headeroffset += 4; 77 | $info['dsf']['fmt']['channels'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); 78 | $headeroffset += 4; 79 | $info['dsf']['fmt']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); 80 | $headeroffset += 4; 81 | $info['dsf']['fmt']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); 82 | $headeroffset += 4; 83 | $info['dsf']['fmt']['sample_count'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); 84 | $headeroffset += 8; 85 | $info['dsf']['fmt']['channel_block_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); 86 | $headeroffset += 4; 87 | $info['dsf']['fmt']['reserved'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 4)); // zero-filled 88 | $headeroffset += 4; 89 | 90 | 91 | $info['dsf']['data']['magic'] = substr($dsfheader, $headeroffset, 4); 92 | $headeroffset += 4; 93 | $magic = 'data'; 94 | if ($info['dsf']['data']['magic'] != $magic) { 95 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$headeroffset.', found "'.getid3_lib::PrintHexBytes($info['dsf']['data']['magic']).'"'); 96 | return false; 97 | } 98 | $info['dsf']['data']['data_chunk_size'] = getid3_lib::LittleEndian2Int(substr($dsfheader, $headeroffset, 8)); 99 | $headeroffset += 8; 100 | $info['avdataoffset'] = $headeroffset; 101 | $info['avdataend'] = $info['avdataoffset'] + $info['dsf']['data']['data_chunk_size']; 102 | 103 | 104 | if ($info['dsf']['dsd']['meta_chunk_offset'] > 0) { 105 | $getid3_id3v2 = new getid3_id3v2($this->getid3); 106 | $getid3_id3v2->StartingOffset = $info['dsf']['dsd']['meta_chunk_offset']; 107 | $getid3_id3v2->Analyze(); 108 | unset($getid3_id3v2); 109 | } 110 | 111 | 112 | $info['dsf']['fmt']['channel_type'] = $this->DSFchannelTypeLookup($info['dsf']['fmt']['channel_type_id']); 113 | $info['audio']['channelmode'] = $info['dsf']['fmt']['channel_type']; 114 | $info['audio']['bits_per_sample'] = $info['dsf']['fmt']['bits_per_sample']; 115 | $info['audio']['sample_rate'] = $info['dsf']['fmt']['sample_rate']; 116 | $info['audio']['channels'] = $info['dsf']['fmt']['channels']; 117 | $info['audio']['bitrate'] = $info['audio']['bits_per_sample'] * $info['audio']['sample_rate'] * $info['audio']['channels']; 118 | $info['playtime_seconds'] = ($info['dsf']['data']['data_chunk_size'] * 8) / $info['audio']['bitrate']; 119 | 120 | return true; 121 | } 122 | 123 | /** 124 | * @param int $channel_type_id 125 | * 126 | * @return string 127 | */ 128 | public static function DSFchannelTypeLookup($channel_type_id) { 129 | static $DSFchannelTypeLookup = array( 130 | // interleaving order: 131 | 1 => 'mono', // 1: Mono 132 | 2 => 'stereo', // 1: Front-Left; 2: Front-Right 133 | 3 => '3-channel', // 1: Front-Left; 2: Front-Right; 3: Center 134 | 4 => 'quad', // 1: Front-Left; 2: Front-Right; 3: Back-Left; 4: Back-Right 135 | 5 => '4-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency 136 | 6 => '5-channel', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Back-Left 5: Back-Right 137 | 7 => '5.1', // 1: Front-Left; 2: Front-Right; 3: Center; 4: Low-Frequency; 5: Back-Left; 6: Back-Right 138 | ); 139 | return (isset($DSFchannelTypeLookup[$channel_type_id]) ? $DSFchannelTypeLookup[$channel_type_id] : ''); 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.dss.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.dss.php // 12 | // module for analyzing Digital Speech Standard (DSS) files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_dss extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $DSSheader = $this->fread(1540); 31 | 32 | if (!preg_match('#^[\\x02-\\x08]ds[s2]#', $DSSheader)) { 33 | $this->error('Expecting "[02-08] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"'); 34 | return false; 35 | } 36 | 37 | // some structure information taken from http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm 38 | $info['encoding'] = 'ISO-8859-1'; // not certain, but assumed 39 | $info['dss'] = array(); 40 | 41 | $info['fileformat'] = 'dss'; 42 | $info['mime_type'] = 'audio/x-'.substr($DSSheader, 1, 3); // "audio/x-dss" or "audio/x-ds2" 43 | $info['audio']['dataformat'] = substr($DSSheader, 1, 3); // "dss" or "ds2" 44 | $info['audio']['bitrate_mode'] = 'cbr'; 45 | 46 | $info['dss']['version'] = ord(substr($DSSheader, 0, 1)); 47 | $info['dss']['hardware'] = trim(substr($DSSheader, 12, 16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400" 48 | $info['dss']['unknown1'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 28, 4)); 49 | // 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen 50 | $info['dss']['date_create_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12)); 51 | $info['dss']['date_complete_unix'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12)); 52 | $info['dss']['playtime_sec'] = ((int) substr($DSSheader, 62, 2) * 3600) + ((int) substr($DSSheader, 64, 2) * 60) + (int) substr($DSSheader, 66, 2); // approximate file playtime in HHMMSS 53 | if ($info['dss']['version'] <= 3) { 54 | $info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512 55 | $info['dss']['priority'] = ord(substr($DSSheader, 793, 1)); 56 | $info['dss']['comments'] = trim(substr($DSSheader, 798, 100)); 57 | $info['dss']['sample_rate_index'] = ord(substr($DSSheader, 1538, 1)); // this isn't certain, this may or may not be where the sample rate info is stored, but it seems consistent on my small selection of sample files 58 | $info['audio']['sample_rate'] = $this->DSSsampleRateLookup($info['dss']['sample_rate_index']); 59 | } else { 60 | $this->getid3->warning('DSS above version 3 not fully supported in this version of getID3. Any additional documentation or format specifications would be welcome. This file is version '.$info['dss']['version']); 61 | } 62 | 63 | $info['audio']['bits_per_sample'] = 16; // maybe, maybe not -- most compressed audio formats don't have a fixed bits-per-sample value, but this is a reasonable approximation 64 | $info['audio']['channels'] = 1; 65 | 66 | if (!empty($info['dss']['playtime_ms']) && (floor($info['dss']['playtime_ms'] / 1000) == $info['dss']['playtime_sec'])) { // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check 67 | $info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000; 68 | } else { 69 | $info['playtime_seconds'] = $info['dss']['playtime_sec']; 70 | if (!empty($info['dss']['playtime_ms'])) { 71 | $this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value'); 72 | } 73 | } 74 | $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds']; 75 | 76 | return true; 77 | } 78 | 79 | /** 80 | * @param string $datestring 81 | * 82 | * @return int|false 83 | */ 84 | public function DSSdateStringToUnixDate($datestring) { 85 | $y = (int) substr($datestring, 0, 2); 86 | $m = substr($datestring, 2, 2); 87 | $d = substr($datestring, 4, 2); 88 | $h = substr($datestring, 6, 2); 89 | $i = substr($datestring, 8, 2); 90 | $s = substr($datestring, 10, 2); 91 | $y += (($y < 95) ? 2000 : 1900); 92 | return mktime($h, $i, $s, $m, $d, $y); 93 | } 94 | 95 | /** 96 | * @param int $sample_rate_index 97 | * 98 | * @return int|false 99 | */ 100 | public function DSSsampleRateLookup($sample_rate_index) { 101 | static $dssSampleRateLookup = array( 102 | 0x0A => 16000, 103 | 0x0C => 11025, 104 | 0x0D => 12000, 105 | 0x15 => 8000, 106 | ); 107 | if (!array_key_exists($sample_rate_index, $dssSampleRateLookup)) { 108 | $this->getid3->warning('unknown sample_rate_index: 0x'.strtoupper(dechex($sample_rate_index))); 109 | return false; 110 | } 111 | return $dssSampleRateLookup[$sample_rate_index]; 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.lpac.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.lpac.php // 12 | // module for analyzing LPAC Audio files // 13 | // dependencies: module.audio-video.riff.php // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); 21 | 22 | class getid3_lpac extends getid3_handler 23 | { 24 | /** 25 | * @return bool 26 | */ 27 | public function Analyze() { 28 | $info = &$this->getid3->info; 29 | 30 | $this->fseek($info['avdataoffset']); 31 | $LPACheader = $this->fread(14); 32 | $StreamMarker = substr($LPACheader, 0, 4); 33 | if ($StreamMarker != 'LPAC') { 34 | $this->error('Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"'); 35 | return false; 36 | } 37 | $info['avdataoffset'] += 14; 38 | 39 | $info['fileformat'] = 'lpac'; 40 | $info['audio']['dataformat'] = 'lpac'; 41 | $info['audio']['lossless'] = true; 42 | $info['audio']['bitrate_mode'] = 'vbr'; 43 | 44 | $info['lpac']['file_version'] = getid3_lib::BigEndian2Int(substr($LPACheader, 4, 1)); 45 | $flags['audio_type'] = getid3_lib::BigEndian2Int(substr($LPACheader, 5, 1)); 46 | $info['lpac']['total_samples']= getid3_lib::BigEndian2Int(substr($LPACheader, 6, 4)); 47 | $flags['parameters'] = getid3_lib::BigEndian2Int(substr($LPACheader, 10, 4)); 48 | 49 | $info['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40); 50 | $info['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x04); 51 | $info['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x02); 52 | $info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01); 53 | 54 | if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) { 55 | $this->warning('24-bit and 16-bit flags cannot both be set'); 56 | } 57 | 58 | $info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000); 59 | $info['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x08000000); 60 | $info['lpac']['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256; 61 | $info['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x00800000); 62 | $info['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x00400000); 63 | $info['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x00040000); 64 | $info['lpac']['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8; 65 | $info['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F); 66 | 67 | if ($info['lpac']['flags']['fast_compress'] && ($info['lpac']['max_prediction_order'] != 3)) { 68 | $this->warning('max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info['lpac']['max_prediction_order'].'"'); 69 | } 70 | switch ($info['lpac']['file_version']) { 71 | case 6: 72 | if ($info['lpac']['flags']['adaptive_quantization']) { 73 | $this->warning('adaptive_quantization expected to be false in LPAC file stucture v6, actually true'); 74 | } 75 | if ($info['lpac']['quantization'] != 20) { 76 | $this->warning('Quantization expected to be 20 in LPAC file stucture v6, actually '.$info['lpac']['flags']['Q']); 77 | } 78 | break; 79 | 80 | default: 81 | //$this->warning('This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org'); 82 | break; 83 | } 84 | 85 | $getid3_temp = new getID3(); 86 | $getid3_temp->openfile($this->getid3->filename); 87 | $getid3_temp->info = $info; 88 | $getid3_riff = new getid3_riff($getid3_temp); 89 | $getid3_riff->Analyze(); 90 | $info['avdataoffset'] = $getid3_temp->info['avdataoffset']; 91 | $info['riff'] = $getid3_temp->info['riff']; 92 | $info['error'] = $getid3_temp->info['error']; 93 | $info['warning'] = $getid3_temp->info['warning']; 94 | $info['lpac']['comments']['comment'] = $getid3_temp->info['comments']; 95 | $info['audio']['sample_rate'] = $getid3_temp->info['audio']['sample_rate']; 96 | unset($getid3_temp, $getid3_riff); 97 | 98 | $info['audio']['channels'] = ($info['lpac']['flags']['stereo'] ? 2 : 1); 99 | 100 | if ($info['lpac']['flags']['24_bit']) { 101 | $info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample']; 102 | } elseif ($info['lpac']['flags']['16_bit']) { 103 | $info['audio']['bits_per_sample'] = 16; 104 | } else { 105 | $info['audio']['bits_per_sample'] = 8; 106 | } 107 | 108 | if ($info['lpac']['flags']['fast_compress']) { 109 | // fast 110 | $info['audio']['encoder_options'] = '-1'; 111 | } else { 112 | switch ($info['lpac']['max_prediction_order']) { 113 | case 20: // simple 114 | $info['audio']['encoder_options'] = '-2'; 115 | break; 116 | case 30: // medium 117 | $info['audio']['encoder_options'] = '-3'; 118 | break; 119 | case 40: // high 120 | $info['audio']['encoder_options'] = '-4'; 121 | break; 122 | case 60: // extrahigh 123 | $info['audio']['encoder_options'] = '-5'; 124 | break; 125 | } 126 | } 127 | 128 | $info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate']; 129 | $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 130 | 131 | return true; 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.mod.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.mod.php // 12 | // module for analyzing MOD Audio files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_mod extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | $this->fseek($info['avdataoffset']); 29 | $fileheader = $this->fread(1088); 30 | if (preg_match('#^IMPM#', $fileheader)) { 31 | return $this->getITheaderFilepointer(); 32 | } elseif (preg_match('#^Extended Module#', $fileheader)) { 33 | return $this->getXMheaderFilepointer(); 34 | } elseif (preg_match('#^.{44}SCRM#', $fileheader)) { 35 | return $this->getS3MheaderFilepointer(); 36 | } elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) { 37 | return $this->getMODheaderFilepointer(); 38 | } 39 | $this->error('This is not a known type of MOD file'); 40 | return false; 41 | } 42 | 43 | /** 44 | * @return bool 45 | */ 46 | public function getMODheaderFilepointer() { 47 | $info = &$this->getid3->info; 48 | $this->fseek($info['avdataoffset'] + 1080); 49 | $FormatID = $this->fread(4); 50 | if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) { 51 | $this->error('This is not a known type of MOD file'); 52 | return false; 53 | } 54 | 55 | $info['fileformat'] = 'mod'; 56 | 57 | $this->error('MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 58 | return false; 59 | } 60 | 61 | /** 62 | * @return bool 63 | */ 64 | public function getXMheaderFilepointer() { 65 | $info = &$this->getid3->info; 66 | $this->fseek($info['avdataoffset']); 67 | $FormatID = $this->fread(15); 68 | if (!preg_match('#^Extended Module$#', $FormatID)) { 69 | $this->error('This is not a known type of XM-MOD file'); 70 | return false; 71 | } 72 | 73 | $info['fileformat'] = 'xm'; 74 | 75 | $this->error('XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 76 | return false; 77 | } 78 | 79 | /** 80 | * @return bool 81 | */ 82 | public function getS3MheaderFilepointer() { 83 | $info = &$this->getid3->info; 84 | $this->fseek($info['avdataoffset'] + 44); 85 | $FormatID = $this->fread(4); 86 | if (!preg_match('#^SCRM$#', $FormatID)) { 87 | $this->error('This is not a ScreamTracker MOD file'); 88 | return false; 89 | } 90 | 91 | $info['fileformat'] = 's3m'; 92 | 93 | $this->error('ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 94 | return false; 95 | } 96 | 97 | /** 98 | * @return bool 99 | */ 100 | public function getITheaderFilepointer() { 101 | $info = &$this->getid3->info; 102 | $this->fseek($info['avdataoffset']); 103 | $FormatID = $this->fread(4); 104 | if (!preg_match('#^IMPM$#', $FormatID)) { 105 | $this->error('This is not an ImpulseTracker MOD file'); 106 | return false; 107 | } 108 | 109 | $info['fileformat'] = 'it'; 110 | 111 | $this->error('ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 112 | return false; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.rkau.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.shorten.php // 12 | // module for analyzing Shorten Audio files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_rkau extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $RKAUHeader = $this->fread(20); 31 | $magic = 'RKA'; 32 | if (substr($RKAUHeader, 0, 3) != $magic) { 33 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"'); 34 | return false; 35 | } 36 | 37 | $info['fileformat'] = 'rkau'; 38 | $info['audio']['dataformat'] = 'rkau'; 39 | $info['audio']['bitrate_mode'] = 'vbr'; 40 | 41 | $info['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1)); 42 | $info['rkau']['version'] = '1.'.str_pad($info['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT); 43 | if (($info['rkau']['version'] > 1.07) || ($info['rkau']['version'] < 1.06)) { 44 | $this->error('This version of getID3() ['.$this->getid3->version().'] can only parse RKAU files v1.06 and 1.07 (this file is v'.$info['rkau']['version'].')'); 45 | unset($info['rkau']); 46 | return false; 47 | } 48 | 49 | $info['rkau']['source_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 4, 4)); 50 | $info['rkau']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 8, 4)); 51 | $info['rkau']['channels'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 12, 1)); 52 | $info['rkau']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 13, 1)); 53 | 54 | $info['rkau']['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 14, 1)); 55 | $this->RKAUqualityLookup($info['rkau']); 56 | 57 | $info['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1)); 58 | $info['rkau']['flags']['joint_stereo'] = !($info['rkau']['raw']['flags'] & 0x01); 59 | $info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x02); 60 | $info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x04); 61 | 62 | if ($info['rkau']['flags']['streaming']) { 63 | $info['avdataoffset'] += 20; 64 | $info['rkau']['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 16, 4)); 65 | } else { 66 | $info['avdataoffset'] += 16; 67 | $info['rkau']['compressed_bytes'] = $info['avdataend'] - $info['avdataoffset'] - 1; 68 | } 69 | // Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes, 70 | // sometimes it's more, sometimes less. No idea why(?) 71 | 72 | $info['audio']['lossless'] = $info['rkau']['lossless']; 73 | $info['audio']['channels'] = $info['rkau']['channels']; 74 | $info['audio']['bits_per_sample'] = $info['rkau']['bits_per_sample']; 75 | $info['audio']['sample_rate'] = $info['rkau']['sample_rate']; 76 | 77 | $info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8)); 78 | $info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['playtime_seconds']; 79 | 80 | return true; 81 | 82 | } 83 | 84 | /** 85 | * @param array $RKAUdata 86 | * 87 | * @return bool 88 | */ 89 | public function RKAUqualityLookup(&$RKAUdata) { 90 | $level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4; 91 | $quality = $RKAUdata['raw']['quality'] & 0x0F; 92 | 93 | $RKAUdata['lossless'] = (($quality == 0) ? true : false); 94 | $RKAUdata['compression_level'] = $level + 1; 95 | if (!$RKAUdata['lossless']) { 96 | $RKAUdata['quality_setting'] = $quality; 97 | } 98 | 99 | return true; 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.shorten.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.shorten.php // 12 | // module for analyzing Shorten Audio files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | class getid3_shorten extends getid3_handler 21 | { 22 | /** 23 | * @return bool 24 | */ 25 | public function Analyze() { 26 | $info = &$this->getid3->info; 27 | 28 | $this->fseek($info['avdataoffset']); 29 | 30 | $ShortenHeader = $this->fread(8); 31 | $magic = 'ajkg'; 32 | if (substr($ShortenHeader, 0, 4) != $magic) { 33 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"'); 34 | return false; 35 | } 36 | $info['fileformat'] = 'shn'; 37 | $info['audio']['dataformat'] = 'shn'; 38 | $info['audio']['lossless'] = true; 39 | $info['audio']['bitrate_mode'] = 'vbr'; 40 | 41 | $info['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1)); 42 | 43 | $this->fseek($info['avdataend'] - 12); 44 | $SeekTableSignatureTest = $this->fread(12); 45 | $info['shn']['seektable']['present'] = substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK'; 46 | if ($info['shn']['seektable']['present']) { 47 | $info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4)); 48 | $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length']; 49 | $this->fseek($info['shn']['seektable']['offset']); 50 | $SeekTableMagic = $this->fread(4); 51 | $magic = 'SEEK'; 52 | if ($SeekTableMagic != $magic) { 53 | 54 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"'); 55 | return false; 56 | 57 | } else { 58 | 59 | // typedef struct tag_TSeekEntry 60 | // { 61 | // unsigned long SampleNumber; 62 | // unsigned long SHNFileByteOffset; 63 | // unsigned long SHNLastBufferReadPosition; 64 | // unsigned short SHNByteGet; 65 | // unsigned short SHNBufferOffset; 66 | // unsigned short SHNFileBitOffset; 67 | // unsigned long SHNGBuffer; 68 | // unsigned short SHNBitShift; 69 | // long CBuf0[3]; 70 | // long CBuf1[3]; 71 | // long Offset0[4]; 72 | // long Offset1[4]; 73 | // }TSeekEntry; 74 | 75 | $SeekTableData = $this->fread($info['shn']['seektable']['length'] - 16); 76 | $info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80); 77 | //$info['shn']['seektable']['entries'] = array(); 78 | //$SeekTableOffset = 0; 79 | //for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) { 80 | // $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 81 | // $SeekTableOffset += 4; 82 | // $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 83 | // $SeekTableOffset += 4; 84 | // $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 85 | // $SeekTableOffset += 4; 86 | // $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); 87 | // $SeekTableOffset += 2; 88 | // $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); 89 | // $SeekTableOffset += 2; 90 | // $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); 91 | // $SeekTableOffset += 2; 92 | // $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 93 | // $SeekTableOffset += 4; 94 | // $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); 95 | // $SeekTableOffset += 2; 96 | // for ($j = 0; $j < 3; $j++) { 97 | // $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 98 | // $SeekTableOffset += 4; 99 | // } 100 | // for ($j = 0; $j < 3; $j++) { 101 | // $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 102 | // $SeekTableOffset += 4; 103 | // } 104 | // for ($j = 0; $j < 4; $j++) { 105 | // $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 106 | // $SeekTableOffset += 4; 107 | // } 108 | // for ($j = 0; $j < 4; $j++) { 109 | // $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); 110 | // $SeekTableOffset += 4; 111 | // } 112 | // 113 | // $info['shn']['seektable']['entries'][] = $SeekTableEntry; 114 | //} 115 | 116 | } 117 | 118 | } 119 | 120 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { 121 | $this->error('PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files'); 122 | return false; 123 | } 124 | 125 | if (GETID3_OS_ISWINDOWS) { 126 | 127 | $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe'); 128 | foreach ($RequiredFiles as $required_file) { 129 | if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { 130 | $this->error(GETID3_HELPERAPPSDIR.$required_file.' does not exist'); 131 | return false; 132 | } 133 | } 134 | $commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$info['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 64'; 135 | $commandline = str_replace('/', '\\', $commandline); 136 | 137 | } else { 138 | 139 | static $shorten_present; 140 | if (!isset($shorten_present)) { 141 | $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`; 142 | } 143 | if (!$shorten_present) { 144 | $this->error('shorten binary was not found in path or /usr/local/bin'); 145 | return false; 146 | } 147 | $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64'; 148 | 149 | } 150 | 151 | $output = `$commandline`; 152 | 153 | if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) { 154 | 155 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 156 | exit; 157 | } 158 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); 159 | 160 | $fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4)); 161 | $DecodedWAVFORMATEX = getid3_riff::parseWAVEFORMATex(substr($output, 20, $fmt_size)); 162 | $info['audio']['channels'] = $DecodedWAVFORMATEX['channels']; 163 | $info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample']; 164 | $info['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate']; 165 | 166 | if (substr($output, 20 + $fmt_size, 4) == 'data') { 167 | 168 | $info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']; 169 | 170 | } else { 171 | 172 | $this->error('shorten failed to decode DATA chunk to expected location, cannot determine playtime'); 173 | return false; 174 | 175 | } 176 | 177 | $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8; 178 | 179 | } else { 180 | 181 | $this->error('shorten failed to decode file to WAV for parsing'); 182 | return false; 183 | 184 | } 185 | 186 | return true; 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.tta.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.tta.php // 12 | // module for analyzing TTA Audio files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_tta extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $info['fileformat'] = 'tta'; 30 | $info['audio']['dataformat'] = 'tta'; 31 | $info['audio']['lossless'] = true; 32 | $info['audio']['bitrate_mode'] = 'vbr'; 33 | 34 | $this->fseek($info['avdataoffset']); 35 | $ttaheader = $this->fread(26); 36 | 37 | $info['tta']['magic'] = substr($ttaheader, 0, 3); 38 | $magic = 'TTA'; 39 | if ($info['tta']['magic'] != $magic) { 40 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['tta']['magic']).'"'); 41 | unset($info['fileformat']); 42 | unset($info['audio']); 43 | unset($info['tta']); 44 | return false; 45 | } 46 | 47 | switch ($ttaheader[3]) { 48 | case "\x01": // TTA v1.x 49 | case "\x02": // TTA v1.x 50 | case "\x03": // TTA v1.x 51 | // "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year." 52 | $info['tta']['major_version'] = 1; 53 | $info['avdataoffset'] += 16; 54 | 55 | $info['tta']['compression_level'] = ord($ttaheader[3]); 56 | $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); 57 | $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); 58 | $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4)); 59 | $info['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); 60 | 61 | $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; 62 | $info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['tta']['sample_rate']; 63 | break; 64 | 65 | case '2': // TTA v2.x 66 | // "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4." 67 | $info['tta']['major_version'] = 2; 68 | $info['avdataoffset'] += 20; 69 | 70 | $info['tta']['compression_level'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); 71 | $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); 72 | $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2)); 73 | $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 2)); 74 | $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); 75 | $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4)); 76 | 77 | $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; 78 | $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; 79 | break; 80 | 81 | case '1': // TTA v3.x 82 | // "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher." 83 | $info['tta']['major_version'] = 3; 84 | $info['avdataoffset'] += 26; 85 | 86 | $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); // getid3_riff::wFormatTagLookup() 87 | $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); 88 | $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2)); 89 | $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 4)); 90 | $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 14, 4)); 91 | $info['tta']['crc32_footer'] = substr($ttaheader, 18, 4); 92 | $info['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4)); 93 | 94 | $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; 95 | break; 96 | 97 | default: 98 | $this->error('This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader[3]); 99 | return false; 100 | } 101 | 102 | $info['audio']['encoder'] = 'TTA v'.$info['tta']['major_version']; 103 | $info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample']; 104 | $info['audio']['sample_rate'] = $info['tta']['sample_rate']; 105 | $info['audio']['channels'] = $info['tta']['channels']; 106 | $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 107 | 108 | return true; 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.voc.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.voc.php // 12 | // module for analyzing Creative VOC Audio files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_voc extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $OriginalAVdataOffset = $info['avdataoffset']; 30 | $this->fseek($info['avdataoffset']); 31 | $VOCheader = $this->fread(26); 32 | 33 | $magic = 'Creative Voice File'; 34 | if (substr($VOCheader, 0, 19) != $magic) { 35 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($VOCheader, 0, 19)).'"'); 36 | return false; 37 | } 38 | 39 | // shortcuts 40 | $thisfile_audio = &$info['audio']; 41 | $info['voc'] = array(); 42 | $thisfile_voc = &$info['voc']; 43 | 44 | $info['fileformat'] = 'voc'; 45 | $thisfile_audio['dataformat'] = 'voc'; 46 | $thisfile_audio['bitrate_mode'] = 'cbr'; 47 | $thisfile_audio['lossless'] = true; 48 | $thisfile_audio['channels'] = 1; // might be overriden below 49 | $thisfile_audio['bits_per_sample'] = 8; // might be overriden below 50 | 51 | // byte # Description 52 | // ------ ------------------------------------------ 53 | // 00-12 'Creative Voice File' 54 | // 13 1A (eof to abort printing of file) 55 | // 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation) 56 | // 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) 57 | // 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) 58 | 59 | $thisfile_voc['header']['datablock_offset'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 20, 2)); 60 | $thisfile_voc['header']['minor_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 22, 1)); 61 | $thisfile_voc['header']['major_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1)); 62 | 63 | do { 64 | 65 | $BlockOffset = $this->ftell(); 66 | $BlockData = $this->fread(4); 67 | $BlockType = ord($BlockData[0]); 68 | $BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3)); 69 | $ThisBlock = array(); 70 | 71 | getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1); 72 | switch ($BlockType) { 73 | case 0: // Terminator 74 | // do nothing, we'll break out of the loop down below 75 | break; 76 | 77 | case 1: // Sound data 78 | $BlockData .= $this->fread(2); 79 | if ($info['avdataoffset'] <= $OriginalAVdataOffset) { 80 | $info['avdataoffset'] = $this->ftell(); 81 | } 82 | $this->fseek($BlockSize - 2, SEEK_CUR); 83 | 84 | $ThisBlock['sample_rate_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 1)); 85 | $ThisBlock['compression_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, 5, 1)); 86 | 87 | $ThisBlock['compression_name'] = $this->VOCcompressionTypeLookup($ThisBlock['compression_type']); 88 | if ($ThisBlock['compression_type'] <= 3) { 89 | $thisfile_voc['compressed_bits_per_sample'] = getid3_lib::CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name'])); 90 | } 91 | 92 | // Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available) 93 | if (empty($thisfile_audio['sample_rate'])) { 94 | // SR byte = 256 - (1000000 / sample_rate) 95 | $thisfile_audio['sample_rate'] = getid3_lib::trunc((1000000 / (256 - $ThisBlock['sample_rate_id'])) / $thisfile_audio['channels']); 96 | } 97 | break; 98 | 99 | case 2: // Sound continue 100 | case 3: // Silence 101 | case 4: // Marker 102 | case 6: // Repeat 103 | case 7: // End repeat 104 | // nothing useful, just skip 105 | $this->fseek($BlockSize, SEEK_CUR); 106 | break; 107 | 108 | case 8: // Extended 109 | $BlockData .= $this->fread(4); 110 | 111 | //00-01 Time Constant: 112 | // Mono: 65536 - (256000000 / sample_rate) 113 | // Stereo: 65536 - (256000000 / (sample_rate * 2)) 114 | $ThisBlock['time_constant'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 2)); 115 | $ThisBlock['pack_method'] = getid3_lib::LittleEndian2Int(substr($BlockData, 6, 1)); 116 | $ThisBlock['stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BlockData, 7, 1)); 117 | 118 | $thisfile_audio['channels'] = ($ThisBlock['stereo'] ? 2 : 1); 119 | $thisfile_audio['sample_rate'] = getid3_lib::trunc((256000000 / (65536 - $ThisBlock['time_constant'])) / $thisfile_audio['channels']); 120 | break; 121 | 122 | case 9: // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit 123 | $BlockData .= $this->fread(12); 124 | if ($info['avdataoffset'] <= $OriginalAVdataOffset) { 125 | $info['avdataoffset'] = $this->ftell(); 126 | } 127 | $this->fseek($BlockSize - 12, SEEK_CUR); 128 | 129 | $ThisBlock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4)); 130 | $ThisBlock['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($BlockData, 8, 1)); 131 | $ThisBlock['channels'] = getid3_lib::LittleEndian2Int(substr($BlockData, 9, 1)); 132 | $ThisBlock['wFormat'] = getid3_lib::LittleEndian2Int(substr($BlockData, 10, 2)); 133 | 134 | $ThisBlock['compression_name'] = $this->VOCwFormatLookup($ThisBlock['wFormat']); 135 | if ($this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) { 136 | $thisfile_voc['compressed_bits_per_sample'] = $this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']); 137 | } 138 | 139 | $thisfile_audio['sample_rate'] = $ThisBlock['sample_rate']; 140 | $thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample']; 141 | $thisfile_audio['channels'] = $ThisBlock['channels']; 142 | break; 143 | 144 | default: 145 | $this->warning('Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset); 146 | $this->fseek($BlockSize, SEEK_CUR); 147 | break; 148 | } 149 | 150 | if (!empty($ThisBlock)) { 151 | $ThisBlock['block_offset'] = $BlockOffset; 152 | $ThisBlock['block_size'] = $BlockSize; 153 | $ThisBlock['block_type_id'] = $BlockType; 154 | $thisfile_voc['blocks'][] = $ThisBlock; 155 | } 156 | 157 | } while (!feof($this->getid3->fp) && ($BlockType != 0)); 158 | 159 | // Terminator block doesn't have size field, so seek back 3 spaces 160 | $this->fseek(-3, SEEK_CUR); 161 | 162 | ksort($thisfile_voc['blocktypes']); 163 | 164 | if (!empty($thisfile_voc['compressed_bits_per_sample'])) { 165 | $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']); 166 | $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; 167 | } 168 | 169 | return true; 170 | } 171 | 172 | /** 173 | * @param int $index 174 | * 175 | * @return string 176 | */ 177 | public function VOCcompressionTypeLookup($index) { 178 | static $VOCcompressionTypeLookup = array( 179 | 0 => '8-bit', 180 | 1 => '4-bit', 181 | 2 => '2.6-bit', 182 | 3 => '2-bit' 183 | ); 184 | return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels'); 185 | } 186 | 187 | /** 188 | * @param int $index 189 | * 190 | * @return string|false 191 | */ 192 | public function VOCwFormatLookup($index) { 193 | static $VOCwFormatLookup = array( 194 | 0x0000 => '8-bit unsigned PCM', 195 | 0x0001 => 'Creative 8-bit to 4-bit ADPCM', 196 | 0x0002 => 'Creative 8-bit to 3-bit ADPCM', 197 | 0x0003 => 'Creative 8-bit to 2-bit ADPCM', 198 | 0x0004 => '16-bit signed PCM', 199 | 0x0006 => 'CCITT a-Law', 200 | 0x0007 => 'CCITT u-Law', 201 | 0x2000 => 'Creative 16-bit to 4-bit ADPCM' 202 | ); 203 | return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false); 204 | } 205 | 206 | /** 207 | * @param int $index 208 | * 209 | * @return int|false 210 | */ 211 | public function VOCwFormatActualBitsPerSampleLookup($index) { 212 | static $VOCwFormatLookup = array( 213 | 0x0000 => 8, 214 | 0x0001 => 4, 215 | 0x0002 => 3, 216 | 0x0003 => 2, 217 | 0x0004 => 16, 218 | 0x0006 => 8, 219 | 0x0007 => 8, 220 | 0x2000 => 4 221 | ); 222 | return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false); 223 | } 224 | 225 | } 226 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.audio.vqf.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.audio.vqf.php // 12 | // module for analyzing VQF audio files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_vqf extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | // based loosely on code from TTwinVQ by Jurgen Faul 30 | // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html 31 | 32 | $info['fileformat'] = 'vqf'; 33 | $info['audio']['dataformat'] = 'vqf'; 34 | $info['audio']['bitrate_mode'] = 'cbr'; 35 | $info['audio']['lossless'] = false; 36 | 37 | // shortcut 38 | $info['vqf']['raw'] = array(); 39 | $thisfile_vqf = &$info['vqf']; 40 | $thisfile_vqf_raw = &$thisfile_vqf['raw']; 41 | 42 | $this->fseek($info['avdataoffset']); 43 | $VQFheaderData = $this->fread(16); 44 | 45 | $offset = 0; 46 | $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4); 47 | $magic = 'TWIN'; 48 | if ($thisfile_vqf_raw['header_tag'] != $magic) { 49 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"'); 50 | unset($info['vqf']); 51 | unset($info['fileformat']); 52 | return false; 53 | } 54 | $offset += 4; 55 | $thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8); 56 | $offset += 8; 57 | $thisfile_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($VQFheaderData, $offset, 4)); 58 | $offset += 4; 59 | 60 | while ($this->ftell() < $info['avdataend']) { 61 | 62 | $ChunkBaseOffset = $this->ftell(); 63 | $chunkoffset = 0; 64 | $ChunkData = $this->fread(8); 65 | $ChunkName = substr($ChunkData, $chunkoffset, 4); 66 | if ($ChunkName == 'DATA') { 67 | $info['avdataoffset'] = $ChunkBaseOffset; 68 | break; 69 | } 70 | $chunkoffset += 4; 71 | $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); 72 | $chunkoffset += 4; 73 | if ($ChunkSize > ($info['avdataend'] - $this->ftell())) { 74 | $this->error('Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset); 75 | break; 76 | } 77 | if ($ChunkSize > 0) { 78 | $ChunkData .= $this->fread($ChunkSize); 79 | } 80 | 81 | switch ($ChunkName) { 82 | case 'COMM': 83 | // shortcut 84 | $thisfile_vqf['COMM'] = array(); 85 | $thisfile_vqf_COMM = &$thisfile_vqf['COMM']; 86 | 87 | $thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); 88 | $chunkoffset += 4; 89 | $thisfile_vqf_COMM['bitrate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); 90 | $chunkoffset += 4; 91 | $thisfile_vqf_COMM['sample_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); 92 | $chunkoffset += 4; 93 | $thisfile_vqf_COMM['security_level'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); 94 | $chunkoffset += 4; 95 | 96 | $info['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1; 97 | $info['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']); 98 | $info['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000; 99 | $info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000); 100 | 101 | if ($info['audio']['bitrate'] == 0) { 102 | $this->error('Corrupt VQF file: bitrate_audio == zero'); 103 | return false; 104 | } 105 | break; 106 | 107 | case 'NAME': 108 | case 'AUTH': 109 | case '(c) ': 110 | case 'FILE': 111 | case 'COMT': 112 | case 'ALBM': 113 | $thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8)); 114 | break; 115 | 116 | case 'DSIZ': 117 | $thisfile_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($ChunkData, 8, 4)); 118 | break; 119 | 120 | default: 121 | $this->warning('Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset); 122 | break; 123 | } 124 | } 125 | 126 | $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']; 127 | 128 | if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'))))) { 129 | switch ($thisfile_vqf['DSIZ']) { 130 | case 0: 131 | case 1: 132 | $this->warning('Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0'); 133 | $info['audio']['encoder'] = 'Ahead Nero'; 134 | break; 135 | 136 | default: 137 | $this->warning('Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'))); 138 | break; 139 | } 140 | } 141 | 142 | return true; 143 | } 144 | 145 | /** 146 | * @param int $frequencyid 147 | * 148 | * @return int 149 | */ 150 | public function VQFchannelFrequencyLookup($frequencyid) { 151 | static $VQFchannelFrequencyLookup = array( 152 | 11 => 11025, 153 | 22 => 22050, 154 | 44 => 44100 155 | ); 156 | return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000); 157 | } 158 | 159 | /** 160 | * @param string $shortname 161 | * 162 | * @return string 163 | */ 164 | public function VQFcommentNiceNameLookup($shortname) { 165 | static $VQFcommentNiceNameLookup = array( 166 | 'NAME' => 'title', 167 | 'AUTH' => 'artist', 168 | '(c) ' => 'copyright', 169 | 'FILE' => 'filename', 170 | 'COMT' => 'comment', 171 | 'ALBM' => 'album' 172 | ); 173 | return (isset($VQFcommentNiceNameLookup[$shortname]) ? $VQFcommentNiceNameLookup[$shortname] : $shortname); 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.graphic.efax.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.archive.efax.php // 12 | // module for analyzing eFax files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_efax extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $efaxheader = $this->fread(1024); 31 | 32 | $info['efax']['header']['magic'] = substr($efaxheader, 0, 2); 33 | if ($info['efax']['header']['magic'] != "\xDC\xFE") { 34 | $this->error('Invalid eFax byte order identifier (expecting DC FE, found '.getid3_lib::PrintHexBytes($info['efax']['header']['magic']).') at offset '.$info['avdataoffset']); 35 | return false; 36 | } 37 | $info['fileformat'] = 'efax'; 38 | 39 | $info['efax']['header']['filesize'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 2, 4)); 40 | if ($info['efax']['header']['filesize'] != $info['filesize']) { 41 | $this->error('Probable '.(($info['efax']['header']['filesize'] > $info['filesize']) ? 'truncated' : 'corrupt').' file, expecting '.$info['efax']['header']['filesize'].' bytes, found '.$info['filesize'].' bytes'); 42 | } 43 | $info['efax']['header']['software1'] = rtrim(substr($efaxheader, 26, 32), "\x00"); 44 | $info['efax']['header']['software2'] = rtrim(substr($efaxheader, 58, 32), "\x00"); 45 | $info['efax']['header']['software3'] = rtrim(substr($efaxheader, 90, 32), "\x00"); 46 | 47 | $info['efax']['header']['pages'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 198, 2)); 48 | $info['efax']['header']['data_bytes'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 202, 4)); 49 | 50 | $this->error('eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 51 | return false; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.graphic.pcd.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.graphic.pcd.php // 12 | // module for analyzing PhotoCD (PCD) Image files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | class getid3_pcd extends getid3_handler 21 | { 22 | public $ExtractData = 0; 23 | 24 | /** 25 | * @return bool 26 | */ 27 | public function Analyze() { 28 | $info = &$this->getid3->info; 29 | 30 | $info['fileformat'] = 'pcd'; 31 | $info['video']['dataformat'] = 'pcd'; 32 | $info['video']['lossless'] = false; 33 | 34 | 35 | $this->fseek($info['avdataoffset'] + 72); 36 | 37 | $PCDflags = $this->fread(1); 38 | $PCDisVertical = ((ord($PCDflags) & 0x01) ? true : false); 39 | 40 | 41 | if ($PCDisVertical) { 42 | $info['video']['resolution_x'] = 3072; 43 | $info['video']['resolution_y'] = 2048; 44 | } else { 45 | $info['video']['resolution_x'] = 2048; 46 | $info['video']['resolution_y'] = 3072; 47 | } 48 | 49 | 50 | if ($this->ExtractData > 3) { 51 | 52 | $this->error('Cannot extract PSD image data for detail levels above BASE (level-3) because encrypted with Kodak-proprietary compression/encryption.'); 53 | return false; 54 | 55 | } elseif ($this->ExtractData > 0) { 56 | 57 | $PCD_levels[1] = array( 192, 128, 0x02000); // BASE/16 58 | $PCD_levels[2] = array( 384, 256, 0x0B800); // BASE/4 59 | $PCD_levels[3] = array( 768, 512, 0x30000); // BASE 60 | //$PCD_levels[4] = array(1536, 1024, ??); // BASE*4 - encrypted with Kodak-proprietary compression/encryption 61 | //$PCD_levels[5] = array(3072, 2048, ??); // BASE*16 - encrypted with Kodak-proprietary compression/encryption 62 | //$PCD_levels[6] = array(6144, 4096, ??); // BASE*64 - encrypted with Kodak-proprietary compression/encryption; PhotoCD-Pro only 63 | 64 | list($PCD_width, $PCD_height, $PCD_dataOffset) = $PCD_levels[3]; 65 | 66 | $this->fseek($info['avdataoffset'] + $PCD_dataOffset); 67 | 68 | for ($y = 0; $y < $PCD_height; $y += 2) { 69 | // The image-data of these subtypes start at the respective offsets of 02000h, 0b800h and 30000h. 70 | // To decode the YcbYr to the more usual RGB-code, three lines of data have to be read, each 71 | // consisting of ‘w’ bytes, where ‘w’ is the width of the image-subtype. The first ‘w’ bytes and 72 | // the first half of the third ‘w’ bytes contain data for the first RGB-line, the second ‘w’ bytes 73 | // and the second half of the third ‘w’ bytes contain data for a second RGB-line. 74 | 75 | $PCD_data_Y1 = $this->fread($PCD_width); 76 | $PCD_data_Y2 = $this->fread($PCD_width); 77 | $PCD_data_Cb = $this->fread(intval(round($PCD_width / 2))); 78 | $PCD_data_Cr = $this->fread(intval(round($PCD_width / 2))); 79 | 80 | for ($x = 0; $x < $PCD_width; $x++) { 81 | if ($PCDisVertical) { 82 | $info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)])); 83 | $info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)])); 84 | } else { 85 | $info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)])); 86 | $info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2[$x]), ord($PCD_data_Cb[(int) floor($x / 2)]), ord($PCD_data_Cr[(int) floor($x / 2)])); 87 | } 88 | } 89 | } 90 | 91 | // Example for plotting extracted data 92 | //getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true); 93 | //if ($PCDisVertical) { 94 | // $BMPinfo['resolution_x'] = $PCD_height; 95 | // $BMPinfo['resolution_y'] = $PCD_width; 96 | //} else { 97 | // $BMPinfo['resolution_x'] = $PCD_width; 98 | // $BMPinfo['resolution_y'] = $PCD_height; 99 | //} 100 | //$BMPinfo['bmp']['data'] = $info['pcd']['data']; 101 | //getid3_bmp::PlotBMP($BMPinfo); 102 | //exit; 103 | 104 | } 105 | 106 | return false; 107 | } 108 | 109 | /** 110 | * @param int $Y 111 | * @param int $Cb 112 | * @param int $Cr 113 | * 114 | * @return int 115 | */ 116 | public function YCbCr2RGB($Y, $Cb, $Cr) { 117 | static $YCbCr_constants = array(); 118 | if (empty($YCbCr_constants)) { 119 | $YCbCr_constants['red']['Y'] = 0.0054980 * 256; 120 | $YCbCr_constants['red']['Cb'] = 0.0000000 * 256; 121 | $YCbCr_constants['red']['Cr'] = 0.0051681 * 256; 122 | $YCbCr_constants['green']['Y'] = 0.0054980 * 256; 123 | $YCbCr_constants['green']['Cb'] = -0.0015446 * 256; 124 | $YCbCr_constants['green']['Cr'] = -0.0026325 * 256; 125 | $YCbCr_constants['blue']['Y'] = 0.0054980 * 256; 126 | $YCbCr_constants['blue']['Cb'] = 0.0079533 * 256; 127 | $YCbCr_constants['blue']['Cr'] = 0.0000000 * 256; 128 | } 129 | 130 | $RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0); 131 | foreach ($RGBcolor as $rgbname => $dummy) { 132 | $RGBcolor[$rgbname] = max(0, 133 | min(255, 134 | intval( 135 | round( 136 | ($YCbCr_constants[$rgbname]['Y'] * $Y) + 137 | ($YCbCr_constants[$rgbname]['Cb'] * ($Cb - 156)) + 138 | ($YCbCr_constants[$rgbname]['Cr'] * ($Cr - 137)) 139 | ) 140 | ) 141 | ) 142 | ); 143 | } 144 | return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']); 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.graphic.svg.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.graphic.svg.php // 12 | // module for analyzing SVG Image files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_svg extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | 31 | $SVGheader = $this->fread(4096); 32 | if (preg_match('#\<\?xml([^\>]+)\?\>#i', $SVGheader, $matches)) { 33 | $info['svg']['xml']['raw'] = $matches; 34 | } 35 | if (preg_match('#\<\!DOCTYPE([^\>]+)\>#i', $SVGheader, $matches)) { 36 | $info['svg']['doctype']['raw'] = $matches; 37 | } 38 | if (preg_match('#\]+)\>#i', $SVGheader, $matches)) { 39 | $info['svg']['svg']['raw'] = $matches; 40 | } 41 | if (isset($info['svg']['svg']['raw'])) { 42 | 43 | $sections_to_fix = array('xml', 'doctype', 'svg'); 44 | foreach ($sections_to_fix as $section_to_fix) { 45 | if (!isset($info['svg'][$section_to_fix])) { 46 | continue; 47 | } 48 | $section_data = array(); 49 | while (preg_match('/ "([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) { 50 | $section_data[] = $matches[1]; 51 | $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]); 52 | } 53 | while (preg_match('/([^\s]+)="([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) { 54 | $section_data[] = $matches[0]; 55 | $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]); 56 | } 57 | $section_data = array_merge($section_data, preg_split('/[\s,]+/', $info['svg'][$section_to_fix]['raw'][1])); 58 | foreach ($section_data as $keyvaluepair) { 59 | $keyvaluepair = trim($keyvaluepair); 60 | if ($keyvaluepair) { 61 | $keyvalueexploded = explode('=', $keyvaluepair); 62 | $key = (isset($keyvalueexploded[0]) ? $keyvalueexploded[0] : ''); 63 | $value = (isset($keyvalueexploded[1]) ? $keyvalueexploded[1] : ''); 64 | $info['svg'][$section_to_fix]['sections'][$key] = trim($value, '"'); 65 | } 66 | } 67 | } 68 | 69 | $info['fileformat'] = 'svg'; 70 | $info['video']['dataformat'] = 'svg'; 71 | $info['video']['lossless'] = true; 72 | //$info['video']['bits_per_sample'] = 24; 73 | $info['video']['pixel_aspect_ratio'] = (float) 1; 74 | 75 | if (!empty($info['svg']['svg']['sections']['width'])) { 76 | $info['svg']['width'] = intval($info['svg']['svg']['sections']['width']); 77 | } 78 | if (!empty($info['svg']['svg']['sections']['height'])) { 79 | $info['svg']['height'] = intval($info['svg']['svg']['sections']['height']); 80 | } 81 | if (!empty($info['svg']['svg']['sections']['version'])) { 82 | $info['svg']['version'] = $info['svg']['svg']['sections']['version']; 83 | } 84 | if (!isset($info['svg']['version']) && isset($info['svg']['doctype']['sections'])) { 85 | foreach ($info['svg']['doctype']['sections'] as $key => $value) { 86 | if (preg_match('#//W3C//DTD SVG ([0-9\.]+)//#i', $key, $matches)) { 87 | $info['svg']['version'] = $matches[1]; 88 | break; 89 | } 90 | } 91 | } 92 | 93 | if (!empty($info['svg']['width'])) { 94 | $info['video']['resolution_x'] = $info['svg']['width']; 95 | } 96 | if (!empty($info['svg']['height'])) { 97 | $info['video']['resolution_y'] = $info['svg']['height']; 98 | } 99 | 100 | return true; 101 | } 102 | $this->error('Did not find expected tag'); 103 | return false; 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.misc.exe.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.misc.exe.php // 12 | // module for analyzing EXE files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_exe extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $EXEheader = $this->fread(28); 31 | 32 | $magic = 'MZ'; 33 | if (substr($EXEheader, 0, 2) != $magic) { 34 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($EXEheader, 0, 2)).'"'); 35 | return false; 36 | } 37 | 38 | $info['fileformat'] = 'exe'; 39 | $info['exe']['mz']['magic'] = 'MZ'; 40 | 41 | $info['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2)); 42 | $info['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2)); 43 | $info['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2)); 44 | $info['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2)); 45 | $info['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2)); 46 | $info['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2)); 47 | $info['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2)); 48 | $info['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2)); 49 | $info['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2)); 50 | $info['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4)); 51 | $info['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2)); 52 | $info['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2)); 53 | 54 | $info['exe']['mz']['byte_size'] = (($info['exe']['mz']['raw']['page_count'] - 1)) * 512 + $info['exe']['mz']['raw']['last_page_size']; 55 | $info['exe']['mz']['header_size'] = $info['exe']['mz']['raw']['header_paragraphs'] * 16; 56 | $info['exe']['mz']['memory_minimum'] = $info['exe']['mz']['raw']['min_memory_paragraphs'] * 16; 57 | $info['exe']['mz']['memory_recommended'] = $info['exe']['mz']['raw']['max_memory_paragraphs'] * 16; 58 | 59 | $this->error('EXE parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 60 | return false; 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.misc.msoffice.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.misc.msoffice.php // 12 | // module for analyzing MS Office (.doc, .xls, etc) files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_msoffice extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $this->fseek($info['avdataoffset']); 30 | $DOCFILEheader = $this->fread(8); 31 | $magic = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"; 32 | if (substr($DOCFILEheader, 0, 8) != $magic) { 33 | $this->error('Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.'); 34 | return false; 35 | } 36 | $info['fileformat'] = 'msoffice'; 37 | 38 | $this->error('MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 39 | return false; 40 | 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.misc.par2.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.misc.par2.php // 12 | // module for analyzing PAR2 files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_par2 extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $info['fileformat'] = 'par2'; 30 | 31 | $this->error('PAR2 parsing not enabled in this version of getID3()'); 32 | return false; 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/module.misc.pdf.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // module.misc.pdf.php // 12 | // module for analyzing PDF files // 13 | // dependencies: NONE // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | 21 | class getid3_pdf extends getid3_handler 22 | { 23 | /** 24 | * @return bool 25 | */ 26 | public function Analyze() { 27 | $info = &$this->getid3->info; 28 | 29 | $info['fileformat'] = 'pdf'; 30 | 31 | $this->error('PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']'); 32 | return false; 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/write.apetag.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // write.apetag.php // 12 | // module for writing APE tags // 13 | // dependencies: module.tag.apetag.php // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true); 21 | 22 | class getid3_write_apetag 23 | { 24 | /** 25 | * @var string 26 | */ 27 | public $filename; 28 | 29 | /** 30 | * @var array 31 | */ 32 | public $tag_data; 33 | 34 | /** 35 | * ReplayGain / MP3gain tags will be copied from old tag even if not passed in data. 36 | * 37 | * @var bool 38 | */ 39 | public $always_preserve_replaygain = true; 40 | 41 | /** 42 | * Any non-critical errors will be stored here. 43 | * 44 | * @var array 45 | */ 46 | public $warnings = array(); 47 | 48 | /** 49 | * Any critical errors will be stored here. 50 | * 51 | * @var array 52 | */ 53 | public $errors = array(); 54 | 55 | public function __construct() { 56 | } 57 | 58 | /** 59 | * @return bool 60 | */ 61 | public function WriteAPEtag() { 62 | // NOTE: All data passed to this function must be UTF-8 format 63 | 64 | $getID3 = new getID3; 65 | $ThisFileInfo = $getID3->analyze($this->filename); 66 | 67 | if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { 68 | if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) { 69 | // Current APE tag between Lyrics3 and ID3v1/EOF 70 | // This break Lyrics3 functionality 71 | if (!$this->DeleteAPEtag()) { 72 | return false; 73 | } 74 | $ThisFileInfo = $getID3->analyze($this->filename); 75 | } 76 | } 77 | 78 | if ($this->always_preserve_replaygain) { 79 | $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain'); 80 | foreach ($ReplayGainTagsToPreserve as $rg_key) { 81 | if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) { 82 | $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]; 83 | } 84 | } 85 | } 86 | 87 | if ($APEtag = $this->GenerateAPEtag()) { 88 | if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { 89 | $oldignoreuserabort = ignore_user_abort(true); 90 | flock($fp, LOCK_EX); 91 | 92 | $PostAPEdataOffset = $ThisFileInfo['avdataend']; 93 | if (isset($ThisFileInfo['ape']['tag_offset_end'])) { 94 | $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']); 95 | } 96 | if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) { 97 | $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']); 98 | } 99 | fseek($fp, $PostAPEdataOffset); 100 | $PostAPEdata = ''; 101 | if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) { 102 | $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset); 103 | } 104 | 105 | fseek($fp, $PostAPEdataOffset); 106 | if (isset($ThisFileInfo['ape']['tag_offset_start'])) { 107 | fseek($fp, $ThisFileInfo['ape']['tag_offset_start']); 108 | } 109 | ftruncate($fp, ftell($fp)); 110 | fwrite($fp, $APEtag, strlen($APEtag)); 111 | if (!empty($PostAPEdata)) { 112 | fwrite($fp, $PostAPEdata, strlen($PostAPEdata)); 113 | } 114 | flock($fp, LOCK_UN); 115 | fclose($fp); 116 | ignore_user_abort($oldignoreuserabort); 117 | return true; 118 | } 119 | } 120 | return false; 121 | } 122 | 123 | /** 124 | * @return bool 125 | */ 126 | public function DeleteAPEtag() { 127 | $getID3 = new getID3; 128 | $ThisFileInfo = $getID3->analyze($this->filename); 129 | if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) { 130 | if (getID3::is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { 131 | 132 | flock($fp, LOCK_EX); 133 | $oldignoreuserabort = ignore_user_abort(true); 134 | 135 | fseek($fp, $ThisFileInfo['ape']['tag_offset_end']); 136 | $DataAfterAPE = ''; 137 | if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) { 138 | $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']); 139 | } 140 | 141 | ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']); 142 | fseek($fp, $ThisFileInfo['ape']['tag_offset_start']); 143 | 144 | if (!empty($DataAfterAPE)) { 145 | fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE)); 146 | } 147 | 148 | flock($fp, LOCK_UN); 149 | fclose($fp); 150 | ignore_user_abort($oldignoreuserabort); 151 | 152 | return true; 153 | } 154 | return false; 155 | } 156 | return true; 157 | } 158 | 159 | /** 160 | * @return string|false 161 | */ 162 | public function GenerateAPEtag() { 163 | // NOTE: All data passed to this function must be UTF-8 format 164 | 165 | $items = array(); 166 | if (!is_array($this->tag_data)) { 167 | return false; 168 | } 169 | foreach ($this->tag_data as $key => $arrayofvalues) { 170 | if (!is_array($arrayofvalues)) { 171 | return false; 172 | } 173 | 174 | $valuestring = ''; 175 | foreach ($arrayofvalues as $value) { 176 | $valuestring .= str_replace("\x00", '', $value)."\x00"; 177 | } 178 | $valuestring = rtrim($valuestring, "\x00"); 179 | 180 | // Length of the assigned value in bytes 181 | $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4); 182 | 183 | //$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false); 184 | $tagitem .= "\x00\x00\x00\x00"; 185 | 186 | $tagitem .= $this->CleanAPEtagItemKey($key)."\x00"; 187 | $tagitem .= $valuestring; 188 | 189 | $items[] = $tagitem; 190 | 191 | } 192 | 193 | return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false); 194 | } 195 | 196 | /** 197 | * @param array $items 198 | * @param bool $isheader 199 | * 200 | * @return string 201 | */ 202 | public function GenerateAPEtagHeaderFooter(&$items, $isheader=false) { 203 | $tagdatalength = 0; 204 | foreach ($items as $itemdata) { 205 | $tagdatalength += strlen($itemdata); 206 | } 207 | 208 | $APEheader = 'APETAGEX'; 209 | $APEheader .= getid3_lib::LittleEndian2String(2000, 4); 210 | $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4); 211 | $APEheader .= getid3_lib::LittleEndian2String(count($items), 4); 212 | $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false); 213 | $APEheader .= str_repeat("\x00", 8); 214 | 215 | return $APEheader; 216 | } 217 | 218 | /** 219 | * @param bool $header 220 | * @param bool $footer 221 | * @param bool $isheader 222 | * @param int $encodingid 223 | * @param bool $readonly 224 | * 225 | * @return string 226 | */ 227 | public function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) { 228 | $APEtagFlags = array_fill(0, 4, 0); 229 | if ($header) { 230 | $APEtagFlags[0] |= 0x80; // Tag contains a header 231 | } 232 | if (!$footer) { 233 | $APEtagFlags[0] |= 0x40; // Tag contains no footer 234 | } 235 | if ($isheader) { 236 | $APEtagFlags[0] |= 0x20; // This is the header, not the footer 237 | } 238 | 239 | // 0: Item contains text information coded in UTF-8 240 | // 1: Item contains binary information °) 241 | // 2: Item is a locator of external stored information °°) 242 | // 3: reserved 243 | $APEtagFlags[3] |= ($encodingid << 1); 244 | 245 | if ($readonly) { 246 | $APEtagFlags[3] |= 0x01; // Tag or Item is Read Only 247 | } 248 | 249 | return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]); 250 | } 251 | 252 | /** 253 | * @param string $itemkey 254 | * 255 | * @return string 256 | */ 257 | public function CleanAPEtagItemKey($itemkey) { 258 | $itemkey = preg_replace("#[^\x20-\x7E]#i", '', $itemkey); 259 | 260 | // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html 261 | switch (strtoupper($itemkey)) { 262 | case 'EAN/UPC': 263 | case 'ISBN': 264 | case 'LC': 265 | case 'ISRC': 266 | $itemkey = strtoupper($itemkey); 267 | break; 268 | 269 | default: 270 | $itemkey = ucwords($itemkey); 271 | break; 272 | } 273 | return $itemkey; 274 | 275 | } 276 | 277 | } 278 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/write.id3v1.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // write.id3v1.php // 12 | // module for writing ID3v1 tags // 13 | // dependencies: module.tag.id3v1.php // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | if (!defined('GETID3_INCLUDEPATH')) { // prevent path-exposing attacks that access modules directly on public webservers 18 | exit; 19 | } 20 | getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true); 21 | 22 | class getid3_write_id3v1 23 | { 24 | /** 25 | * @var string 26 | */ 27 | public $filename; 28 | 29 | /** 30 | * @var int 31 | */ 32 | public $filesize; 33 | 34 | /** 35 | * @var array 36 | */ 37 | public $tag_data; 38 | 39 | /** 40 | * Any non-critical errors will be stored here. 41 | * 42 | * @var array 43 | */ 44 | public $warnings = array(); 45 | 46 | /** 47 | * Any critical errors will be stored here. 48 | * 49 | * @var array 50 | */ 51 | public $errors = array(); 52 | 53 | public function __construct() { 54 | } 55 | 56 | /** 57 | * @return bool 58 | */ 59 | public function WriteID3v1() { 60 | // File MUST be writeable - CHMOD(646) at least 61 | if (!empty($this->filename) && is_readable($this->filename) && getID3::is_writable($this->filename) && is_file($this->filename)) { 62 | $this->setRealFileSize(); 63 | if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) { 64 | $this->errors[] = 'Unable to WriteID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; 65 | return false; 66 | } 67 | if ($fp_source = fopen($this->filename, 'r+b')) { 68 | fseek($fp_source, -128, SEEK_END); 69 | if (fread($fp_source, 3) == 'TAG') { 70 | fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag 71 | } else { 72 | fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag 73 | } 74 | $this->tag_data['track_number'] = (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : ''); 75 | 76 | $new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag( 77 | (isset($this->tag_data['title'] ) ? $this->tag_data['title'] : ''), 78 | (isset($this->tag_data['artist'] ) ? $this->tag_data['artist'] : ''), 79 | (isset($this->tag_data['album'] ) ? $this->tag_data['album'] : ''), 80 | (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''), 81 | (isset($this->tag_data['genreid'] ) ? $this->tag_data['genreid'] : ''), 82 | (isset($this->tag_data['comment'] ) ? $this->tag_data['comment'] : ''), 83 | (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : '')); 84 | fwrite($fp_source, $new_id3v1_tag_data, 128); 85 | fclose($fp_source); 86 | return true; 87 | 88 | } else { 89 | $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")'; 90 | return false; 91 | } 92 | } 93 | $this->errors[] = 'File is not writeable: '.$this->filename; 94 | return false; 95 | } 96 | 97 | /** 98 | * @return bool 99 | */ 100 | public function FixID3v1Padding() { 101 | // ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces 102 | // This function rewrites the ID3v1 tag with correct padding 103 | 104 | // Initialize getID3 engine 105 | $getID3 = new getID3; 106 | $getID3->option_tag_id3v2 = false; 107 | $getID3->option_tag_apetag = false; 108 | $getID3->option_tags_html = false; 109 | $getID3->option_extra_info = false; 110 | $getID3->option_tag_id3v1 = true; 111 | $ThisFileInfo = $getID3->analyze($this->filename); 112 | if (isset($ThisFileInfo['tags']['id3v1'])) { 113 | $id3v1data = array(); 114 | foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) { 115 | $id3v1data[$key] = implode(',', $value); 116 | } 117 | $this->tag_data = $id3v1data; 118 | return $this->WriteID3v1(); 119 | } 120 | return false; 121 | } 122 | 123 | /** 124 | * @return bool 125 | */ 126 | public function RemoveID3v1() { 127 | // File MUST be writeable - CHMOD(646) at least 128 | if (!empty($this->filename) && is_readable($this->filename) && getID3::is_writable($this->filename) && is_file($this->filename)) { 129 | $this->setRealFileSize(); 130 | if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) { 131 | $this->errors[] = 'Unable to RemoveID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; 132 | return false; 133 | } 134 | if ($fp_source = fopen($this->filename, 'r+b')) { 135 | 136 | fseek($fp_source, -128, SEEK_END); 137 | if (fread($fp_source, 3) == 'TAG') { 138 | ftruncate($fp_source, $this->filesize - 128); 139 | } else { 140 | // no ID3v1 tag to begin with - do nothing 141 | } 142 | fclose($fp_source); 143 | return true; 144 | 145 | } else { 146 | $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")'; 147 | } 148 | } else { 149 | $this->errors[] = $this->filename.' is not writeable'; 150 | } 151 | return false; 152 | } 153 | 154 | /** 155 | * @return bool 156 | */ 157 | public function setRealFileSize() { 158 | if (PHP_INT_MAX > 2147483647) { 159 | $this->filesize = filesize($this->filename); 160 | return true; 161 | } 162 | // 32-bit PHP will not return correct values for filesize() if file is >=2GB 163 | // but getID3->analyze() has workarounds to get actual filesize 164 | $getID3 = new getID3; 165 | $getID3->option_tag_id3v1 = false; 166 | $getID3->option_tag_id3v2 = false; 167 | $getID3->option_tag_apetag = false; 168 | $getID3->option_tags_html = false; 169 | $getID3->option_extra_info = false; 170 | $ThisFileInfo = $getID3->analyze($this->filename); 171 | $this->filesize = $ThisFileInfo['filesize']; 172 | return true; 173 | } 174 | 175 | } 176 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/write.lyrics3.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // write.lyrics3.php // 12 | // module for writing Lyrics3 tags // 13 | // dependencies: module.tag.lyrics3.php // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | 18 | class getid3_write_lyrics3 19 | { 20 | /** 21 | * @var string 22 | */ 23 | public $filename; 24 | 25 | /** 26 | * @var array 27 | */ 28 | public $tag_data; 29 | //public $lyrics3_version = 2; // 1 or 2 30 | 31 | /** 32 | * Any non-critical errors will be stored here. 33 | * 34 | * @var array 35 | */ 36 | public $warnings = array(); 37 | 38 | /** 39 | * Any critical errors will be stored here. 40 | * 41 | * @var array 42 | */ 43 | public $errors = array(); 44 | 45 | public function __construct() { 46 | } 47 | 48 | /** 49 | * @return bool 50 | */ 51 | public function WriteLyrics3() { 52 | $this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3'; 53 | return false; 54 | } 55 | 56 | /** 57 | * @return bool 58 | */ 59 | public function DeleteLyrics3() { 60 | // Initialize getID3 engine 61 | $getID3 = new getID3; 62 | $ThisFileInfo = $getID3->analyze($this->filename); 63 | if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { 64 | if (is_readable($this->filename) && getID3::is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { 65 | 66 | flock($fp, LOCK_EX); 67 | $oldignoreuserabort = ignore_user_abort(true); 68 | 69 | fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end']); 70 | $DataAfterLyrics3 = ''; 71 | if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) { 72 | $DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']); 73 | } 74 | 75 | ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']); 76 | 77 | if (!empty($DataAfterLyrics3)) { 78 | fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start']); 79 | fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3)); 80 | } 81 | 82 | flock($fp, LOCK_UN); 83 | fclose($fp); 84 | ignore_user_abort($oldignoreuserabort); 85 | 86 | return true; 87 | 88 | } else { 89 | $this->errors[] = 'Cannot fopen('.$this->filename.', "a+b")'; 90 | return false; 91 | } 92 | } 93 | // no Lyrics3 present 94 | return true; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/write.metaflac.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | // see readme.txt for more details // 9 | ///////////////////////////////////////////////////////////////// 10 | // // 11 | // write.metaflac.php // 12 | // module for writing metaflac tags // 13 | // dependencies: /helperapps/metaflac.exe // 14 | // /// 15 | ///////////////////////////////////////////////////////////////// 16 | 17 | 18 | class getid3_write_metaflac 19 | { 20 | /** 21 | * @var string 22 | */ 23 | public $filename; 24 | 25 | /** 26 | * @var array 27 | */ 28 | public $tag_data; 29 | 30 | /** 31 | * Any non-critical errors will be stored here. 32 | * 33 | * @var array 34 | */ 35 | public $warnings = array(); 36 | 37 | /** 38 | * Any critical errors will be stored here. 39 | * 40 | * @var array 41 | */ 42 | public $errors = array(); 43 | 44 | private $pictures = array(); 45 | 46 | public function __construct() { 47 | } 48 | 49 | /** 50 | * @return bool 51 | */ 52 | public function WriteMetaFLAC() { 53 | 54 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { 55 | $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written'; 56 | return false; 57 | } 58 | 59 | $tempfilenames = array(); 60 | 61 | 62 | if (!empty($this->tag_data['ATTACHED_PICTURE'])) { 63 | foreach ($this->tag_data['ATTACHED_PICTURE'] as $key => $picturedetails) { 64 | $temppicturefilename = tempnam(GETID3_TEMP_DIR, 'getID3'); 65 | $tempfilenames[] = $temppicturefilename; 66 | if (getID3::is_writable($temppicturefilename) && is_file($temppicturefilename) && ($fpcomments = fopen($temppicturefilename, 'wb'))) { 67 | // https://xiph.org/flac/documentation_tools_flac.html#flac_options_picture 68 | // [TYPE]|[MIME-TYPE]|[DESCRIPTION]|[WIDTHxHEIGHTxDEPTH[/COLORS]]|FILE 69 | fwrite($fpcomments, $picturedetails['data']); 70 | fclose($fpcomments); 71 | $picture_typeid = (!empty($picturedetails['picturetypeid']) ? $this->ID3v2toFLACpictureTypes($picturedetails['picturetypeid']) : 3); // default to "3:Cover (front)" 72 | $picture_mimetype = (!empty($picturedetails['mime']) ? $picturedetails['mime'] : ''); // should be auto-detected 73 | $picture_width_height_depth = ''; 74 | $this->pictures[] = $picture_typeid.'|'.$picture_mimetype.'|'.preg_replace('#[^\x20-\x7B\x7D-\x7F]#', '', $picturedetails['description']).'|'.$picture_width_height_depth.'|'.$temppicturefilename; 75 | } else { 76 | $this->errors[] = 'failed to open temporary tags file, tags not written - fopen("'.$temppicturefilename.'", "wb")'; 77 | return false; 78 | } 79 | } 80 | unset($this->tag_data['ATTACHED_PICTURE']); 81 | } 82 | 83 | 84 | // Create file with new comments 85 | $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3'); 86 | $tempfilenames[] = $tempcommentsfilename; 87 | if (getID3::is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) { 88 | foreach ($this->tag_data as $key => $value) { 89 | foreach ($value as $commentdata) { 90 | fwrite($fpcomments, $this->CleanmetaflacName($key).'='.$commentdata."\n"); 91 | } 92 | } 93 | fclose($fpcomments); 94 | 95 | } else { 96 | $this->errors[] = 'failed to open temporary tags file, tags not written - fopen("'.$tempcommentsfilename.'", "wb")'; 97 | return false; 98 | } 99 | 100 | $oldignoreuserabort = ignore_user_abort(true); 101 | if (GETID3_OS_ISWINDOWS) { 102 | 103 | if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { 104 | //$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-all-tags --import-tags-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; 105 | // metaflac works fine if you copy-paste the above commandline into a command prompt, 106 | // but refuses to work with `backtick` if there are "doublequotes" present around BOTH 107 | // the metaflac pathname and the target filename. For whatever reason...?? 108 | // The solution is simply ensure that the metaflac pathname has no spaces, 109 | // and therefore does not need to be quoted 110 | 111 | // On top of that, if error messages are not always captured properly under Windows 112 | // To at least see if there was a problem, compare file modification timestamps before and after writing 113 | clearstatcache(); 114 | $timestampbeforewriting = filemtime($this->filename); 115 | 116 | $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename); 117 | foreach ($this->pictures as $picturecommand) { 118 | $commandline .= ' --import-picture-from='.escapeshellarg($picturecommand); 119 | } 120 | $commandline .= ' '.escapeshellarg($this->filename).' 2>&1'; 121 | $metaflacError = `$commandline`; 122 | 123 | if (empty($metaflacError)) { 124 | clearstatcache(); 125 | if ($timestampbeforewriting == filemtime($this->filename)) { 126 | $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written'; 127 | } 128 | } 129 | } else { 130 | $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; 131 | } 132 | 133 | } else { 134 | 135 | // It's simpler on *nix 136 | $commandline = 'metaflac --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename); 137 | foreach ($this->pictures as $picturecommand) { 138 | $commandline .= ' --import-picture-from='.escapeshellarg($picturecommand); 139 | } 140 | $commandline .= ' '.escapeshellarg($this->filename).' 2>&1'; 141 | $metaflacError = `$commandline`; 142 | 143 | } 144 | 145 | // Remove temporary comments file 146 | foreach ($tempfilenames as $tempfilename) { 147 | unlink($tempfilename); 148 | } 149 | ignore_user_abort($oldignoreuserabort); 150 | 151 | if (!empty($metaflacError)) { 152 | 153 | $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; 154 | return false; 155 | 156 | } 157 | 158 | return true; 159 | } 160 | 161 | /** 162 | * @return bool 163 | */ 164 | public function DeleteMetaFLAC() { 165 | 166 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { 167 | $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted'; 168 | return false; 169 | } 170 | 171 | $oldignoreuserabort = ignore_user_abort(true); 172 | if (GETID3_OS_ISWINDOWS) { 173 | 174 | if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { 175 | // To at least see if there was a problem, compare file modification timestamps before and after writing 176 | clearstatcache(); 177 | $timestampbeforewriting = filemtime($this->filename); 178 | 179 | $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-all-tags "'.$this->filename.'" 2>&1'; 180 | $metaflacError = `$commandline`; 181 | 182 | if (empty($metaflacError)) { 183 | clearstatcache(); 184 | if ($timestampbeforewriting == filemtime($this->filename)) { 185 | $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted'; 186 | } 187 | } 188 | } else { 189 | $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; 190 | } 191 | 192 | } else { 193 | 194 | // It's simpler on *nix 195 | $commandline = 'metaflac --remove-all-tags "'.$this->filename.'" 2>&1'; 196 | $metaflacError = `$commandline`; 197 | 198 | } 199 | 200 | ignore_user_abort($oldignoreuserabort); 201 | 202 | if (!empty($metaflacError)) { 203 | $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; 204 | return false; 205 | } 206 | return true; 207 | } 208 | 209 | /** 210 | * @param int $id3v2_picture_typeid 211 | * 212 | * @return int 213 | */ 214 | public function ID3v2toFLACpictureTypes($id3v2_picture_typeid) { 215 | // METAFLAC picture type list is identical to ID3v2 picture type list (as least up to 0x14 "Publisher/Studio logotype") 216 | // http://id3.org/id3v2.4.0-frames (section 4.14) 217 | // https://xiph.org/flac/documentation_tools_flac.html#flac_options_picture 218 | //return (isset($ID3v2toFLACpictureTypes[$id3v2_picture_typeid]) ? $ID3v2toFLACpictureTypes[$id3v2_picture_typeid] : 3); // default: "3: Cover (front)" 219 | return (($id3v2_picture_typeid <= 0x14) ? $id3v2_picture_typeid : 3); // default: "3: Cover (front)" 220 | } 221 | 222 | /** 223 | * @param string $originalcommentname 224 | * 225 | * @return string 226 | */ 227 | public function CleanmetaflacName($originalcommentname) { 228 | // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. 229 | // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through 230 | // 0x7A inclusive (a-z). 231 | 232 | // replace invalid chars with a space, return uppercase text 233 | // Thanks Chris Bolt for improving this function 234 | // note: *reg_replace() replaces nulls with empty string (not space) 235 | return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname))); 236 | } 237 | 238 | } 239 | -------------------------------------------------------------------------------- /@/php-getid3/getid3/write.vorbiscomment.php: -------------------------------------------------------------------------------- 1 | // 5 | // available at https://github.com/JamesHeinrich/getID3 // 6 | // or https://www.getid3.org // 7 | // or http://getid3.sourceforge.net // 8 | ///////////////////////////////////////////////////////////////// 9 | // see readme.txt for more details // 10 | ///////////////////////////////////////////////////////////////// 11 | // // 12 | // write.vorbiscomment.php // 13 | // module for writing VorbisComment tags // 14 | // dependencies: /helperapps/vorbiscomment.exe // 15 | // /// 16 | ///////////////////////////////////////////////////////////////// 17 | 18 | 19 | class getid3_write_vorbiscomment 20 | { 21 | /** 22 | * @var string 23 | */ 24 | public $filename; 25 | 26 | /** 27 | * @var array 28 | */ 29 | public $tag_data; 30 | 31 | /** 32 | * Any non-critical errors will be stored here. 33 | * 34 | * @var array 35 | */ 36 | public $warnings = array(); 37 | 38 | /** 39 | * Any critical errors will be stored here. 40 | * 41 | * @var array 42 | */ 43 | public $errors = array(); 44 | 45 | public function __construct() { 46 | } 47 | 48 | /** 49 | * @return bool 50 | */ 51 | public function WriteVorbisComment() { 52 | 53 | if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { 54 | $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written'; 55 | return false; 56 | } 57 | 58 | // Create file with new comments 59 | $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3'); 60 | if (getID3::is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) { 61 | 62 | foreach ($this->tag_data as $key => $value) { 63 | foreach ($value as $commentdata) { 64 | fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n"); 65 | } 66 | } 67 | fclose($fpcomments); 68 | 69 | } else { 70 | $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written'; 71 | return false; 72 | } 73 | 74 | $oldignoreuserabort = ignore_user_abort(true); 75 | if (GETID3_OS_ISWINDOWS) { 76 | 77 | if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { 78 | //$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; 79 | // vorbiscomment works fine if you copy-paste the above commandline into a command prompt, 80 | // but refuses to work with `backtick` if there are "doublequotes" present around BOTH 81 | // the metaflac pathname and the target filename. For whatever reason...?? 82 | // The solution is simply ensure that the metaflac pathname has no spaces, 83 | // and therefore does not need to be quoted 84 | 85 | // On top of that, if error messages are not always captured properly under Windows 86 | // To at least see if there was a problem, compare file modification timestamps before and after writing 87 | clearstatcache(); 88 | $timestampbeforewriting = filemtime($this->filename); 89 | 90 | $commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; 91 | $VorbiscommentError = `$commandline`; 92 | 93 | if (empty($VorbiscommentError)) { 94 | clearstatcache(); 95 | if ($timestampbeforewriting == filemtime($this->filename)) { 96 | $VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written'; 97 | } 98 | } 99 | } else { 100 | $VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; 101 | } 102 | 103 | } else { 104 | 105 | $commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; 106 | $VorbiscommentError = `$commandline`; 107 | 108 | } 109 | 110 | // Remove temporary comments file 111 | unlink($tempcommentsfilename); 112 | ignore_user_abort($oldignoreuserabort); 113 | 114 | if (!empty($VorbiscommentError)) { 115 | 116 | $this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError; 117 | return false; 118 | 119 | } 120 | 121 | return true; 122 | } 123 | 124 | /** 125 | * @return bool 126 | */ 127 | public function DeleteVorbisComment() { 128 | $this->tag_data = array(array()); 129 | return $this->WriteVorbisComment(); 130 | } 131 | 132 | /** 133 | * @param string $originalcommentname 134 | * 135 | * @return string 136 | */ 137 | public function CleanVorbisCommentName($originalcommentname) { 138 | // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. 139 | // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through 140 | // 0x7A inclusive (a-z). 141 | 142 | // replace invalid chars with a space, return uppercase text 143 | // Thanks Chris Bolt for improving this function 144 | // note: *reg_replace() replaces nulls with empty string (not space) 145 | return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname))); 146 | 147 | } 148 | 149 | } 150 | -------------------------------------------------------------------------------- /@/php-getid3/license.txt: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////// 2 | /// getID3() by James Heinrich // 3 | // available at http://getid3.sourceforge.net // 4 | // or https://www.getid3.org // 5 | // also https://github.com/JamesHeinrich/getID3 // 6 | ///////////////////////////////////////////////////////////////// 7 | 8 | ***************************************************************** 9 | ***************************************************************** 10 | 11 | getID3() is released under multiple licenses. You may choose 12 | from the following licenses, and use getID3 according to the 13 | terms of the license most suitable to your project. 14 | 15 | GNU GPL: https://gnu.org/licenses/gpl.html (v3) 16 | https://gnu.org/licenses/old-licenses/gpl-2.0.html (v2) 17 | https://gnu.org/licenses/old-licenses/gpl-1.0.html (v1) 18 | 19 | GNU LGPL: https://gnu.org/licenses/lgpl.html (v3) 20 | 21 | Mozilla MPL: https://www.mozilla.org/MPL/2.0/ (v2) 22 | 23 | getID3 Commercial License: https://www.getid3.org/#gCL (payment required) 24 | 25 | ***************************************************************** 26 | ***************************************************************** 27 | 28 | Copies of each of the above licenses are included in the 'licenses' 29 | directory of the getID3 distribution. 30 | -------------------------------------------------------------------------------- /@/php-getid3/licenses/license.commercial.txt: -------------------------------------------------------------------------------- 1 | getID3() Commercial License 2 | =========================== 3 | 4 | getID3() is licensed under the "GNU Public License" (GPL) and/or the 5 | "getID3() Commercial License" (gCL). This document describes the gCL. 6 | 7 | --------------------------------------------------------------------- 8 | 9 | The license is non-exclusively granted to a single person or company, 10 | per payment of the license fee, for the lifetime of that person or 11 | company. The license is non-transferrable. 12 | 13 | The gCL grants the licensee the right to use getID3() in commercial 14 | closed-source projects. Modifications may be made to getID3() with no 15 | obligation to release the modified source code. getID3() (or pieces 16 | thereof) may be included in any number of projects authored (in whole 17 | or in part) by the licensee. 18 | 19 | The licensee may use any version of getID3(), past, present or future, 20 | as is most convenient. This license does not entitle the licensee to 21 | receive any technical support, updates or bugfixes, except as such are 22 | made publicly available to all getID3() users. 23 | 24 | The licensee may not sub-license getID3() itself, meaning that any 25 | commercially released product containing all or parts of getID3() must 26 | have added functionality beyond what is available in getID3(); 27 | getID3() itself may not be re-licensed by the licensee. 28 | -------------------------------------------------------------------------------- /@/php-getid3/licenses/license.lgpl-30.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## version 3.0.0 | *Date: 07/04/2020* 5 | | **Changed** | | 6 | | :---: | --- | 7 | | - | New style of Playlist Page ( Material ). | 8 | | - | Improved on playlist system. | 9 | | **Added** | | 10 | | - | Music controls on browser notification | 11 | 12 | 13 | ## version 2.0.0 | *Date: 26/03/2020* 14 | | **Added** | | 15 | | :---: | --- | 16 | | - | Check for duplicated tracks on upload. | 17 | | - | New audio type are supported: (mp3,ogg) + m4a, webm. | 18 | | **Changed** | | 19 | | - | Now php is in object orientated code (up/dj.php). | 20 | | - | Improved upload system. | 21 | 22 | 23 | ## version 0.9.9 | *Date: 23/03/2020* 24 | | **Changed** | | 25 | | :---: | --- | 26 | | - | Fixed security issue in admin panel. | 27 | | **Removed** | | 28 | | - | PHP library to upload files. | 29 | 30 | ## version 0.9.8 | *Date: 23/03/2020* 31 | | **Added** | | 32 | | :---: | --- | 33 | | - | Login on admin panel. | 34 | | - | First signup on admin panel. | 35 | | **Changed** | | 36 | | - | Start using PHP/Javascript for track upload. | 37 | | - | Fixed some graphics bugs. | 38 | | **Removed** | | 39 | | - | PHP library to get audio lenght. | 40 | 41 | 42 | ## version 0.7.9 | *Date: 22/03/2020* 43 | | **Added** | | 44 | | :---: | --- | 45 | | - | "Remove a track" section on admin panel. | 46 | | **Changed** | | 47 | | - | Page style on admin panel. | 48 | 49 | ## version 0.7.8 | *Date: 21/03/2020* 50 | | **Changed** | | 51 | | :---: | --- | 52 | | - | Start using Changelog. | 53 | 54 | 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Greco Domenico 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written consent to the following 19 | email address: gr3music.license@greco395.it. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 25 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | # IGNORE THIS FILE (can delete) 3 | -------------------------------------------------------------------------------- /media/.not_delete_ThisFolder: -------------------------------------------------------------------------------- 1 | # not delete This Folder but can delete this file 2 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | GR3Music Player is a simple HTML5/PHP Audio player that supports [_modern_](https://updatemybrowser.org/) browsers - *ONLY* for Linux host. 2 | 3 | [Checkout the demo](https://gr3studios.com/projects/GR3Music/) - [Donate](#donate) 4 | 5 | [![Image of GR3Music](https://gr3studios.com/projects/GR3Music/docs/screen.jpg)](https://greco395.com/projects/GR3Music/) 6 | 7 | # Features 8 | 9 | - 📼 **Supported Extensions** - support for mp3, ogg, webm and m4a. 10 | - 💪 **Modern design** - the website is designed with the google material design. 11 | - 📱 **Responsive** - works with any screen size. 12 | 13 | # To do 14 | 15 | - [x] Login in management panel (v2) 16 | - [x] Support other audio type (v2) 17 | - [x] Style in Material design (v3) 18 | - [ ] Multiple playlist 19 | - [ ] Offline play 20 | 21 | # Installation 22 | Installing this script is really simple, just upload it to the server in the public folder (from VPS for example in /var/www/). Then go on your website to the folder containing the script for configuring the admin panel, example: 23 | ``` 24 | http://yourwebsite.com/folderTo/php-Music-Player-master/up/ 25 | ``` 26 | 27 | # Donate 28 | 29 | Support my job with a Donation, any help with costs is appreciated... 30 | 31 | - [Donate via PayPal](https://paypal.me/greco395) 32 | - [Buy me a coffee](https://www.buymeacoffee.com/greco395) 33 | 34 | 35 | [Powered by Domenico Greco](https://domenicogreco.com/) 36 | -------------------------------------------------------------------------------- /up/tmp/.not_delete_ThisFolder: -------------------------------------------------------------------------------- 1 | # not delete This Folder but can delete this file 2 | --------------------------------------------------------------------------------