Ver índice
Transferencia de ficheros

        Ocultar índice  

   Índice de contenidos
   Instalación en Windows
   Instalación en Ubuntu
   Servidores seguros
   Páginas dinámicas
   Sintaxis básica
   Operaciones
   Arrays
   Formatos de presentación
   Operadores
   Bucles
   Extraer y ord. información
   Funciones
   Ficheros externos
   Imágenes dinámicas
   Gestión de directorios
   Cookies y sesiones
   Clases y objetos
   Ficheros en formato PDF
   Bases de datos MySQL
   PHP y XML
   PDO - Bases SQLite / MySQL
   MySQL a traves de misqli
   Algo de JavaScript y AJAX


Comprobación de la configuración

Antes de empezar con este tema debemos comprobar cuál es la configuración de nuestro php.ini. Si por alguna circunstancia los valores no coincidieran con los que tenemos aquí debajo, tendríamos que abrir php.ini y modificar aquellas directivas. Cuando publicamos en un hosting no tenemos acceso al fichero de configuración php.ini pero sí podemos conocer su configuración mediante el script info.php.

Recordemos que ese fue nuestro primer script –lo hemos creado y utilizado– para comprobar nuestra instalación y lo hemos guardado con ese nombre en el root de nuestro servidor –/home/rinconas/public_html– así que podremos acceder a él escribiendo como dirección http://localhost/info.php.

La abundante lista que nos muestra info.php contiene las siguientes líneas (las podemos localizar fácilmente porque están ordenadas alfabéticamente), que en nuestro caso –configuración por defecto– tendrán los valores que vemos en la imagen.

Es imprescindible que file_uploads=On (tal como aparece en la imagen) y resulta muy útil también conocer el valor de upload_max_filesize que por defecto –tal como ves en la imagen– es de 2Mb. La primera directiva nos dice que PHP sí permite subir ficheros al servidor y la segunda nos indica el tamaño máximo (en Mbytes) de los ficheros que pueden ser objeto de esa transferencia.

Si te apetece, y como simple experimento, podemos cambiar el límite del tamaño máximo de transferencia poniendo un valor más reducido: upload_max_filesize=500K que nos servirá para hacer alguna prueba sencilla.

Transferencia de ficheros

La transferencia de un fichero requiere dos documentos: un formulario que la inicie y un script que la recoja.

El formulario

Se diferencia del que hemos visto en páginas anteriores en tres aspectos. Dos de ellos se refieren a cambios dentro de la etiqueta <form> y el tercero es un nuevo tipo de input del que aún no hemos hablado. En la etiqueta <form> hemos de incluir –obligatoriamente– method='POST' y ENCTYPE = "multipart/form-data" ya que no soporta ni otro método ni otra forma de codificación.

El cuerpo del formulario ha de contener un nuevo tipo de input que utiliza la siguiente sintaxis:

<input type='file' name='nombre'>

Observa que en el formulario hemos insertado una variable oculta (hidden) con el fin de limitar el tamaño máximo e impedir la transferencia de ficheros que excedan ese tamaño.

<html>
<body>
<form enctype="multipart/form-data" action="ejemplo169.php" method="post">
# con este input "oculto" establecemos el límite máximo
# del tamaño del fichero a transferir. En este ejemplo 1.000.000 bytes
<INPUT type="hidden" name="lim_tamano" value="1000000">
<p><b>Archivo a transferir<b><br>
<input type="file" name="archivo"></p>
<p><input type="submit" name="enviar" value="Aceptar"></p>
</form>
</body>
</html>

La tranferencia

Una vez enviado el formulario, el fichero transferido se guarda en un directorio temporal del servidor –salvo que php.ini especifique una cosa distinta– con un nombre que le es asignado de forma automática, y, además, se recogerán todos los datos relativos al contenido del fichero y a los resultados de la transferencia en la variable predefinida $_FILES.

El la variable $_FILES tiene formato de array bidimensional. El primero de sus índices es el nombre de variable usado para la transferencia (el especificado como name='nombre' en el input type='file').

Los segundos índices –se trata de un array asociativo– tiene como valores: name, type, tmp_name, error y size. En ellos se recogen: el nombre original del fichero transferido, su formato, el nombre con el que ha sido guardado en el directorio temporal, el tipo de error de transferencia y el tamaño del archivo.

El error puede ser CERO o UNO. Si es CERO indica que la transferencia se ha realizado con éxito. En caso contrario, el valor de ese error es UNO.

Este script, al que hemos llamado ejemplo169.php es el que recoge la action de formulario que hemos incluido unas líneas más arriba.

<?php
/* Mediante el bucle foreach leemos el array $_FILES.
   Observa la sintaxis. Escribimos como nombre del array
   $_['archivo'] con lo cual foreach leerá los elementos
   del array que tienen 'archivo" como primer índice
   (coincide con el name que hemos puesto
   en la etiqueta input=file del formulario) */

foreach ($_FILES['archivo'] as $indice=>$valor){
	print $indice."--->".$valor."<br>";

}
/*Dependiendo del navegador que estés utilizando puede ocurrir
que varían los valores del índice type sean distintos.
Cuando se trata de un fichero jpg, con IE devolverá image/pjpeg,
mientras que con Mozilla, Firefox, Opera y Netscape
devolverá image/jpeg.*/ 
 ?>
ejemplo168.php

Envía un fichero cualquiera –de menos de 2Mb– y verás que el error es 0. Repite el envío, ahora con un fichero que sobrepase ese tamaño, y comprobarás que el error toma valor 1 dado que la directiva upload_max_filesize=2M del fichero php.ini habrá bloqueado la transferencia.

Puedes modificar la configuración de php.ini y modificar esos límites de transferencia. Al hacerlo incrementarás o reducirás el límite máximo de transferencia.

Copia del fichero

Tal como hemos visto, el fichero transferido aún no está en el servidor. Por el momento se encuentra en un directorio temporal y será preciso hacer una copia en nuestro espacio de servidor. Para este proceso puede utilizarse una función que ya hemos visto en páginas anteriores:

copy(fichero1, fichero2)

donde fichero1 sería el fichero temporal y fichero2 el del nuevo fichero. El primero de los nombres es el valor contenido en: $_FILES['nm']['tmp_name'] donde nm es el valor incluido como name en el formulario usado para la transferencia y tmp_name es una palabra reservada que debe escribirse exactamente con esa sintaxis.

El valor fichero2 podría ser un nombre cualquiera asignado en el propio script –podemos verlo en el ejemplo– o el nombre original del fichero transferido. En este caso habría que recogerlo del elemento del array anterior cuyo segundo índice es name.

En la cadena fichero2 podría incluirse –recuerda que debes ponerlo entre comillas– un path señalando el directorio o subdirectorio donde queremos que guarde la copia. De no incluirlo, el fichero se copiaría en el directorio desde el que se está ejecutando el script.

Sintaxis alternativa

La opción anterior tiene una alternativa, igual de eficiente y mucho más segura. Se trata de:

move_uploaded_file(fich1, fich2)

que tiene la misma utilidad que copy y añade algunas ventajas tales como:

  ¡Cuidado!  

Al usar esta función bajo Windows conviene indicar en el parámetro fichero2 la ruta absoluta completa junto con el nombre del fichero ya que –de no hacerlo así– en algunas ocasiones la imagen no será transferida al directorio desde el que se ejecuta el script.

Mejorando las trasnferencias

Cuando está habilitada la opción de transferencias de ficheros es conveniente –en previsión de sorpresas desagradables– tomar algunas cautelas. Una de ellas sería limitar la posibilidad de transferencia a determinados tipos de archivos –imágenes, por ejemplo– impidiendo con ello que pudieran transferirse al servidor ficheros de riesgo, tales como: ejecutables, virus, etcétera.

Cuando se establece este tipo de limitaciones, PHP comprueba los contenidos de los ficheros sin tomar en consideración la extensión de los mismos. Con ello se evita el riesgo de que puedan esconderse –cambiando la extensión– ficheros distintos de los permitidos.

Aquí tienes un ejemplo de script que impide la transferencia de ficheros con extensión distinta a .jpg o .gif.

<?php
/* filtramos el tipo de archivos recibidos
de forma que solo se permitan imagenes en formato
jpg ó gif. Si el fichero transferido tuviera formato
distinto, la función exit() acabaría la ejecución del script */

if(!($_FILES['archivo']['type']=="image/pjpeg" OR 
                   $_FILES['archivo']['type']=="image/jpeg" OR 
	               $_FILES['archivo']['type']=="image/gif")){
    print "El formato ".$FILES['archivo']['type'].
	                                   " no está permitido";
     exit();
 }else{
	            # anidamos este segundo condicional
	            # para guardar en una variable
	            # la extensión real del fichero
	            # mas adelante la utilizaremos
	if ($_FILES['archivo']['type']=="image/pjpeg" OR
	             $_FILES['archivo']['type']=="image/jpeg" ){
		$extension=".jpg";
	}else{
		$extension=".gif";
	}
 }
 /* filtremos ahora el tamaño de modo que no supere
 el máximo establecido en el hidden del formulario
 (lógicamente ese valor no puede superar el valor máximo
 de la configuración de php, pero si puede ser menor)
 y también evitaremos archivos sin contenido, 
 es decir con tamaño CERO */
if($_FILES['archivo']['size']>$_POST['lim_tamano'] 
	                             OR $_FILES['archivo']['size']==0){
 print "El tamaño ".$FILES['archivo']['size']." excede el límite";
 exit();
 }

# asignemos un nombre a la imagen transferida
# de modo que se guarde en el servidor 
# con un nombre distinto, asignado por nosotros
# con ello, podemos evitar duplicidades de nombres
# ya que si existiera un fichero con el mismo nombre
# que el enviado por el cliente, se sobreescribiría

 $nuevo_nombre="foto_abuelita";
# añadámosle la extensión real de fichero que teníamos
# recogida en la variable nuevo_nombre

 $nuevo_nombre .=$extension;
# aceptemos la transferencia siempre que el archivo tenga nombre
if ($_FILES['archivo']['tmp_name'] != "none" ){
/* con la función copy
pasaremos el archivo que está en el directorio temporal
al subdirectorio que contiene el script que estamos
ejecutando. Podríamos incluir un path y copiarlo
a otro directorio */
           if (copy($_FILES['archivo']['tmp_name'], $nuevo_nombre)) {
	             echo "<h2>Se ha transferido el archivo</h2>"; 
		   }
    }else{
    echo "<h2>No ha podido transferirse el fichero</h2>";  
}

?>