I have a form where a user can upload multiple images with Dropzone.js and then I store those images in the database and in the public/images folder.
But what I need is to add a watermark to all of these images before I save them in the public/images directory, because these images will show in the front-end as "preview" images.
I found documentation on how to add watermarks using Intervention Image here.
But I just cant figure out how I would proceed in adding that in my current setup.
Here is my form with the script:
<div id="file-preview_images" class="dropzone"></div>
<script>
let dropPreview = new Dropzone('#file-preview_images', {
url: '{{ route('upload.preview.store', $file) }}',
headers: {
'X-CSRF-TOKEN': document.head.querySelector('meta[name="csrf-token"]').content
}
});
dropPreview.on('success', function(file, response) {
file.id = response.id;
});
</script>
$file variable is when a user clicks on create a new File, it creates a new File with a unique identifier before its even saved. A file can have many uploads.
Here is my store method:
public function store(File $file, Request $request) {
// Make sure the user owns the file before we store it in database.
$this->authorize('touch', $file);
// Get the file(s)
$uploadedFile = $request->file('file');
$upload = $this->storeUpload($file, $uploadedFile);
$request->file( 'file' )->move(
base_path() . '/public/images/previews/', $upload->filename
);
return response()->json([
'id' => $upload->id
]);
}
protected function storeUpload(File $file, UploadedFile $uploadedFile) {
// Make a new Upload model
$upload = new Upload;
// Fill the fields in the uploads table
$upload->fill([
'filename' => $uploadedFile->getClientOriginalName(),
'size' => $uploadedFile->getSize(),
'preview' => 1
]);
// Associate this upload with a file.
$upload->file()->associate($file);
// Associate this upload with a user
$upload->user()->associate(auth()->user());
// Save the file
$upload->save();
return $upload;
}
All of that works as intended, I just need to add watermarks to each of these images, which I'm having trouble with.
I already saved a watermark image in public/images/shutterstock.png
I figured it out. This is what I had to do:
public function store(File $file, Request $request) {
// Make sure the user owns the file before we store it in database.
$this->authorize('touch', $file);
// Get the file(s)
$uploadedFile = $request->file('file');
$upload = $this->storeUpload($file, $uploadedFile);
// Get the image, and make it using Image Intervention
$img = Image::make($request->file('file'));
// Insert the image above with the watermarked image, and center the watermark
$img->insert('images/home/shutterstock.png', 'center');
// Save the image in the 'public/images/previews' directory
$img->save(base_path() . '/public/images/gallery/pre/'.$upload->filename);
return response()->json([
'id' => $upload->id
]);
}
And on the "storeUpload" method, changed the 'filename' too:
$upload->fill([
'filename' => $file->identifier.'-'.uniqid(10).$uploadedFile->getClientOriginalName(),
'size' => $uploadedFile->getSize(),
'preview' => 1
]);
Related
I have a Leave application project that generates a PDF file.
this is the code that generates the pdf after I click submit.
$id = DB::table('leave')->where('user_id', auth()->user()->id)->max('id');
$data = leave::where('id', $id)->select('*')->get();
$filename = auth()->user()->name." - S - ". "LEAVE - ".$randomString->randomString(8)."-".$request->filing_date.".pdf";
$path = storage_path('app/leave_file/'.$filename);
PDF::loadView('pdf_views.leave_pdf', $data[0])->setPaper('legal')->save($path);
if(file_exists($path)){
DB::table('leave_files')->insert([
'filename' => $filename,
'leave_id' => DB::table('leave')->where('user_id', auth()->user()->id)->max('id'),
]);
}
return redirect()->route('leave')->with('success', "success");
I wonder if I can make the newly generated pdf open in the new tab after I click submit on my leave application. thank you to anyone who can help
According to the Laravel docs this is what you need: https://laravel.com/docs/9.x/responses#file-responses
File Responses
The file method may be used to display a file, such as an image or PDF, directly in the user's browser instead of initiating a download. This method accepts the path to the file as its first argument and an array of headers as its second argument:
return response()->file($pathToFile);
return response()->file($pathToFile, $headers);
Use the Cache Facade, to store the generated pdf temporary.
$uuid = Str::uuid();
return response()->stream(function () use ($uuid) {
echo Cache::remember($uuid, 300, function() {
return 'genertated pdf content'
});
}, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => sprintf('attachment; filename=%s;', $uuid),
]);
Create a route to access to cached file. Name the route.
Now you can open it in a new tab from you frontend e.g. Generate the route with route('routename', ['param' => 123]) and pass it to your FE with a REST endpoint for example.
window.open(url,'_blank');
I'm trying to get the file ID of a created file using the google drive API so I can then use that to delete files. Here is the code:
$file = new Google_Service_Drive_DriveFile();
$file->setName($fileName);
$file->setDescription('Volunteer Hours');
$file->setParents(array($folderId));
$data = file_get_contents($filePath);
$createdFile = $this->service->files->create($file, array(
'data' => $data,
'uploadType' => 'multipart'
));
Is there some kind of .id method where I can say:
$createdFileID = $createdFile.id;
I have looked into the google drive api but wasn't able to find any such method. The reason I want an id for an uploaded file is so I can delete files if I wanted to using that specific id
Ultimately, here is the function I'm trying to write:
// Deletes a specific file from a specific folder
function deleteFile($folderName, $fileID) {
}
This way, we are protected and delete the right file if there happens to be files with the same name in a given folder.
I believe your goal as follows.
You want to retrieve the file ID of the uploaded file on Google Drive using googleapis for php.
When the filename of $fileName is existing in the specific folder of $folderName, you want to delete the existing file.
Answer for Question 1:
In this case, how about the following modification?
From:
$createdFile = $this->service->files->create($file, array(
'data' => $data,
'uploadType' => 'multipart'
));
To:
$createdFile = $this->service->files->create($file, array(
'data' => $data,
'uploadType' => 'multipart'
));
$createdFileID = $createdFile->getId(); // Added
By this, the file ID of the uploaded file can be retrieved with $createdFileID.
Answer for Question 2:
When you want to delete the file using the filename and folder name at function deleteFile($folderName, $fileName) {}, how about the following sample script?
Sample script:
function deleteFile($folderName, $fileName) {
$client = getClient();
$drive = new Google_Service_Drive($client);
$res1 = $drive->files->listFiles(array("q" => "name='{$folderName}' and trashed=false"));
$folderId = $res1->getFiles()[0]->getId();
$res2 = $drive->files->listFiles(array("q" => "name='{$fileName}' and '{$folderId}' in parents and trashed=false"));
if (count($res2->getFiles()) == 0) {
// When the filename of $fileName is not existing,
// do something
} else {
$fileId = $res2->getFiles()[0]->getId();
$drive->files->delete($fileId);
}
}
In this case, when the filename of $fileName is existing in the specific folder of $folderName, the existing file is deleted.
References:
Files: delete
Added:
When you want to delete the file using the file ID, you can use the following script.
function deleteFile($fileID) {
$client = getClient();
$drive = new Google_Service_Drive($client);
$drive->files->delete($fileID);
}
In this case, $folderName is not required to be used. Because at Google Drive, all files has the unique file ID.
Download link:-
<a href='"+ downloadlink + '/attachment-download/' + $('#employee_ID').val()+'/'+ res[i].file_name +"'>
Route:-
Route::get('/attachment-download/{id}/{filename}', array(
'uses' => 'AttachmentsController#getDownloadAttachments'
));
Attachment Controller:-
public function getDownloadAttachments($id,$filename){
$file="./img/user-icon.png";
$resource = \Employee::WhereCompany()->findOrfail($id);
$path = $this->attachmentsList($resource);
foreach($path as $index => $attachment){
if ($filename == $attachment['file_name']) {
$filePath = $attachment['url'];
}
}
//return \Response::download($file);
return \Response::download($filePath);
}
File URL Output:-
https://zetpayroll.s3.ap-south-1.amazonaws.com/employees/81/Screenshot%20from%202017-04-26%2015%3A07%3A45.png?X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAI57OFN3HPCBPQZIQ%2F20170612%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Date=20170612T144818Z&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Signature=59ecc4d11b7ed71bd336531bd7f4ab7c84da6b7424878d6487679c97a8c52ca7
In this, if try to download the file by using a static path like
$file="./img/user-icon.png";
return \Response::download($file);
it is downloaded fine. But not possible to downloading file from AWS URL, Please help me how to down file automatically using URL. Or How to get Path from URL in laravel or PHP.
Thank you.
Using the above function all the files are being downloaded. But while trying to open the files, text, pdf, ... files open (.text, .csv, .pdf..) without problem, but images don't.
$fileContent = file_get_contents($filePath);
$response = response($fileContent, 200, [
'Content-Type' => 'application/json',
'Content-Disposition' => 'attachment; filename="'.$filename.'"',
]);
return $response;
I'm building a small asset management system in Laravel 5.2
A user can upload images, video etc to the app and the asset meta data gets stored in the assets table. While that's happening, the asset is renamed to match the asset id (I'm storing the original filename too), I'm storing the mime type and uploading the file to S3.
Where I've come unstuck is storing the S3 url in database.
This is my method
public function store(AssetRequest $request)
{
// Initialise new asset and set the name
// from the form
$asset = new Asset(array(
'name' => $request->get('name')
));
$asset->user_id = Auth::user()->id;
// save the asset to the db
$asset->save();
// set the file var = form input
$file = $request->file('asset_path');
$extension = $file->getClientOriginalExtension();
// modify the asset name
$assetFile = $asset->id . '.' . $request->file('asset_path')->getClientOriginalExtension();
// push the new asset to s3
Storage::disk('s3')->put('uploads/' . $assetFile, file_get_contents($file));
$asset->mime = $file->getClientMimeType();
$s3Url = Storage::url($file);
$asset->s3_url = $s3Url;
$asset->original_filename = $file->getClientOriginalName();
$asset->filename = $assetFile;
$asset->file_extension = $extension;
// return ok
$asset->save();
return \Redirect::route('asset.create')->with('message', 'Asset added!');
}
The lines relating to my attempt at storing the S3 url
$s3Url = Storage::url($file);
$asset->s3_url = $s3Url;
Only seems to store a temporary path /storage//tmp/php8su2r0 rather than an actual S3 url. I'd like to avoid having to set the bucket manually, rather hoping I can use what is configured in config/filesystem.php
Any ideas?
you can get everything from the config using the config(key) function helper
so to get the s3 public url of file, do this:
function publicUrl($filename){
return "http://".config('filesystems.disks.s3.bucket').".s3-website.".config('filesystems.disks.s3.region').".amazonaws.com/".$filename;
}
or you can use the underlying S3Client:(taken from here)
$filesystem->getAdapter()->getClient()->getObjectUrl($bucket, $key);
What your are trying to achieve, I have been doing that in many projects.
All you need to do is create image_url column in database. And pass the s3 bucket link + the name of the file + the extension.
You should know the bit that is constant for me like : https://s3-eu-west-1.amazonaws.com/backnine8/fitness/events/ then I have the id and the extension. in your case it could be name and extension.
if(Input::get('file')) {
$extension = pathinfo(Input::get('filename'), PATHINFO_EXTENSION);
$file = file_get_contents(Input::get('file'));
$s3 = AWS::get('s3');
$s3->putObject(array(
'ACL' => 'public-read',
'Bucket' => 'backnine8',
'Key' => '/fitness/events/'.$event->id.'.'.$extension,
'Body' => $file,
));
$event->image_url = 'https://s3-eu-west-1.amazonaws.com/backnine8/fitness/events/'.$event->id.'.'.$extension;
$event->save();
}
What i am trying to achieve:
Force download a zip file that contains user opted pdf files.
What i did in controller to achieve this:
Generate pdf reports in folder APP.WEBROOT_DIR.DS."package_files" (i used MPDF library)
*it generates correct readable pdf. I call here $this->render();
With Zip feature of php, Generate package.zip (which consists pdf files from above specified folder)
*it generates correct zip file, when downloaded from server it opens as valid zip file in windows.
Set the controller viewClass to Media and set parameters to force download as zip file,
*Again here I call here $this->render();
Issue:
When i run i get zip file but when opened with winrar, Zip file obtained reports Unexpected end of archive.
I am not getting any usefull articles to get through this issue...
What i guess is calling two times render is making file corrupt
Thanks
My controller code:
/** before this code i generate pdf files and have no issue **/
/** now scan through the directory and add all the pdf files to a zip archive **/
$dir = new Folder("".APP.WEBROOT_DIR.DS."package_files");
$files = $dir->find('.*\.pdf');
$zip = new ZipArchive();
foreach ($files as $file) {
$file_path = $dir->pwd() . DS . $file;
$filename = $dir->pwd() . DS ."package.zip";
if ($zip->open($filename, ZIPARCHIVE::CREATE)!==TRUE) {
exit("cannot open <$filename>\n");
}
$zip->addFile($file_path,$file);
}
$zip->close();
/** now render the action to download the generated zip file **/
$this->viewClass = 'Media';
$params = array(
'id' => 'package.zip',
'name' => 'packaged_file',
'download' => true,
'extension' => 'zip',
'path' => APP . WEBROOT_DIR.DS.'package_files' . DS
);
$this->set($params);
$this->render();
at fisrt if you use Cakephp 2.3 use cake response file instaed of mediaView with these structure:
$this->response->file($file['path']);
// Return response object to prevent controller from trying to render
// a view
return $this->response;
here is doc: http://book.cakephp.org/2.0/en/controllers/request-response.html#cake-response-file
else remove $this->render(); at the end of your action and specify mime type option specially for zip and rar file for example for docx file add mime type option like:
// Render app/webroot/files/example.docx
$params = array(
'id' => 'example.docx',
'name' => 'example',
'extension' => 'docx',
'mimeType' => array(
'docx' => 'application/vnd.openxmlformats-officedocument' .
'.wordprocessingml.document'
),
'path' => 'files' . DS
);