diff --git a/app/Console/Commands/CalculateTraffic.php b/app/Console/Commands/CalculateTraffic.php index 904b66a..2caa408 100644 --- a/app/Console/Commands/CalculateTraffic.php +++ b/app/Console/Commands/CalculateTraffic.php @@ -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(); diff --git a/app/Entity/File.php b/app/Entity/File.php new file mode 100644 index 0000000..4c9a932 --- /dev/null +++ b/app/Entity/File.php @@ -0,0 +1,49 @@ + $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; + } +} diff --git a/app/Helper/Access.php b/app/Helper/Access.php new file mode 100644 index 0000000..6176020 --- /dev/null +++ b/app/Helper/Access.php @@ -0,0 +1,48 @@ +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(); + } +} diff --git a/app/Helper/Image.php b/app/Helper/Image.php new file mode 100644 index 0000000..65bc5e1 --- /dev/null +++ b/app/Helper/Image.php @@ -0,0 +1,108 @@ +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; + } +} diff --git a/app/Helper/ImagePreparation.php b/app/Helper/ImagePreparation.php new file mode 100644 index 0000000..9717435 --- /dev/null +++ b/app/Helper/ImagePreparation.php @@ -0,0 +1,75 @@ +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; + } +} diff --git a/app/Http/Controllers/PublicController.php b/app/Http/Controllers/PublicController.php index 4ec7dfc..3ff001f 100644 --- a/app/Http/Controllers/PublicController.php +++ b/app/Http/Controllers/PublicController.php @@ -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(); diff --git a/app/Jobs/ResizeImage.php b/app/Jobs/ResizeImage.php index f25da24..ec50609 100644 --- a/app/Jobs/ResizeImage.php +++ b/app/Jobs/ResizeImage.php @@ -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); } } diff --git a/database/migrations/2021_01_20_232501_fast_access_log.php b/database/migrations/2021_01_20_232501_fast_access_log.php new file mode 100644 index 0000000..e54aed3 --- /dev/null +++ b/database/migrations/2021_01_20_232501_fast_access_log.php @@ -0,0 +1,35 @@ +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() + { + // + } +}