Upload de archivos con PHP

Valoración del artículo:
Realizamos unas páginas PHP que reciben un archivo del discoduro del visitante y lo suben al servidor remoto.
Publicado: 09/11/03
Atención: Contenido exclusivo de DesarrolloWeb.com. No reproducir. Copyright.
En PHP tenemos muchas funcionalidades desarrolladas desde el principio y sin necesidad de instalar ningún añadido en nuestro servidor. Es el caso de subir archivos a un servidor web por HTTP y a través de una página con un formulario, donde se permite seleccionar el archivo que queremos cargar de nuestro disco duro.

El ejemplo se encuentra bien documentado en un montón de páginas para desarrolladores, sin ir más lejos en la página de la propia tecnología: http://www.php.net/manual/es/features.file-upload.php. Nosotros en este caso vamos a intentar ir un poco más allá, realizando un par de comprobaciones al subir el fichero y combinando en el mismo formulario campos de tipo file y tipo text.

El formulario para subir seleccionar los archivos

Es un formulario cualquiera, pero tiene una serie de particularidades y campos file, que no solemos utilizar habitualmente.

<form action="subearchivo.php" method="post" enctype="multipart/form-data">
    <b>Campo de tipo texto:</b>
    <br>
    <input type="text" name="cadenatexto" size="20" maxlength="100">
    <input type="hidden" name="MAX_FILE_SIZE" value="100000">
    <br>
    <br>
    <b>Enviar un nuevo archivo: </b>
    <br>
    <input name="userfile" type="file">
    <br>
    <input type="submit" value="Enviar">
</form>


Para empezar vemos que se ha colocado un nuevo atributo en el formulario: enctype="multipart/form-data", necesario para subir en un mismo formulario datos y archivos.

También tenemos el campo hidden MAX_FILE_SIZE, que sirve para indicar el tamaño en bytes de los archivos a subir. Este campo algunos navegadores no tienen porqué entenderlo o hacerle caso. Además, es fácil saltarse esa protección, por lo que deberemos en las propias páginas PHP comprobar que el archivo tenga el tamaño que deseamos.

Por último, tenemos el campo tipo file, donde se seleccionará el archivo a subir. También hemos colocado un campo de tipo text, para subir datos por POST de tipo texto acompañados a los datos binarios del archivo.

Página que sube los archivos

Esta página debe hacer las comprobaciones necesarias para saber si las características del archivo a subir son las que deseamos y realizar la copia del archivo en un directorio del servidor.

Para hacer las comprobaciones, PHP nos crea una serie de variables que podemos acceder con la información del archivo enviado.

$HTTP_POST_FILES['userfile']['name']
El nombre original del fichero en la máquina cliente.

$HTTP_POST_FILES['userfile']['type']
El tipo mime del fichero (si el navegador lo proporciona). Un ejemplo podría ser "image/gif".

$HTTP_POST_FILES['userfile']['size']
El tamaño en bytes del fichero recibido.

$HTTP_POST_FILES['userfile']['tmp_name']
El nombre del fichero temporal que se utiliza para almacenar en el servidor el archivo recibido.

Nota: En este momento (a partir de PHP 5) el array $HTTP_POST_FILES ha sido sustituido por el array $_FILES. En realidad es exactamente lo mismo, con la diferencia que $_FILES es más corto de escribir. Dependiendo de la configuración de tu PHP el nombre de variable antigua $HTTP_POST_FILES puede existir o no, pero en cualquier caso te recomendamos utilizar $_FILES para que tus scripts funcionen en cualquier servidor, independientemente de la configuración. Por ejemplo, usa $_FILES['userfile']['tmp_name'] en lugar de $HTTP_POST_FILES['userfile']['tmp_name'].

<?
//tomo el valor de un elemento de tipo texto del formulario
$cadenatexto = $_POST["cadenatexto"];
echo "Escribió en el campo de texto: " . $cadenatexto . "<br><br>";

//datos del arhivo
$nombre_archivo = $HTTP_POST_FILES['userfile']['name'];
$tipo_archivo = $HTTP_POST_FILES['userfile']['type'];
$tamano_archivo = $HTTP_POST_FILES['userfile']['size'];
//compruebo si las características del archivo son las que deseo
if (!((strpos($tipo_archivo, "gif") || strpos($tipo_archivo, "jpeg")) && ($tamano_archivo < 100000))) {
    echo "La extensión o el tamaño de los archivos no es correcta. <br><br><table><tr><td><li>Se permiten archivos .gif o .jpg<br><li>se permiten archivos de 100 Kb máximo.</td></tr></table>";
}else{
    if (move_uploaded_file($HTTP_POST_FILES['userfile']['tmp_name'], $nombre_archivo)){
       echo "El archivo ha sido cargado correctamente.";
    }else{
       echo "Ocurrió algún error al subir el fichero. No pudo guardarse.";
    }
}
?>


Para empezar, recogemos el campo de texto enviado por POST, de la forma habitual. Aunque esto no tenga nada que ver con subir archivos, es muy normal que en el mismo formulario deseemos mezclar varios tipos de información.

Luego se recogen los datos necesarios del archivo, como su nombre, extensión y tamaño para, en el siguiente if, comprobar que la extensión sea .gif o .jpg y que el tamaño menor que 100000 bytes.

Si el archivo tenía las características deseadas, se puede subir al servidor. Para ello se utiliza la función move_uploaded_file(), que recibe el nombre del archivo temporal que se desea subir y el nombre del archivo que se desea dar.

Cuando se sube el archivo, el servidor lo copia en una localización temporal para que seamos nosotros los que elijamos la posición definitiva donde queremos que se almacene. Si no lo copiamos a ningún sitio, después de la ejecución de la página, se borra de su localización temporal.

La función move_uploaded_file() se utiliza para mover el archivo a la posición definitiva. Recibe por un lado el nombre temporal del fichero y por otro el nombre que deseamos colocarle definitivamente y, si se desea, la ruta para llegar al directorio donde queremos guardarlo. En el caso del ejemplo sólo se indica el nombre del archivo, por ello el fichero se subirá al mismo directorio donde están las páginas PHP que hacen el upload. Esta función devuelve un boleano que indica si hubo o no éxito al subir el archivo.

Nota: Es importante señalar que el upload de archivos es un proceso crítico que puede dar lugar a errores y agujeros de seguridad. Por ejemplo, si los directorios destino están protejidos contra escritura, nos dará un error. Podemos ver los errores comunes relatados en la página de PHP.

Recomendamos una vez más ampliar esta información en la página de PHP: http://www.php.net/manual/es/features.file-upload.php

Se pueden descargar los códigos del ejemplo en este enlace.

Comentarios
Fueron enviados 27 comentarios al artículo
5 comentarios no revisados
22 comentarios revisados:
Por: Ducados
16/1/04
¿Algun usuario se ha topado con este estupendo error al probar este ejemplo?

Valor del Campo de Texto: archivo

Warning: Unable to create '016.jpg': Permiso denegado in /var/www/html/subir.php on line 55

Warning: Unable to move '/var/www/html/tmp/php8Y90P3' to '016.jpg' in /var/www/html/subir.php on line 55
Ocurrió algún error al subir el fichero. No pudo guardarse.

Lo dicho, si alguien sabe como solucionar esto, que postee aqui o me mande un email.

Gracias por Anticipado
Por: Nehos
25/1/04
El problema esta en los permisos del directorio donde se van a mover los archivos, en modo consola haz un chmod 777 nombreDirectorio, o implementa un pequeño script con php que te lo haga si no tienes accesso en modo consola
Por: speack
30/1/04
los errores que muestras parece ser que es porque en el directorio donde pusiste los scripts no le diste el permiso chmod, colocate arriba del directorio y con el menu contextual te aparecera un a opcion de chmod ponle 777...
bye
Por: Ducados
24/2/04
No es por problema de permisos, haciendole un "ls" al directorio en cuestión sale esto:
[root@ServidorWEB directorio]# ls -al /directorio/en/cuestion
total 80
drwxrwxrwx 2 usuario usuario 4096 feb 24 20:33 .
Dios mio, no siento las piernas... ¿será problema de la RedHat 9.0, del php.ini, de bush?
Saludos y Gracias
Por: FASAT
04/3/04
efectivamente, son los permisos en los directorios los que influyen en el envio de los archivos, no obstante, aconsejo crear una carpeta y en esa colocar el form y el php, ya que en ella, también quedan los archivos enviados.
FASAT
SANTIAGO, CHILE
Por: david
07/5/04
El campo MAX_FILE_SIZE = 100000, en que se mide exactamente, en bits o bytes? Lo que quiere decir en este ejemplo es que no se pueden subir ficheros de más de 100 Kb o 100 KB.

Es verdad que sólo se pueden subir ficheros de hasta 2 MB.
Si la unidad de medida es en bits, entonces para poder subir como mucho ficheros de un 1MB el valor de MAX_FILE_SIZE será 1024 KB que es 1024 * 1000 * B = 1024 * 1000 * 8 bits, no?
Espero que alguien lo entienda Saludos, david
Por: José A. Rivas G.
01/10/04
He utilizado este ejemplo para construir un upload de logotipos para un directorio que tengo en mi web, el comentario va por lo siguiente: Ya se establecen es el ejemplo como limitar el tipo de archivo y tamaño del mismo, pero necesito bloquear las dimensiones del mismo, realice distintas pruebas con getimagesize() y efectivamente me muestra las dimensiones de la imagen pero solo despues de que la misma se subió, hay alguna variable de tipo $HTTP_POST_FILES que deuelva el alto y ancho de un archivo de imagen. Gracias...
Por: Elias
10/3/05
funciona perfecto el upload, salvo con los archivos de extension "rar", le añadi el codiogo qeu realiza la comprobacion pero no me funciona, no asi con los zip u otras extensiones con las que no tengo problemas
Por: Victor
01/4/05
Genial el artículo. Me gustaría saber si es posible incluir en el archivo alguna sentencia para enviar por email desde el servidor el documento subido para tener una copia al momento de los archivos subidos desde el formulario. Gracias
Por: cesar sepulveda
14/4/05
Encuentro espectacular su ayuda. Estube tratando de aplicar este codigo al formulario de envio y no me adjunta el archivo y no lo envia al correo. Quisiera saber como se hace, serian tan amables de enviarme alguna ayuda.
Concretamente quisiera saber como adjuntar un archivo a un formulario y enviar los datos de este con el archivo al correo de destino.
gracias.
Por: cesar sepulveda
26/4/05
Exelente demostración de upload en php. Los felicito de verdad. Les cuento que me resulto perfectamente. El unico inconveniente es que no se a donde envia el archivo. Hay alguna de enviarlo a un correo electronico?. Ojala me contesten gracias por todo y los felicito!!!!
Por: oriol soriano
26/7/05
El script del ejemplo, sube el archivo al directorio pre-definido por defecto en php.ini para uploads, lo que hace la función move_uploaded_file() es moverlo de este directorio temporal al que tu decidas de la siguiente manera move_uploaded_file(directorio_temporal,directorio_nuevo) en el ejemplo solo pone nombre del archivo, con lo que se queda en el mismo directorio temporal definido en php.ini
Por: Dario Cortes Martinez
17/11/05
amigos
encontre la manera de guardar los archivos en carpetas designadas aqui les envio el codigo

<?
$path="\wwwarchivos/";

$nombre_archivo = $_FILES['userfile']['name'];
$tipo_archivo = $_FILES['userfile']['type'];
$tamano_archivo = $_FILES['userfile']['size'];

if (!((strpos($tipo_archivo, "doc") || strpos($tipo_archivo, "zip") || strpos($tipo_archivo,"jpg")) && ($tamano_archivo < 2000000000))) {
echo "La extensión o el tamaño de los archivos no es correcta. <br><br><table><tr><td><li>Se permiten archivos *.doc, *.zip o *.jpg<br><li>se permiten archivos de ?? máximo.</td></tr></table><br>";
echo "<a href='index.php'>Click aquí</a> para corregir los campos.";
}else{
if (move_uploaded_file($HTTP_POST_FILES['userfile']['tmp_name'], $path.$_FILES['userfile']['name'])){
echo "El archivo ha sido cargado correctamente.";
}else{
echo "Ocurrió algún error al subir el fichero. No pudo guardarse.";
}
}
?>

si se dan cuenta ocupe una variable path para darle la direccion
en mi caso trabajo con una carpeta archivos dentro de la raiz
localhostwwwarchivos

espero que les sirva
10.4
Por: Rodrigo Mazzo
28/1/06
Para los que tengan problemas con las extensiones rar o pptsimilares, para efectos de este script hay cosas que cambian. Por ejmplo, un archivo doc es msword, y uno ppt debe escribirse como vnd.ms-powerpoint. Para averiguar la extensión de una extensión particular, yo usé un "echo $HTTP_POST_FILES['userfile']['type']; "
Espero le sirva a alguien.. saludos,
Rodrigo
Por: Fabian
15/8/06
Me encanto el articulo pero tengo una duda muy pequeña estoy apenas aprendiendo php, y me gustaria saber o que me explicaran un poco mas donde se descarga el archivo que se subio ?
Por: Edgardo
07/9/06
el archivo se guarda en el directorio en donde se encuentra la pagina.php
Por: JEJE
24/12/06
imponente, explica muchas cosas que no sabia, muchas gracias, hace como 3 dias que buscaba algo que me explicara asi de claro, gracias
Por: César Santos
03/1/07
Muchas Gracias por esta demostración ordenada, correcta y muy bien definida, con tu aporte será suficiente para actulizar mi página web muchas gracias...

PorFavor no dejes de escribir Articulos para los iniciantes en PHP. Otra vez Gracias...
Por: Germán
30/6/07
Hola aquí les envio un script modificado que si funciona:tu página se llamrá:subir_archivo.php
<body>
Hola, estoy probando el codigo
<?php
echo $_POST['cadenatexto']." Nombres<br>";
if ($_POST['cadenatexto']!='')
{
$path="./archivos_php/";
$nombre_archivo = $_FILES['userfile']['name'];
$tipo_archivo = $_FILES['userfile']['type'];
$tamano_archivo = $_FILES['userfile']['size'];
if (!((strpos($nombre_archivo, "doc") || strpos($nombre_archivo, "gif") || strpos($nombre_archivo,"jpg"))))
{
echo "La extensión o el tamaño de los archivos no es correcta";
}
else
{
if (move_uploaded_file($HTTP_POST_FILES['userfile']['tmp_name'], $path.$_FILES['userfile']['name']))
{
echo "El archivo ha sido cargado correctamente.";
}
else
{
echo "Ocurrió algún error al subir el fichero. No pudo guardarse.";
}
}
}
?>
<form action="subir_archivo.php" method="post" enctype="multipart/form-data">
<b>Campo de tipo texto:</b>
<br>
<input type="text" name="cadenatexto" size="20" maxlength="100">
<input type="hidden" name="MAX_FILE_SIZE" value="100000000">
<br>
<br>
<b>Enviar un nuevo archivo: </b>
<br>
<input name="userfile" type="file">
<br>
<input type="submit" value="Enviar">
</form>
</body>
Por: iim.vxk
07/9/07
a los que tengan éstas 2 Advertencias - rutas son un ejemplo real - ::

-
move_uploaded_file(/uploads/images/sample.png) [function.move-uploaded-file]: failed to open stream: No such file or directory in /scripts/php/system/upload-file.php on line X
-

y

-
move_uploaded_file() [function.move-uploaded-file]: Unable to move '/tmp/somefilename' to '/uploads/images/sample.png' in /scripts/php/system/upload-file.php on line X
-

probablemente la ruta '/uploads/images/sample.png' esté incompleta, en mi caso la ruta completa es "/home/x-user/public_html/uploads/images/sample.png"

para saber el directorio actual de trabajo pueden usar getcwd(), de seguro se chingan al error.

XD

:)
Por: Leonardo Lux
03/11/07
Pueden encontrar una manera más actualizada de subir archivos en:

http://cl2.php.net/manual/es/features.file-upload.php

(por ejemplo, los arreglos $HTTP_POST_FILES están desactualizados en PHP5. Siempre vean la documentación en php.net).
Por: dsayritupac
04/11/08
<form action="subir_archivo.php" method="post" enctype="multipart/form-data">
<b>Campo de tipo texto:</b>
<br>
<input type="text" name="cadenatexto" size="20" maxlength="100">
<input type="hidden" name="MAX_FILE_SIZE" value="100000000">
<br>
<br>
<b>Enviar un nuevo archivo: </b>
<br>
<input name="userfile" type="file">
<br>
<input type="submit" value="Enviar">
</form>
</body>

<?php
// getcwd() ---> Captura la direccion correcta
$dir=getcwd();
echo $_POST['cadenatexto']." Nombres<br>";
if ($_POST['cadenatexto']!='')
{
// Utilizamos la variable $path para capturar la direccion completa incluyendo las carpetas [ /img_productos/webcams/] donde desea guardar sus imagenes
$path=$dir."/img_productos/webcams/";
$nombre_archivo = $_FILES['userfile']['name'];
$tipo_archivo = $_FILES['userfile']['type'];
$tamano_archivo = $_FILES['userfile']['size'];
if (!((strpos($nombre_archivo, "doc") || strpos($nombre_archivo, "gif") || strpos($nombre_archivo,"jpg"))))
{
echo "La extensión o el tamaño de los archivos no es correcta";
}
else
{
if (move_uploaded_file($HTTP_POST_FILES['userfile']['tmp_name'], $path.$_FILES['userfile']['name']))
{
echo "El archivo ha sido cargado correctamente.";
}
else
{
echo "Ocurrió algún error al subir el fichero. No pudo guardarse.";
}
}
}
?>

Manuales relacionados
Categorias relacionadas
El autor
Últimas noticias
Alojados en el grupo