【问题标题】:Add Laravel storage disk/filesystem on the fly动态添加 Laravel 存储磁盘/文件系统
【发布时间】:2018-05-16 11:32:34
【问题描述】:

我在一个数据库表中保存了多个 FTP 帐户,并希望每个帐户都可以用作 Laravel 中的存储磁盘。

通常,Laravel's disksconfig/filesystems.php 中定义。但我不想在那里对我的 FTP 帐户进行硬编码,而是想动态定义它们(在中间件中)。

这可能吗?我该如何做到这一点?

【问题讨论】:

  • 您可以使用 config() 助手来动态设置配置
  • 也许laravel.com/docs/5.5/filesystem#custom-filesystems 这对您有帮助吗?这并不完全是您想要的,但它应该为您指明动态创建和使用文件系统的正确方向。
  • 您必须在某处定义它们... DB 或 config (.env) 我会采用 .env 方式并在 config 中加载变量。
  • @AdnanMumtaz 我把config('filesystems.disks.foo', ['driver' => 'local', 'root' => storage_path('app/foo')]); 放在我的AppServiceProvider::boot() 中。那是行不通的。原因是配置中的文件系统是在 AppServiceProvider 运行之前注册的。
  • @Kyslik 你能说得更清楚些吗?

标签: laravel filesystems storage


【解决方案1】:

我用这个方法创建了一个服务提供者MyDiskServiceProdiver

public function boot()
{
    MyDisk::all()->each(function(MyDisk $myDisk) {
        $this->app['config']["filesystems.disks.{$myDisk->name}"] = ['driver' => $myDisk->driver] + $myDisk->config;
    });
}

config 属性在数据库中属于 json 类型,并包含多个驱动程序特定的属性。

【讨论】:

    【解决方案2】:

    创建一个新的服务提供者 php artisan make:provider FileSystemServiceProvider

    config/app.php 中注册提供商 如果你打开 Laravel 附带的 config/app.php 文件,你会看到一个 provider's array。在那里注册创建的服务提供者。

    在创建的服务提供商的The Boot Method 中使用下面提到的代码来注册磁盘 假设 fileSystemsDetails 是模型名称

    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,
                    ];
            }
        });
    }
    

    【讨论】:

      【解决方案3】:

      Laravel 的 FilesystemManager 具有创建最常用磁盘的方法。

      <?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 */]);
      

      除此之外,你可以创建任何你的联赛/flysystem 安装支持的文件系统,你只需要将它包装在 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);
      

      通过这种方式,您可以即时创建磁盘,而无需修改应用程序配置,如果您有大量连接(例如,与合作伙伴的 FTP/SFTP 服务器、GCloud 或 S3 存储桶)的连接,则非常方便。

      【讨论】:

        【解决方案4】:

        您可以将您的 FTP 帐户配置存储在项目中的 csv 文件中,然后使用 laravel 中的核心 php 将每个帐户用作存储磁盘。你有一些想法从这个链接上传文件: https://cloudinary.com/blog/file_upload_with_php.

        在这个 $currentDir = getcwd(); $uploadDirectory = "/上传/"; 您可以从 CSV 文件中获取这两个文件。 在实施正确的逻辑后,这可能会对您有所帮助。

        【讨论】:

          【解决方案5】:

          我通过在配置文件(在我的例子中是数据库配置)中添加一些普通 PHP 解决了同样的问题。关键是 laravel 配置文件仍然只是“普通”的 PHP 文件,所以没有什么能阻止你在这里访问你的数据库,你不能使用 Eloquent,因为配置是首先处理的。

          因此,使用这种方法 - 您可以在通过 PDO 从数据库中读取磁盘后将磁盘添加到配置数组中。

          未编辑的配置文件返回一个对象数组(因此在您的情况下也是“磁盘”)

          1. 更改文件系统配置并将当前数组添加到名为 $staticConfig 之类的变量中

            $staticConfig = 
            [
             /*the current default contents of filesystems.php
            ]
            
          2. 为您的数据库设置 PDO(实际设置在您的 .env 文件中)

            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);
             }
            
          3. 添加一个函数以从数据库中获取磁盘(正如您在问题中所述,它在数据库中) - 类似这样(以 FTP 为例):

            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;
            }
            
          4. 最后要做的是将您的动态配置添加到“静态”配置并返回数组,如下所示:

            $dynamicFTPS = fetchMyFTPs();
            $staticConfig['disks'] = array_merge($staticConfig['disks'],$dynamicFTPS);
            return $staticConfig
            

          这样你仍然可以像往常一样将配置添加到静态配置数组中,并从 db 中合并到你的动态磁盘中。

          ** 请注意,这肯定会对性能产生一些影响 - 首选文字配置。然而,在某些情况下(就像我在数据库方面也有过的那样)似乎没有其他实用的方法。这个调用的“结果”无论如何都会被缓存,所以我认为数据库代码不会在每次调用时执行。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-03-06
            • 1970-01-01
            • 2019-02-11
            • 2014-07-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多