Home > OS >  How can I load images efficiently while hiding the actual image url?
How can I load images efficiently while hiding the actual image url?

Time:08-24

So in the following code I have to query the database each time for every image. It's quite slow. Is there a way to do this in a single query while keeping the actual image urls hidden like I currently have in the blade file?

Blade:

<img src="/image/1">
<img src="/image/2">
<img src="/image/3">

Route:

Route::get('/image/{id}', [ImageController::class, 'image']);

Controller:

public function image($id)
{
    $img = DB::where('id', '=', $id)
        ->select('path', 'filename', 'extension')
        ->first();

    $image_path = $img->path.'/'.$img->filename.$img->extension;

    return response()->file( $image_path );
}

I'm basically getting the links from the database and the images should be accessible without having to login. I just want to hide the filename without having to change the actual filename to hash ids. The reason for this is because the filenames help me identify what I'm looking at. I just want to hide the filenames in the browser while not having to sacrifice performance.

CodePudding user response:

This looks like a perfect candidate for a View Composer:

app\Composers\ImageComposer.php (New file in new Folder app\Composers)

<?php

namespace App\Providers\Composers;

use App\Models\Image;
use Illuminate\View\View;

class ImageComposer {
  public function compose(View $view) {
    // Note: Important to use an `Image` model here for extended functionality
    $images = Image::whereIn('id', [1, 2, 3])->get();

    return $view->with(['images' => $images]);
  }
}

app\Providers\AppServiceProvider.php) (Existing File)

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Providers\Composers\ImageComposer;

class AppServiceProvider extends ServiceProvider {
  public function boot() {
    view()->composer('images', ImageComposer::class);
  }
}

app\Models\Image.php (New or Existing Model)

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Image extends Model {
  public function getDisplayPathAttribute() {
    return $this->path. '/' . $this->filename . $this->extension;
  }

  public function getBase64EncodedStringAttribute() {
    return 'data:image/' . $this->extension . ';base64,' . base64_encode(file_get_contents($this->display_path));
  }
}

images.blade.php (Existing file where your /images/1, etc. code is)

@foreach($images as $image)
  <img src="{{ $image->display_path }}"/>
  <!-- OR -->
  <img src="{{ $image->base64_encoded_string }}"/>
@endforeach

The basic logic here is that images.blade.php is a view, the Composer creates an $images variable, which you can then iterate over and fill in the src property with display_path, which is an Accessor on your Image model for returning the full path. Any time you render the images.blade.php view, either via @include('images'), or view('images'), etc., it will have $images available.

  • Related