I am working on a Laravel application and at some point, when I allow users to upload their own images for different purposes, I want to generate resized previews for these images.
I am uploading all user content to Amazon S3 and the first thing I did about resizing image is uploading the original image, then went through a foreach, resized the image and re-uploaded it to S3.
As you can image, having 4 sizes for each image dramatically increases the upload time and is a performance concern for me.
Here is a code snippet that I use in my upload function:
$storageDriver = Storage::disk('cloud-storage')->getDriver();
$parentSuccess = $storageDriver->put("/$parentId", file_get_contents($file), [
'visibility' => 'public',
'ACL' => 'public-read',
'ContentType' => $contentType,
]);
$ratio = $imageSize[0] / $imageSize[1];
foreach (self::IMAGE_SIZES as $size) {
if ($size > $imageSize[0] || ($size / $ratio) > $imageSize[1]) {
continue;
}
$id = DB::table('storage')->insertGetId([
'content_type' => $contentType,
'parent_id' => $parentId,
'image_width' => $size,
'image_height' => intval($size / $ratio),
]);
$image = Image::make($file)->encode('jpg');
$image->resize($size, null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
$image->save();
$success = $storageDriver->put("/$id", (string)$image, [
'visibility' => 'public',
'ACL' => 'public-read',
'ContentType' => 'image/jpeg',
]);
if (!$success) {
return null;
}
}
(I know there is a lot of code not included, but it's not relevant).
What method would you choose for handling this in a more efficient way?
Had to implement something like this in my last project, I used Lazy loading. Upload the parent image to s3 and generate the thumbnails only when needed.
You can have the function getThumbnails() attached to the model that has image. The function checks if thumbnails have been generated for that model and returns it, else it generates them.
public function getThumbnails(){
$thumbDir = "path/to/model/thumbnail/dir";
//Check if the folder exists.
//You can also double check if the directory actually has the thumbnails in it
if(!file_exists($thumbDir)){
$this->generateThumbnails($thumbDir);
}
//Return something
}
For more fun, you can be more specific and have a function handle each thumbnail.
public function getThumbnailX(){
$thumb = "path/to/specific/model/thumbnail";
if(!file_exists($thumb)){
$this->generateThumbnailX($thumb);
}
return $thumb;
}
public function getThumbnailX2(){
...
}
Super fun, add it as an attribute of the model.
public function getThumbXAttribute(){
return getThumbnailX();
}
so you can go ahead and call $model->thumbX whenever you need thumbX.
This reduces processing time and also the size of storage required as not all images may have their thumbnail generated.
Related
This is the code that i use now, this works for uploading single images, but i want the option to choose multiple images at the same time and upload them to the s3 bucket.
public function create() {
return view(view: 'images.create');
}
public function store(Request $request) {
$path = $request -> file(key: 'image') -> store(path: 'images', options: 's3');
$image = Image::create([
'filename' => basename($path),
'url' => Storage::disk(name: 's3') -> url($path)
]);
return $image;
}
public function show(Image $image) {
return $image -> url;
}
I have been looking into the answer to this question: Uploading multiple files to Amazon S3 from PHP
But struggle to understand and how to implement it into my own code.
i am trying to update the image of profil ,because to user at the beginning it creates account without image, after it goes the update, so i store the image in root /aswakfolder/public/storage/profiles and i insert image link in db profiles/nameimage.jpeg, i created a function in helpers.php file to display the image its work very will, the problem here is that I do not understand the helpers function, and it does not meet my needs, my need is when image upload and exists it displays my image if not it displays image not-found.jpeg,in my case it always displays not-found.jpeg.
stock image in my folder, and url image insert in db very well.
UsersController.php
public function update(Request $request, $id)
{
$user=User::find($id);
if($request->hasFile('image'))
{
$image = $request->file('image');
$path = $request->image->store('profiles');
$user->image = $path;
}
$request->image = $user->image;
$user->id = Auth::user()->id;
$user->update([
$user->name => $request->name,
$user->email => $request->email,
$user->telephone => $request->telephone,
$user->daten => $request->daten,
$user->country_id=> $request->country_id,
$user->state_id => $request->state_id,
$user->city_id => $request->city_id,
$user->image => $request->image,
]);
session()->flash('success', 'user updated successfully !!');
return redirect('users');
}
helpers.php
function productImage($path)
{
return $path && file_exists('/aswakfolder/public/storage/'.$path) ? asset('/aswakfolder/public/storage/'.$path) : asset('/aswakfolder/public/storage/not-found.jpg');
}
index.blade.php
<div class="inner" style="background-image: url({{ asset(productImage($users->image)) }})">
Make sure you run the commend php artisan storage:link to create the shortcurt on public/ folder.
Documentation
Please guys any idea how to delete multiple records that involve images. i do not know any approach that i can use. i have tried a lot.this is the what i have tried below.Pls help me guys i really need your help.Thanks in advance
please this is the code below
public function multipleUserDelete(Request $request,$id, $post_image){
if ($request->isMethod("post")) {
$data=$request->all();
//$del_user = $request->del_user;
// $ids=$del_user[];
//foreach(session('posts') as $session){
//foreach(session('products') as $postDelete){
$postDeletes=Post::where(['id'=> $id])
->where('post_image', $post_image)
->get();
foreach ($postDeletes as $postDelete) {
# code...
// $postDeletes=Post::where(['id'=> $id])->get();
//}
$large_image_paths='images/backend_image/admin_users/small/';
$medium_image_paths='images/backend_image/admin_users/medium/';
$small_image_paths='images/backend_image/admin_users/large/';
//Delete Image permenently from product table begins
//Delete Large image if not exist
if(file_exists($large_image_paths. $postDelete->post_image)){
unlink($large_image_paths. $postDelete->post_image);
}
//Delete Large image if not exist
if(file_exists($small_image_paths. $postDelete->post_image)){
unlink($small_image_paths. $postDelete->post_image);
}
//Delete Medium image if not exist
if(file_exists($medium_image_paths. $postDelete->post_image)){
unlink($medium_image_paths. $postDelete->post_image);
}
}
//$del_id=$request->input('del_feedback');
Post::whereIn('id', $data['del_user'])->delete();
return redirect()->back()->with("flash_message_success","you Successfully Deleted The Selected Users(s)");
}
Not tested, but I think something like this should work fine.
$image_path = "/images/"; // Value is not URL but directory file path
Post::where(['id'=> $id])
->where(function($query){
if(File::exists($image_path . $post_image)) {
File::delete($image_path . $post_image);
}
$query->where('post_image', $post_image)
})
->delete();
In general, the path issue should probably be
absolute.
See How to delete file from public folder in laravel 5.1
I don't know in Laravel 6, but it should work.
i.e. using File :: delete ()
Add the folder that contains your image to your config/filesystems.php files:
'disks' => [
'local' => [
'driver' => 'local',
'root' => base_path('app'),
],
//Above bit should already be there. So add this....
'some-image-path' => [
'driver' => 'local',
'root' => base_path("wherever/your/directory/is/from/root/"),
],
You would then use it like this:
$myImage = 'some-image.png';
Storage::disk('some-image-path')->delete($myImage);
public function multipleUserDelete(Request $request,$id, $post_image){
if ($request->isMethod("post")) {
$data=$request->all();
$postDeletes=Post::where(['id'=> $id])
->where('post_image', $post_image)
->get();
$img_array = array();
foreach ($postDeletes as $postDelete) {
$large_image_paths='images/backend_image/admin_users/small/';
$medium_image_paths='images/backend_image/admin_users/medium/';
$small_image_paths='images/backend_image/admin_users/large/';
$img='';
if(file_exists(public_path($large_image_paths. $postDelete->post_image))){
$img = $large_image_paths. $postDelete->post_image;
}
if(file_exists(public_path($small_image_paths. $postDelete->post_image))){
$img = $small_image_paths. $postDelete->post_image;
}
if(file_exists(public_path($medium_image_paths. $postDelete->post_image))){
$img = $medium_image_paths. $postDelete->post_image;
}
array_push($img_array,$img);
}
\File::delete($img_array);
Post::whereIn('id', $data['del_user'])->delete();
return redirect()->back()->with("flash_message_success","you Successfully Deleted The Selected Users(s)");
}
First at all I'm sorry for my bad English, I have been searching all how to fix my problem (Image on database is gone when trying to not update the image) and I found this : codeigniter image update
My problem is pretty same like that question, but when I try to fix it to be like that its still error.
So I can update an image or change the old image into new image, but when I try to not update the image (maybe just edit the another values in form, not the image), the image value on database is gone (NULL). And what I want is when I not update the image, the image is still same like the old image. Here is my code, placed in same file on model directory :
Constructor :
public function __construct()
{
parent::__construct();
// Setting up the upload configuration
$config['upload_path'] = 'photo_dir/';
$config['allowed_types'] = 'jpg|jpeg|png';
$config['file_ext_tolower'] = TRUE;
$config['max_size'] = 2048;
$this->load->library('upload', $config);
}
Function to get old image value :
// This function is to read the old image in database
private function _selected_img($id)
{
return $this->db->select()
->from('tb_exam')
->where('id_exam', $id)
->limit(1)
->get()
->row();
}
Update function :
// The update function
public function update($id)
{
// Get the old image first and declare it in variable `file`
$file = $this->_selected_img($id)->img;
// Upload the image
$this->upload->do_upload('img');
// If upload image data is not null, and then change the
// `file` value into the image file_name
if ($this->upload->data() !== '')
{
$file = $this->upload->data('file_name');
}
// Object to update
$this->object = array(
'id_teacher' => $this->input->post('id_teacher'),
'id_subject' => $this->input->post('id_subject'),
'question' => $this->input->post('question'),
'img' => $file,
'option_a' => $this->input->post('option_a'),
'option_b' => $this->input->post('option_b'),
'option_c' => $this->input->post('option_c'),
'option_d' => $this->input->post('option_d'),
'option_e' => $this->input->post('option_e'),
'answer_key' => $this->input->post('answer_key')
);
// Update the data
$this->db->where($this->main_id, $id)->update($this->table, $this->object);
// If record is success, return TRUE
// but if not, return FALSE
if ($this->db->affected_rows() > 0)
{
return TRUE;
}
else
{
return FALSE;
}
}
All of your helps and answer is highly appreciated !
Have you got the old image name correctly. please check that by echo $file; exit;
if you are not getting the file name correctly use the following code to get the old image name$query = $this->db->get_where('tb_exam', array('id_exam' => $id));
$data=$query->result_array();
$file=$data[0]['img'];
use this code directly in your update function
I am giving the validation rule for image file types is:
array('employeedetails_photo', 'file', 'types' => 'jpg,gif,png', 'allowEmpty' => true,'on' => 'insert', 'on' => 'update'),
But, the problem is that if extension of .doc file is changed to .docx.jpg and upload this as employee photo is also accepted. How to give validation for this issue in yii ?
The best way to validate pictures is to recreate them using GD imagecreatefrom* (or Imagick) and save/replace the processed image. The most simple example
public function rules(){
return array(
array( 'employeedetails_photo', 'validateImage' )
);
}
public function validateImage( $attribute ){
$file = CUploadedFile::getInstance($this, $attribute);
if ( !$file ) {
return;
}
// http://php.net/manual/en/function.imagecreatefromstring.php
// These types will be automatically detected if your build of PHP supports them: JPEG, PNG, GIF, WBMP, and GD2
$gd = #imagecreatefromstring(file_get_contents($file->getTempName()));
if ($gd === false) {
$this->addError($attribute, 'Image is corrupted');
}
}
You must check file type with file mimetype. Php should made it for you. use mime-content-type function