views:

132

answers:

2

Something in here is incompatible with PHP5, but I am totally lost as to what. I have an .htaccess file on my web server that has the line "AddHandler x-mapp-php5 .php", as it is required by just about everything else on the server and it defaults to PHP4...however; I need this one script to work, but it only works on PHP4. Any idea where the problem is?

<?  
/* config for the script */  
$download_path = "content"; /* path to your files, NB: no slash at the end */  
$sort = "asort"; /* array sorting - alphabetical sorting for the array */  

/* start the script... no more editing from here on... */  

/* get a list of the files + dirs and turn the list into an array */  
function file_list($dir) {  
  global $sort;  
  global $file_file_count;  
  if (is_dir($dir)) {  
 $fd = @opendir($dir);  
 while (($part = @readdir($fd)) == true) {  
   clearstatcache();  
   if ($part != "." && $part != "..") {  
  $file_array[] = $part;  
   }  
 }  
  if ($fd == true) {  
 closedir($fd);  
  }  
  if (is_array($file_array)) {  
 $sort($file_array);  
 $file_file_count = count($file_array);  
 return $file_array;  
  } else {  
 return false;  
  }  
  } else {  
 return false;  
  }  
}  

/* function to convert to Mb, Kb and bytes */  
function file_size($size) {  
  $megabyte = 1024 * 1024;  
 if ($size > $megabyte) { /* literal.float */  
   $re_sized = sprintf("%01.2f", $size / $megabyte) . " Mb";  
 } elseif ($size > 1024) {  
   $re_sized = sprintf("%01.2f", $size / 1024) . " Kb";  
 } else {  
   $re_sized = $size . " bytes";  
 }  
  return $re_sized;  
}  

/* get a list of the files/dirs, put them into a table. */  
function generate_file_list($path) {  
  global $download_path;  
  global $PHP_SELF;  
  $final_path = str_replace("//","/",str_replace("..","",urldecode($path)));  
  $file_array = file_list("$download_path/$final_path/");  
  echo "<b>$final_path/</b>\n";  
  echo "<br><br>\n\n";  
  if ($file_array == false) { /* check if the dir is an array before we process it to foreach(); */  
 echo "directory empty\n";  
  } else {  
 echo "<table width=\"75%\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n";  
 echo "<tr><td><b>file</b></td><td><b>size</b></td></tr>\n";  
 foreach ($file_array as $file_name) {  
   $is_file = "$download_path/$final_path/$file_name";  
   $final_dir_name = urlencode($final_path); /* urlencode(); to prevent any broken links - decode on do_download(); */  
   $final_file_name = urlencode($file_name);  
   $file_size = filesize("$download_path/$final_path/$file_name");  
   $final_file_size = file_size($file_size);  
   if (is_file($is_file)) {  
  print "<tr><td><a href=\"$PHP_SELF?go=download&path=$final_dir_name&file=$final_file_name\">$file_name</a></td><td>$final_file_size</td></tr>\n";  
   } elseif (is_dir($is_file)) {  
  print "<tr><td><a href=\"$PHP_SELF?go=list&path=$final_dir_name/$final_file_name\">$file_name/</a></td><td>&lt;dir&gt;</td></tr>\n"; /* we don't need a size for a directory */  
   }  
 }  
 echo "</table>\n";  
  }  
}  
/* allow the user to download the file... */  
function do_download($path,$file) {  
  global $download_path;  
  $get_path = str_replace("//","/",str_replace("..","",stripslashes(urldecode($path)))); /* fopen adds \ to ' - so we strip 'em. */  
  $get_file = str_replace("//","/",str_replace("..","",stripslashes(urldecode($file))));  
 header("Content-Disposition: atachment; filename=$get_file");  
 header("Content-Type: application/octet-stream");  
 header("Content-Length: ".filesize("$download_path/$get_path/$get_file"));  
 header("Cache-Control: no-cache, must-revalidate");  
 header("Pragma: no-cache");  
 header("Expires: 0");  
  $fp = fopen("$download_path/$get_path/$get_file","r");  
  print fread($fp,filesize("$download_path/$get_path/$get_file"));  
  fclose($fp);  
  exit;  
}  

if (!isset($go)) {  
  $go = "dirlist";  
} if ($go == "dirlist") {  
 generate_file_list(""); /* null, so we get a list for the root directory */  
  } elseif ($go == "list" && isset($path)) {  
 if (isset($path)) { /* if the path is null - it returns a list for the root directory */  
   generate_file_list($path); /* get a list for the path specified */  
 } else {  
   generate_file_list("");  
 }  
  } elseif ($go == "download") {  
   if (isset($path) && isset($file)) {  
  do_download($path,$file); /* download the file... */  
   } else {  
 echo "no file selected to download :)\n";  
  }  
}  
?>
+1  A: 

The code is assuming that the $go, $file, and $path variables are being magically set. To get around this (and fix the script) you could change the beginning of the script to look like this:

<?  
/* config for the script */  
$download_path = 'content'; /*path to your files, NB: no slash at the end*/  
$sort = 'asort'; /* array sorting - alphabetical sorting for the array */  

/* start the script... no more editing from here on... */  
$go   = $_REQUEST['go'];
$file = $_REQUEST['file'];
$path = $_REQUEST['path'];

// ...

This use to work for you because of something known as Register Globals. This is now turned off since it was a pretty big security problem and it led to sloppy coding practices.

fiXedd
Almost, there are isset calls in there. You want to do an if (isset($_REQUEST['go'])) {$go = $_REQUEST['go'];} to make sure the later code still works.
jmucchiello
That isn't necessary. If there's no values for them then they'll be set to null. Null evaluates to false in isset().
fiXedd
Awesome, that worked great. This is actually some old code I picked up somewhere eons ago and just dumped it onto a local server for testing purposes--security is unimportant as the server is only open to the local network.
Stephen Belanger
+2  A: 

When you've fixed the Register Globals issue suggested by fiXedd and jmucchiello, make sure you remove the reference to $PHP_SELF in the *generate_file_list* function. First, it doesn't exist like that anymore: it's now $_SERVER['PHP_SELF'] but more importantly, the way your script is using it is exposing you to a cross-site-scripting issue.

Read more on this on: http://www.seancoates.com/xss-woes

MathieuK
Good catch, I totally missed those. :)
fiXedd
Yeah, I fixed them in my continued incompatibility hunting after posting this thread, though it was somewhat unnecessary as this is a local server only...so unless I plan on hacking myself I think it'll be fine. :OThis code is pretty ancient, so I guess it's to be expected that it'd be pretty horrible. It works for what I need though and I really didn't want to take the time to rewrite it.
Stephen Belanger