Giter VIP home page Giter VIP logo

flysystem-bunnycdn's Introduction

Bunny CDN Logo

Flysystem Adapter for BunnyCDN Storage

Build Status - Flysystem v2 Build Status - Flysystem v3
Codecov Packagist Version Minimum PHP Version: 7.4 Licence: MIT Downloads

Installation

To install flysystem-bunnycdn, require the package with no version constraint. This should match the flysystem-bunnycdn version with your version of FlySystem (v2, v3 etc).

composer require platformcommunity/flysystem-bunnycdn "*"

Usage

use League\Flysystem\Filesystem;
use PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNAdapter;
use PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNClient;
use PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNRegion;

$adapter = new BunnyCDNAdapter(
    new BunnyCDNClient(
        'storage-zone', 
        'api-key', 
        BunnyCDNRegion::FALKENSTEIN
    )
);

$filesystem = new Filesystem($adapter);

Usage with Pull Zones

To have BunnyCDN adapter publish to a public CDN location, you have to a "Pull Zone" connected to your BunnyCDN Storage Zone. Add the full URL prefix of your Pull Zone (including http:///https://) to the BunnyCDNAdapter parameter like shown below.

$adapter = new BunnyCDNAdapter(
    new BunnyCDNClient(
        'storage-zone',
        'api-key',
        BunnyCDNRegion::FALKENSTEIN
    ),
    'https://testing.b-cdn.net/' # Pull Zone URL
);
$filesystem = new Filesystem($adapter);

Note: You can also use your own domain name if it's configured in the pull zone.

Once you add your pull zone, you can use the ->getUrl($path), or in Laravel, the ->url($path) command to get the fully qualified public URL of your BunnyCDN assets.

Usage in Laravel 9

To add BunnyCDN adapter as a custom storage adapter in Laravel 9, install using the v3 composer installer.

composer require platformcommunity/flysystem-bunnycdn "^3.0"

Next, install the adapter to your AppServiceProvider to give Laravel's FileSystem knowledge of the BunnyCDN adapter.

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Storage::extend('bunnycdn', function ($app, $config) {
            $adapter = new BunnyCDNAdapter(
                new BunnyCDNClient(
                    $config['storage_zone'],
                    $config['api_key'],
                    $config['region']
                ),
                'http://testing.b-cdn.net' # Optional
            );

            return new FilesystemAdapter(
                new Filesystem($adapter, $config),
                $adapter,
                $config
            );
        });
    }

Finally, add the bunnycdn driver into your config/filesystems.php configuration file.

        ... 
        
        'bunnycdn' => [
            'driver' => 'bunnycdn',
            'storage_zone' => env('BUNNYCDN_STORAGE_ZONE'),
            'api_key' => env('BUNNYCDN_API_KEY'),
            'region' => env('BUNNYCDN_REGION', \PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNRegion::DEFAULT)
        ],
        
        ...

Lastly, populate your BUNNYCDN_STORAGE_ZONE, BUNNYCDN_API_KEY BUNNYCDN_REGION variables in your .env file.

BUNNYCDN_STORAGE_ZONE=testing_storage_zone
BUNNYCDN_API_KEY="api-key"
# BUNNYCDN_REGION=uk

After that, you can use the bunnycdn disk in Laravel 9.

Storage::disk('bunnycdn')->put('index.html', '<html>Hello World</html>');

return response(Storage::disk('bunnycdn')->get('index.html'));

Note: You may have to run php artisan config:clear in order for your configuration to be refreshed if your app is running with a config cache driver / production mode.

Regions

For a full region list, please visit the BunnyCDN API documentation page.

flysystem-bunnycdn also comes with constants for each region located within PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNRegion.

List of Regions

# Europe
BunnyCDNRegion::FALKENSTEIN = 'de';
BunnyCDNRegion::STOCKHOLM = 'se';

# United Kingdom
BunnyCDNRegion::UNITED_KINGDOM = 'uk';

# USA
BunnyCDNRegion::NEW_YORK = 'ny';
BunnyCDNRegion::LOS_ANGELAS = 'la';

# SEA
BunnyCDNRegion::SINGAPORE = 'sg';

# Oceania
BunnyCDNRegion::SYDNEY = 'syd';

# Africa
BunnyCDNRegion::JOHANNESBURG = 'jh';

# South America
BunnyCDNRegion::BRAZIL = 'br';

Contributing

Pull requests welcome. Please feel free to lodge any issues as discussion points.

Development

Most of the understanding of how the Flysystem Adapter for BunnyCDN works comes from tests/. If you want to complete tests against a live BunnyCDN endpoint, copy the tests/ClientDI_Example.php to tests/ClientDI.php and insert your credentials into there. You can then run the whole suite by running vendor/bin/phpunit, or against a specific file by running vendor/bin/phpunit --bootstrap tests/ClientDI.php tests/ClientTest.php.

Licence

The Flysystem adapter for Bunny.net is licensed under MIT.

flysystem-bunnycdn's People

Contributors

ben182 avatar helloiamlukas avatar jjprojects avatar joshbmarshall avatar n-e-m-a-nj-a avatar rickkuilman avatar sifex avatar stevenmond avatar stof avatar tinect avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

flysystem-bunnycdn's Issues

Deleting directories doesn't work

Hi,
I've noticed that folders aren't being deleted from my storage zone and I've tracked it down to a path issue. When performing a DELETE request for a folder, BunnyCDN API returns 404 if path doesn't end with /.
See my two requests below done via the Insomnia app:

Zrzut ekranu 2021-02-24 o 16 09 31

Zrzut ekranu 2021-02-25 o 15 25 43

The / at the end should be added in deleteDir method of BunnyCDNAdapter class, but since the fullPath method doesn't get info about an object being a directory, it doesn't pass it along to Util::normalizePath, which has a condition to add / at the end of directory paths.

delete without any input should throw an error

Delete without any input should throw an error, shouldn't it?

adapter->delete('') will delete the entire storage. Heard of it happening ๐Ÿ™ˆ Devils are everywhere - regarding my need, there are other 3rd parties in the shopware environment doing strange things.

I checked deletion with same empty parameter in different filesystems (s3, local, ...), these are throwing errors.

Should we implement a check, like here? #68

listContents with deep option does not work

Hi,

The CMS I am using is trying to call listContents on the root folder with the second argument deep set to true. Sadly, this does not seem to be implemented in this adapter. Any way we can make this work?

Problems when path includes storage zone name

When handling files in folders that include the storage zone name, the adapter will not work as expected.

This problem occurs because str_replace is used to remove the storage zone from the path.

$bunny_file_array['Path'] = str_replace($this->prependPrefix(''), '', $bunny_file_array['Path']);

str_replace(
$bunny_file_array['StorageZoneName'].'/',
'/',
$bunny_file_array['Path'].$bunny_file_array['ObjectName']
)

str_replace(
$bunny_file_array['StorageZoneName'].'/',
'/',
$bunny_file_array['Path'].$bunny_file_array['ObjectName']
)

This will also remove folders from the path that have the same name.

Laravel 9 support

Hi,

Thanks for this package.

Will this package be upgraded for laravel 9 ?

Thanks!

features + fixes

Hey there,

thank you for the project!!! :-)

I have a few things which seems not to have finished yet.
I'll try to support by PR next days.

  • readStream should throw UnableToReadFile, not BunnyCDNException or NotFoundException
  • listContents with deep should be supported
  • possibility to specify root-directory/prefix-path

Mime type exception

Hi,

We are running Laravel 8 and Statamic 3.4.
Wen i implement Bunny CDN i get the error like issue: #23
I see it is fixed in the driver version 3 but we cant install v3 or v2 because our Laravel installation requires flysystem v1.1.10
Could you make te fix to be backported to v1 and mayby also v2?

Thanks

[Bugs] BunnyCDNException dont work properly

Hey, I noticed something peculiar. By default, both BunnyCDNClient and BunnyCDNAdapter share the same exception handler, which is BunnyCDNExceptions. However, when attempting to perform actions with invalid credentials or invalid operations like deleting an invalid file, I couldn't catch the errors using the try block. After spending a considerable amount of time investigating the issue, I discovered that creating a new exception and using different exception handlers for BunnyClient and BunnyAdapter allows the errors to be thrown correctly.

Driver [bunnycdn] is not supported.

Got this error:

Driver [bunnycdn] is not supported.

at .....\vendor\laravel\framework\src\Illuminate\Filesystem\FilesystemManager.php:149
145โ–•
146โ–• $driverMethod = 'create'.ucfirst($name).'Driver';
147โ–•
148โ–• if (! method_exists($this, $driverMethod)) {
โžœ 149โ–• throw new InvalidArgumentException("Driver [{$name}] is not supported.");
150โ–• }
151โ–•
152โ–• return $this->{$driverMethod}($config);
153โ–• }

I did everything according to the documentation
Laravel Framework 9.52.4

Set root path on config

Hi,

what would be a really helpful feature is if the adapter would respect the root config attribute that you can specify to put your files right into a specific directory, like the S3 adapter does.

getObject doesn't pass proper path to the listContents function

Right now the code for getObject in the BunnyCDNAdapter is as follows

/**
     * @param $path
     * @return mixed
     */
    protected function getObject($path): StorageAttributes
    {
        $list = (new DirectoryListing($this->listContents()))
            ->filter(function (StorageAttributes $item) use ($path) {
                return $item->path() === $path;
            })->toArray();

        if (count($list) === 1) {
            return $list[0];
        } elseif (count($list) > 1) {
            throw UnableToReadFile::fromLocation($path, 'More than one file was returned for path:"' . $path . '", contact package author.');
        } else {
            throw UnableToReadFile::fromLocation($path, 'Error 404:"' . $path . '"');
        }
    }

However this will only list contents for the root directory on BunnyCDN - i.e. if Bunny is laid out like

a [Folder]
---1.jpg

b [Folder]
---2.jpg

c [Folder]
---3.jpg

Calling getObject('a/1.jpg') will always return an error since 1.jpg isn't in the root directory. To fix this, the code needs to be updated to search in the directory where the object is located

/**
     * @param $path
     * @return mixed
     */
    protected function getObject(string $path = ''): StorageAttributes
    {
       $directory = $path ? pathinfo($path, PATHINFO_DIRNAME) : '';
        $list = (new DirectoryListing($this->listContents($directory)))
            ->filter(function (StorageAttributes $item) use ($path) {
                return $item->path() === $path;
            })->toArray();

        if (count($list) === 1) {
            return $list[0];
        } elseif (count($list) > 1) {
            throw UnableToReadFile::fromLocation($path, 'More than one file was returned for path:"' . $path . '", contact package author.');
        } else {
            throw UnableToReadFile::fromLocation($path, 'Error 404:"' . $path . '"');
        }
    }

Now a/1.jpg will return as expected

[Question] Path Prefixing

Hello!

How do you set-up the path prefixing?

I've attempted to set it up with Laravel, and it uploads the files as expected in the prefixed path, but upon URL retrieval it throws:
"This driver does not support retrieving URLs.",

Do you have an example with a prefixed path?

I cannot get it working

Hi,

I have tried to setup this for my Bunny CDN, I followed the steps carefully for Laravel 9, but can't get it working. There must be something that I am missing to configure correctly. Can you please help me set this up.

Thanks

Crash in normalizeObject

Hi guys,
I'm using v1.3.0 of your library at the moment. Looks like a crash appears sometimes in normalizeObject method of BunnyCDNAdapter class which produces this exception: Call to a member function getTimestamp() on bool. We only noticed it in production due to the sheer amount of files we are processing there.

After adding some logs to the class I found out that Bunny API sometimes returns file change and creation timestamps in the format you expect (e.g. 2022-04-10T17:43:49.297) but sometimes the fractional seconds are missing: 2022-04-10T16:40:48. When fractional seconds are missing, the code crashes because the DateTime object can't be created from format and date_create_from_format returns false.

Could you find a fix for this issue? We already contacted the bunny team too to standarize the timestamps a bit more but the issue is quite urgent for us hence the ticket here too. :)

BunnyCDN does not support steam writing

When uploading a file, I get:

League\Flysystem\NotSupportedException: BunnyCDN does not support steam writing, use ->write() instead in file /Users/xxx/Code/xxx/vendor/platformcommunity/flysystem-bunnycdn/src/BunnyCDNAdapter.php on line 75

Can't request file containing json

If you request a file which contains json, it gets decoded as array.

private function request(string $path, string $method = 'GET', array $options = []): mixed
{
$response = $this->client->request(
$method,
self::get_base_url($this->region).Util::normalizePath('/'.$this->storage_zone_name.'/').$path,
array_merge_recursive([
'headers' => [
'Accept' => '*/*',
'AccessKey' => $this->api_key, // Honestly... Why do I have to specify this twice... @BunnyCDN
],
], $options)
);
$contents = $response->getBody()->getContents();
return json_decode($contents, true) ?? $contents;
}

"Unknown Mimetype" exception thrown

After successfully using the package in a Laravel 8 project, I wanted to check it out with Laravel 9 and Statamic 3.3. I created the filesystem and also followed the Laravel 9 instructions.

When connecting the filesystem to Statamic, I get the following exception:

Screenshot 2022-06-02 at 10 20 59

I can upload files (they appear in the bunny.net File Manager) but are not shown in Statamic, instead, the mentioned exception is thrown.

Listing Directories doesn't work

Hi guys, it's me again :) Last time I was trying to delete a directory, now I'm trying to list directories inside a directory. The case is I have a folder which contains a bunch of other folders:

sites/
โ”œโ”€ inner folder 1/
โ”œโ”€ inner folder 2/
โ”œโ”€ ... etc

I'm trying to get a list of folders inside sites folder but I get an empty array when running the following code even though there should be tons of folders there:

$directories = $disk->directories('sites');

I've managed to trace and fix this bug locally. And I'm happy to create a PR with the fix but want to get your opinions about it first.

What is the issue?
When listing directories, the results of listContents() from the adapter are passed to \League\Flysystem\Util\ContentListingFormatter@formatListing. This formatter filters the list using, among others, this piece of code:

$entry['dirname'] === $this->directory

Source: https://github.com/thephpleague/flysystem/blob/1.x/src/Util/ContentListingFormatter.php#L64

And the "dirname" of each entry returned from adapter looks like this: /sites/. Obviously "/sites/" !== "sites" which is why each folder is deemed out of range.

A fix would be to change the PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNAdapter@normalizeObject a bit from this:

'dirname' => $this->removePathPrefix($fileObject->Path),

to this:

'dirname' => trim($this->removePathPrefix($fileObject->Path), "/"),

But not sure if this would be a breaking change maybe? What do you guys think?

lastModified does not throw error when path is a directory

Hi,

I discovered an issue with the lastModified function if you pass a directory as the path. On other adapters like the ftp adatper, the function should throw an error like so: https://github.com/thephpleague/flysystem-ftp/blob/e59ae1b1370503a7925a75cc44f6f99cced1b2f0/FtpAdapter.php#L334. It will check if the file returned a lastModified date and since directories do not return that, it will fail. On the bunnycdn adapter it will not fail. It will only check for 404s or more than one file returned. This results also in a type error because lastModified expects FileAttributes to be returned but if you pass a directory, DirectoryAttributes will be returned.

Reproducible by just trying to call lastModified on a folder path.

What do you think about just checking for:

if (is_a($object, DirectoryAttributes::class)) {
    throw UnableToReadFile::fromLocation($path, 'Path is a directory');
}

in the function lastModified?

Upgrade to guzzlehttp/guzzle ^7.0

Could we upgrade this package to require the latest version of guzzle, v 7.0.ie "guzzlehttp/guzzle": "^7.0"

I am trying to resolve this issue: composer/composer#9306
and am seeing conflicts because of different minimum required versions of guzzle.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.