PHP File Browser - Userlinux.net

Siempre quise programar un explorador de archivos/directorios en PHP. Sé que es crítico jugar con el contenido de un disco duro y su visualización vía web, pero sin riesgo no hay adrenalina. La única premisa que me había marcado era un enjaulamiento complicado de saltar, algo así como definir una…

PHP File Browser

25.Sep.2006 ~ 5 Comentarios ~ 3719 Lecturas
Siempre quise programar un explorador de archivos/directorios en PHP. Sé que es crítico jugar con el contenido de un disco duro y su visualización vía web, pero sin riesgo no hay adrenalina. La única premisa que me había marcado era un enjaulamiento complicado de saltar, algo así como definir una ruta base de la cual no se podría subir, por seguridad. Esto es lo que ha salido:
File Browser
El File Browser (todavía por bautizar) consta de tres funciones:

  • evalua_ruta(): Encargada de evaluar si la ruta que se le pasa como parámetro es válida o no, básicamente comprueba que se encuentre dentro del chroot virtual (que también se pasa por parámetro).
  • contenido_ruta(): Siempre que la ruta sea válida, imprime su contenido.
  • rmime(): No estoy demasiado orgulloso de esta función, pero el entorno-servidor ha hecho que sea usable. Se encarga de identificar el tipo de archivo (o directorio) en función a la extensión y añadirle una clase CSS para imprimir un icono correspondiente. Lo lógico sería haberlo hecho con Mimetype, pero no me parecía apropiado instalar/habilitar más extensiones en el servidor solamente para ésto.
El pseudocódigo es sencillo, atiende a un par de condiciones y poco más:
	definimos_base;
	evaluamos_base+ruta;
	si es correcta:
		imprimimos su contenido;
	si no es correcta:
		imprimimos contenido de base;
En un principio ruta será una cadena vacía porque el directorio principal es base, pero a medida que vayamos entrando en subdirectorios dentro de base, ésto se pasan por url como la variable dir, (que la función llama ruta).

evalua_ruta()

Siempre la ruta real será $base+$ruta, para asegurarnos de que no salimos del chroot, así que le pasamos ambos parámetros, la función los convierte en rutas absolutas y usa strncmp() para ver que una está contenida en la otra. En un principio había pensado en devolver un array con dos valores, 0 si la ruta era incorrecta y 1 si era una ruta válida; pero pensé que sería más sencillo hacer toda validación dentro de esta función. Si la ruta es correcta se devuelve, si no lo es, se devuelve la $base:
<?php
	// Parametros: Ruta a evaluar y base desde la que enjaulamos
	function evalua_ruta($ruta, $base)
	{
		if($ruta) $ruta=$base."/".$ruta."/";
		else $ruta=$base."/";
		$ruta_real=realpath($ruta);
					$base_real=realpath($base);

		// Miramos si es real o no
		if(strncmp($base_real, $ruta_real, strlen($base_real))==0)
			return $ruta_real;
		else
			return $base_real;
		return $arr;
	}
?>

contenido_ruta()

Una vez la ruta es correcta pasamos a imprimir su contenido de forma explorable, con enlaces en sus directorios para poder entrar en ellos, etc. Se presentan varios problemas, como descomponer la ruta relativa en arrays para calcular los enlaces de los directorios especiales . y ... Una vez calculados dichos enlaces ($ruta_dot y $ruta_dotdot) evaluamos si se trata de un directorio o un archivo para enlazar de forma correspondiente. También calculo los Kb. de cada archivo como extra:
<?php
	// Parametros: Ruta a leer, base desde la que enjaulamos y base del enlace para directorios
	function contenido_ruta($ruta, $base, $baselink)
	{
		$ruta_real=realpath($ruta);
		$base_real=realpath($base);

		$ruta_dot=str_replace($base_real, "", $ruta_real);

		$arr_dotdot=explode("/", $ruta_dot); array_pop($arr_dotdot);
		$ruta_dotdot=implode("/",$arr_dotdot);

		$output="<h1>{$base}{$ruta_dot}</h1>ntt<ul>n";

		$dir=opendir($ruta);
		while($f = readdir($dir))
		{
			// Si es directorio modificamos enlace de . y ..
			if(is_dir($ruta."/".$f))
			{
				switch($f)
				{
					case ".": 	$txt="."; $link="{$baselink}$ruta_dot"; break;
					case "..": 	$txt="..";$link="{$baselink}$ruta_dotdot"; break;
					default: 	$txt="$f";$link="{$baselink}{$ruta_dot}/$f"; break;
				}
				$filldot="";
				$clase="folder";
			}
			// Si es archivo enlazamos a lo bruto
			else
			{
				$filldot="";
				for($i=0; $i<=(50-strlen($f)); $i++) $filldot.=" ";
				$kb=(filesize("{$base}{$ruta_dot}/{$f}")/1024);
				$kb=number_format($kb, 0); $filldot.=$kb." Kb.";
				$txt="$f"; $link="{$base}{$ruta_dot}/{$f}";
				$clase=rmime("{$base}{$ruta_dot}/{$f}");
			}
			$output.="ttt<pre><li class="{$clase}"><a href="{$link}">{$txt}</a>{$filldot}</pre></li>n";
		}
		$output.="tt</ul>n";
		return $output;
	}

?>
El parámetro que veis como $baselink es una variable que paso para completar el enlace. Para que se entienda, si la página donde está el File Browser es:
http://www.midominio.com/index.php?p=browser
$baselink=index.php?p=browser;
Imagino que se podría automatizar con las variables $_SERVER, pero no vamos a cubrir todo en la versión 0.1 :D

rmime()

Poco que comentar, le pasamos una cadena con el nombre de archivo y mira su extensión, dependiendo del case devuelve un valor u otro. Tiene los mimetypes más comunes, sencillo de completar con más:
<?php
	// Parametro: archivo
	function rmime($file)
	{
		$ext=array_pop(explode('.', basename($file)));
		$ext=strtolower($ext);
		switch ($ext)
		{
			case "jpeg": $img="jpg"; break;
			case "gif": $img="gif"; break;
			case "jpg": $img="jpg"; break;
			case "png": $img="png"; break;
			case "bmp": $img="bmp"; break;

			case "pdf": $img="pdf"; break;
			case "txt": $img="txt"; break;
			case "doc": $img="doc"; break;
			case "xls": $img="xls"; break;

			case "mp3": $img="audio"; break;
			case "wav": $img="audio"; break;
			case "wma": $img="audio"; break;
			case "ogg": $img="audio"; break;

			case "mpeg": $img="video"; break;
			case "mpg": $img="video"; break;
			case "avi": $img="video"; break;
			case "qt": $img="video"; break;
			case "wmv": $img="video"; break;

			case "arj": $img="arj"; break;
			case "gz": $img="gz"; break;
			case "rar": $img="rar"; break;
			case "zip": $img="zip"; break;
			case "tar": $img="tar"; break;

			case "ttf": $img="fuente"; break;

			default: $img="empty"; break;
		}
		return $img;
	}
?>

main()

En tres lineas creamos el flujo principal del programa, tan simple como definir la base del chroot, llamar a una función y llamar a la siguiente:
<?php
	$base="pub";
	$rruta=evalua_ruta($_GET[dir],$base);	
	echo contenido_ruta($rruta, $base, "index.php?p=pub&dir=");
?>

CSS

Para imprimir el contenido utilizo un listado no numerado (ul, li) de forma que cada elemento del listado tiene una clase de un tipo (jpg, png, rar...) previamente definido en un fichero css:
<li class="folder"><a href="#">.</a></li>
<li class="folder"><a href="#">..</a></li>
<li class="gz"><a href="#">rweb.tar.gz</a></li>
li.folder {background: url("images/mime/folder.png") no-repeat 8px 4px; }
li.gz {background: url("images/mime/gz.png") no-repeat 8px 4px; }
El set de iconos usado para los tipos de archivo es el Vista Inspirate sacados de Gnome-Look:
Mime Types

Agradecimientos

Como siempre a Juanjo por algunas ideas referidas a realpath y por beta-tester. Esto solo es el intento de materialización de una idea más, imagino que todo este código se podrá mejorar, así que cualquier comentario será apreciado y valorado.

Comentarios


gravatar
26.Sep.2006
Grande!

Un amigo mío tiene una herramienta por el estilo, pero un poco más avanzada. Se llama PHPfileNavigator, pero para cosas básicas puede resultar demasiado grande.

Como nombre yo le pondría br0wsker ;D

gravatar
17.Dec.2008
Hola, me gustaria saber si tienes por ahi el zip con la css, y los iconos directamente. Estaba intentando usar tu explorador.

Te lo agradezco.

Un saludo

Gracias

gravatar
17.Dec.2008
Hola, me gustaria saber si tienes por ahi el zip con la css, y los iconos directamente. Estaba intentando usar tu explorador.

Te lo agradezco.

Un saludo

Gracias

gravatar
julmadgfmdrv
17.Dec.2008
Funciona perfecto. Ya pille iconos y demas y sin problemas.

Aunque si la base es "/" no funciona. Hay un problema con las /

Un saludo.Gracias.

gravatar
TomNaz
09.Sep.2009
use urlencode para q navegue en directorios con espacios, y agregue al link comillas para q tbn se pueda acceder a archivos cuyos nombres tienen espacios : $output.="</p> <li><a>".$txt."</a></li> <p>"; Saludos Gracias

Comentarios


Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 15 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.

Buscar

Cargando...

Últimos comentarios

  • graffic
  • reidrac
  • reidrac
  • Wu
  • dilam
  • r0sk
  • reidrac
  • r0sk
  • chucu
  • r0sk
  • el_palomo_programador
  • r0sk
  • reidrac
  • Player 1
  • r0sk

Moneting

Valor de mi cuenta de Facebook según Moneting
Valor de mi cuenta de Twitter según Moneting

Tagcloud

bsd humor bake twitter vacaciones ps3 hack 2007 python blog django alemania_2006 mundial cake felicidades games conciertos rsidenotes juegos openbsd web iphone sidenotes rfilms ubuntu barça cakephp blogsfera mac bash meme macosx deportes canción ds personal films freebsd 2008 opinion nintendo sysadmin futbol mysql php frases userlinux debian ssh linux blogs champions apple lugo league programación twitt lucux seguridad cumpleaños

Archivo

Año 2012

Año 2011

Año 2010

Año 2009

Año 2008

Año 2007

Año 2006

Año 2005

Año 2004

Año 2003

Año 2002

Social

Enlaces de interés