PHP en CableNaranja

Cómo subir archivos al servidor con PHP

¡Comparte nuestro contenido!

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)

En esta ocasión, aprenderemos a subir archivos al servidor con PHP. Algo muy útil para trabajar con galerías, bibliotecas, listas de archivos, fichas, entre otros. Como siempre buscaremos hacerlo de manera sencilla y rápida, pero funcional e incluso un poco segura ¡Manos a la obra!

Preparando el formulario HTML

Coloquemos un formulario sencillo, el método será de envío de datos será POST y el action lo haremos en el mismo documento gracias a la constante $PHP_SELF, la cual haremos pasar por la función htmlentities para evitar los típicos ataques XSS. Adicionalmente a eso usaremos el atributo enctype con el valor multipart/form-data para indicar que el formulario enviará datos en partes. Esto último es obligatorio para enviar archivos.

<form method="post" action="<?php echo htmlentities($PHP_SELF); ?>" enctype="multipart/form-data">
</form>

Dentro de nuestro formulario sólo contaremos un un input de tipo file y un botón submit.

<p><label>Envía una imagen (8MB Máx):</label><input type="file" name="imagen" /></p>
<p><input type="submit" value="Enviar" name="btnOK" /></p>

Procesando los datos del formulario con PHP

Abrimos nuestro bloque PHP justo debajo de lo anterior. Lo primero que necesitamos es verificar que la variable tipo POST del botón existe. Esto lo logramos con la función isset.

if(isset($_POST["btnOK"])){
}

Ahí dentro capturamos el archivo tipo file usando el array $_FILES que contiene los datos de nuestro input de tipo file. concretamente los siguientes atributos:

  1. name: Contiene el nombre del archivo.
  2. size: Contiene el tamaño físico del archivo en bytes.
  3. tmp_name: Contiene el nombre temporal que recibe en el sistema host.

Por ejemplo:

$fileName = $_FILES["imagen"]["name"];
$fileSize = $_FILES["imagen"]["size"];
$fileTemp = $_FILES["imagen"]["tmp_name"];

Ahora, verifiquemos que se haya enviado un archivo, la manera simple es verificar que el tamaño físico sea mayor a cero.

if($fileSize==0){
   echo "<p>Ningún archivo fue seleccionado. Intente otra vez.</p>";
}else{
   // De lo contrario...
}

Si hay un archivo, necesitamos extraer su extensión o formato para verificar que sea una imagen. Primero extraigamos la extensión, utilizando la función explode.

$extension = explode(".", $fileName);

Todavía nos sobra el punto, pero lo hemos separado en un array de dos valores: (0) . y (1) jpg – Por citar un ejemplo – Ahora eliminemos el punto, al quedarnos simplemente con la extensión del archivo.

$formato = $extension[1];

A continuación, hagamos una lista de formatos soportados dentro de un array:

$validos =  array("png", "jpg", "jpeg", "gif");

Ocupemos una variable que empiece en cero. Dado que vamos a revisar nuestro array de formatos soportados con un clásico ciclo for, esta variable sólo aumentará su valor si la extensión de nuestro archivo se encuentra en la lista.

$contarExt = 0;
for($e=0;$e<count($validos);$e++){
   if($formato==$validos[$e]) $contarExt++;
}

Si nuestra variable nunca pasó de cero, significa que el archivo no se encuentra dentro de los formatos válidos, ya que el ciclo no encontró nada parecido.

if($contarExt==0) echo "<p>No es un formato de imagen adecuado. Prueba con otro.</p>";
else{
   // De lo contrario
}

En caso contrario, lo siguiente que necesitamos, es verificar que no exceda el tamaño que establecimos. Como el tamaño de nuestro archivo se encuentra en bytes, necesitamos convertirlo en kilobytes, para ello simplemente lo dividimos entre 1024.

$tamInKBs = $fileSize / 1024;

Ahora, establecemos nuestro límite en 8192 KB – Por que 8192 / 1024 = 8MB –

$maxSize = 8192;

Y si el tamaño del archivo excede dicho límite…

if($tamInKBs > $maxSize) echo "<p>El archivo excede el tamaño permitido.</p>";
else{
   // De lo contrario...
}

Pero si el archivo tiene un tamaño permitido, entonces, definimos la ruta física el archivo con la función dirname.

define('APP_PATH', dirname(__FILE__));

Y le ponemos el separador apropiado de acuerdo al sistema operativo de nuestro host

$ruta = APP_PATH . DIRECTORY_SEPARATOR;

Le agregamos el nombre físico del archivo con la función basename.

$subir = $ruta . basename($fileName);

Si todo salió bien, movemos el archivo temporal a la ruta física que hemos creado. La función move_uploaded_file se encarga de ello.

if(move_uploaded_file($fileTemp, $subir)){
   echo "<p>¡Imagen recibida, gracias!</p>";
}else echo "<p>Hubo un problema al intentar subir la imagen.</p>";

Es importante notar, que no hicimos validación del formato del archivo por medio de su MIME type, ya que como se menciona en Acunetix, realmente es muy fácil para un atacante ignorar esa validación.

Actualizar el servidor y probar el ejemplo

Necesitamos actualizar el límite de subida de archivos en PHP, para ello buscamos el archivo php.ini (si tenemos acceso a dicho archivo) y lo abrimos para su edición. Buscamos 3 valores : primero upload_max_filesize que actualizaremos con el límite que establecimos en nuestro código.

upload_max_filesize = 8M

Luego, post_max_size que debe tener como recomendación, al menos 50% más que el valor anterior, por ejemplo:

post_max_size = 12M

Por último, verificamos que memory_limit tenga asignada suficiente memoria, a partir de PHP 7 el valor mínimo es 128 MB, recomendable para la mayoría de casos

memory_limit = 128M

Reiniciemos nuestro servidor, y probemos el ejemplo (fullscreen para ver el video)

Por cierto, muy posiblemente en sistemas Linux / Unix, será necesario ajustar los permisos de la carpeta.

Descarga el ejemplo

Como siempre, puedes probar el código descargando el código fuente completo. Y eso es todo por ahora ¿Te ha gustado? ¿Aprendiste algo nuevo? Déjanos saber en los comentarios aquí abajo, en nuestra cuenta de twitter @cablenaranja7 o en nuestra página de facebook.

¡Comparte nuestro contenido!

Entradas relacionadas

Un comentario en "Cómo subir archivos al servidor con PHP"

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *