Cannot save image intervention image. NotWritableException in Image.php line 138 - php

Im trying to save a manipulated image which i will them push to s3.
My code that works This code saves the image directly within the public folder*
public function store(Filesystem $filesystem)
{
$request = Input::all();
$validator = Validator::make($request, [
'images' => 'image'
]);
if ($validator->fails()) {
return response()->json(['upload' => 'false']);
}
$postId = $request['id'];
$files = $request['file'];
$media = [];
$watermark = Image::make(public_path('img/watermark.png'));
foreach($files as $file) {
$image = Image::make($file->getRealPath());
$image->crop(730, 547);
$image->insert($watermark, 'center');
$image->save($file->getClientOriginalName());
}
}
What i would like to achieve is to be able to save it within a folder of it's own. Firstly what is the best place to store an image for a blog post, within the storage of public folder? But anyway when i do this:
$image->save('blogpost/' . $postId . '/' . $file->getClientOriginalName());
// Or this
$image->save(storage_path('app/blogpost/' . $postId . '/' . $file->getClientOriginalName()));
I get the error:
folder within public
NotWritableException in Image.php line 138: Can't write image data to
path (blogpost/146/cars/image.jpg)
or
storage path
NotWritableException in Image.php line 138: Can't write image data to
path /code/websites/blog/storage/app/blogpost/146/image.jpg
I've tried
cd storage/app/
chmod -R 755 blogpost
And it still wont work
Thank you for reading this

Ok so here is how i solved it, I made the directory first before storing,
Storage::disk('local')->makeDirectory('blogpost/' . $postId);
Once the folder is created i then go on to store the manipulated images like so:
$image->save(storage_path('app/blogpost/' . $postId . '/' . $imageName));
And then pushing the image to S3
$filesystem->put('blogpost/' . $postId . '/' . $imageName, file_get_contents(storage_path('app/blogpost/' . $postId . '/' . $imageName)));
This worked

You can solve it by casting the Intervation/Image variable to a data stream using function stream. Then use the Storage Laravel facade to save the image.
$img = Image::make('path-to-the-image.png')->crop(...)->insert->stream('jpg', 90)
Storage::put('where_I_want_the_image_to_be_stored.jpg', $img);

Laravel 5 needs permission to write to entire Storage folder so try following,
sudo chmod 755 -R storage
if 755 dont work try 777.

Am improving #Amol Bansode answer.
You are getting this error because $postId folder does not exist in the path you specified.
You could do it like this:
//I suggest you store blog images in public folder
//I assume you have created this folder `public\blogpost`
$path = public_path("blogpost/{$postId}");
//Lets create path for post_id if it doesn't exist yet e.g `public\blogpost\23`
if(!File::exists($path)) File::makeDirectory($path, 775);
//Lets save the image
$image->save($path . '/' . $file->getClientOriginalName());

In my case I migrated a project from Windows 10 to Parrot (Debian-Linux) and I had the same problem and turned out the slashes were backward slashes and Linux interpret them differently. Unlike Windows, it doesn't really matter.
//Windows Code:
$image_resize->save(public_path('\storage\Features/' .'Name'.".".'png'));
//Linux Code (Working):
$image_resize->save(public_path('storage/Features/' .'Name'.".".'jpg'));

I know the question is related to Laravel but I came across from making it to work with WordPress. If somebody is coming from WordPress world, this code works (I was getting the same 'cannot write' error) and changing directory permission would not work as the library probably needs the relative path (the code below is valid for direct installation of Intervention through composer into any PHP application, not Laravel per se)-
require 'vendor/autoload.php';
use Intervention\Image\ImageManager;
$manager = new ImageManager(array('driver' => 'imagick'));
$image = $manager->make('PUBLIC IMAGE URL/LOCAL IMAGE PATH');
$image->crop(20, 20, 40, 40);
$image->save(__DIR__ . '/img/bar.png');

in my case:
i double check my symlinks in filesystem.php in config folder in laravel
and remove all symlink then regenerate them
php artisan storage:link

in my case my fileName is not valid format for naming in windows but it worked on linux or docker
$make_name = date('Y-m-d-H:i:s') . hexdec(uniqid()) . '.' . $img->getClientOriginalExtension();
when I remove this date('Y-m-d-H:i:s') it worked as well

I have faced the same issue but 775 permission not sort it so I changed the write permission to the folder(also sub-folders) to 777 to get over this issue.

Related

How to store multiple uploaded files with Laravel's Storage Facade

Currently I have a project that is running Laravel 5.8 and I am trying to use a form that allows user's to upload their own images to the site and store it in the public folder. When trying to use the Storage facade with the 'put' method, a path gets returned but the images do not actually get stored.
if ($request->hasfile('images')) {
foreach ($request->file('images') as $file) {
$path = Storage::disk('public')->put('images', $file);
echo $path;
}
}
This is the code I am trying to use. The path gets echo'd as it should and I have not made any changes to the filesystem config. In the form, the input field images allows for submitting multiple files and the form does hasenctype="multipart/form-data". The $file variable also contains an instance of Illuminate\Http\UploadedFile.
The previous code I used which did work was:
if ($request->hasfile('images')) {
foreach ($request->file('images') as $file) {
$file->move(public_path('images'), $file->getClientOriginalName());
}
}
I would be okay with using my previous code if Laravel can give it a unique file name on upload but what would be causing my code with the Storage facade to not save the images properly? Does the put function just not work like that or is there something I am overlooking?
Edit:
So I realise the images were in fact saving correctly as they should be. I was looking inside the public folder rather than the storage folder which is why my second code example 'worked' but not the first. I realise when using the Storage facade I need to make use of Symbolic linking if I want to access these files on the web.
You need to also make sure you have created the symbolic link on your Ubuntu server or Windows development machine to the storage folder.
Windows you can use : mklink /j /path/to/laravel/public/youfolder /path/to/laravel/storage/youfolder
Ubuntu: ln -s /path/to/laravel/public/youfolder /path/to/laravel/storage/youfolder
To check & set you can also use use php artisan storage:link
Hope this helps
if ($request->hasfile('images')) {
foreach ($request->file('images') as $file) {
$path = Storage::disk('public')->put('images', $file);
$new_file_name = time() . "_" . uniqid() . "_" . $file->getClientOriginalName();
$path = Storage::disk('public')->put($new_file_name, file_get_contents($file));
echo $path;
}
}

Delete file from a specific directory in Laravel local storage

I am storing files at local storage. So, in /storage/app/public directory.
I am storing my files in /storage/app/public/userId/images ;
I used php artisan storage:link , so I can access that files in view, having a shortcut to this folder in /public/storage/userId/images
Inside that path I have 2 images - test.jpg and test2.jpg
I can't find a response at Laravel documentation, how to delete file test.jpg from /public/storage/userId/images
I tried in this way :
$path = 'public/' . $id . '/diploma';
$files = Storage::files($path);
return $files;
It returns me :
[
"public/303030/images/test.jpg"
"public/303030/images/test2.jpg"
]
Now, how can I call Storage::delete('test.jpg') on that array?
There is multiple ways to delete image
//In laravel
File::delete($image);
//for specific directory
File::delete('images/' . 'image1.jpg');
and other way (Simple PHP)
//Simple PHP
unlink(public_path('storage/image/delete'));
and if you want to delete more than 1 images than
Storage::delete(['file1.jpg', 'file2.jpg']);
//or
File::delete($image1, $image2, $image3);
for more detail about Delete File in Laravel
Use Storage::delete(). The delete method accepts a single filename or an array of files to remove from the disk.
Storage::delete($file_to_delete);
May be you want to do something like-
$files = Storage::files($path);
Storage::delete($files);
use File;
public function destroy($id,$src)
{
File::delete('file/' . $src);
fileModel::find($id)->delete();
return back()->withErrors("");
}
if you store your image public/file folder you can delete like this . it will work . in the $src just pass the file name .
Example: $src = example.png;

Getting a Storage file and copying to another storage place

So, I have storage files saved and can access them like this:
$file = Storage::disk('public')->url("featured/{$i->image}")
That nets me the full url of the file I have in my storage/ directory. How can I make it so that can copy and paste that same exact file into a new directory but with a new file name?
I have tried:
$url = Storage::disk('public')->url("featured/{$i->image}");
$fileName = 'u_' . (new \DateTime())->getTimestamp() . '.png';
$fileDestination = '/new_folder/' . $fileName;
$i->image = $fileDestination;
File::copy($url, $fileDestination);
I am getting PHP execution timeout errors. I don't think I am referencing the paths correctly.
I want to copy /storage/app/public/featured/imageOne.png to /storage/app/public/new_folder/imageOneWITHNEWFILENAME.png
Is there a Storage facade solution?
Use Storage facade instead of File::copy to copy file to the new destination like
Storage::disk('public')->copy("featured/{$i->image}", $fileDestination);
Reference: Laravel 5.5 file storage

creating image inside a folder results in creating an image with name folder/image.jpg

I have this piece of code:
$file = $faker->image($dir = public_path().'/tmp', $width = 800, $height = 600, '', true);
$hash = str_random(7);
$thumbnailName = $hash . '.jpg';
$thumbnailImage = ImgResizer::make($file)->fit(180, 180);
$thumbnailImage->save( public_path() . '\\thumb\\'. $thumbnailName);
rename($file, 'public/'.$hash.'.jpg');
As you can see I am using faker to populate the database. Faker supports images as well and it's getting images from lorempixel.com. I save this image directly in public folder and that works. I also create a thumbnail of the image using InternventionImage and save it to public/thumb folder as you can see in the code.
When I run the db:seed, no errors were produced, it all went well. However when I looked inside thumb folder there were no files there. There were bunch of images created inside public folder but not inside thumb. I logged in the server and cd into default folder and typed ls and I got this output:
As you can see on the image there are bunch of public/thumb/hashcode.jpg images there. How is this possible, they are not inside thumb folder, why is it listing them there? Did the script instead create file with filename public/thumb/hashcode.jpg? How do I put them inside thumb folder? This code works on my local machine windows 10 under apache2 and php7.
Try change this:
public_path() . '\\thumb\\'. $thumbnailName
To this:
public_path().DIRECTORY_SEPARATOR.'thumb'.DIRECTORY_SEPARATOR.$thumbnailName
Also, create thumb directory and set correct permissions:
chmod -R 755 /public/thumb

How to get all images in a folder using CakePHP

I am trying get all images which are located in standard cakePHP image folder. I am using:
App::uses('Folder', 'Utility');
App::uses('File', 'Utility');
$dir = new Folder('/app/webroot/img/');
$files = $dir->find('.*\.png');
pr($files);
but i always get empty array. Where is the problem?
Ina addition when I try make dir in that folder i get error:
mkdir(): No such file or directory [CORE\Cake\Utility\Folder.php, line 515]
By doing new Folder('/app/webroot/img/'); you're actually saying your app folder is in the root of the drive, and since it isn't, CakePHP will try and create it, which it can't (that mkdir error).
You probably need to do something like
$dir = new Folder(App.imageBaseUrl);
or
$dir = new Folder(APP_DIR . DS . "webroot" . DS . "img");.
Check the constants CakePHP gives you to handle paths http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#core-definition-constants should be usefull
Knowing the answer is given and accepted,
This is a right way given by the documents.
<?php
// Find all .png in your app/webroot/img/ folder and sort the results
$dir = new Folder(WWW_ROOT . 'img');
$files = $dir->find('.*\.png', true);
http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::find

Categories