How to avoid hard code in uploaded files path? - php

I'm creating logic about uploading avatars to users:
blade.php
<image src="{{ $user->profile->image ? storage_path() . '/ app/public/' . $user->profile->image : '' }}"/>
<input type="file" id="avatar" name="avatar" style="display:none;"/>
<label for="avatar">{{ __('text.select_file') }}</label>
Controller (update method):
public function update(User $user)
{
$this->authorize('update', $user->profile);
$data = request()->validate([
'name' => 'required',
]);
if (request('avatar')) {
$imagePath = request('avatar')->store('uploads/avatars', 'public');
$image = Image::make(storage_path("app/public/{$imagePath}"))->fit(800, 800);
$image->save();
$imageArray = ['image' => $imagePath];
}
auth()->user()->profile->update(array_merge(
$data,
$imageArray ?? []
));
return redirect("/profile/{$user->id}");
}
When I upload a picture it is stored in storage/app/public/uploads/avatars in DB value for avatar is uploads/avatars/name.jpeg
As you can see I have hard code app/public/ in controller and in view files, this is by default, I didn't change any paths, here is filesystem.php:
<?php
return [
'default' => env('FILESYSTEM_DRIVER', 'local'),
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false),
],
],
'links' => [
public_path('storage') => storage_path('app/public'),
],
];
So how do I avoid these coded paths? And why Laravel default store folder is in storage and not in public directory ? Should I upload avatars to public directory or to leave them in storage? I'm looking for best and correct practices ?

I'm not well versed in Laravel, but I think you should be storing everything publicly accessible in /public/ with public_path(): Difference between storing files in public directory and in storage in Laravel 5.4
Just calling public_path($user->profile->image) should work, but you'll probably want to keep some path in there to make sure the avatars are in their own directory. Perhaps you could write another helper function:
function avatar_path($filename){
return public_path('avatars/'.$filename);
}
Then use avatar_path() everywhere rather than storage_path()/public_path(). I'm not sure if something as straightforward as that is the "Laravel way" though.

Related

Show this error "Undefined index: thumbnail" when add filesystem in laravel

When I add new public directory in Filesystem Disks in filesystems.php like below
'thumbnail' => [
'driver' => 'local',
'root' => storage_path('app/public/relativeContentPath/thumbnail'),
'url' => env('APP_URL').'/storage',
'visibility' => 'thumbnail',
'permissions' => [
'file' => [
'public' => 0664,
'private' => 0600,
],
'dir' => [
'public' => 0775,
'private' => 0700,
],
],
],
And in my Controller I want to save an image into thumbnail directory like below
$fileNameToStore = md5(time()).'.jpg';
$photoThumbnail = ImageResize::make($productContent)
->resize(80, 80, function ($constraint) { $constraint->aspectRatio(); } )
->encode('jpg',80);
Storage::disk('thumbnail')->put( $fileNameToStore, $photoThumbnail);
But it shows me the error Undefined index: thumbnail. I don't know why this error shows me. Any help appreciate
Change 'visibility' => 'thumbnail', to 'visibility' => 'public',
https://laravel.com/docs/8.x/filesystem#file-visibility
it can be public or private other then you can not set anything as per doc

Display image in a view Laravel 6

I can't display my images in a tag img in my view. I can save my uploaded image in storage->app->public->books and save the image name in my database as well. But after I run php artisan storage:link to access my file in public->storage, but whatever if I user asset() or url() method, I can't display my images in img tag, just alt="" atribute, Someone knows what I'm doing wrong?
This is my Controller store().
public function store(Request $request)
{
// Handle File Upload
if($request->hasFile('book_image')){
// Get filename with the extension
$filenameWithExt = $request->file('book_image')->getClientOriginalName();
// Get just filename
$filename = pathinfo($filenameWithExt, PATHINFO_FILENAME);
// Get just ext
$extension = $request->file('book_image')->getClientOriginalExtension();
// Filename to store
$fileNameToStore= $filename.'_'.time().'.'.$extension;
// Upload Image
$path = $request->file('book_image')->storeAs('books', $fileNameToStore);
} else {
$fileNameToStore = 'noimage.png';
}
//save in database
$itens = \App\Book::create([
'book_name' => mb_strtolower($request->book_name),
'author_name' => mb_strtolower($request->author_name),
'publishing_name' => mb_strtolower($request->publishing_name),
'description' => $request->description,
'release_date' => $request->release_date,
'category' => mb_strtolower($request->category),
'book_image' => $fileNameToStore
]);
flash('Livro criado com sucesso !')->success();
return redirect()->route('admin.books.index');
}
And this is my html where I'm trying to display.
#foreach($books as $book)
<tr>
<td><input type="checkbox" class="checkthis" /></td>
<td>
<img style="width: 80px;height: 80px" src="{{ url('books/{$book->book_image}') }}" alt="{{$book->book_image}}">
</td>
<td>{{$book->book_name}}</td>
<td>{{$book->author_name}}</td>
<td>{{$book->publishing_name}}</td>
<td>{{$book->release_date}}</td>
<td>
</tr>
And my config->filesystems.php
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
'endpoint' => env('AWS_ENDPOINT'),
],
],
You need to pass src as below.
src="{{ url('books/'.$book->book_image) }}"
as storage folder
src="{{ asset('storage/books/'.$book->book_image) }}"

Laravel i am not able to link storage on my server (Production)

I am using laravel for a website, of which slider is dynamic, can be added from admin, to store I’m using laravel storage
When i add slider, the image is uploaded to laravel/storage/app/public/settings/slider
When i try the command php artisan storage:link, I am getting the following error:
ErrorException : symlink(): No such file or directory
at /home/invplatform/investors/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:263
259| */
260| public function link($target, $link)
261| {
262| if (! windows_os()) {
> 263| return symlink($target, $link);
264| }
265|
266| $mode = $this->isDirectory($target) ? 'J' : 'H';
267|
Exception trace:
1 symlink("/home/invplatform/investors/storage/app/public", "/home/invplatform/investors/public/storage")
/home/invplatform/investors/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:263
2 Illuminate\Filesystem\Filesystem::link("/home/invplatform/investors/storage/app/public", "/home/invplatform/investors/public/storage")
/home/invplatform/investors/vendor/laravel/framework/src/Illuminate/Foundation/Console/StorageLinkCommand.php:35
Please use the argument -v to see more details.
My config/filesystem.php code is
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL') . '/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
'url' => env('AWS_URL'),
],
],
I am using blow code for storing image is
if($request->has('image'))
{
$image_path=request()->image->hashName();
$request->file('image')->store('/settings/slider');
$slider->image='settings/slider/'.$image_path;
}
Now when i am adding the image it is uploaded to laravel/storage/app/public/settings/slider
but not found in public_html/storage/settings/slider
Anyone has any idea about this
Probably you have wrong directory structure. (i think you are using cpanel). So your public folder and storage folder must be in same directory for php artisan storage:link. If these must be in different directory please manually create symlink.
ln -s {source-filename} {symbolic-filename}

Laravel File::delete not working

So I have a hidden input in my form where I set the name of old file
<input type="hidden" name="old_logo" value="{{ $company->logo }}">
And it is being set successfully:
<input type="hidden" name="old_logo" value="GsdRHGtbm950k6tegfuyjjDlnC3ABg4uQKB2mHrE.jpeg">
Then it goes to my controller:
public function update(Request $request, $id)
{
$company = Company::find($id);
$company->name = $request->input('name');
$company->address = $request->input('address');
// $company->logo = $request->input('logo');
if(null !== (($request->file('logo')))) {
File::delete('logo/' . $request->input('old_logo'));
$request->file('logo')->store('logo');
$company->logo = $request->file('logo')->hashName();
}
$company->save();
return redirect('admin/companies');
}
My file that I want to delete is stored in storage/app/public/logo/
Filesystems.php
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app/public'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
's3' => [
'driver' => 's3',
'key' => env('AWS_ACCESS_KEY_ID'),
'secret' => env('AWS_SECRET_ACCESS_KEY'),
'region' => env('AWS_DEFAULT_REGION'),
'bucket' => env('AWS_BUCKET'),
],
],
];
It should be trying to delete from storage/app/public/logo/ ? As I tested $request->input('old_logo') is passed successfully as well. What I'm doing wrong? Can it be rights problem?
Ofcourse I wrote this: use File;
You need to pass the full path to the file. So, if the file is in public/logo directory, do this:
File::delete(public_path('logo/' . $request->old_logo));

Laravel Storage facade not returning good path

I'm trying to upload some files to a specific "disk" in Laravel and then to retrieve the URL from these files.
Here is my config/filesystem.php file:
'disks' => [
...
'thumbnails' => [
'driver' => 'local',
'root' => storage_path('app/public/pictures/thumbnails'),
'visibility' => 'public',
],
...
],
Here is the way I handle an uploaded file (very basic, just for testing purposes):
Route::post('upload', function(Request $request) {
$file = $request->file('file');
$path = $file->storeAs('/', 'myFile.'.$file->getClientOriginalExtension(), 'thumbnails');
return dd($path);
});
The file /storage/app/public/pictures/thumbnails/myFile.jpg is created, which is fine, but $path equals "myFile.jpg" instead of the full path. First strange thing.
Then if I use:
$url = Storage::disk('thumbnails')->url('myFile.jpg');
$url equals "/storage/myFile.jpg" instead of "/storage/app/public/pictures/thumbnails/myFile.jpg".
Am I missing something ?
By default the disk url method just prepends /storage as stated in the docs.
To customize the url add a url to your config:
'thumbnails' => [
'driver' => 'local',
'root' => storage_path('app/public/pictures/thumbnails'),
'visibility' => 'public',
'url' => 'the url',
],

Categories