Subir una imagen a ImgBB con Laravel

Subir una imagen a ImgBB con Laravel

Subir imágenes es una tarea muy común en la web, pero debes considerar donde vas a guardar dichas imágenes. Cargarlos en tu servidor no suele ser la mejor opción. La mejor alternativa es subirlos a un servicio de hosting de imágenes. ImgBB es un servicio de hosting de imágenes gratuito que cuenta con un API muy sencillo de integrar con tu proyecto Laravel.

Captura de pantalla 2022-09-09 172122.png

En este artículo construiremos un pequeño proyecto Laravel en el que cubriremos los pasos necesarios y de forma sencilla para usar ImgBB API.

La aplicación contará con un formulario que nos permitirá cargar una imagen y ponerle un nombre. Una vez enviado el formulario, el API de ImgBB subirá la imagen a nuestra cuenta y nos retornará un enlace. Este enlace y el nombre serán guardados en una tabla de nuestra base de datos. Finalmente extraeremos los datos de la tabla para mostrar la imagen y el título en una galería de imágenes.

formulario_imagen.png

galeria.png

Crear cuenta en ImgBB

Lo primero, dirígete a imgbb.com y regístrate con una cuenta gratuita. Una vez que hayas iniciado sesión podrás comenzar a subir imágenes directamente, pero lo que nos interesa es obtener el API KEY para poder subir nuestra imagen por medio de nuestra app. Ve al menú "Acerca" que está en la parte superior izquierda de la pantalla y elige la opción API.

pantalla_imgbb_edited.png

pantalla_api_key_edited.png

Ahora puedes ver el campo con el API KEY que utilizaremos en nuestra aplicación. El siguiente paso es crear nuestro proyecto Laravel.

Instalación y configuración del proyecto Laravel

Corremos el comando para instalar nuestro proyecto. Yo lo llamé tutorial-laravel-imgbb.

composer create-project laravel/laravel tutorial-laravel-imgbb

Cuando finalice la instalación entra al directorio tutorial-laravel-imgbb que se ha creado y corre el comando para instalar las dependencias de NPM.

npm install

Ahora debemos traer el package que nos permitirá usar el API KEY de ImgBB. Lo instalamos con el siguiente comando.

composer require 101infotech/imgbb

Luego hacemos un publish de los archivos de configuración del package que acabamos instalar.

php artisan vendor:publish  --tag="ImgBB"

Finalmente, busca el archivo de variables de entorno ".env", creamos una nueva variable "IMGBB_API_KEY" y pegamos el API KEY que vimos anteriormente.

variables_entorno_edited.png

Ya tenemos todo listo para comenzar a escribir un poco de código. A continuación seguimos con la creación de las vistas y agregaremos un poco de estilos.

Creación del formulario

Dentro del directorio views creamos un archivo home.blade.php, que tendrá nuestro formulario. Corre el comando para iniciar el servidor de desarrollo.

npm run dev

Colocamos el formulario y agregamos las clases para los estilos.

<main class="bg-slate-900">
        <section class="h-[100vh] flex justify-center items-center">
            <section class="w-full max-w-[400px] p-3">
                <h1 class="text-3xl text-stone-300 text-center py-10">Tutorial de Laravel e ImgBB</h1>
                <form action="" method="post" enctype="multipart/form-data">
                    @csrf
                    <img src="https://fakeimg.pl/350x350/?text=500x500" class="w-[150px] h-auto mx-auto mb-10 rounded" id="preview-img">                

                    <label class="block mb-10">
                        <span class="sr-only">Choose File</span>
                        <input type="file" class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-full file:border-0 file:text-sm file:font-semibold file:bg-indigo-900 file:text-stone-300 hover:file:bg-sky-800 hover:file:cursor-pointer"
                        id="fileinput" name="fileimage"/>
                    </label>

                    <input type="text" name="title" id="title" placeholder="Name image" class="block w-full p-2 mb-10 bg-transparent border-indigo-900 border-b-2 outline-0 focus:border-sky-800 text-stone-300">
                    <input type="submit" value="Enviar" class="text-center bg-indigo-900 hover:bg-sky-800 text-stone-300 p-3 rounded-xl cursor-pointer block w-full">
                </form>
            </section>
        </section>
    </main>

Hasta aquí nada nuevo. El formulario tiene tres input. El primer input es de tipo file, con el que cargaremos nuestra imagen, tiene el atributo name con el valor fileimage. El segundo input es de tipo text, para el título que le daremos a la imagen, tiene el atributo name con el valor title. El tercer input es de tipo submit que es el que envía el formulario. También tenemos una etiqueta <img> para la vista previa de nuestra imagen. Antes de la etiqueta de cierre del body agregamos un script JS para actualizar la vista previa cuando elegimos la imágen que vamos a subir.

<script>
        const fileinput = document.querySelector("#fileinput");
        fileinput.addEventListener("change", function (e) { 
            const target = e.target.files[0];
            const previewimg = document.querySelector("#preview-img");
            previewimg.src = URL.createObjectURL(target);
         }, false);
</script>

Analicemos lo que hace este script. La primer línea selecciona el input de tipo file por medio de su atributo id, y lo guarda en la const fileinput. En la segunda línea adjunta al fileinput una escucha de eventos para el evento change. Esto significa que cuando se produzca algún cambio en el elemento, el evento change lo detectará y entonces despachará la función. Dentro de la función vemos la línea e.target.files[0], esto le da acceso al archivo seleccionado y lo guarda en la const target. Luego selecciona el elemento img por medio de su atributo id="preview-img" y lo carga en la const previewimg. Finalmente actualiza el atributo src de la vista previa con el método estático URL.createObjectURL(target) y pasando como parámetro el target.

A continuación crearemos el componente para la galería.

Galería de imágenes

Para la galería utilizaremos un componente anónimo. Dentro del directorio views añadimos un directorio components y dentro creamos un archivo galeria.blade.php.

<section class="p-4 max-w-[960px] mx-auto grid grid-cols-1 gap-4 justify-items-center sm:grid-cols-2 lg:grid-cols-3">
    @for ($i = 0; $i < 6; $i++)
        <div class="bg-red-500 w-[300px] h-[300px] sm:even:justify-self-start sm:odd:justify-self-end lg:even:justify-self-auto lg:odd:justify-self-auto flex justify-center items-center text-white last:bg-sky-500">
            <figure class="relative">
                <img src="https://fakeimg.pl/500x500/?text=IMG" alt="image" class="w-full h-auto">
                <figcaption class="absolute bg-black/75 bottom-0 left-0 w-full p-4">IMAGE {{ $i + 1 }}</figcaption>
            </figure>
        </div>        
    @endfor
</section>

Con el código anterior queda formateado una grilla de imágenes que por ahora utiliza imágenes generadas por fakeimg.pl, mas tarde modificaremos esta vista para mostrar las imágenes que cargamos a nuestra cuenta imgbb.

Insertamos el componente a la vista principal home justo antes de la etiqueta de cierre <main/> como sigue.

<section>
      <h3 class="text-xl text-stone-300 text-center pb-4">GALERÍA</h3>
</section>
<x-galeria />

Por ahora hemos terminado con las vistas, lo que sigue es conectar la app a la base de datos, crear el modelo y la migración de la tabla que guardará los datos de las imágenes.

Base de datos

Para la base de datos vamos a usar MySQL. Ingresa a tu gestor de base de datos y crea uno. Yo estoy utilizando phpMyAdmin. A la base de datos lo llamé tutorial_imgbb.

base_datos.png

Ve al archivo de variables de entorno .env, busca la variable DB_DATABASE y coloca el nombre que le diste a tu base de datos.

DB_DATABASE=tutorial_imgbb

Ya estamos conectados, ahora crearemos el modelo y la migración de la tabla images.

Modelo y migración

Para generar el modelo y la migración de Images ejecutamos el siguiente comando.

php artisan make:model Image -m

Este comando generará dos ficheros. El fichero del modelo se encuentra el el directorio app/models/Image.php. Aquí colocamos los atributos que serán "mass assignable". El modelo quedará como sigue.

class Image extends Model
{
    use HasFactory;

    protected $fillable = ['title', 'url'];
}

Ahora la migración. El fichero se encuentra en database/migrations/create_images_table.php. Dentro de la función up() añadimos los campos title y url. La función quedará como sigue.

public function up()
    {
        Schema::create('images', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->string('url');
            $table->timestamps();
        });
    }

Ahora corremos las migraciónes.

php artisan migrate

Este comando debe insertar la tabla images en la base de datos tutorial_imgbb, con la estructura definida en la migración.

images_table_edited.png

A continuación generaremos los controladores y definiremos las rutas.

Controladores

Nuestra aplicación tendrá un solo controlador, ImageController.php. Lo generamos con el siguiente comando.

php artisan make:controller ImageController

El controlador generado se insertará en el directorio app/Http/Controllers/ImageController.php. Abrimos el fichero y vamos a crear primero la función save() que se encargará de subir la imagen a nuestra cuenta imgbb.com y guardará los datos en la tabla images.

public function save(Request $request)
    {
        $data = ImgBB::image($request->file('fileimage'));
        $image = new Image();
        $image->title = $request->title;
        $image->url = $data['data']['url'];
        $image->save();

        return redirect()->route('home');
    }

Veamos que sucede aquí. En la primer línea podemos ver en acción el package ImgBB que habíamos instalado y configurado. Esta sencilla línea de código se encarga de subir la imagen a nuestra cuenta. La función ImgBB::image() recibe como parámetro la imagen que queremos subir. Accedemos a dicha imagen por medio del método file de la instancia de la clase Request ($request->file()). El string que recibe este método debe coincidir con el atributo name del input file del formulario.

En la siguiente línea creamos una instancia del modelo Image. Establecemos el atributo title accediendo por medio de la instancia de $request->title. Para establecer el atributo url usamos $data. El método ImgBB::image() sube la imagen y retorna un array con un conjunto de datos. El dato que nos interesa está en $data['data']['url']. A continuación llamamos el método save() para guardar los datos en la tabla images.

Finalmente, la última línea hace un redireccionamiento hacia la misma vista home.

Debajo del método save() añadimos la función show() e insertamos el siguiente código.

public function show()
    {
        $data = Image::all();
        return view('home', ['images' => $data]);
    }

Este código es muy sencillo. En primer lugar el método Image::all() recupera todos los registros de la tabla images y los guarda en la variable $data. La línea siguiente hace un llamado a la vista home y le pasa la variable $data.

Continuamos definiendo las rutas.

Rutas

Para este ejemplo vamos definir solo dos rutas. Accedemos al fichero routes/web.php e insertamos el siguiente código.

Route::get('/', [ImageController::class, 'show'])->name('home');

Route::post('/', [ImageController::class, 'save'])->name('save-image');

La primer línea define una petición GET y lo vincula al método show de la clase ImageController que definimos anteriormente. Nombramos esta ruta con el nombre home.

La segunda línea realiza una petición POST y lo enlaza al método save del controlador ImageController. Lo nombramos save-image.

Regresamos a las vista para terminar con algunos detalles para finalizar.

Últimos detalles

En la vista home buscamos el atributo action del formulario y lo vinculamos la ruta POST. Debe quedar action='{{ route("save-image") }}'.

Más abajo en la sección de la galería agregamos una condición para verificar si hay registros o no.

@if($images->isNotEmpty())
      <section>
           <h3 class="text-xl text-stone-300 text-center pb-4">GALERÍA</h3>
      </section>
      <x-galeria :images="$images"/>
@endif

Como se observa en la código anterior, al componente galería le pasamos la variable $images para que los datos estén disponibles dentro del componente.

Ahora en el componente galeria debemos establecer que variables estarán disponibles dentro de este componente por medio de la directiva @props.

@props(['images'])

Finalmente modificamos el bucle for por un foreach para recorrer la variable de $images que recordemos es un array con los registros de la tabla images. El componente debe quedar como se muestra a continuación.

@props(['images'])

<section class="p-4 max-w-[960px] mx-auto grid grid-cols-1 gap-4 justify-items-center sm:grid-cols-2 lg:grid-cols-3">
    @foreach ($images as $image)
        <div class="bg-red-500 w-[300px] h-[300px] sm:even:justify-self-start sm:odd:justify-self-end lg:even:justify-self-auto lg:odd:justify-self-auto flex justify-center items-center text-white last:bg-sky-500">
            <figure class="relative">
                <img src="{{ $image->url }}" alt="image" class="w-full h-auto">
                <figcaption class="absolute bg-black/75 bottom-0 left-0 w-full p-4">{{ $image->title}}</figcaption>
            </figure>
        </div>                    
    @endforeach
</section>

El bucle recorre los registros que están en $images y guarda cada fila en $image. Remplazamos el valor del atributo src de <img> con $image->url para acceder a dirección de la imagen, luego en la etiqueta <figcaption> mostramos el título de la imagen a través de $image->title.

Ahora nuestra app es completamente funcional. Debes poder cargar una imagen, subirla a cuenta imgbb y mostrarlas en tu galería.

Para terminar, sería genial tener alguna notificación que nos avise cuando la imagen ha sido subida y guardada. Pues, para ello existe un package genial que se integra muy bien con proyectos Laravel, PHPFlasher.

PHPFlasher

PHPFlasher es un poderoso sistema de notificaciones para PHP. Para integrarlo a nuestro proyecto lo instalamos con el siguente comando.

composer require php-flasher/flasher-laravel

PHPFlasher cuenta con un conjunto de diversas notificaciones. Para nuestra app elegí SweetAlert 2. Para usarlo debemos instalar el correspondiente adaptador para Laravel.

composer require php-flasher/flasher-sweetalert-laravel

Está listo para usarlo. Abrimos nuestro controlador ImageController y al método save le pasamos una instancia SweetAlertFactory y luego llamamos al método addSuccess.

<?php

namespace App\Http\Controllers;

use App\Models\Image;
use Flasher\SweetAlert\Prime\SweetAlertFactory;
use Illuminate\Http\Request;
use Infotech\ImgBB\ImgBB;

class ImageController extends Controller
{
    public function save(Request $request, SweetAlertFactory $flasher)
    {
        $data = ImgBB::image($request->file('fileimage'));
        $image = new Image();
        $image->title = $request->title;
        $image->url = $data['data']['url'];
        $image->save();

        $flasher->addSuccess("La imágen ha sido guardado con éxito!");

        return redirect()->route('home');
    }

    public function show()
    {
        $data = Image::all();
        return view('home', ['images' => $data]);
    }
}

Una vez que la imagen suba a nuestra cuenta imgbb y guarde los datos en la tabla images se disparará una notificación con el texto que le pasamos al método addSuccess.

Conclusión

Hemos concluido con el proyecto. Pudimos comprobar los fácil que es usar ImgBB API e integrarlo a un proyecto Laravel. Logramos subir nuestras imágenes, guardar los datos en nuestra base de datos y mostrarlos en una sencilla galería.

El proyecto estará en mi repositorio de GitHub, puedes encontrarlo haciendo clic AQUÍ.

Espero que lo hayas encontrado entretenido, instructivo y claro. Si tienes alguna duda, puedes hacérmelo saber en los comentarios. Pronto estaré subiendo más tutoriales.

Nos vemos en la próxima. Saludos!👋😊