Remove "/public" from file path in Laravel when linking public directory - laravel

I use Laravel of 5.7.25 version.
I have a symbolic link from public/storage to /storage/app/public.
I'm storing files in /storage/app/public/place-images directory.
I keep the path of stored file in table files which keeps all stored files. The file path would be public/images/some_hash.jpg.
Now I made a file resource, which is used when I'm getting files from my API. The file path retured from api equals public/images/some_hash.jpg. But instead I need it to be images/some_hash.jpg. However, in the table I prefer to keep real path of the file related to the storage folder. After all, I can keep files in AWS or somewhere else.
As far as I understand storage is the root of my disk. The $file->store() method includes public part of the file path.
I end up doing something like this:
// This is ImageResource file, Image model has File relation. One Image has one File
// TODO: Dirty hack
$path = $this->file->path; // This equals 'public/place-images/hash.jpg'
// Removing 'public' part
$charIndex = strpos($path, '/');
$path = substr($path, $charIndex + 1);
return [
'id' => $this->id,
'original_name' => $this->file->original_name,
url' => asset('storage/' . $path) // now we have /storage/place-images/some_hash.jpg which is correct
];
Is there anyway to avoid this dirty hack? I think I'm missing something obvious

storage is not the root of your disk. You can set the root for a disk in config\filesystems.php.
Default root for the public disk defined in config/filesystems.php is /storage/app/public so just store place-images/hash.jpg without public.
If you want to keep files from different disks in one table just add a field with a disk name to this table.

Related

Get correct URL for uploaded files

I have a function in my platform for letting users upload their own icon images. Once they've uploaded them I save them using $request->icon->store('public/icons') and simply save the returned path, something like "public/icons/xa6y2am3e4cOdqQuLpvEhFSXDKwFMDOgggS2i67l.png".
I'm not really clear though on what's the correct way to show the icons. The URL for showing the icon in the above example is "/storage/icons/xa6y2am3e4cOdqQuLpvEhFSXDKwFMDOgggS2i67l.png", thus I need to replace "public" in the path with "storage", which makes me think I've done something wrong somewhere (I see no reason why the store() method should provide me with a path that's not correct).
I have done my symlinks as described in the documentation. Using the local storage. What am I missing?
This is how I handle my storage in one of my apps that includes blogs:
$storedImageName = $request->file('main_image')->store('blog_images', 'public');
The store method actually returns the stored file name along with the path. Here, I specify that my disk is public and that the folder inside public is blog_images. I store the result of that in $storedImageName.
Now, to save it in the database, I do not actually save the whole path, I save ONLY the image name. This is because, you may want to update your directory name in the future, or move it to another location, etc. You can get that like this:
$onlyImageName = basename($storedImageName);
basename() is PHP's function, has nothing to do with Laravel.
This way, I can render my images in my blade files like this:
<img ... src="{{ asset('/storage/blog_images/' . $blog->main_image) }}" />
asset() helper will provide you with path to your public directory, and then you just need to specify the rest of the path to your image.

Laravel: How to prevent users loading files from outside the base path

I have a Laravel website and I have several routes that load the contents of images from Storage. I do this using the following code:
public function show_image($name) {
echo Storage::disk('images')->get($name);
}
I want to prevent users being able to set name to something like ../../../error.log. So I don't want users to escape the Storage directory. I have a few ideas on how to accomplish this however I want to know is there a best practice?
If you need just file name, not location, disallow them from inputting folder of any kind. Just cut the string on /.
end(preg_split("#/#", $name));
When you need to allow some folders and all of the contents, check the folder name, subfolder name, etc.
You could either keep a registry/index of the uploaded images, and only allow the user to show a image from that registry (e.g. an images database table).
Or you could do a scan of the directory, that you are allowing files from, and make sure, that the requested file is in that list.
public function show_image($name) {
$files = Storage::disk('images')->files();
if (! in_array($name, $files)) {
throw new \Exception('Requested file not found');
}
echo Storage::disk('images')->get($name);
}
(code untested)

Laravel Managing File Path

In my application users can upload files. In my controller I have the following:
//...
$request->file->storeAs('/public/user_files',$fileName);
I don't like how I have to hard code the path /public/user_files, what is the proper way to manage file paths? I could simply create a variable but is there any better ways for maximum maintainability?
From my understanding I have a few options:
Create a variable
Create a new file in config directory that manages the path
Create a disk in filesystem.php and use storeAs with the custom disk
What is the best way to handle paths?
In most cases, you should use filesystem disks as you specified in your last option, it allows a centralized flexibility.
In this case, you may use Laravel helpers such as public_path or storage_path, for example:
$request->file->storeAs(
storage_path('app/public'), $fileName
);
Combined to a symbolic link, it allows flexibility about public assets.
https://laravel.com/docs/7.x/filesystem#the-public-disk
you can use helpper public_path()
$request->file->storeAs( public_path('/user_files') ,$fileName);
doc: https://laravel.com/docs/7.x/helpers#method-public-path

Return file name with laravel 5.4

I want to return the files names of a dir called public/uploads. I used Storage::allFiles and Storage::files, but only return an empty array.
Storage works only for storage directory. If you want to use it, you'll need to create a symbolic link.
Use File facade instead:
File::files(public_path('uploads'));

How to use storage_path() to view an image in laravel 4

I'm using storage_path() for storing uploaded images, but when I use it is pointing wrong on my page.
I use it like this {{ $data->thumbnail }} where $data came from the database and thumbnail comes as the string which used storage_path
Let us take a look at the default L4 application structure:
app // contains restricted server-side application data
app/storage // a writeable directory used by L4 and custom functions to store data ( i.e. log files, ... )
public // this directory is accessible for clients
If I were you, I would upload the file to the public directory directly:
Store image here: public_path() . 'img/filename.jpg'
Save the 'img/filename.jpg' in database
Generate the image URL with url('img/filename.jpg') => http://www.your-domain.com/img/filename.jpg
Hope this helps.
The storage_path function returns the path to the storage folder, which is inside the app folder --and outside the public folder-- so it's not directly accessible from the client, that's why your images are not being displayed. You can move them to the public folder path, or you could use a custom controller to handle the image requests, read the image from the storage folder and return the value.

Resources