# 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](https://cdn.hashnode.com/res/hashnode/image/upload/v1662754940717/ryI24Y7JV.png align="left")

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](https://cdn.hashnode.com/res/hashnode/image/upload/v1662759580671/cpYMMQPLN.png align="left")

![galeria.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662759608153/ajqfTEX_a.png align="left")

### Crear cuenta en ImgBB

Lo primero, dirígete a [imgbb.com](https://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](https://cdn.hashnode.com/res/hashnode/image/upload/v1662928903193/-zta8xtSJ.png align="left")

![pantalla_api_key_edited.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1662928855846/VXcXDHDU3.png align="left")

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.

```javascript
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.

```javascript
npm install
```

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

```javascript
composer require 101infotech/imgbb
```

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

```javascript
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](https://cdn.hashnode.com/res/hashnode/image/upload/v1662931222680/MYmkfODE3.png align="left")

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.

```javascript
npm run dev
```

Colocamos el formulario y agregamos las clases para los estilos.

```html
<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.

```html
<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`.

```html
<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](https://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.

```html
<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](https://cdn.hashnode.com/res/hashnode/image/upload/v1663105236437/IkpXK94O7.png align="left")

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.

```apache
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.

```javascript
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.

```php
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.

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

Ahora corremos las migraciónes.

```javascript
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](https://cdn.hashnode.com/res/hashnode/image/upload/v1663276249249/EhBDDhsdS.png align="left")

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.

```javascript
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`.

```php
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.

```php
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.

```php
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.

```html
@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`.

```php
@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.

```html
@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](https://php-flasher.io/).

### PHPFlasher

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

```php
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.

```php
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
<?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](https://github.com), puedes encontrarlo haciendo clic [AQUÍ](https://github.com/AlegreCode/tutorial-laravel-imgbb).

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!👋😊
