Fast Access
This commit is contained in:
parent
6ef747b027
commit
18b6fb6807
8 changed files with 339 additions and 107 deletions
|
@ -74,6 +74,12 @@ class CalculateTraffic extends Command
|
|||
$traffic->hour = $split[5];
|
||||
$traffic->date = $split[2]."-".$split[3]."-".$split[4];
|
||||
}
|
||||
if($traffic->gallery == "") {
|
||||
$traffic->gallery = null;
|
||||
}
|
||||
if($traffic->tenant == "") {
|
||||
continue;
|
||||
}
|
||||
if($traffic->traffic != $trafficSize) {
|
||||
$traffic->traffic = $trafficSize;
|
||||
$traffic->saveOrFail();
|
||||
|
|
49
app/Entity/File.php
Normal file
49
app/Entity/File.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
namespace App\Entity;
|
||||
|
||||
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class File
|
||||
{
|
||||
private $drive;
|
||||
private $path;
|
||||
|
||||
private $size = null;
|
||||
private $content = null;
|
||||
|
||||
public function __construct(?string $drive, ?string $path)
|
||||
{
|
||||
Log::info("Create File Object", ["path" => $path, "driver" => $drive]);
|
||||
$this->drive = $drive;
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function setContent($content) {
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function getSize() {
|
||||
if(is_null($this->size)) {
|
||||
$this->size = Storage::disk($this->drive)->size($this->path);
|
||||
}
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
public function getContent() {
|
||||
if(is_null($this->content)) {
|
||||
Log::info("Get Content for file from Storage", ["driver" => $this->drive, "path" => $this->path]);
|
||||
$this->content = Storage::disk($this->drive)->get($this->path);
|
||||
}
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function response() {
|
||||
return Storage::disk($this->drive)->response($this->path);
|
||||
}
|
||||
|
||||
public function getDrive() {
|
||||
return $this->drive;
|
||||
}
|
||||
}
|
48
app/Helper/Access.php
Normal file
48
app/Helper/Access.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
namespace App\Helper;
|
||||
use App\Entity\File;
|
||||
use App\Models\Gallery;
|
||||
use App\Models\Tenant;
|
||||
|
||||
class Access {
|
||||
const TYPE_S3 = "Access";
|
||||
const TYPE_CACHE = "Cache";
|
||||
private $valideTyps = [self::TYPE_S3, self::TYPE_CACHE];
|
||||
|
||||
public function add(\App\Models\Image $image,File $file, string $typ) {
|
||||
if(!in_array($typ, $this->valideTyps)) {
|
||||
throw new \Exception("Invalide Typ for Access Log");
|
||||
}
|
||||
|
||||
$this->addAccessLog(null, null, $image->id, $typ, $file->getSize());
|
||||
}
|
||||
|
||||
public function addById(int $image_id, File $file, string $typ) {
|
||||
if(!in_array($typ, $this->valideTyps)) {
|
||||
throw new \Exception("Invalide Typ for Access Log");
|
||||
}
|
||||
$this->addAccessLog(null, null, $image_id, $typ, $file->getSize());
|
||||
}
|
||||
|
||||
public function addComplete(\App\Models\Image $image, Gallery $gallery, Tenant $tenant, File $file, string $typ) {
|
||||
if(!in_array($typ, $this->valideTyps)) {
|
||||
throw new \Exception("Invalide Typ for Access Log");
|
||||
}
|
||||
|
||||
$this->addAccessLog($tenant->id, $gallery->id, $image->id, $typ, $file->getSize());
|
||||
}
|
||||
|
||||
private function addAccessLog(?int $tenant, ?int $gallery, int $image, string $typ, int $size) {
|
||||
$access = new \App\Models\Access();
|
||||
$access->year = date("Y");
|
||||
$access->month = date("m");
|
||||
$access->day = date("d");
|
||||
$access->hour = date("H");
|
||||
$access->image = $image;
|
||||
$access->gallery = $gallery;
|
||||
$access->tenant = $tenant;
|
||||
$access->typ = $typ;
|
||||
$access->size = $size;
|
||||
$access->saveOrFail();
|
||||
}
|
||||
}
|
108
app/Helper/Image.php
Normal file
108
app/Helper/Image.php
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
namespace App\Helper;
|
||||
|
||||
use App\Entity\File;
|
||||
use App\Models\Gallery;
|
||||
use App\Models\Tenant;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class Image {
|
||||
/*
|
||||
* @var \App\Helper\ImagePreparation $imagePreparation
|
||||
*/
|
||||
private $imagePreparation;
|
||||
|
||||
/*
|
||||
* @var \App\Helper\Access $access
|
||||
*/
|
||||
private $access;
|
||||
|
||||
|
||||
|
||||
public function __construct(ImagePreparation $imagePreparation, Access $access)
|
||||
{
|
||||
Log::info("Create Image Helper Class");
|
||||
$this->imagePreparation = $imagePreparation;
|
||||
$this->access = $access;
|
||||
}
|
||||
|
||||
public function getImageById(int $id, ?int $size) : File {
|
||||
Log::info("Get Image by id", ["id" => $id, "size" => $size]);
|
||||
$image = \App\Models\Image::query()->where("id", "=", $id)->firstOrFail();
|
||||
return $this->getImage($image, $size);
|
||||
}
|
||||
|
||||
public function validateGalleryAndTenant(\App\Models\Image $image, string $gallery_url, string $tenant_url) : bool
|
||||
{
|
||||
$res = DB::select("SELECT `galleries`.`url` AS 'gallery_url', `tenants`.`url` AS 'tenant_url' FROM images LEFT JOIN `galleries` ON `images`.`gallery` = `galleries`.`id` LEFT JOIN `tenants` ON `tenants`.`id` = `galleries`.`tenant` WHERE `images`.`id` = ".$image->id.";");
|
||||
if($res[0]->gallery_url == $gallery_url && $res[0]->tenant_url == $tenant_url) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getImage(\App\Models\Image $image, ?int $size) : File {
|
||||
$cacheName = $this->getCachePath($image, $size);
|
||||
Log::info("Get Image", ["id" => $image->id, "size" => $size, "cachename" => $cacheName]);
|
||||
|
||||
if(Storage::disk("cache")->exists($cacheName) && $image->refreshCache == false) {
|
||||
Log::info("Found Image on Cache", ["id" => $image->id, "size" => $size, "cachename" => $cacheName]);
|
||||
return new File("cache", $cacheName);
|
||||
}
|
||||
|
||||
$file = $this->getRawImage($image);
|
||||
$gallery = Gallery::query()->where("id", "=", $image->gallery)->firstOrFail();
|
||||
$tenant = Tenant::query()->where("id", "=", $gallery->tenant)->firstOrFail();
|
||||
|
||||
$watermarkFile = null;
|
||||
if(!is_null($tenant->watermark)) {
|
||||
Log::info("Image has Watermark", ["id" => $image->id, "size" => $size, "cachename" => $cacheName]);
|
||||
$watermarkModel = \App\Models\Image::query()->where("id", "=", $tenant->watermark)->firstOrFail();
|
||||
$watermarkFile = $this->getRawImage($watermarkModel, true);
|
||||
}
|
||||
|
||||
$jpg = $this->imagePreparation->prepare($file, $size, $watermarkFile);
|
||||
|
||||
Storage::disk("cache")->put($cacheName, $jpg);
|
||||
|
||||
$file = new File("cache", $cacheName);
|
||||
$file->setContent($jpg);
|
||||
unset($jpg);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
public function getRawImage(\App\Models\Image $image, boolean $cache = null): File {
|
||||
$cacheName = $this->getCachePath($image, null);
|
||||
if(Storage::disk("cache")->exists($cacheName)) {
|
||||
Log::info("Get RAW-Image File from cache", ["image_id" => $image->id]);
|
||||
return new File("cache", $cacheName);
|
||||
}
|
||||
|
||||
if($cache === true || is_null($cache)) {
|
||||
Log::info("Get RAW-Image File from s3", ["image_id" => $image->id]);
|
||||
$content = Storage::disk($image->driver)->get($image->path);
|
||||
Storage::disk("cache")->put($cacheName, $content);
|
||||
$file = new File("cache", $cacheName);
|
||||
$this->access->add($image, $file, Access::TYPE_S3);
|
||||
$file->setContent($content);
|
||||
return $file;
|
||||
}
|
||||
|
||||
return new File($image->driver, $image->path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public function getCachePath(\App\Models\Image $image, ?int $size): string
|
||||
{
|
||||
if(is_null($size)) {
|
||||
$size = "orginal";
|
||||
}
|
||||
$cacheName = $image->id."_".$size."_".$image->filename;
|
||||
return $cacheName;
|
||||
}
|
||||
}
|
75
app/Helper/ImagePreparation.php
Normal file
75
app/Helper/ImagePreparation.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
namespace App\Helper;
|
||||
use App\Entity\File;
|
||||
use Intervention\Image\ImageManager;
|
||||
|
||||
class ImagePreparation {
|
||||
|
||||
public function prepare(File $file, ?int $size, ?File $watermarkFile) :string {
|
||||
$img = $this->prepareImage($file, $size, $watermarkFile);
|
||||
$jpg = (string)$img->encode('jpg', 100);
|
||||
$img->destroy();
|
||||
return $jpg;
|
||||
}
|
||||
public function prepareImage(File $file, ?int $size, ?File $watermarkFile) : \Intervention\Image\Image {
|
||||
$manager = new ImageManager(array('driver' => 'imagick'));
|
||||
$img = $manager->make($file->getContent());
|
||||
$watermark = null;
|
||||
if(!is_null($watermarkFile)) {
|
||||
$watermark = $manager->make($watermarkFile->getContent());
|
||||
}
|
||||
|
||||
if(!is_null($size)) {
|
||||
$img = $this->resizeImage($img, $size);
|
||||
}
|
||||
if(!is_null($watermark)) {
|
||||
$img = $this->addWatermarkImage($img, $watermark);
|
||||
}
|
||||
|
||||
return $img;
|
||||
|
||||
}
|
||||
|
||||
private function resizeImage(\Intervention\Image\Image $img, int $size) : \Intervention\Image\Image
|
||||
{
|
||||
if($img->getWidth() > $img->getHeight()) {
|
||||
$newWidth = $size;
|
||||
$newHeight = $img->getHeight() * ($newWidth / $img->getWidth() );
|
||||
} else {
|
||||
$newHeight = $size;
|
||||
$newWidth = $img->getWidth() * ($newHeight / $img->getHeight());
|
||||
}
|
||||
$img->resize($newWidth, $newHeight);
|
||||
|
||||
return $img;
|
||||
}
|
||||
|
||||
private function addWatermarkImage(\Intervention\Image\Image $img, \Intervention\Image\Image $watermark) : \Intervention\Image\Image {
|
||||
if($watermark->getWidth() > $img->getWidth()) {
|
||||
$newWidth = $img->getWidth() / 1.2;
|
||||
$newHeight = $watermark->getHeight() * ($newWidth / $watermark->getWidth());
|
||||
$watermark->resize($newWidth, $newHeight);
|
||||
}
|
||||
if($watermark->getHeight() > $img->getHeight()) {
|
||||
$newHeight = $img->getHeight() / 1.1;
|
||||
$newWidth = $watermark->getWidth() * ($newHeight / $watermark->getHeight());
|
||||
$watermark->resize($newWidth, $newHeight);
|
||||
}
|
||||
$watermark->opacity(40);
|
||||
$img->insert($watermark, 'center');
|
||||
$watermark->destroy();
|
||||
return $img;
|
||||
}
|
||||
|
||||
private function addWatermarkText(\Intervention\Image\Image $img, string $text) : \Intervention\Image\Image {
|
||||
$img->resizeCanvas(0, 28, 'top', true, "#000000");
|
||||
$img->text($text, $img->getWidth() - 10, $img->getHeight() - 25, function($font) {
|
||||
$font->file(storage_path("OpenSans-Light.ttf"));
|
||||
$font->size(18);
|
||||
$font->color('#ffffff');
|
||||
$font->align('right');
|
||||
$font->valign('top');
|
||||
});
|
||||
return $img;
|
||||
}
|
||||
}
|
|
@ -69,13 +69,28 @@ class PublicController extends BaseController
|
|||
return Storage::disk($image->drive)->response($image->path);
|
||||
}
|
||||
|
||||
public function returnImageFile($tenant_url, $gallery_url, $image_id, Request $request) {
|
||||
public function returnImageFile($tenant_url, $gallery_url, $image_id, \App\Helper\Image $image, \App\Helper\Access $access, Request $request) {
|
||||
$sizeName = $request->input("size", "medium");
|
||||
if(!array_key_exists($sizeName, self::$size)) {
|
||||
abort(400, "Size not exists");
|
||||
}
|
||||
$size = (int)self::$size[$sizeName];
|
||||
|
||||
$imageModel = Image::query()->where("id", "=", $image_id)->firstOrFail();
|
||||
if(!$image->validateGalleryAndTenant($imageModel, $gallery_url, $tenant_url)) {
|
||||
abort(404);
|
||||
}
|
||||
$img = $image->getImage($imageModel, $size);
|
||||
$typ = \App\Helper\Access::TYPE_S3;
|
||||
if($img->getDrive() == "cache") {
|
||||
$typ = \App\Helper\Access::TYPE_CACHE;
|
||||
}
|
||||
$access->addById($image_id, $img, $typ);
|
||||
return $img->response();
|
||||
|
||||
return
|
||||
|
||||
|
||||
$image = Image::query()->where("id", "=", $image_id)->firstOrFail();
|
||||
$gallery = Gallery::query()->where("url", "=", $gallery_url)->firstOrFail();
|
||||
$tenant = Tenant::query()->where("url", "=", $tenant_url)->firstOrFail();
|
||||
|
|
|
@ -42,112 +42,8 @@ class ResizeImage implements ShouldQueue
|
|||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
public function handle(\App\Helper\Image $imageHelper)
|
||||
{
|
||||
//Get Database Entitiys
|
||||
$image = Image::query()->where("id", "=", $this->image_id)->firstOrFail();
|
||||
$gallery = Gallery::query()->where("id", "=", $image->gallery)->firstOrFail();
|
||||
$tenant = Tenant::query()->where("id", "=", $gallery->tenant)->firstOrFail();
|
||||
$cacheName = "cache/".$tenant->url."_".$gallery->url."_".$image->id;
|
||||
|
||||
//Check if orginal size is cached on the current system
|
||||
$file = $this->getImage($tenant, $gallery, $image, $cacheName);
|
||||
|
||||
$manager = new ImageManager(array('driver' => 'imagick'));
|
||||
$img = $manager->make($file);
|
||||
|
||||
$newHeight = $img->getHeight();
|
||||
$newWidth = $img->getWidth();
|
||||
if($img->getWidth() > $img->getHeight()) {
|
||||
$newWidth = $this->size;
|
||||
$newHeight = $img->getHeight() * ($newWidth / $img->getWidth() );
|
||||
} else {
|
||||
$newHeight = $this->size;
|
||||
$newWidth = $img->getWidth() * ($newHeight / $img->getHeight());
|
||||
}
|
||||
|
||||
$tmpfname = tempnam("/tmp", "FOO").".jpg";
|
||||
|
||||
$img->resize($newWidth, $newHeight);
|
||||
|
||||
//$img->blur(50);
|
||||
if($this->size > 500 && !is_null($tenant->watermark)) {
|
||||
Log::info("Add Watermark");
|
||||
|
||||
|
||||
$waterMarkImage = Image::query()->where("id", "=", $tenant->watermark)->firstOrFail();
|
||||
$cacheNameWatermark = "watermark/".$waterMarkImage->id."_".$waterMarkImage->filename;
|
||||
$watermarkSource = $this->getImage($tenant, $gallery, $waterMarkImage, $cacheNameWatermark);
|
||||
|
||||
$watermark = $manager->make($watermarkSource);
|
||||
if($watermark->getWidth() > $img->getWidth()) {
|
||||
$newWidth = $img->getWidth() / 1.2;
|
||||
$newHeight = $watermark->getHeight() * ($newWidth / $watermark->getWidth());
|
||||
$watermark->resize($newWidth, $newHeight);
|
||||
}
|
||||
if($watermark->getHeight() > $img->getHeight()) {
|
||||
$newHeight = $img->getHeight() / 1.1;
|
||||
$newWidth = $watermark->getWidth() * ($newHeight / $watermark->getHeight());
|
||||
$watermark->resize($newWidth, $newHeight);
|
||||
}
|
||||
$watermark->opacity(40);
|
||||
$img->insert($watermark, 'center');
|
||||
|
||||
/*
|
||||
* Reddit like balken unten
|
||||
$img->resizeCanvas(0, 28, 'top', true, "#000000");
|
||||
$img->text('www.kuvia.cloud/'.$tenant->url, $img->getWidth() - 10, $img->getHeight() - 25, function($font) {
|
||||
$font->file(storage_path("OpenSans-Light.ttf"));
|
||||
$font->size(18);
|
||||
$font->color('#ffffff');
|
||||
$font->align('right');
|
||||
$font->valign('top');
|
||||
//$font->angle(45);
|
||||
});
|
||||
*/
|
||||
} else {
|
||||
Log::info("No Watermark");
|
||||
}
|
||||
|
||||
|
||||
|
||||
$img->save($tmpfname);
|
||||
Log::info("Update cache for Image", ["id" => $image->id, "size" => $this->size]);
|
||||
Storage::disk("cache")->put($cacheName."_".$this->size, file_get_contents($tmpfname));
|
||||
$image->refreshCache = false;
|
||||
$image->saveOrFail();
|
||||
unlink($tmpfname);
|
||||
|
||||
//Watermark
|
||||
//Storage::disk("cache")->put($cacheName."_".$this->size, $image->getImageAsString(IMAGETYPE_JPEG, 100));
|
||||
}
|
||||
|
||||
private function getImage(Tenant $tenant, Gallery $gallery, Image $image, $cacheName) {
|
||||
if (Storage::disk('cache')->exists($cacheName."_orginal") && $image->refreshCache == false) {
|
||||
$file = Storage::disk("cache")->get($cacheName."_orginal");
|
||||
} else {
|
||||
$this->addAccessLog($tenant->id, $gallery->id, $image->id, "Access", $image->size);
|
||||
$file = Storage::disk($image->driver)->get($image->path);
|
||||
if (env("CACHE_ORGINAL")) {
|
||||
Storage::disk("cache")->put($cacheName . "_orginal", $file);
|
||||
}
|
||||
}
|
||||
return $file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function addAccessLog(int $tenant, int $gallery, int $image, string $typ, int $size) {
|
||||
$access = new Access();
|
||||
$access->year = date("Y");
|
||||
$access->month = date("m");
|
||||
$access->day = date("d");
|
||||
$access->hour = date("H");
|
||||
$access->image = $image;
|
||||
$access->gallery = $gallery;
|
||||
$access->tenant = $tenant;
|
||||
$access->typ = $typ;
|
||||
$access->size = $size;
|
||||
$access->saveOrFail();
|
||||
$imageHelper->getImageById($this->image_id, $this->size);
|
||||
}
|
||||
}
|
||||
|
|
35
database/migrations/2021_01_20_232501_fast_access_log.php
Normal file
35
database/migrations/2021_01_20_232501_fast_access_log.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class FastAccessLog extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table("access", function(Blueprint $table) {
|
||||
$table->unsignedBigInteger("gallery")->nullable()->change();
|
||||
$table->unsignedBigInteger("tenant")->nullable()->change();
|
||||
});
|
||||
|
||||
Schema::table("traffic", function(Blueprint $table) {
|
||||
$table->unsignedBigInteger("gallery")->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue