ICANN), ## adding a "x-" before the subtype ## 1. /usr/local/apache/conf/mime.types.default ## 2. http://sander.vanzoest.com/talks/apachecon/2001/notes/notes_apachecon.txt ## 3. http://www.mp3dev.org/ support mp3 bitrate(use lame) ## 4. RFC 1806, The Content-Disposition Header ## 5. RFC 3003, The audio/mpeg Media Type ## 6. vorbis OGG : http://www.xiph.org/ and http://www.vorbis.com/faq.psp ## ## [test] ## 1. Linux/2.4 (redhat 7.x) ## 2. Apache/1.3.x ## 3. PHP/4.2.x PHP/4.1.x, PHP/4.0.x ## 4. useragent : ## - MSIE5/6 ## - netscape/4,6 (linux,win) ## - mozilla/0.9.x(linux) ## - xmms/1.2.x(linux) : ok ## - winamp(win) : ok ## - winmap3(win) : ok ## - Zinf(FreeAMP) : ok ## - XMPlay(win) : ok ## - RMA, RealMedia-Player(win) : ok ## - Window-Media-Player(win) : fail ## - NSPlayer(win) : fail ## 5. test only *.mp3(korean file name success) ## 6. support lame(only *.mp3 bitrate) ## 7. support access log write(options) ## 8. support direct access(such as xmms, winamp ...) ## 9. support vorbis OGG file ## ## [TODO] - I just think. ## 1. user auth(option) ## 2. check more useragent ## 3. more useragent support ## 4. ID3tag support ## 5. mp3 list view and select playing(unit readdir()). ## 6. etc, .... T.T ## ## enjoy !!! ## ##################################################### ## //session_start(); /*** function session_mp3list($MP3LIST) { session_register('MP3LIST'); } ***/ ## do not set to $GLOBALS in $array ## $GLOBALS dump : _var_dump(get_defined_vars()) ## function _var_dump($array, $name='', $constants=0) { foreach($array AS $k=>$v) { $var = $name ? "${name}[\"$k\"]" : $k; if(!$constants) $var = '$'.$var; echo "$var = $v
\n"; if(is_array($v) && sizeof($v)>0) { echo "\n"; } } } ## if you using the PHP/4.0.x ## http://www.php.net/ChangeLog-4.php ## function _globals() { global $_SERVER; // add user vars for 4.0.x if(preg_match('/^4\.0/',PHP_VERSION)) { $GLOBALS[_SERVER] = array_merge($GLOBALS[HTTP_SERVER_VARS],$_SERVER); $GLOBALS[_GET] = $GLOBALS[HTTP_GET_VARS]; $GLOBALS[_POST] = $GLOBALS[HTTP_POST_VARS]; $GLOBALS[_COOKIE] = $GLOBALS[HTTP_COOKIE_VARS]; $GLOBALS[_SESSION] = $GLOBALS[HTTP_SESSION_VARS]; $GLOBALS[_ENV] = $GLOBALS[HTTP_ENV_VARS]; $GLOBALS[_FILES] = $GLOBALS[HTTP_POST_FILES]; // ??? $GLOBALS[_REQUEST] = array_merge($_GET,$_COOKIE); } } function check_useragent() { global $_SERVER; $player = 'xmms|Winamp|RMA|Zinf|XMPlay|FreeAMP|RealMedia|Player'; if(preg_match("/$player/i",$_SERVER[HTTP_USER_AGENT])) { return 1; } } ## check for vorbis OGG file ## function get_ftype($file) { if(preg_match('/\.ogg$/i',$file)) { $ftype[subtype] = 'application/x-ogg'; $ftype[ext] = '&.ogg'; // good idea ??? } else $ftype[subtype] = 'audio/mpeg'; return $ftype; } ## mp3 stream core module ## function php_mp3stream($mp3file, $lame='', $ftype='') { $file[name] = basename($mp3file); $file[size] = filesize($mp3file); clearstatcache(); // flush buffer if(is_executable($lame) && !$ftype[ext]) { clearstatcache(); // flush buffer $mp3file = "$lame -q 3 -b 64 -m m -S --quiet --silent ". "--tt '$file[name]' '$mp3file' - 2>/dev/null"; $open = 'popen'; } else $open = 'fopen'; if(!$ftype[subtype]) $ftype[subtype] = 'audio/mpeg'; if($fp = @$open($mp3file,r)) { header("Content-Type: $ftype[subtype]"); header("Content-Disposition: filename=$file[name]"); header('Content-Transfer-Encoding: binary'); header("Content-Length: $file[size]"); // check(do not win32 agent) fpassthru($fp); } } ## mp3 playlist core module ## 2002.05.15 patch random play(for direct access BAD user) ## function php_mp3plist($mp3_dir, $mp3list='', $player='') // $mp3list = array(); { global $_SERVER; if(is_array($mp3list)) { if($player) { // for BAD user $randkey = array_rand($mp3list); if(is_readable("$mp3_dir/".agent_decode($randfile=$mp3list[$randkey]))) { $ftype = get_ftype($randfile); header("Location: http://$_SERVER[HTTP_HOST]$_SERVER[_PHP_SELF]". "?stream=$randfile$ftype[ext]"); } exit; } header('Content-Disposition: inline; filename=playlist_lcn.m3u'); header('Content-Type: audio/x-mpegurl'); foreach($mp3list AS $k=>$v) { if(is_readable($mp3file="$mp3_dir/".agent_decode($v))) { $ftype = get_ftype($mp3file); echo "http://$_SERVER[HTTP_HOST]$_SERVER[_PHP_SELF]". "?stream=$v$ftype[ext]\n"; } } } else exit; // stop } ## check and go stream module ## request file(from xmms/winamp) ## function php_stream($mp3_dir, $mp3list, $mp3file, $lame='') { $player = check_useragent(); if($mp3file) { if(is_readable($mp3file = "$mp3_dir/".agent_decode($mp3file))) { clearstatcache(); // flush buffer if($player) php_mp3stream($mp3file,$lame,get_ftype($mp3file)); sleep(1); } exit; // force to go next stream } else php_mp3plist($mp3_dir,$mp3list,$player); } function write_log($log_dir) { global $_SERVER; if(!$log_dir) return 0; $time = date('Y.m.d H:i:s'); $logfile = 'php_stream_access.' . preg_replace('/ .+$/i','',$time) . '.log'; $logformat = sprintf("%-16s%25s \"%s\"\t%s\n", $_SERVER['REMOTE_ADDR'],"[$time]",$_SERVER['REQUEST_URI'], $_SERVER['HTTP_USER_AGENT']); if(file_exists($file="$log_dir/$logfile")) { if($fp = @fopen($file,r)) { $content = @fread($fp,filesize($file)); fclose($fp); } } if($fp = @fopen($file,'w+')) { fputs($fp,$content.$logformat); fclose($fp); } } ## for xmms/winapm ## function agent_encode($str) { $str = base64_encode($str); return str_replace('+','__PLUS__',$str); } function agent_decode($str) { $str = str_replace('__PLUS__','+',$str); return base64_decode($str); } ## inital var(security) ######################## ## do not delete unset() functions ## unset($mp3_dir); unset($lame); unset($file_name); unset($MP3LIST); unset($log_dir); ## ################################################# ## configuration ################################ ## $not = 1; // don't print check microtime result $mp3_dir = '/home/linuxchannel/mp3'; // do not set ducumentroot inside //$lame = '/usr/local/bin/lame'; // require lame(http://www.mp3dev.org/) $log_dir = '/home/linuxchannel/mp3/log'; // logging directory(nobody access and writable) ## ## end configuration ############################# ## example ## if($hdle = @opendir($mp3_dir)) { while($file = readdir($hdle)) { // only 1 depth if(is_file("$mp3_dir/$file") && is_readable("$mp3_dir/$file") && preg_match('/\.(mp3|ogg)$/i',$file)) { $file_name[] = $file; } clearstatcache(); // flush buffer } closedir($hdle); } ## must session var or cookie var($MP3LIST) ## foreach($file_name AS $k=>$v) $MP3LIST[$k] = agent_encode($v); _globals(); ## are you use the 'Action' directive? ## $_SERVER['_PHP_SELF'] = preg_replace('/\?.*$/','',$_SERVER[REQUEST_URI]); @write_log($log_dir); php_stream($mp3_dir,$MP3LIST,$_GET['stream'],$lame); exit; // don't print any messages ?>