Reputation: 405
I keep multiple FTP accounts in a database table and would like each one to be available as a storage disk in Laravel.
Normally, Laravel's disks are defined in config/filesystems.php
. But instead of hardcoding my FTP accounts there, I would like to define them on the fly (in a middleware).
Is this possible? How do I accomplish that?
Upvotes: 19
Views: 11757
Reputation: 413
Laravel's FilesystemManager has methods to create most common disks.
<?php
use Illuminate\Filesystem\FilesystemManager;
$fsMgr = new FilesystemManager(app());
// local disk
$localDisk = $fsMgr->createLocalDriver(['root' => "/path/to/root"]);
// FTP disk
$ftpDisk = $fsMgr->createFtpDriver([/* FTP options */]);
// SFTP disk
$sftpDisk = $fsMgr->createSftpDriver([/* SFTP options */]);
// S3 disk
$s3Disk = $fsMgr->createS3Driver([/* S3 options */]);
Apart from that, you can create any filesystem supported by your league/flysystem installation, you only need to wrap it in Illuminate\Filesystem\FilesystemAdapter:
<?php
use League\Flysystem\FilesystemInterface;
// create any Flysystem instance and wrap it in Laravel's adapter
$myDisk = new FilesystemAdapter(/* \League\Flysystem\FilesystemInterface */ $filesystem);
This way you create your disks on-the-fly, without the need to modify the application config, handy if you have lots of connections, for example, to partners' FTP/SFTP servers, GCloud or S3 buckets.
Upvotes: 12
Reputation: 288
Create a new service provider
php artisan make:provider FileSystemServiceProvider
Register the provider in the config/app.php
If you open the config/app.php
file included with Laravel, you will see a provider's array
. register the created service provider there.
In The Boot Method
of the created service provider use the below-mentioned code to register the disks
Assuming fileSystemsDetails
is the model name
public function boot() {
DomainSettings::all()->each(function(DomainSettings $myDisk) {
if (!is_null($myDisk->driver_name) && !is_null($myDisk->driver_type)
&& !is_null($myDisk->driver_host) && !is_null($myDisk->driver_username) && !is_null($myDisk->driver_password)) {
$this->app['config']["filesystems.disks.{$myDisk->driver_name}"] =
[ 'driver' => $myDisk->driver_type,
'host' => $myDisk->driver_host,
'username' => $myDisk->driver_username,
'password' => $myDisk->driver_password,
'root' => $myDisk->driver_root,
];
}
});
}
Upvotes: 7
Reputation: 39
I solved the same issue by adding some vanilla PHP to the config file (in my case the database config). The point is that the laravel config files are still just "normal" PHP files so nothing prevents you from getting at your database in here, you just cant use Eloquent since the config is processed first.
So with that approach - you can just add your disks to the configuration array after reading them from the database via PDO.
The config file unedited returns an array of objects (so in your case also 'disks')
Change the filesystems config and add the current array into a variable called something sensible like $staticConfig
$staticConfig =
[
/*the current default contents of filesystems.php
]
Set up a PDO to your database (real setting would be in your .env file)
function get_db_pdo()
{
$host = env('DB_HOST', '127.0.0.1');
$db = env('DB_DATABASE', '3306');
$user = env('DB_USERNAME', 'your username');
$pass = env('DB_PASSWORD', '');
$charset = 'utf8mb4';
$dsn = "mysql:host=$host;dbname=$db;charset=$charset";
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
];
return new PDO($dsn, $user, $pass, $opt);
}
Add a function to fetch your disks from your DB (as you stated in your question it is in the DB) - something like this (using FTP as an example):
function fetchMyFTPs() {
$db = get_db_pdo();
$ftpList = [];
$sql = 'SELECT * FROM myftpservers';
foreach ($db->query($sql) as $row) {
$newConnection = [
'driver' => 'ftp',
'host' => $row['ftpserver'],
'username' => $row['ftpusername'],
'password' => $row['ftppassword']
];
$ftpList[$row['my_ft_connection_name']] = $newConnection;
}
return $ftpList;
}
Last thing to do is to add your dynamic config to the "static" config and return the array like so:
$dynamicFTPS = fetchMyFTPs();
$staticConfig['disks'] = array_merge($staticConfig['disks'],$dynamicFTPS);
return $staticConfig
This way you can still add config as per normal to the static config array, and just merge in your dynamic disks from db.
** Please note this will most definitely have some effect on performance - the literal configuration is preferred. However, in some cases (like I also had on the DB side) there seems to be no other practical way. The "results" of this call are cached anyway so I don't think the DB code will execute on every call.
Upvotes: -2
Reputation: 405
I created a service provider MyDiskServiceProdiver
with this method:
public function boot()
{
MyDisk::all()->each(function(MyDisk $myDisk) {
$this->app['config']["filesystems.disks.{$myDisk->name}"] = ['driver' => $myDisk->driver] + $myDisk->config;
});
}
Where the config
attribute is of type json in database and holds several driver-specific attributes.
Upvotes: 8
Reputation: 85
You can store your FTP accounts configurations in a csv file in your project and then use each accounts as a storage disk using core php in laravel . you have some idea to upload file from this link: https://cloudinary.com/blog/file_upload_with_php.
in this $currentDir = getcwd(); $uploadDirectory = "/uploads/"; you can get these two fileds from CSV file. May be this can help you after implementing correct logic.
Upvotes: -3