Question

The PHP League Flysystem for "Spaces" object storage

I am trying to use https://github.com/thephpleague/flysystem-aws-s3-v3 adapter for use with digital ocean spaces as the storage provider as the documentation suggests the api matches amazon s3

Has anyone managed to get flysystem working in any form with digital ocean spaces? I cant seem to work out how to override the base url, the rest of the credentials seem to be passed through.

Show comments

Submit an answer

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

Sign In or Sign Up to Answer

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Accepted Answer

This was actually very simple simply set the ‘endpoint’ in your filesystem config to the FQDN of DO spaces eg. in filesytems.php

    'DO' => [
        'driver' => 's3',
        'key' => env('AWS_KEY'),
        'secret' => env('AWS_SECRET'),
        'region' => env('AWS_REGION'),
        'bucket' => env('AWS_BUCKET'),
        'endpoint' => env('AWS_URL')
    ],

and in your .env

AWS_URL=https://nyc3.digitaloceanspaces.com

Tested and it’s working:

  1. install v.1 of league flysystem library (documentation)
user@machine:~$ composer require league/flysystem-aws-s3-v3:^1.0

// 2) php code

class DigitalOceanSpacesClient {
   protected $privateKey;
   protected $publicKey;
   protected $path;
   protected $bucket;
   protected $region;
   protected $version;
   protected $spacesEndpoint = 'https://BUCKET.REGION.digitaloceanspaces.com';
   protected $error = false;
   /** @var boolean $log If you should log errors and properties for debuging */
   protected $log = false;

   /** @var \League\Flysystem\Filesystem $client The `\League\Flysystem\Filesystem` class object */
   protected $client;

   /**
    * Constructor.
    * 
    * The passed argument is a hash array with the following keys and types:
    * ```
    * string privateKey
    * string publicKey
    * string path
    * string bucket
    * string region
    * string version
    * bool log
    * ```
    * 
    * @param array[] $arr A hash array of key-values for the class properties
    * 
    * @return DigitalOceanSpacesClient A DigitalOceanSpacesClient object
    */
   public function __construct(array $arr = array()) {
      $this->privateKey = @$arr['privateKey'];
      $this->publicKey = @$arr['publicKey'];
      $this->path = @$arr['path'];
      $this->bucket = @$arr['bucket'];
      $this->region = @$arr['region'];
      $this->version = @$arr['version'];
      $this->log = (bool)@$arr['log'];
      $this->setSpacesEndpoint($this->bucket, $this->region);
   }

   /**
    * Dependency inversion principle.
    * 
    * @return \League\Flysystem\Filesystem A `\League\Flysystem\Filesystem` object
    */
   public function getClient() {
      if(!isset($this->client)) {
         $options = [

            /*
             * version 2
            'driver' => 's3',
            'key' => $this->publicKey,
            'secret' => $this->privateKey,
            'region' => $this->region,
            'bucket' => $this->bucket,
            'endpoint' => $this->spacesEndpoint
            */

            'credentials' => [
               'key'    => $this->publicKey,
               'secret' => $this->privateKey,
            ],
            'region' => $this->region,
            'version' => $this->version,
            'endpoint' => $this->spacesEndpoint

         ];
         // This is my custom method at Flysystem as I don't
         // use composer and I want global functions to load
         // on demand - don't care about composer's approach; 
         // just skip it if you use composer :((
         //\League\Flysystem\Utils::run();
         $client = new S3Client($options);
         $adapter = new AwsS3Adapter($client, $this->bucket);
         $this->client = new Filesystem($adapter);
      }
      return $this->client;
   }
   
   /**
    * Calculates spaces url based on object properties.
    * 
    * @param string $bucket The Spaces name
    * @param string $region The Spaces region
    * 
    * @return void
    */
   public function setSpacesEndpoint(string $bucket, string $region) {
      if($bucket && $region) {
         $this->spacesEndpoint = \str_replace(['BUCKET.', '.REGION.'], [$bucket . '.', '.' . $region . '.'], $this->spacesEndpoint);
      }
   }
}
  1. Now, it’s easy to build a \League\Flysystem\Filesystem object
   $arr = array(
         'log' => false,
         'privateKey' => 'private key',
         'publicKey' => 'public key',
         'path' => 'a filepath',
         'bucket' => 'spaces name',
         'region' => 'e.g. ams3'
      );
   $test = new DigitalOceanSpacesClient($arr);

I get the following error: class Storage not found… Where does this class come from?

I’ve set the visibility to public. But it doesn’t work. Can anyone help me?

'spaces' => [
            'driver' => 's3',
            'key' => 'your-key',
            'secret' => 'your-secret',
            'region' => 'your-region',
            'bucket' => 'your-bucket',
            'visibility' => 'public',
],