Fast Access

This commit is contained in:
Kekskurse 2021-01-21 01:13:41 +01:00
parent 6ef747b027
commit 18b6fb6807
8 changed files with 339 additions and 107 deletions

View file

@ -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
View 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
View 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
View 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;
}
}

View 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;
}
}

View file

@ -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();

View file

@ -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);
}
}

View 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()
{
//
}
}