Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: 'ubuntu-latest'
strategy:
matrix:
php-versions: [ '8.0', '8.1', '8.2' ]
php-versions: [ '8.2', '8.3', '8.4', '8.5', ]

steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"league/mime-type-detection": "^1.11"
},
"require-dev": {
"phpunit/phpunit": "@stable",
"phpunit/phpunit": "^10.0",
"league/flysystem-adapter-test-utilities": "^3",
"league/flysystem-memory": "^3.0",
"league/flysystem-path-prefixing": "^3.3",
Expand Down
15 changes: 14 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ $adapter = new BunnyCDNAdapter(
)
);

// for temporary URL support, define a signing key
$adapter->setTokenAuthKey('token-auth-signing-key');

$filesystem = new Filesystem($adapter);
```

Expand All @@ -45,14 +48,19 @@ $adapter = new BunnyCDNAdapter(
),
'https://testing.b-cdn.net/' # Pull Zone URL
);

// for temporary URL support, define a signing key
$adapter->setTokenAuthKey('token-auth-signing-key');

$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
## Usage in Laravel 9 & up

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

```bash
Expand All @@ -78,6 +86,9 @@ Next, install the adapter to your `AppServiceProvider` to give Laravel's FileSys
),
$config['pull_zone']
);

// for temporary URL support, define a signing key
$adapter->setTokenAuthKey('token-auth-signing-key');

return new FilesystemAdapter(
new Filesystem($adapter, $config),
Expand All @@ -98,6 +109,7 @@ Finally, add the `bunnycdn` driver into your `config/filesystems.php` configurat
'storage_zone' => env('BUNNYCDN_STORAGE_ZONE'),
'pull_zone' => env('BUNNYCDN_PULL_ZONE'),
'api_key' => env('BUNNYCDN_API_KEY'),
'token_auth_key' => env('BUNNYCDN_TOKEN_AUTH_KEY', ''), // optional if you'd like signed URLs
'region' => env('BUNNYCDN_REGION', \PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNRegion::DEFAULT)
],

Expand All @@ -111,6 +123,7 @@ BUNNYCDN_STORAGE_ZONE=testing_storage_zone
BUNNYCDN_PULL_ZONE=https://testing.b-cdn.net
BUNNYCDN_API_KEY="api-key"
# BUNNYCDN_REGION=uk
#BUNNYCDN_TOKEN_AUTH_KEY="your-token-auth-key" (optional, under CDN > Security > Token Authentication)
```

After that, you can use the `bunnycdn` disk in Laravel 9.
Expand Down
15 changes: 13 additions & 2 deletions src/BunnyCDNAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,27 @@ class BunnyCDNAdapter implements FilesystemAdapter, PublicUrlGenerator, Checksum
{
use CalculateChecksumFromStream;

private string $token_auth_key = '';

public function __construct(
private BunnyCDNClient $client,
private string $pullzone_url = '',
private string $token_auth_key = ''
) {
if (\func_num_args() > 2 && (string) \func_get_arg(2) !== '') {
throw new \RuntimeException('PrefixPath is no longer supported directly. Use PathPrefixedAdapter instead: https://flysystem.thephpleague.com/docs/adapter/path-prefixing/');
}
}

/**
* Set the token auth key for generating temporaryUrls.
*/
public function setTokenAuthKey(string $tokenAuthKey): BunnyCDNAdapter
{
$this->token_auth_key = $tokenAuthKey;

return $this;
}

/**
* @param $source
* @param $destination
Expand Down Expand Up @@ -563,7 +574,7 @@ public function publicUrl(string $path, Config $config): string
public function temporaryUrl(string $path, DateTimeInterface $expiresAt, Config $config): string
{
if ($this->token_auth_key === '') {
throw new UnableToGenerateTemporaryUrl('In order to generate temporary URLs for a BunnyCDN object, you must pass the "token_auth_key" parameter to the BunnyCDNAdapter.', $path);
throw new UnableToGenerateTemporaryUrl('In order to generate temporary URLs for a BunnyCDN object, you must call the `setTokenAuthKey` method on the BunnyCDNAdapter.', $path);
}

// convert our expiration to a unix timestamp
Expand Down
41 changes: 20 additions & 21 deletions tests/FlysystemAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
use League\Flysystem\FilesystemException;
use League\Flysystem\UnableToCopyFile;
use League\Flysystem\UnableToDeleteFile;
use League\Flysystem\UnableToGenerateTemporaryUrl;
use League\Flysystem\UnableToMoveFile;
use League\Flysystem\UnableToProvideChecksum;
use League\Flysystem\UnableToRetrieveMetadata;
Expand Down Expand Up @@ -92,7 +91,10 @@ private static function bunnyCDNClient(): BunnyCDNClient

public static function createFilesystemAdapter(): FilesystemAdapter
{
return new BunnyCDNAdapter(self::bunnyCDNClient(), static::$publicUrl);
$adapter = new BunnyCDNAdapter(self::bunnyCDNClient(), static::$publicUrl);
$adapter->setTokenAuthKey('test-token-auth-key');

return $adapter;
}

/**
Expand All @@ -103,25 +105,6 @@ public function setting_visibility(): void
$this->markTestSkipped('No visibility support is provided for BunnyCDN');
}

public function generating_a_temporary_url(): void
{
$adapter = new BunnyCDNAdapter(self::bunnyCDNClient(), '', 'test-key');

$expiresAt = new \DateTimeImmutable('+1 hour');
$url = $adapter->temporaryUrl('path.txt', $expiresAt, new Config());

$this->assertStringContainsString('path.txt?token=', $url);
$this->assertStringContainsString('&expires=', $url);
}

public function test_temporary_url_throws_exception_if_not_configured(): void
{
$this->expectException(UnableToGenerateTemporaryUrl::class);
$this->expectExceptionMessage('In order to generate temporary URLs for a BunnyCDN object, you must pass the "token_auth_key" parameter to the BunnyCDNAdapter.');

$this->adapter()->temporaryUrl('path.txt', new \DateTimeImmutable('+1 hour'), new Config());
}

/**
* @test
*/
Expand Down Expand Up @@ -320,6 +303,21 @@ public function test_without_pullzone_url_error_thrown_accessing_url(): void
$myAdapter->publicUrl('/path.txt', new Config());
}

/**
* @test
*/
public function generating_a_temporary_url(): void
{
$adapter = new BunnyCDNAdapter(self::bunnyCDNClient(), '');
$adapter->setTokenAuthKey('test-key');

$expiresAt = new \DateTimeImmutable('+1 hour');
$url = $adapter->temporaryUrl('path.txt', $expiresAt, new Config());

$this->assertStringContainsString('path.txt?token=', $url);
$this->assertStringContainsString('&expires=', $url);
}

/**
* @test
*/
Expand Down Expand Up @@ -412,6 +410,7 @@ public function test_checksum_throws_error_with_non_existing_file_on_default_alg
public function test_checksum_throws_error_with_empty_checksum_from_client(): void
{
$client = $this->createMock(BunnyCDNClient::class);

$client->expects(self::exactly(1))->method('list')->willReturnCallback(
function () {
['file' => $file, 'dir' => $dir] = Util::splitPathIntoDirectoryAndFile('file.txt');
Expand Down
34 changes: 21 additions & 13 deletions tests/PrefixTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ private static function bunnyCDNClient(): BunnyCDNClient

private static function bunnyCDNAdapter(): BunnyCDNAdapter
{
return new BunnyCDNAdapter(self::bunnyCDNClient(), 'https://example.org.local/assets/');
$adapter = new BunnyCDNAdapter(self::bunnyCDNClient(), 'https://example.org.local/assets/');
$adapter->setTokenAuthKey('test-token-auth-key');

return $adapter;
}

public static function createFilesystemAdapter(): FilesystemAdapter
Expand All @@ -65,18 +68,6 @@ public function setting_visibility(): void
$this->markTestSkipped('No visibility support is provided for BunnyCDN');
}

public function generating_a_temporary_url(): void
{
$adapter = new BunnyCDNAdapter(self::bunnyCDNClient(), '', 'test-key');
$prefixAdapter = new PathPrefixedAdapter($adapter, self::PREFIX_PATH);

$expiresAt = new \DateTimeImmutable('+1 hour');
$url = $prefixAdapter->temporaryUrl('path.txt', $expiresAt, new Config());

$this->assertStringContainsString(self::PREFIX_PATH.'/path.txt?token=', $url);
$this->assertStringContainsString('&expires=', $url);
}

/**
* Overwritten (usually because of visibility)
*/
Expand Down Expand Up @@ -108,6 +99,23 @@ public function overwriting_a_file(): void
});
}

/**
* @test
*/
public function generating_a_temporary_url(): void
{
$adapter = new BunnyCDNAdapter(self::bunnyCDNClient(), 'https://example.org.local/assets/');
$adapter->setTokenAuthKey('test-token-auth-key');

$prefixAdapter = new PathPrefixedAdapter($adapter, self::PREFIX_PATH);

$expiresAt = new \DateTimeImmutable('+1 hour');
$url = $prefixAdapter->temporaryUrl('path.txt', $expiresAt, new Config());

$this->assertStringContainsString(self::PREFIX_PATH.'/path.txt?token=', $url);
$this->assertStringContainsString('&expires=', $url);
}

/**
* @test
*/
Expand Down
37 changes: 37 additions & 0 deletions tests/TemporaryUrlTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace PlatformCommunity\Flysystem\BunnyCDN\Tests;

use League\Flysystem\Config;
use League\Flysystem\UnableToGenerateTemporaryUrl;
use PHPUnit\Framework\TestCase;
use PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNAdapter;
use PlatformCommunity\Flysystem\BunnyCDN\BunnyCDNClient;

class TemporaryUrlTest extends TestCase
{
public function test_temporary_url_throws_exception_if_not_configured()
{
$this->expectException(UnableToGenerateTemporaryUrl::class);
$this->expectExceptionMessage('you must call the `setTokenAuthKey`');

$client = new BunnyCDNClient('test', 'test');
$adapter = new BunnyCDNAdapter($client, 'pz-key');

$expiresAt = new \DateTimeImmutable('+1 hour');
$adapter->temporaryUrl('testing.text', $expiresAt, new Config());
}

public function test_it_can_generate_signing_key()
{
$client = new BunnyCDNClient('test', 'test');
$adapter = new BunnyCDNAdapter($client, 'pz-key');
$adapter->setTokenAuthKey('test-auth-key');

$expiresAt = new \DateTimeImmutable('+1 hour');
$url = $adapter->temporaryUrl('testing.txt', $expiresAt, new Config());

$this->assertStringContainsString('testing.txt?token=', $url);
$this->assertStringContainsString('expires='.$expiresAt->getTimestamp(), $url);
}
}