Storing files outside the Laravel 5 Root Folder - laravel

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.

Related

Laravel storage link doesnt link with public

Try to upload my files to storage, and link it with my public folder.
I used
php artisan storage:link
Then, I upload photos like below;
$filename = uniqid().".".$file->getClientOriginalExtension();
$filePath = 'uploads/announcement';
Storage::disk('public')->putFileAs($filePath, $file, $filename, ['visibility' => 'public']);
$announcement->photo = $filename ?? $announcement->filename;
But my /public/storage folder is empty, when I upload files.
Whats wrong with it?
My filesystem.php is below;
'public' => [
'driver' => 'local',
'root' => storage_path(),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
this is the way i do it (i n livewire but the storePubliclyAs Is not livewire)
if($this->image != null){
$imageName = time().'.'.$this->image->extension();
$company->image= $imageName;
// on upload l image dans le folder
$this->image->storePubliclyAs('companylogos',$imageName);
}
companylogos is the name of the folder in (storage/app)
i had same problem as you first ! you need to make sure your folder is linked , for that you need to see a little logo on the folder like a link logo meaning that the two folders are sync (linked) , the error is to create both files and try to link them , no you have to create only the storage/app/companylogos folder first and then use artisan to link php artisan storage:link
of course you need to have prepared your file in config filesystems, this is how i did it
'links' => [
public_path('storage') => storage_path('app/public'),
public_path('profilecv') => storage_path('app/profilecv'),
public_path('companylogos') => storage_path('app/companylogos'),
],
I think you have to change file system
filesystem.php is below;
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],

No such file, Storing file into the local storage is not working on production

I have a laravel application deployed on Elasticbeanstalk, I'm working on a feature where I need to get a zip file from s3 bucket, store it into the local storage in order to be able to use laravel-zip to remove a pdf file from that zip.
the code is working locally, but I'm receiving 'No Such file error' after testing on production:
// get the file from s3 and store it into local storage
$contents = Storage::disk('s3')->get($file_name);
$zip_local_name = 'my_file.zip';
Storage::disk('local')->put($zip_local_name, $contents);
// use laravel-zip to remove the unwanted pdf file from the result
$manager = new ZipManager();
$file_path = storage_path('app').'\\'.$zip_local_name; // register existing zips
$manager->addZip(Zip::open($file_path));
$zip = $manager->getZip(0);
$zip->delete($data["Iso_Bus"]["field_name"].'.pdf');
$zip->close();
I made sure that the file exists on s3, so I think my main problem is that the file is not stored in the local storage.
Any help is appreciated
Edit filesystems configrations:
'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' => '***',
'secret' => '***',
'region' => '***',
'bucket' => '****',
'url' => '****',
],
],
You're getting full path for the file wrongly, try this one instead:
$file_path = Storage::disk('local')->path($zip_local_name);
Note: It's better to check if the Storage::put was successful before continue:
// get the file from s3 and store it into local storage
$contents = Storage::disk('s3')->get($file_name);
$zip_local_name = 'my_file.zip';
if (Storage::disk('local')->put($zip_local_name, $contents)) {
// `Storage::put` returns `true` on success, `false` on failure.
// use laravel-zip to remove the unwanted pdf file from the result
$manager = new ZipManager();
$file_path = $file_path = Storage::disk('local')->path($zip_local_name);
$manager->addZip(Zip::open($file_path));
$zip = $manager->getZip(0);
$zip->delete($data["Iso_Bus"]["field_name"].'.pdf');
$zip->close();
}

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(...

Choose Amazon S3 storage class using Laravel Filesystem

Amazon S3 has different storage classes, with different price brackets.
I was wondering if there's a way I can choose a storage class in Laravel's Filesystem / Cloud Storage solution?
It would be good to choose a class on a per upload basis so I can choose throughout my application, not just once in a configuration file.
To pass additional options to flysystem you have to use getDriver()
Storage::disk('s3')->getDriver()->put(
'sample.txt',
'This is a demo',
[
'StorageClass' => 'REDUCED_REDUNDANCY'
]
);
This can be used in Laravel 7
Storage::disk('s3')->put(
'file path',
$request->file('file'),
[
'StorageClass' => 'STANDARD|REDUCED_REDUNDANCY|STANDARD_IA|ONEZONE_IA|INTELLIGENT_TIERING|GLACIER|DEEP_ARCHIVE',
]
);
You can use putFileAs() Method As Well Like Below
Storage::disk('s3')->putFileAs(
'file path',
$request->file('file'),
'file name',
[
'StorageClass' => 'STANDARD|REDUCED_REDUNDANCY|STANDARD_IA|ONEZONE_IA|INTELLIGENT_TIERING|GLACIER|DEEP_ARCHIVE',
]
);
I can't really find this answer on the internet. Hope it helps someone else.
If you want to set StorageClass on the disk level (once for every upload).
You can change it on the config\filesystems.php
'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),
'throw' => false,
'options' => [
'StorageClass' => 'INTELLIGENT_TIERING'
]
],
Other possible options...
'ACL',
'CacheControl',
'ContentDisposition',
'ContentEncoding',
'ContentLength',
'ContentType',
'Expires',
'GrantFullControl',
'GrantRead',
'GrantReadACP',
'GrantWriteACP',
'Metadata',
'RequestPayer',
'SSECustomerAlgorithm',
'SSECustomerKey',
'SSECustomerKeyMD5',
'SSEKMSKeyId',
'ServerSideEncryption',
'StorageClass',
'Tagging',
'WebsiteRedirectLocation',
Ref: thephpleague/flysystem-aws-s3-v3

Resources