Formulario para subir archivos con php

Hoy vamos a ver como crear un formulario con la opción de subir archivos utilizando php y html. El proceso de subida se realiza desde el PC del usuario al servidor de tu web utilizando el navegador. Por ello, es necesario que la carpeta dónde se van a guardar los archivos subidos tenga permisos '777'. Permisos '777' indica que puede ser leído y escrito por el usuario visitante de tu web. En algunas configuraciones de servidor no es necesario y bastará con permisos '755'; si no conoces la configuración de tu servidor prueba con '755' (es más seguro) y si no funciona prueba a cambiarlo a '777'. Antes de seguir puede serte útil echar un vistazo al artículo Manejo de archivos en php.

Vistos los apuntes preliminares comencemos con el groso del artículo, primero veremos la construcción del formulario con html y luego el script php que controlará la subida de los archivos al servidor.

El formulario para subir archivos

Como ejemplo vamos a poner un formulario que va a consistir únicamente en el campo de subida y el botón para enviar el archivo. Puedes añadir los campos que necesites y procesarlos luego en el mismo script php. Pero esto ya no es asunto de este artículo.

Lo más importante a tener en cuenta cuando se construye un formulario para subir archivos al servidor es establecer el atributo enctype del formulario en "multipart/data" y en el campo input donde se va a seleccionar el archivo hay que poner el atributo type="file".

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es-es" lang="es-es" >
<head>
  <title>Ejemplo de formulario para subir archivos</title>
</head>
<body>
  <div id="formulario">
    <form action="subir.php" method="post" enctype="multipart/form-data" name="form"> 
      <label for="archivo">Archivo</label>
      <input name="archivo" type="file" id="archivo" /> 
      <input name="boton" type="submit" id="boton" value="Enviar" />
     </form>
  </div>
</body>
</html>

El formulario apunta al archivo subir.php, que pondremos en el mismo directorio que el archivo html o php que contenga el formulario. Este archivo contendrá el script que va a procesar la información enviada a través del formulario.

El script php para controlar la subida del archivo

Una vez construido nuestro formulario, pasamos a preparar el script php que procesará la petición de subida de archivo. El siguiente código lo pondremos en subir.php.

<?php 
 $uploaddir = "uploads/";
 $uploadfile = $uploaddir . basename($_FILES['archivo']['name']);
 $error = $_FILES['archivo']['error'];
 $subido = false;
 if(isset($_POST['boton']) && $error==UPLOAD_ERR_OK) { 
   $subido = copy($_FILES['archivo']['tmp_name'], $uploadfile); 
  } 
   if($subido) { 
    echo "El archivo subio con exito"; 
   } else {
    echo "Se ha producido un error: ".$error;
  }
?>

Veamos este código paso por paso:

  • $uploaddir: Esta variable contiene el directorio donde vamos a subir los archivos enviados a través del formulario. Es importante como escribimos el valor de esta variable. En el ejemplo escribimos $uploaddir = "uploads/", esto quiere decir que en el mismo directorio donde tenemos el archivo subir.php existe el directorio "uploads"; si este directorio no está, php dará un error al copiar el archivo subido. Otra forma de poner el directorio de subida es con el path absoluto, por ejemplo, en el servidor donde está alojado en este dominio seria $uploaddir = "/home/bloogie/public_html/undirectorio/el_directorio_de_subidas/". Nota como siempre tenemos que poner el último "/" y que cuando ponemos el path absoluto también ponemos un "/" al principio.
  • $uploadfile: En esta variable juntamos el directorio de subida con el nombre del archivo subido, de esta forma construimos la ruta a la que será copiado el archivo subido.
  • $_FILES: esta es una variable superglobal que contiene un array con información del archivo subido por método POST (como es nuestro caso).  La variable $HTTP_POST_FILES contiene la misma información pero es obsoleta desde php 4.1.0. Nuestro input para el archivo se llamaba "archivo" por lo que para obtener la información del archivo subido utilizaremos $_FILES['archivo']['info_a_obtener']. Entre la info más importante que podemos obtener está name (nombre), size (tamaño en bytes), type (contiene el MIME, por ejemplo "image/gif" para una imagen tipo gif), tmp_name (contiene la ruta temporal del archivo subido) y error (contiene el código de error del proceso de subida, será 0 si no hay ningún error).
  • $error: aquí vamos a guardar el código de error. Para posteriores comprobonaciones.
  • $subido: la variable que usaré para comprobar si finalmente el archivo se ha subido y guardado correctamente donde deseo.

La siguiente parte del código es comprobar que venimos del formulario (isset($_POST['boton'])) y que no hay error en la subida del archivo ($error==UPLOAD_ERR_OK). UPLOAD_ERR_OK tiene valor 0 por lo que también sería válido comparar la variable $error con 0 (más info en http://php.net/manual/en/features.file-upload.errors.php).

Bien, una vez comprobado que no hay error, realizamos la copia del archivo subido desde el directorio temporal a su ubicación definitiva cuya ruta ya construimos y almacenamos en la variable $uploadfile. Si se copia de forma satisfactoria la variable $subido será = true y lanzaremos un mensaje de éxito, de lo contrario se mostrará un mensaje de error incluyendo el código del error (visita el link que deje unas líneas más arriba sobre los códigos de errores al subir archivos).

Aunque el tamaño máximo para subida de archivos puede especificarse en la directiva upload_max_filesize establecida en la configuración de php, puede que no tengas acceso a esta configuración o que quieras limitar el tamaño de subida específicamente para este formulario. Así que compliquemos un poco más el script php con la comprobación del nombre, tipo y tamaño del archivo subido.

<?php
 $uploaddir = "uploads/";
 $uploadfilename = strtolower(str_replace(" ", "_",basename($_FILES['archivo']['name'])));
 $uploadfile = $uploaddir.$uploadfilename;
 $error = $_FILES['archivo']['error'];
 $subido = false;
 if(isset($_POST['boton']) && $error==UPLOAD_ERR_OK) {
    if($_FILES['archivo']['type']!="image/gif" || $_FILES['archivo']['size'] > 100000) {
      $error = "Comprueba que el archivo sea una imagen en formato gif y de tamano inferior a 10Kb.";
    } elseif(preg_match("/[^0-9a-zA-Z_.-]/",$uploadfilename)) {
      $error = "El nombre del archivo contiene caracteres no válidos.";
    } else {
        $subido = copy($_FILES['archivo']['tmp_name'], $uploadfile); 
    }
 } 
 if($subido) {
    echo "El archivo subio con exito";
   } else {
    echo "Se ha producido un error: ".$error;
  }
?>

Este script solo permitiría la subida de archivos de imagen en formato gif y de un tamaño inferior a 100Kb. Toma nota de la comprobación del nombre del archivo para que no contenga espacios ni caracteres no alfanuméricos (ni otros caracteres especiales como la ñ, que darían problemas en la inmensa mayoría de servidores que están basados en unix).

Nota: No me hago responsable si utilizas el código mostrado y este contiene errores o fallas de seguridad que pudieran comprometer algún aspecto de tu web.



Comentarios (38)

Community Builder Avatar
victor manuel
(18.05.2012 (18:15:16))
subir imagen desde iphone o ipad Sí No la parte de subir imagenes desde un iphone o ipad no se actiba queda bloqueado, sera el navegador del mismo.
Community Builder Avatar
cybnet
(16.05.2012 (22:15:02))
URL del archivo subido Sí No Citando "Alvaro" :
se podría hacer que cada imagen que subo se vea inmediatamente, generando una nueva url?
Tu decides donde van las imagenes subidas. En el script de ejemplo van al directorio especificado en la variable $uploaddir. La URL sería del tipo "http://www.tu-dominio.com/directorio-de-subida/imagen-subida.gif". Como ves saber la URL de la imagen es fácil de obtener y puedes mostrarla en el HTML para que se vea nada más subirla.
Community Builder Avatar
Alvaro
(16.05.2012 (13:24:13))
Y para que se vea la imagen, inmediatamente después de subirla? Sí No Hola, la explicación esta genial y me funciona de maravilla,muchísimas gracias... pero tengo una consulta: se podría hacer que cada imagen que subo se vea inmediatamente, generando una nueva url?

Gracias!!!
Community Builder Avatar
Alfredo
(15.05.2012 (20:56:51))
Problema con iis al subir archivo Sí No Citando "Alfredo" :
hola.
estoy realizando na craga de un archivo en donde guardo el nombre del archivo en una tabla de sql, al subir el archivo por ejemplo "Archivo.xml" con Apache la propiedad $_FILES['archivo']['name'] me regresa el nombre correcto, pero en IIS esa misma propiedad me arroja "rchivo.xml", todo el tiempo me quita la primer letra del nombre...

alguien sabe por que pasa eso???

muchas gracias.


investigando y leyendo sobre este problema que se me presento, no identifique ninguna posible solución, así que opte usar una función javascript pasandole como parametro el archivo y ahí si me pasaba el nombre completo junto con la ruta temporal. corte con un substring el nombre completo y lo almaceno en un campo oculto. con eso solucione el problemita que se me presento mas, sin envargo no lo solucione como me hubiera gustado..
muchas gracias por su tiempo y apoyo.

Saludos.
Community Builder Avatar
Alfredo
(15.05.2012 (20:09:52))
Problema al cargar archivo con iis Sí No Citando "El Preguntón" :
Saludos Alfredo,
Hace tiempo leí que la superglobal $_FILES presenta algunos problemas en IIS si tienes "fix_gpc_magic = On" activo en tu php.ini. Puedes mirar por ahí. No se me ocurre otra cosa. ¿Te pasa sólo si la primera letra del archivo es mayúscula?


Muchas gracias por la colavoracion, pero no encontre nada en mi php.ini sobre fix_gpc_magic, y me sucede con cualquier tipo de caracter, mayusculas, minuscula, numero...
Community Builder Avatar
El Preguntón
(15.05.2012 (19:59:20))
¿fix_gpc_magic() activo? Sí No Saludos Alfredo,
Hace tiempo leí que la superglobal $_FILES presenta algunos problemas en IIS si tienes "fix_gpc_magic = On" activo en tu php.ini. Puedes mirar por ahí. No se me ocurre otra cosa. ¿Te pasa sólo si la primera letra del archivo es mayúscula?
Community Builder Avatar
Alfredo
(15.05.2012 (19:42:51))
tengo un problema Sí No hola.
estoy realizando na craga de un archivo en donde guardo el nombre del archivo en una tabla de sql, al subir el archivo por ejemplo "Archivo.xml" con Apache la propiedad $_FILES['archivo']['name'] me regresa el nombre correcto, pero en IIS esa misma propiedad me arroja "rchivo.xml", todo el tiempo me quita la primer letra del nombre...

alguien sabe por que pasa eso???

muchas gracias.
Community Builder Avatar
cybnet
(14.05.2012 (19:59:40))
File_exists Sí No Citando "Marx" :
...como puedo evitar que una imagen con un nombre ya existente en un archivo subido anteriormente se rescriba ....
Puedes comprobar la existencia de un archivo con el mismo nombre con la función file_exists.
Community Builder Avatar
Marx
(14.05.2012 (19:43:00))
Evitar duplicidad de imagenes Sí No Hola cybnet al estar subiendo imagenes, como puedo evitar que una imagen con un nombre ya existente en un archivo subido anteriormente se rescriba o remplace.
Gracias por la ayuda
Community Builder Avatar
jorge
(14.05.2012 (18:37:10))
apoyo Sí No Hola, estoy modificando la pagina web de mi trabajo pero necesito subir archivos pdf a una tabla hecha en dreamweaver en dónde me ponga el link del archivo, un nombre diferente al del archivo y la fecha, me podrían ayudar por fa? tengo instalado un server win2008 y vertrigo. Gracias!!!
Community Builder Avatar
cybnet
(07.05.2012 (22:08:30))
Caracteres especiales en el nombre de archivo Sí No María y todos los demás: POR FAVOR LEEROS EL POST!!!!!!!!!!!!
Community Builder Avatar
maria
(07.05.2012 (20:57:13))
ayuda subida de pdf con caracteres especiales como el acento Sí No el problema que tengo es que tengo un formulario en el cual puedo subir archivos word y pdf , la subida df elos archivos es normal pero cuando el nombre del archivo contiene algun acento u otro caracter especial no lo sube y sale error porfaaa necesito ayuda :(
Community Builder Avatar
cybnet
(06.05.2012 (10:48:01))
Dudo que ese código te haya funcionado alguna vez Sí No Citando "Marcela" :
Tengo este código que me funcionaba pero no se que paso y ya no funciona para subir archivos pdf te agradeceria tus comentarios.
pongo el codigo pdf.
Marcela lo siento pero dudo mucho que el código que has puesto te haya funcionado alguna vez por lo que no puedo ayudarte, no sería ayuda si no montarte un script enterito para tus necesidades y eso es trabajo.
Community Builder Avatar
Marcela
(06.05.2012 (05:07:53))
pregunta Sí No hola oye mira me podrías colaborar, quiero subir un archivo pdf y que la ruta me quede almacenada en una base de datos. tengo este código que me funcionaba pero no se que paso y ya no funciona para subir archivos pdf te agradeceria tus comentarios.
pongo el codigo pdf.
Código :
</iframe>
<?php
require_once('Connections/imagenes.php');
?>
<?
//datos del arhivo
$nombre_archivo = $_FILES['userfile']['name'];
//echo $nombre_archivo;
$tipo_archivo = $_FILES['userfile']['type'];
//echo $tipo_archivo;
$tamano_archivo = $_FILES['userfile']['size'];
$rutaimg = "img/$nombre_archivo";
$rutadoc = "pdf/$nombre_archivo";

//compruebo si las características del archivo son las que deseo
if (!(strpos($tipo_archivo, "gif") || strpos($tipo_archivo, "x-download") || strpos($tipo_archivo, "jpeg") || strpos($tipo_archivo, "pdf")) ) {
echo "Tienes que insertar un archivo formato JPG, GIF o PNG";
}
else{
if(($tipo_archivo == "image/jpeg") || ($tipo_archivo == "image/gif") || ($tipo_archivo == "image/png"))
{
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $rutaimg)){
echo "El archivo ".$nombre_archivo." ha sido cargado correctamente.<br>";
list($width, $height, $type, $attr) = getimagesize("img/$nombre_archivo");
if($width > 2400)
{
$width = $width/3;
$height = $height/3;
}elseif($width > 1000)
{
$width = $width/2;
$height = $height/2;
}
echo "Ancho: " .$width;
echo '<br />';
echo "Alto: " .$height;
echo '<br />';
echo "Tipo: " .$type;
echo '<br />';
echo "Atributos: " .$attr."<br>";

echo '<img src="/img/'.$nombre_archivo.'" width="'.$width.'" height="'.$height.'">';
$insertar_img = "INSERT INTO `imagenes`.`imagenes` (`id`, `nombre`, `tipo`, `size`, `ancho`, `alto`, `fecha`, `ruta`) VALUES (NULL, '$nombre_archivo', '$tipo_archivo', '$tamano_archivo', '$width', '$height', '', 'img/$nombre_archivo'); ";

mysql_query("$insertar_img");
}else{
echo "Ocurrió algún error al subir el fichero. No pudo guardarse.";
}


}
elseif($tipo_archivo == "application/x-download" || $tipo_archivo == "application/pdf")
{
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $rutadoc)){
echo "El archivo ".$nombre_archivo." ha sido cargado correctamente.<br>";
$insertar_doc = "INSERT INTO `imagenes`.`pdf` (`id`, `nombre`, `ruta`, `fecha`) VALUES (NULL, '$nombre_archivo', 'pdf/$nombre_archivo', ''); ";
mysql_query("$insertar_doc");
}else{
echo "Ocurrió algún error al subir el fichero. No pudo guardarse.";
}
echo'<iframe width="500" height="500" src="/pdf/$nombre_archivo">';
}
}


?>
Community Builder Avatar
Samuel
(28.04.2012 (21:34:49))
excelente!! Sí No Gracias, estube buscando por muchos lados y no encontré algo que me funcionara.. esto me sirvió bastante. Saludos.

Smileys

:confused::cool::cry::laugh::lol::normal::blush::rolleyes::sad::shocked::sick::sleeping::smile::surprised::tongue::unsure::whistle::wink: