How to save image metadata in Laravel 5.6 - php

I'm trying to make an image gallery. For this purpose i'm storing the original images (right now about 7000 and in future there will be over 60.000) in the storage laravel path.
Next i make a job that stores the path and metadata(image size, resolution, mimetype, width and height) to db.
The problem is its very very slow.
this is my controller:
public function startJob() {
// Start doing Jobs
CreateDirectories::withChain([
new RecordPaths,
// new OptimizeImage,
// new SendNotification,
])->dispatch()->delay(now()->addSeconds(3));
echo 'create directories and stored paths to database!';
}
In my controller i make some jobs.
First it will make a directory where i'm storing thumbs. After this job is done the next one is RecordPaths to the DB.
And here is the problem it is very slow (image/2sec).
this is my job:
class RecordPaths implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function handle()
{
$this->truncate();
$files = Storage::disk('gallery')->allFiles();
foreach($files as $file) {
$thumb = new Thumb;
$thumb->brand = explode("/", $file, 2)[0];
$thumb->name = array_slice(explode("/", $file),-1)[0];
$thumb->path = $file;
//
$thumb->size = $this->imageMetadata($file, 'fileSize');
$thumb->width = $this->imageMetadata($file, 'imageWidth');
$thumb->height = $this->imageMetadata($file, 'imageHeight');
$thumb->mime = $this->imageMetadata($file, 'mimeType');
//
$thumb->save();
}
}
public function truncate() {
return Thumb::truncate();
}
public function imageMetadata($file, $type) {
$metaData = [];
$metaData['mimeType'] = \Image::make(storage_path("app\public\gallery\\") . $file)->exif('MimeType');
$metaData['fileSize'] = \Image::make(storage_path("app\public\gallery\\") . $file)->exif('FileSize');
$metaData['imageWidth'] = \Image::make(storage_path("app\public\gallery\\") . $file)->exif('ExifImageWidth');
$metaData['imageHeight'] = \Image::make(storage_path("app\public\gallery\\") . $file)->exif('ExifImageLength');
return $metaData[$type];
}
}
the $files = Storage::disk('gallery')->allFiles(); in the handle method return this:
and my db after some insers:
Do have anybody any idea how to speed it up ?

First of all do only one \Image::make instead of 4, then just call ->exif method with params.
Second, replace $thumb->save(); with batch inserting. You can use this library or write own code (look this).
P.S. It will increase your execution time.
P.S.S. Also you can try to use laravel chunks or split images between few job workers.

Related

How to track the uploaded size of a file in api laravel 8

I am developing a file system management using laravel 8.
I created a function that accept file.
public function uploadExperiment(Request $request)
{
$file = $request->file('file');
$uniqueId = time();
$fileName = $file->getClientOriginalName();
$filePath = $uniqueId . '/' . $fileName;
Storage::disk('local')->put($filePath, file_get_contents($file));
return response()->json(["success"=>true]);
}
I need to track the uploaded size during the uploading process and this progress I need to save it in a database.
For example, If I want to upload a file with 2GB of size, It will takes time. So any idea about how to track it?
maybe do you want create this:
https://www.itsolutionstuff.com/post/php-laravel-file-upload-with-progress-bar-exampleexample.html
to get size file upload in laravel use:
$size = $request->file('file')->getSize();
maybe could use this for get % of your upload you can use jquery. but if you want to do in php, with this example i think that you have one idea that you could to do:
function timeout_trigger() {
var loaded = file.getLoaded(); // loaded part
p = parseInt(loaded / size);
$(".progress").css("max-width",p+"%");
$(".progress-view").text(p+"%");
if(p!=100) {
setTimeout('timeout_trigger()', 20);
}
}
timeout_trigger();
i think that you have one form and you send it with POST for this use this function.

PHP - How to pass class to another class method

Im trying to pass the verot image editing class to a custom class that I created, but it doesnt seem to work, it doesnt do anything when I try to run it. How do I pass the verot image class to my class?
//Edit.php
//Now I run my class
$process = new ProcessEventLogo();
$process->editEventLogo($event_id,$file_ext,$savepath,new upload(''));
Here is my custom class. I thought by running upload('') to this method, Im passing a copy of the verot upload class that I can access in my custom class method. But when I run it, it doesnt even get past the $mainimg->uploaded path. In fact $mainimg = $fileupload->upload($savefile); returns NULL when I var_dump it. What am I doing wrong?
class ProcessEventLogo {
public function editEventLogo($eventid,$fext,$url,$savepath,$fileupload)
{
//We generate the file name to save this image to
$savefile = $savepath .'event_' .$eventid .'.' .$fext;
//We check to see if the event image is there
$mainimg = $fileupload->upload($savefile);
//We now resize the image
if($mainimg->uploaded)
{
$mainimg->file_overwrite = TRUE;
$mainimg->image_ratio_crop = TRUE;
$mainimg->image_resize = TRUE;
$mainimg->image_x = 50;
$mainimg->image_y = 50;
$mainimg->process($savefile);
if($mainimg->processed)
{
echo $mainimg->error;
}
}
}
It appears this worked, can someone verify this is the proper way of doing this? So instead of this line:
//We check to see if the event image is there
$mainimg = $fileupload->upload($savefile);
This worked.
//We check to see if the event image is there
$mainimg = new $fileupload($savefile);
#mr.void Right, so how else would I pass this class to my custom class
method? Just seems like this is the wrong way
I think writing a little Factory is the right way for this:
class uploadFac {
public function getUploadInstance($file)
{
return new upload($file)
}
}
And use it like this:
$uplFac = new uploadFac();
$process = new ProcessEventLogo();
$process->editEventLogo($event_id,$file_ext,$savepath,$uplFac);
and in the method:
public function editEventLogo($eventid,$fext,$url,$savepath,$uplFac)
{
//We generate the file name to save this image to
$savefile = $savepath .'event_' .$eventid .'.' .$fext;
$mainimg = $uplFac->getUploadInstance($savefile);

validating and save an uploaded ajax image in Yii

I need to send an image to server via an ajax request and it gets through just fine
and in my controller I can just use $_FILES["image"] to do stuff to it.
But I need to validate the image before I save it.
And in the Yii this can be achieved by doing something like this
$file = CUploadedFile::getInstance($model,'image');
if($model->validated(array('image'))){
$model->image->saveAs(Yii::getPathOfAlias('webroot') . '/upload/user_thumb/' . $model->username.'.'.$model->photo->extensionName);
}
But the problem is I don't have a $model, all I have is $_FILES["image"], now what should I put instead of the $model???
is there any other way where I can validate and save files without creating a model and just by Using $_FILES["image"]?
thanks for this awesome community... :)
Exists many ways how you can do upload. I want offer to you one of them.
1.You need to create model for your images.
class Image extends CActiveRecord {
//method where need to specify validation rules
public function rules()
{
return [
['filename', 'length', 'max' => 40],
//other rules
];
}
//this function allow to upload file
public function doUpload($insName)
{
$file = CUploadedFile::getInstanceByName($insName);
if ($file) {
$file->saveAs(Yii::getPathOfAlias('webroot').'/upload/user_thumb/'.$this->filename.$file->getExtensionName());
} else {
$this->addError('Please, select at least one file'); // for example
}
}
}
2.Now, need to create controller, where you will do all actions.
class ImageController extends CController {
public function actionUpload()
{
$model = new Image();
if (Yii::app()->request->getPost('upload')) {
$model->filename = 'set filename';
$insName = 'image'; //if you try to upload from $_FILES['image']
if ($model->validate() && $model->doUpload($insName)) {
//upload is successful
} else {
//do something with errors
$errors = $model->getErrors();
}
}
}
}
Creating a model might be overkill in some instances.
The $_FILE supervariable is part of the HTTP mechanism.
You can handle the copy by using the native PHP function move_uploaded_file()
$fileName = "/uploads/".myimage.jpg";
unlink($fileName);
move_uploaded_file($_FILES['Filedata']['tmp_name'], $fileName);
However, you lose the niceties of using a library that provides additional functionality and checks (eg file type and file size limitations).

Repositories with Laravel, saving image to DB

I have setup a repository to create a new resident.
<?php namespace Crescent\Repos;
interface ResidentRepository {
public function create($input);
}
Then in my controller I have, which uses the intervention image class to resize an image and it uploads correctly to the directory, but how can I save the name of the file to the DB using this repo?
public function store()
{
if (Input::hasFile('photo')){
$res = new Residents;
$file = Input::file('photo');
$name = $file->getClientOriginalName();
$input = Input::all();
$image = Image::make(Input::file('photo')->getRealPath())->resize(200, 200);
$image->save(public_path() . '/uploads/residents/' . $input['photo']->getClientOriginalName());
$res->photo = $name; // This doesn't work
}
$this->resident->create(Input::all());
}
Everything else works all the data, but the image isn't storing the name just showing some temp dir/name like /tmp/phpIX7KcY
I see that you have done $res = new Residents; and $res->photo = $name; but you haven't done $res->save(); which would have saved the name to the table corresponding to Residents. Also since you haven't added anything else to $res, only the photo would be saved.
Replace the code in your controller with the following:
public function store()
{
$input = Input::all();
if (Input::hasFile('photo')){
$file = Input::file('photo');
$name = $file->getClientOriginalName();
$image = Image::make(Input::file('photo')->getRealPath())->resize(200, 200);
$image->save(public_path() . '/uploads/residents/' . $input['photo']->getClientOriginalName());
$input['photo'] = $name;
}
$this->resident->create($input);
}
If in your code $this->resident->create(Input::all()); saves all data properly except the photo, it is because by passing Input::all() you're saving everything exactly as it was received from the client and the filename received from the resizing operation isn't present in Input::all(). By assigning Input::all() to the variable $input and doing $input['photo'] = $name;, the location of the file on the server is stored instead of the location on the client. So, by doing $this->resident->create($input);, the location on the server is stored along with other data received from the client.

ZF2 - Job queue to create a PDF file using SlmQueueBeanstalkd and DOMPDFModule

I'm trying to run a job queue to create a PDF file using SlmQueueBeanstalkd and DOMPDFModule in ZF".
Here's what I'm doing in my controller:
public function reporteAction()
{
$job = new TareaReporte();
$queueManager = $this->serviceLocator->get('SlmQueue\Queue\QueuePluginManager');
$queue = $queueManager->get('myQueue');
$queue->push($job);
...
}
This is the job:
namespace Application\Job;
use SlmQueue\Job\AbstractJob;
use SlmQueue\Queue\QueueAwareInterface;
use SlmQueue\Queue\QueueInterface;
use DOMPDFModule\View\Model\PdfModel;
class TareaReporte extends AbstractJob implements QueueAwareInterface
{
protected $queue;
public function getQueue()
{
return $this->queue;
}
public function setQueue(QueueInterface $queue)
{
$this->queue = $queue;
}
public function execute()
{
$sm = $this->getQueue()->getJobPluginManager()->getServiceLocator();
$empresaTable = $sm->get('Application\Model\EmpresaTable');
$registros = $empresaTable->listadoCompleto();
$model = new PdfModel(array('registros' => $registros));
$model->setOption('paperSize', 'letter');
$model->setOption('paperOrientation', 'portrait');
$model->setTemplate('empresa/reporte-pdf');
$output = $sm->get('viewPdfrenderer')->render($model);
$filename = "/path/to/pdf/file.pdf";
file_put_contents($filename, $output);
}
}
The first time you run it, the file is created and the work is successful, however, if you run a second time, the task is buried and the file is not created.
It seems that stays in an endless cycle when trying to render the model a second time.
I've had a similar issue and it turned out it was because of the way ZendPdf\PdfDocument reuses it's object factory. Are you using ZendPdf\PdfDocument?
You might need to correctly close factory.
class MyDocument extends PdfDocument
{
public function __destruct()
{
$this->_objFactory->close();
}
}
Try to add this or something similar to the PdfDocument class...
update : it seem you are not using PdfDocument, however I suspect this is the issue is the same. Are you able to regenerate a second PDF in a normal http request? It is your job to make sure the environment is equal on each run.
If you are unable to overcome this problem a short-term quick solution would be to set max_runs configuration for SlmQueue to 1. That way the worker is stopped after each job and this reset to a vanilla state...

Categories