Como subir una imagen con jQuery, Ajax y PHP
En este artículo vamos a explicar como permitir al usuario subir una imagen al servidor con jQuery, Ajax y PHP sin necesidad de recargar la página y sin utilizar plugins de terceros.
En el ejemplo en funcionamiento tenemos un formulario que contiene un imagen, el campo para seleccionar un archivo y un botón para realizar la subida. El usuario puede subir una imagen en formato png, jpg o gif. La imagen es cargada al servidor y se pre visualiza en pantalla sin recargar la página después de pulsar el botón «Subir».
¿Cómo lo conseguimos?
Hace tiempo andaba buscando un código como este que simplifique mucho el proceso, usando menos recursos y con un efecto similar. Resulta que es muy sencillo. Lo vamos a explicar utilizando el ejemplo que hemos creado para este tutorial.
Aspecto visual o diseño
La interfaz o aspecto visual es el siguiente:
Conseguido sin mucho esfuerzo gracias a la tecnología Bootstrap 4.
Código JavaScript necesario
En la cabecera o dentro de la etiqueta <head> de tu página tienes que agregar la librería jQuery y la llamada al evento:
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script>
$(document).ready(function() {
$(".upload").on('click', function() {
var formData = new FormData();
var files = $('#image')[0].files[0];
formData.append('file',files);
$.ajax({
url: 'upload.php',
type: 'post',
data: formData,
contentType: false,
processData: false,
success: function(response) {
if (response != 0) {
$(".card-img-top").attr("src", response);
} else {
alert('Formato de imagen incorrecto.');
}
}
});
return false;
});
});
</script>
El código anterior también puede estar incrustado justo antes de la etiqueta de cierre </body>.
Tan solo estamos esperando a que se haga click en el botón que contiene la clase «upload» para obtener el archivo seleccionado desde el ordenador para pasarlo al archivo «upload.php» para que pueda ser procesado en el servidor. Una vez se ha proceso la imagen en el servidor, si la respuesta es diferente de 0, el atributo src de nuestra imagen se cambiará por la respuesta. En caso contrario mostrar un alerta de error.
La clave del asunto está en la utilización de la clase FormData.
Los objetos FormData permiten compilar un conjunto de pares clave/valor para enviar mediante XMLHttpRequest. Están destinados principalmente para el envío de los datos del formulario, pero se pueden utilizar de forma independiente con el fin de transmitir los datos tecleados. Los datos transmitidos estarán en el mismo formato que usa el método submit() del formulario para enviar los datos si el tipo de codificación del formulario se establece en «multipart/form-data».
En el ejemplo estamos creando un objeto de tipo FormData para agregarle la imagen. El objeto FormData se lo pasamos al archivo PHP mediante la técnica Ajax. De esta forma, en el archivo PHP tendremos la información necesaria para procesar la imagen.
Este código también puede ser útil para subir otro tipo de archivos, tan solo realizando algunos ajustes.
Código HTML que debes añadir dentro del body de tu página
En el cuerpo o dentro de la etiqueta <body> agregamos el formulario que permite subir archivos:
<form method="post" action="#" enctype="multipart/form-data">
<div class="card" style="width: 18rem;">
<img class="card-img-top" src="images/default-avatar.png">
<div class="card-body">
<h5 class="card-title">Sube una foto</h5>
<p class="card-text">Sube una imagen...</p>
<div class="form-group">
<label for="image">Nueva imagen</label>
<input type="file" class="form-control-file" name="image" id="image">
</div>
<input type="button" class="btn btn-primary upload" value="Subir">
</div>
</div>
</form>
Se trata de un formulario simple que utiliza el atributo enctype=»multipart/form-data» para permitir la subida de archivos y se apoya de la tecnología Bootstrap para el diseño. Tan solo tenemos una imagen por defecto, el campo para seleccionar una imagen desde el ordenador y un botón que permite realizar la acción de subida al servidor.
Código PHP que se ejecuta en el servidor
El arhivo «upload.php» que usamos para procesar la imagen contiene lo siguiente:
<?php
if (($_FILES["file"]["type"] == "image/pjpeg")
|| ($_FILES["file"]["type"] == "image/jpeg")
|| ($_FILES["file"]["type"] == "image/png")
|| ($_FILES["file"]["type"] == "image/gif")) {
if (move_uploaded_file($_FILES["file"]["tmp_name"], "images/".$_FILES['file']['name'])) {
//more code here...
echo "images/".$_FILES['file']['name'];
} else {
echo 0;
}
} else {
echo 0;
}
Simplemente comprobamos que el archivo que se está intentando subir sea del tipo adecuado. En este caso, solo queremos que se puedan subir imágenes .png, .jpg o .gif y, seguidamente, usamos la función move_uploaded_file() de PHP para depositar el archivo seleccionado en el lugar que deseamos. Lo guardamos con el mismo nombre de subida.
Después de esta acción se podrían hacer muchos más procesos, como por ejemplo registrar algo en la base de datos o enviar un email. Recuerda que todo esto se puede hacer sin recargar la página.
Como respuesta usamos la función echo de PHP para retornar un 0 en caso de error o la ruta del archivo subido para depositarlo en el src tal y como puedes ver en el success de la llamada Ajax.
Conclusiones
El efecto que conseguimos con este código de ejemplo se puede conseguir con infinidad de plugins de terceros que andan rondando por la Web pero, pensamos que este código puede resultar muy útil en casos extremos en los que sea necesario utilizar los menos recursos posibles para hacerlo funcionar o en casos que se necesite algo simple para permitir al usuario subir una imagen. El caso es que los plugins de terceros suelen tener infinidad de opciones que finalmente no se utilizan, lo que los hace muy complejos y grandes en tamaño para tenerlos depositados en el servidor.
Hola. Me funciona muy bien el código, sin embargo, quisiera cambiarle el nombre. Estoy de acuerdo que lo puedo hacer directo en el archivo «upload.php», no obstante quiero mandar el nombre desde el primer script PHP donde se manda la foto, ya que el nombre proviene de una variable que se encuentra en el script original y lo quiero mandar a «upload.php» y usar ese nombre. Gracias de antemano.
Hola,
Para mandar el nombre al fichero upload.php quizá te pueda interesar hacerlo desde el javascript. Antes de la llamada Ajax puedes agregar una variable más como parámetro:
formData.append(‘nombre’,’Nombre del fichero’);
Saludos
Hola
tengo un problema, el script funciona, pero la imagen me la copia y es ilegible.
creo que tiene que ver con que no la codifica en base64
alguna sugerencia?
Gracias
buenas noches estoy haciendo un formulario, pero necesito que el programa me reconozca al cargar un archivo tipo texto (pdf, word) y me muestre un comodin que me diga que no es una imagen si no un archivo escrito.
Hola,
Una solución rápìda es explorar el nombre del archivo para separarlo por el «.» y mirar la extensión.
Saludos
Hay otras formas mas sencillas puedes poner mi script antes de
$(«.imgAdd»).click(function(){
$(this).closest(«.row»).find(‘.imgAdd’).before(‘Upload‘);
});
$(document).on(«click», «i.del» , function() {
$(this).parent().remove();
});
$(function() {
$(document).on(«change»,».uploadFile», function()
{
var uploadFile = $(this);
var files = !!this.files ? this.files : [];
if (!files.length || !window.FileReader) return; // no file selected, or no FileReader support
if (/^image/.test( files[0].type)){ // only image file
var reader = new FileReader(); // instance of the FileReader
reader.readAsDataURL(files[0]); // read the local file
reader.onloadend = function(){ // set image data as background of div
//alert(uploadFile.closest(«.upimage»).find(‘.imagePreview’).length);
uploadFile.closest(«.imgUp»).find(‘.imagePreview’).css(«background-image», «url(«+this.result+»)»);
}
}
});
});
Agregar las clases en tu formulario: imgUp , imagePreview esas dos clases las veras en el html que sigue:
Subir
Como puedo guardar una imagen desde un modal en una base de datos mysqli
Hola,
Para este tipo de ayudas que se salen de lo que hay en el blog debe enviarnos un ticket al centro de soporte situado en:
https://www.jose-aguilar.com/modulos-prestashop/es/soporte
y allí ya le indicaremos como podemos proceder para resolver este caso particular.
Saludos
Hola, muy bueno y claro el ejemple. Estoy utilizando tu codigo para un sistema de inventarios. Lo estoy haciendo para que lo utilizen cargando datos desde telefonos moviles. Con la camara frontal, menor calidad de imagen, la sube bien, con la camara posterior, mejor calidad, me da error de formato. En ambos casos las genera en jpg. Calculo que debe ser por el tamaño. Puede ser ese el problema? como lo puedo solucionar? Muchas gracias!!
Hola,
Si, podría ser que el tamaño sea el inconveniente ya que las fotografías que hacen los dispositivos móviles suelen ser imágenes con un tamaño en megas bastante grande para la subida a la web.
Seguramente tu servidor está limitado a un tamaño concreto. Solicita si fuera posible ampliar ese tamaño máximo de subida.
Saludos
Muchísimas Gracias por tu aporte, me sirvió mucho, una consulta, si quisiera restringir por tamaño de imagen, que debería hacer. Gracias de antemano.
Hola,
Si en el PHP haces un print_r($_FILES[‘file’]) podrás observar que hay un valor del array que contiene el size de la imagen. Puedes agregar una condición más para controlar el tamaño antes de guardar en el servidor.
Saludos
muchas gracias! despues de mirar 50 veces tu codigo…funciono el mio
Buenas noches, estoy intentando agregar a mi formulario la parte tuya de ajax y me sale el error undefined index file. Es un formulario con text, number y un file, los post los coge bien, pero el file no.
tengo el ajax asi:
$(«#art_button»).click(function(event){
event.preventDefault();
var formData = new FormData();
var files = $(‘#imagen’)[0].files[0];
formData.append(‘file’,files);
$.ajax({
url : «articulosalta.php»,
method : «POST»,
data : $(«form»).serialize(), formData,
success : function(data){
$(«#art_msg»).html(data);
}
})
})
y el fichero articulosalta.php me da de tiene que dar de alta el articulo, lo único que me falla es el campo file.
Hola,
A la llamada Ajax le faltan parámetros.
Saludos
en la linea , como agrego valor «nombre» asi
data: formData,{nombre:nombre}, no sale esta linea..
Hola muy buenas, me encanto ,gracias por el aporte, solo un apunte, si quisiéramos cambiar el nombre de la imagen como lo haríamos, por ejemplo si en el mismo formulario envió un imput con un id único, como se lo podría aplicar a la imagen para re nombrarla antes de pasarla a la carpeta de almacenamiento.
gracias de antemano.
Hola,
En la llamada a move_uploaded_file() tu puedes darle el nombre que quierar al archivo que se está subiendo. En el segundo parámetro específica la ruta del archivo agregando el identificador que haga falta como nombre del fichero .jpg
Saludos
hola de que manera podria implementar un formulario con esto y que solo se guarde el nombre de la imagen y la imagen en la carpeta y se relacione seria de mucha ayuda
Hola,
En el código del ejemplo casi lo tienes listo. Solo tienes que ver la forma de guardar el nombre en el lugar que desees y lo mismo con guardar el archivo en la ruta que desees.
Saludos
Muchísimas gracias, este código sin lugar a dudas perfecciona mucho cualquier sistema que trabaje o controle datos de personas y hace que el sistema sea muchos más ameno, bonito y ágil. Gracias por compartir
Andres que mejoras le arías, pudieras compartirla con nosotros?
lo implementare en mi pagina ya con algunas mejoras, amo este tipo de paginas ya que hacen que uno aplique mejoras en los codigos.
Gracias, me ayudó bastante este post.