iTunes_Control permissions error in PHP script

Discussion in 'Mobile Web Development' started by KrakaJap, May 18, 2008.

  1. KrakaJap

    KrakaJap New Member

    Joined:
    Oct 18, 2007
    Messages:
    33
    Likes Received:
    0
    Ok... I apologize for my 2 previous threads... hopefully this time I get it in the right place with a more appropriate topic.

    Please Register or Log in to view images



    I'm working on a PHP script to parse the iTunes_Control/Music folder and read the ID3 tags of each MP3 and display a list of these within a browser so that anyone can browse to my iPod and listen/download my music. The script I've come up with works perfectly fine on a desktop; however, it fails within Apache/PHP on the iPod with a permissions error.

    My code:
    Code:
    <?php
    	function find_files($path, $pattern, $callback) {
    		$path = rtrim(str_replace("\\", "/", $path), '/') . '/';
    		$matches = Array();
    		$entries = Array();
    		$dir = dir($path);
    		while (false !== ($entry = $dir->read())) {
    			$entries[] = $entry;
    		}
    		$dir->close();
    		foreach ($entries as $entry) {
    			$fullname = $path . $entry;
    			if ($entry != '.' && $entry != '..' && is_dir($fullname)) {
    				find_files($fullname, $pattern, $callback);
    			} else if (is_file($fullname) && preg_match($pattern, $entry)) {
    				call_user_func($callback, $fullname);
    			}
    		}
    	}
    
    	function my_handler($filename) {
    		$id = filesize($filename) - 128;
    		$fp = fopen($filename, "r");
    		fseek($fp, $id);
    		$tag = fread($fp, 3);
    		if ($tag == "TAG") {
    			$title = rtrim(fread($fp, 30));
    			$artist = rtrim(fread($fp, 30));
    			fclose($fp);
    		}
    		echo "<a href='$filename'>$artist - $title<br />";
    	}
    
    	find_files('/private/var/mobile/Media/iTunes_Control/Music', '/mp3/', 'my_handler');
    ?>
    
    The errors:
    Anyone have any ideas? I've been told to search for ways to run Apache as root but all I've found so far is that the Apache service always starts as root, but each call from a browser is run as mobile. Any way to change this or get past the permissions error on that folder? I've tried changing the permissions manually but this doesn't have any effect.

    I've even gone as far as creating a symlink in root and pointing to that folder instead (which obviously will not work since it ends up in the same place anyway, but I was desperate).

    Please Register or Log in to view images

    I'm aware of the apps already out there that will allow file browsing via Safari but I've yet to find one that does simply what I want to do, considering the cryptic naming scheme of the iTunes_Control folder.

    Please Register or Log in to view images

  2. The Ax

    The Ax Banned

    Joined:
    Mar 11, 2008
    Messages:
    647
    Likes Received:
    22
    Whoa

    I was jut looking into that,
    Il PM you
  3. KrakaJap

    KrakaJap New Member

    Joined:
    Oct 18, 2007
    Messages:
    33
    Likes Received:
    0
    Figured it out!

    Apparently my "Media" folder (/private/var/mobile/iTunes_Control/Music) did not have the proper permissions set. Not sure how I overlooked that but once set to 755 everything worked like a charm. I also updated the code and created a symlink within the webroot called "music".

    In /Library/WebServer/Documents create a symlink:
    ln -s /private/var/mobile/Media/iTunes_Control/Music music

    PHP script:
    Code:
    <?php
    	function find_files($path, $pattern, $callback) {
    		$path = rtrim(str_replace("\\", "/", $path), '/') . '/';
    		$matches = Array();
    		$entries = Array();
    		$dir = dir($path);
    		while (false !== ($entry = $dir->read())) {
    			$entries[] = $entry;
    		}
    		$dir->close();
    		foreach ($entries as $entry) {
    			$fullname = $path . $entry;
    			if ($entry != '.' && $entry != '..' && is_dir($fullname)) {
    				find_files($fullname, $pattern, $callback);
    			} else if (is_file($fullname) && preg_match($pattern, $entry)) {
    				call_user_func($callback, $fullname);
    			}
    		}
    	}
    
    	function my_handler($filename) {
    		$id = filesize($filename) - 128;
    		$fp = fopen($filename, "r");
    		fseek($fp, $id);
    		$tag = fread($fp, 3);
    		if ($tag == "TAG") {
    			$title = rtrim(fread($fp, 30));
    			$artist = rtrim(fread($fp, 30));
    			fclose($fp);
    		}
    		echo "<a href='$filename'>$artist - $title<br />";
    	}
    
    	find_files('music', '/mp3/', 'my_handler');
    ?>
    
    This also prevents anyone from browsing your directories directly (with the symlink) and forces them to go through the script first (which is better anyway because it gives them non-cryptic names).

    Works like a charm!
  4. optimo

    optimo New Member

    Joined:
    Sep 28, 2007
    Messages:
    535
    Likes Received:
    17
    and thats why nobody had the right answer

    good job, I'm looking forward to trying your script soon

    Please Register or Log in to view images

  5. KrakaJap

    KrakaJap New Member

    Joined:
    Oct 18, 2007
    Messages:
    33
    Likes Received:
    0
    lol very true. I must have adjusted permissions from term on the ipod and missed it (kinda hard to read). But now the challenge would be to get this into an app that only starts that script when the app is active. I need to make a few adjustments to the script anyway to make it nicer. For instance... right now it's a straight list, unsorted, no numbers, etc., just artist - track. Hell I can probably add a feature in there to allow you to directly edit the ID3 tag!

    EDIT: here's a question then that might take a little work...
    I'm attempting now to get this list in alphabetical order. I figured I need to get the entire list into an array (2 dimensional i assume for display name to filename) and then pass that back to the find_files function and use sort(); however, I can't seem to get this working. any ideas?

    Ok I figured that out too and updated my code (for anyone interested):

    new code:
    Code:
    <?php
    	function find_files($path, $pattern) {
    		$path = rtrim(str_replace("\\", "/", $path), '/') . '/';			//rewrite appropriate paths
    		$matches = Array();
    		$entries = Array();
    		$dir = dir($path);									//open directory
    		while (false !== ($entry = $dir->read())) {					//check directory and store entries
    			$entries[] = $entry;
    		}
    		$dir->close();									//close directory
    		static $alist = Array();
    		static $x = 0;
    		foreach ($entries as $entry) {							//loop each directory
    			$fullname = $path . $entry;							//store full path to file
    			if ($entry != '.' && $entry != '..' && is_dir($fullname)) {		//check for sub-directories
    				find_files($fullname, $pattern);
    			} else if (is_file($fullname) && preg_match($pattern, $entry)) {	//identify each file and store ID3 info
    				$id = filesize($fullname) - 128;
    				$fp = fopen($fullname, "r");
    				fseek($fp, $id);
    				$tag = fread($fp, 3);
    				if ($tag == "TAG") {							//check for ID3 and set tags
    					$title = rtrim(fread($fp, 30));
    					$artist = rtrim(fread($fp, 30));
    					fclose($fp);							//close file
    				}
    				$listing = "$artist - $title";					//store simple listing variable
    				$alist[$x]['listing'] = "$listing";				//store listing in array tag
    				$alist[$x]['source'] = "$fullname";				//store path in array tag
    				$x++;
    			}
    		}
    		return $alist;									//return multi-array to caller
    	}
    
    	$alist = find_files('music', '/mp3/');							//store returned array from function into new array
    	array_multisort($alist, SORT_ASC);								//sort multi-array ASC
    	for ($i = 0; $i < count($alist); $i++) {							//begin output of array listings
    		$count = $i + 1;
    		if ($count < 10) { $count = "0".$count; }
    		echo $count." - <a href='".$alist[$i][source]."'>".$alist[$i]['listing']."</a><br />";
    	}
    ?>
    

Share This Page