/**
* Recursive directory scanner
*
* param path - str: the path to scan with no trailing slash
* param allowed_filetypes  arr: mp3, ogg etc
* param media_scanner str: the media scanner object
*/
function scan_directory($path, $allowed_filetypes, $media_scanner, $id3_scanner)
{
    $dp = opendir($path);
    while ($filename = readdir($dp)) {
        //create the full pathname and streeme pathname
        $full_file_path = $path . '/' . $filename;
        //skip hidden files/folders
        if ($filename[0] === '.') {
            continue;
        }
        //it's a directory, recurse from this level
        if (is_dir($full_file_path)) {
            scan_directory($full_file_path, $allowed_filetypes, $media_scanner, $id3_scanner);
            continue;
        }
        //Stat the file
        $file_stat = stat($full_file_path);
        //is it a usable file?
        if ($file_stat['size'] === 0 || !in_array(strtolower(substr($filename, -3)), $allowed_filetypes)) {
            continue;
        }
        $streeme_path_name = iconv(sfConfig::get('app_filesystem_encoding', 'ISO-8859-1'), 'UTF-8//TRANSLIT', $full_file_path);
        //has it been scanned before?
        if ($media_scanner->is_scanned($streeme_path_name, $file_stat['mtime'])) {
            continue;
        }
        echo "Scanning " . $filename . "\n";
        //get the file information from pathinfo in case we need a substitute song name
        $pinfo = pathinfo($full_file_path);
        /**
         * Pure ugliness - there's 3 possible containers for scraps of ID3 data - they're in order of preference and data integrity
         * Tempted to move this to its own container
         * high    high    medium    none
         * apex -> id3v2 -> id3v1 -> null
         * getID3 is a bit of a tricky lib to work with, but it has great features
         */
        $value = $id3_scanner->analyze($full_file_path);
        $tags = $value['tags'];
        //track number is a nuisance - regress to find the tags
        if (isset($tags['id3v1']['track'][0]) && is_int($tags['id3v1']['track'][0])) {
            //could be an int
            $tracknumber = $tags['id3v1']['track'][0];
        } else {
            if (isset($tags['id3v2']['track_number'][0]) && !empty($tags['id3v2']['track_number'][0])) {
                //or it could be 5/12
                $temp = explode('/', $tags['id3v2']['track_number'][0]);
                $tracknumber = $temp[0];
            } else {
                if (isset($tags['ape']['track_number'][0]) && !empty($tags['ape']['track_number'][0])) {
                    //or it could be 5/12 APEX
                    $temp = explode('/', $tags['ape']['track_number'][0]);
                    $tracknumber = $temp[0];
                } else {
                    //or it's missing
                    $tracknumber = 0;
                }
            }
        }
        $song_array = array();
        $song_array['artist_name'] = StreemeUtil::xmlize_utf8_string(@$tags['ape']['artist'][0] ? @$tags['ape']['artist'][0] : ($tags['id3v2']['artist'][0] ? $tags['id3v2']['artist'][0] : ($tags['id3v1']['artist'][0] ? $tags['id3v1']['artist'][0] : null)));
        $song_array['album_name'] = StreemeUtil::xmlize_utf8_string(@$tags['ape']['album'][0] ? @$tags['ape']['album'][0] : ($tags['id3v2']['album'][0] ? $tags['id3v2']['album'][0] : ($tags['id3v1']['album'][0] ? $tags['id3v1']['album'][0] : null)));
        $song_array['song_name'] = StreemeUtil::xmlize_utf8_string(@@$tags['ape']['title'][0] ? @$tags['ape']['title'][0] : ($tags['id3v2']['title'][0] ? $tags['id3v2']['title'][0] : ($tags['id3v1']['title'][0] ? $tags['id3v1']['title'][0] : $pinfo['filename'])));
        $song_array['song_length'] = $value['playtime_string'];
        $song_array['accurate_length'] = floor((double) $value['playtime_seconds'] * 1000);
        $song_array['genre_name'] = @$tags['ape']['genre'][0] ? @$tags['ape']['genre'][0] : ($tags['id3v2']['genre'] ? $tags['id3v2']['genre'][0] : ($tags['id3v1']['genre'][0] ? $tags['id3v1']['genre'][0] : null));
        $song_array['filesize'] = $file_stat['size'];
        $song_array['bitrate'] = floor((int) $value['audio']['bitrate'] / 1000);
        $song_array['yearpublished'] = @$tags['ape']['year'][0] ? @$tags['ape']['year'][0] : ($tags['id3v2']['year'][0] ? $tags['id3v2']['year'][0] : ($tags['id3v1']['year'][0] ? $tags['id3v1']['year'][0] : null));
        $song_array['tracknumber'] = $tracknumber;
        $song_array['label'] = StreemeUtil::xmlize_utf8_string(@$tags['ape']['label'][0] ? @$tags['ape']['label'][0] : ($tags['id3v2']['label'][0] ? $tags['id3v2']['label'][0] : null));
        //not available in V1
        $song_array['mtime'] = $file_stat['mtime'];
        $song_array['atime'] = $file_stat['atime'];
        $song_array['filename'] = $streeme_path_name;
        unset($value, $tags, $file_stat, $temp);
        //free the RAM used by the temp containters
        /* End Ugliness */
        $media_scanner->add_song($song_array);
    }
    closedir($dp);
}
<?php

include dirname(__FILE__) . '/../bootstrap/doctrine.php';
include dirname(__FILE__) . '/../../apps/client/lib/StreemeUtil.class.php';
// Initialize the test object
$t = new lime_test(10, new lime_output_color());
$t->comment('->itunes_format_decode()');
$t->is(StreemeUtil::itunes_format_decode('file://localhost/Z:/music/music.mp3', true), 'Z:/music/music.mp3', 'Decoded an itunes path with mapped drive replacements');
$mapped_drive_locations = array('file://localhost/Z:' => '\\mediabox');
$t->is(StreemeUtil::itunes_format_decode('file://localhost/Z:/music/music.mp3', true, array('file://localhost/Z:' => '\\mediabox')), '\\mediabox/music/music.mp3', 'Decoded an iTunes path with mapped drive replacements');
$t->is(StreemeUtil::itunes_format_decode('file://localhost/home/foo/bar%20man', false), '/home/foo/bar man', 'Decoded an itunes formatted path');
$t->comment('->slugify()');
$t->is(StreemeUtil::slugify('stuff & thing fox\'s Name'), 'stuff-thing-fox-s-name', 'Processed sting pattern into valid url');
$t->comment('->xmlize_uf8_string()');
$t->is(StreemeUtil::xmlize_utf8_string(join(range(chr(0), chr(127)))), join(range(chr(1), chr(127))), 'passes printable US-ascii chars');
$t->is(StreemeUtil::xmlize_utf8_string(' 小低胡' . chr(0)), '小低胡', 'passes printable UTF-8 chars');
$t->is(StreemeUtil::xmlize_utf8_string('äöüæøy'), 'äöüæøy', 'passes printable UTF-8 tremas');
$t->is(StreemeUtil::xmlize_utf8_string('m̥mn̥nɲ̊ɲŋ̊ŋðóíáþ'), 'm̥mn̥nɲ̊ɲŋ̊ŋðóíáþ', 'passes printable UTF-8 icelandic chars');
$t->is(StreemeUtil::xmlize_utf8_string('YÿþAÿþ#ÿþÿþ'), '', 'removes id3 signalling leak');
$t->comment('->replace_url_nonfs_chars()');
$t->is(StreemeUtil::replace_url_nonfs_chars('%E2%80%93' . '%E2%80%A6' . '%E2%80%BA'), '%96' . '%85' . '%9B', 'change mb_strings to single byte latin');
 /**
  * Get a combined file from the cache dir
  *
  * @param type      string css or js
  * @param namespace string the combined file namespace (eg. module+action names)
  * @return          string filesystem path to combined file
  */
 public function getFileName($type, $namespace)
 {
     $type = $type === 'css' ? 'css' : 'js';
     $namespace = StreemeUtil::slugify($namespace);
     return sprintf('%s/combine/%s/%s.%s', sfConfig::get('sf_cache_dir'), $type, $namespace, $type);
 }
 * @package    streeme
 * @author     Richard Hoar
 * @version    SVN: $Id: Builder.php 7490 2010-03-29 19:53:27Z jwage $
 */
$itunes_music_library = sfConfig::get('app_itunes_xml_location');
$mapped_drive_locations = sfConfig::get('app_mdl_mapped_drive_locations');
$allowed_filetypes = array_map('strtolower', sfConfig::get('app_aft_allowed_file_types'));
$media_scanner = new MediaScan();
$itunes_parser = new StreemeItunesTrackParser($itunes_music_library);
while ($value = $itunes_parser->getTrack()) {
    //if it's not a valid filetype, ignore
    if (!in_array(strtolower(substr($value['Location'], -3)), $allowed_filetypes)) {
        continue;
    }
    //decode the itunes file scheme for checking is_readable
    $location = StreemeUtil::itunes_format_decode($value['Location'], StreemeUtil::is_windows(), $mapped_drive_locations);
    //convert it from user's filesystem value to UTF-8 for the database
    $value['Location'] = iconv(sfConfig::get(app_filesystem_encoding, 'ISO-8859-1'), 'UTF-8//TRANSLIT', $location);
    //if this file's scanned already and nothing about the file has been modified, ignore
    if ($media_scanner->is_scanned($value['Location'], strtotime($value['Date Modified']))) {
        continue;
    }
    //smooth times from itunes format to minutes:seconds
    $minutes = floor($value['Total Time'] / 1000 / 60);
    $seconds = str_replace('.', '0', substr(($value['Total Time'] - floor($value['Total Time'] / 1000 / 60) * 60 * 1000) / 1000, 0, 2));
    if ($seconds > 60) {
        $seconds = '00';
    }
    //create an array of song information
    $song_array = array();
    $song_array['artist_name'] = @$value['Artist'];
function mapItunes($collection)
{
    return array('filename' => iconv(sfConfig::get(app_filesystem_encoding, 'ISO-8859-1'), 'UTF-8//TRANSLIT', StreemeUtil::itunes_format_decode($collection['filename'], StreemeUtil::is_windows(), sfConfig::get('app_mdl_mapped_drive_locations'))));
}