Laravel store files with permissions 774 - laravel

Im loosing mind. I upload files via laravel API, they are stored in folder and file always get permission 644, is there any way how to store files as 775 ?
can i somehow add this to my function ?
(0755, true, true)
function for store files:
$result=$request->file('file_path')->store('apiFiles/'.$idParameter);
thanks for any help

In laravel you can use 'public' or 'private' disks and set the permissions options in the config file filesystems.php
https://laravel.com/docs/8.x/filesystem#permissions
The public visibility translates to 0755 for directories and 0644 for files. You can modify the permissions mappings in your filesystems configuration file:
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'permissions' => [
'file' => [
'public' => 0664,
'private' => 0600,
],
'dir' => [
'public' => 0775,
'private' => 0700,
],
],
],
You can then store files with specific visibility like it suggests here https://laravel.com/docs/8.x/filesystem#file-visibility
Or you can use the built in php function chmod()
https://www.php.net/manual/en/function.chmod.php

you can change permission of file after creating them by chmod command like this:
$result=$request->file('file_path')->store('apiFiles/'.$idParameter);
chmod('file path',0775);

Related

How to retrieve file from Laravel storage subfolder?

I'm trying to retrieve a file from this path in a laravel project:
/storage/app/public/blog/3.jpg
These approaches produce following errors:
1.
$image = Storage::disk('public')->get('/storage/blog/3.jpg');
->
local.ERROR: File not found at path: storage/blog/3.jpg {"userId":16,"exception":"[object] (Illuminate\\Contracts\\Filesystem\\FileNotFoundException(code: 0): File not found at path: storage/blog/3.jpg at /Users/artur/PhpstormProjects/safa-ameedee.com/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php:171)
[stacktrace]
$image = Storage::disk('public')->get('/storage/app/public/blog/3.jpg');
$image = Storage::get('/storage/app/public/blog/3.jpg');
->
local.ERROR: File not found at path: storage/app/public/blog/3.jpg {"userId":16,"exception":"[object]
The weird thing is that I store the files in the storage like so:
Storage::disk('public')->put('/blog/' . $request->path, $image);
So should they not be retrievable in the same way?
TL/DR
Storage::disk('public')->get('block/3.jpg');
Explanation
The problem is you're putting storage in the path for some reason. It's not necessary and is leading to the wrong path being built.
Take a look at the default filesystems config:
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
'throw' => false,
],
The root is what is useful to see here. storage_path() returns the full path to the storage folder. So something like storage_path('folder_1') -> /home/user/project/storage/folder_1.
The local disk is the default, so just doing Storage::get() will use it automatically.
You're using the public disk, so the actual location of these files is storage/public (symlinked into public/storage). This means doing Storage::disk('public') already begins at /home/user/project/storage/app/public. Adding storage again makes the path incorrect.
Using path may help with future debugging. Storage::disk('public')->path('block/3.jpg') will output the full path, and you can see where it's going wrong. For your code given it would probably show something like /home/user/project/storage/app/public/storage/app/public.

Default create log files with 664 permissions

How can I configure my Laravel or Ubuntu server so my Laravel logger creates a log file with the 664 permissions? Right now it defaults to 644.
Open config\logging.php file and add permission key to your default log channel. Is seems that this feature is available from Laravel 5.6.10.
Example:
return [
'channels' => [
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'permission' => 0664, // this is the new key to add
],
],
];
Notes:
in this example the default log channel is single
make sure the permission key has the value without quotes and with leading zero. read more about this in php manual of chmod

Illuminate\Contracts\Filesystem\FileNotFoundException in Laravel 5.6 using Storage facade

This code is returning an strange error:
$file = Storage::get(Storage::disk('notas_xml')->path('') . 't.txt');
As you can see the file does exist.
Get the file directly from the disk
$exists = Storage::disk('notas_xml')->exists('t.txt');
if ($exists) {
$file = Storage::disk('notas_xml')->get('t.txt');
}
And if you didn't setup notas_xml disk in filesystems.php
$file = Storage::get('public/arquivos/notas_xml/t.txt');
And to use your code, you need to setup a disk like so in config/filesystems.php
'notas_xml' => [
'driver' => 'local',
'root' => storage_path('app/public/arquivos/notas_xml'),
'url' => env('APP_URL') . '/storage',
'visibility' => 'public',
],
And get the file simply like this
$file = Storage::disk('notas_xml')->get('t.txt');
You need to get the file as below code:
Storage::disk('notas_xml')->has('t.txt');
Above has method may be used to determine if a given file exists on the disk:
Please read documentation https://laravel.com/docs/5.1/filesystem#retrieving-files
To better understand all this... The trick is in: config/filesystems.php
If you have this code (which is the default value of Laravel in Github)
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
This Facade Storage will act in the folders
root_laravel_project/storage/app
So if you want to check if an "israel.txt" file exists
if( Storage::exists('israel.txt') ){
echo "File found. And it exists on the path: root_laravel_project/storage/app/israel.txt";
}
Remember that up to this point it has nothing to do with the symbolic link php artisan storage: link
This symbolic link is only to make a folder called "public" within the "storage" folder be part of the public access through HTTP
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
Then at the time of doing the sym. You can access the files by http (which are public for any user)
This example assumes that you are using a virtual host (and if not, you must do it as a recommendation for work better locally)
http:// root_laravel_project.test/storage/israel-alvarez.txt
Or so that it is better understood as in the old school without a virtual host
http:// localhost/public/storage/israel-alvarez.txt
Then these urls will look inside your folder
root_laravel_project/storage/app/public/israel-alvarez.txt
Laravel's documentation is somewhat brief and can be confusing regarding this issue. But you just have to remember that one thing is to access through the "storage Facade" (which is the correct way to upload and verify if there are files) and another thing is to access through the http (through url) which is the symbolic link (which is the treatment you already give to users to download files or see if it is a PDF for example).
I hope it helps. Good day

Laravel Storage SFTP and uploaded files permissions

I'm using Storage:SFTP (league/flysystem-sftp) to upload some files to an external server. Everything goes fine with a small issue: the files are uploaded with a 0644 (-rw-r--r--) permission. I've tried to use 'public' option on the put method as the example from docs, like
Storage::disk('remote-sftp')->put($filename, $contents, 'public');
but if fails returning FALSE and doesn't uploads the file.
If I remove the 'public' parameter, everything goes well but with the wrong permissions for file.
Is there any way to set the uploaded file permissions to something like 0666?
Finally the solution was a combination of Alpy's answer and configuration.
Calling setVisibility() went without failure, but keep permissions in 0644. Digging into the FTP/SFTP driver found that the 'public' permission has a pattern that can be assigned in config using 'permPublic' key, so writting in config/filesystems.php the desired octal permission it worked as spected.
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
'remote-sftp' => [
'driver' => 'sftp',
'host' => '222.222.222.222',
'username' => 'myuser',
'password' => 'mypassword',
'visibility' => 'public',
'permPublic' => 0766, /// <- this one did the trick
// 'port' => 22,
'root' => '/home',
// 'timeout' => 30,
],
],
];
File permissions are based on two factors. Visibility and Permissions. You can set these two options in the driver config as such:
'remote' => [
'driver' => 'sftp',
'host' => 'hostname',
'root' => '/',
'username' => 'user',
'password' => env('SYSTEM_PASS'),
'visibility' => 'public', // defaults to 'private'
'permPublic' => 0775
]
The permissions are set based on the visibility. So if you set 'permPublic' and don't set 'visibility' nothing will change as, the setVisibility() function uses 'visibility' to get the permissions.
vendor/league/flysystem-sftp/src/SftpAdapter.php
public function setVisibility($path, $visibility)
{
$visibility = ucfirst($visibility);
// We're looking for either permPublic or permPrivate
if (! isset($this->{'perm'.$visibility})) {
throw new InvalidArgumentException('Unknown visibility: '.$visibility);
}
$connection = $this->getConnection();
return $connection->chmod($this->{'perm'.$visibility}, $path);
}
The public default is 0755.
The private default is 0700.
umask
If 'visibility' is not set, I believe the permissions are set based on the remote system user's umask. You are able to modify this on the remote system, if you so choose. set umask for user
Directories
One thing to note while working with permissions is that this will only affect created files. To set the permissions on created directories, use the 'directoryPerm' attribute in your config.
This defaults to 0744
Here is a more global and efficient solution. I needed to control permission on Files and also directories when saving a file under recursive directories.
League SftpAdapter is creating the directories recursively if not exist yet. But the main problem is that, it won't add the permPublic => 0755 for directories, but only files, hence www-data user end up to have no access to the file if it's inside of a newly created directory. The solution is to dive in the code to see what's happening:
'disks' => [
'remote-sftp' => [
'driver' => 'sftp',
'host' => '222.222.222.222',
'port' => 22,
'username' => 'user',
'password' => 'password',
'visibility' => 'public', // set to public to use permPublic, or private to use permPrivate
'permPublic' => 0755, // whatever you want the public permission is, avoid 0777
'root' => '/path/to/web/directory',
'timeout' => 30,
'directoryPerm' => 0755, // whatever you want
],
],
In League\Flysystem\Sftp\StfpAdapter, there is 2 important attributes to see clearly:
/**
* #var array
*/
protected $configurable = ['host', 'hostFingerprint', 'port', 'username', 'password', 'useAgent', 'agent', 'timeout', 'root', 'privateKey', 'passphrase', 'permPrivate', 'permPublic', 'directoryPerm', 'NetSftpConnection'];
/**
* #var int
*/
protected $directoryPerm = 0744;
The $configurable is all possible keys to configure filesystem sftp driver above. You can change directoryPerm from 0744 to 0755 in config file:
'directoryPerm' => 0755,
HOWEVER, because there is kind a like a Bug in StfpAdapter https://github.com/thephpleague/flysystem-sftp/issues/81 that won't use the $config parameter on createDir:
$filesystem = Storage::disk('remote-sftp');
$filesystem->getDriver()->getAdapter()->setDirectoryPerm(0755);
$filesystem->put('dir1/dir2/'.$filename, $contents);
Or set it with public in purpose:
$filesystem->put('dir1/dir2/'.$filename, $contents, 'public');
I found this while looking for a solution and I think I've found what works in Laravel 9 after digging through the flysystem code.
Adding the following settings to my config looks to have done the trick.
'visibility' => 'public',
'permissions' => [
'file' => [
'public' => 0664,
'private' => 0664,
],
'dir' => [
'public' => 0775,
'private' => 0775,
],
],
Please try this:
Storage::disk('remote-sftp')->put($filename, $contents)->setVisibility( $filename, 'public');
assuming the filename is also having the path..
Storage::disk('sftp')->download(...

Storing files outside the Laravel 5 Root Folder

I am developing a laravel 5 project and storing image files using imagine. I would want to store my image files in a folder outside the project's root folder. I am stuck at the moment The external folder where image files are supposed to be stored, I want to make it accessible via a sub-domain something like http://cdn.example.com Looking towards your solutions.
The laravel documentation could give you a helping hand.
Otherwise you could go to config/filesystems.php and add your own custom storage path for both local and production:
return [
'default' => 'custom',
'cloud' => 's3',
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path().'/app',
],
'custom' => [
'driver' => 'custom',
'root' => '../path/to/your/new/storage/folder',
],
's3' => [
'driver' => 's3',
'key' => 'your-key',
'secret' => 'your-secret',
'region' => 'your-region',
'bucket' => 'your-bucket',
],
'rackspace' => [
'driver' => 'rackspace',
'username' => 'your-username',
'key' => 'your-key',
'container' => 'your-container',
'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/',
'region' => 'IAD',
],
],
];
get ur path name from base_path(); function, then from the string add your desired folder location.
suppose ur
base_path() = '/home/user/user-folder/your-laravel-project-folder/'
So ur desired path should be like this
$path = '/home/user/user-folder/your-target-folder/'.$imageName;
make sure u have the writing and reading permission
You can move all or a part of storage folder in any folder of yours in your server. You must put a link from old to new folder.
ln -s new_fodler_path older_folder_path
You can make a new virtual host to serve the new folder path.

Resources