-A compact, dependency-less Amazon S3 API client implementing the most commonly used features
+A compact, dependency-less Amazon S3 API client implementing the most commonly used features.
+
+This library is designed to work with Amazon S3 proper, as well as S3-compatible services such as but not limited to Wasabi, Google Storage, Synology C2, ExoScale etc.
## Why reinvent the wheel
@@ -275,7+277,9 @@ $connector = new \Akeeba\S3\Connector($configuration);
```php
$configuration->setSSL(false);
-```
+```
+
+Caveat: HTTPS will only work if PHP can verify the TLS certificate of your endpoint. This may not be the case when using a local testing service (e.g. LocalStack), or for some buckets with dots in their names. Moreover, if you are on Windows, do note that neither PHP comes with a Certification Authority cache, nor is there a system-wide CA cache; you'll have to [download](https://curl.se/docs/caextract.html) it and configure PHP, or use [composer/ca-bundle](https://packagist.org/packages/composer/ca-bundle) in your `composer.json` file.
### Custom endpoint
@@ -293,6+297,8 @@ $configuration = new \Akeeba\S3\Configuration(
$connector = new \Akeeba\S3\Connector($configuration);
```
+Caveat: Setting the endpoint resets the signature version and region. This is why you need to set them _a second time_, after setting the endpoint, as seen in the first example above.
+
### Legacy path-style access
The S3 API calls made by this library will use by default the subdomain-style access. That is to say, the endpoint will be prefixed with the name of the bucket. For example, a bucket called `example` in the `eu-west-1` region will be accessed using the endpoint URL `example.s3.eu-west-1.amazonaws.com`.
-If you have buckets with characters that are invalid in the context of DNS (most notably dots and uppercase characters) this will fail. You will need to use the legacy path style instead. In this case the endpoint used is the generic region specific one (`s3.eu-west-1.amazonaws.com` in our example above) and the API URL will be prefixed with the bucket name.
+If you have buckets with characters that are invalid in the context of DNS (most notably dots and uppercase characters) this will fail. You will need to use the legacy path style instead. In this case the endpoint used is the generic region specific one (`s3.eu-west-1.amazonaws.com` in our example above), and the API URL will be prefixed with the bucket name.
You need to do:
```php
$configuration->setUseLegacyPathStyle(true);
```
-Caveat: this will not work with v2 signatures if you are using Amazon AWS S3 proper. It will very likely work with the v2 signatures if you are using a custom endpoint, though.
+Caveats:
+* This will not work with v2 signatures if you are using Amazon AWS S3 proper. It will very likely work with the v2 signatures if you are using a custom endpoint, though.
+* This option has no effect on pre-authorised (pre-signed) URLs. Legacy path-style access is used for these URLs by default.
### Dualstack (IPv4 and IPv6) support
@@ -333,4+343,26 @@ Amazon S3 supports dual-stack URLs which resolve to both IPv4 and IPv6 addresses
$connector->setUseDualstackUrl(true);
```
-Caveat: this option only takes effect if you are using Amazon S3 proper. It will _not_ have any effect with custom endpoints.
\ No newline at end of file
+Caveat: This option only takes effect if you are using Amazon S3 proper. It will _not_ have any effect with custom endpoints. DualStack support is deprecated by Amazon S3. We strongly advise you NOT to use it anymore.
+
+### Alternate Date Format
+
+By default, this library uses the standard date format `D, d M Y H:i:s O` which Amazon _incorrectly_ documents as "ISO 8601" (it's not, see the [ISO 8601 Wikipedia entry](https://en.wikipedia.org/wiki/ISO_8601) for reference). Most third party, Amazon S3-compatible services use the same and understand it just fine.
+
+A minority of services don't understand the GMT offset at the end of the date format, and instead need the format `D, d M Y H:i:s T`. You can set a flag to enable this behaviour like so:
+Caveat: Enabling this flag breaks compatibility with S3 proper.
+
+### Using The HTTP Date Header Instead Of X-Amz-Date
+
+Amazon documents that you should be using the standard HTTP `Date` header, and only resort to using the `X-Amz-Date` header when using the standard header is impossible, e.g. when creating pre-authorised (signed) URLs, or when your HTTP library does not let you set the standard header.
+
+Unfortunately, some third party S3-compatible services such as Wasabi and ExoScale do _NOT_ support the standard `Date` header at all. Using it makes them falsely spit out a message about the signature being wrong. They are the reason why, by default, we are passing the request date and time using the `X-Amz-Date` header.
+
+If you are using a third party service which for any reason does not understand the `X-Amz-Date` header you need to set a flag which forces the use of the standard `Date` header like so:
+**⚠️ WARNING**: Running all tests across all services takes _hours_. It is recommended that you use the SignedURLs test as a quick validation tool across multiple services, then test against the `$standardTests` suite overnight.
+
## Against Amazon S3 proper
This is the _canonical_ method for testing this library since Amazon S3 proper is the canonical provider of the S3 API (and not all of its quirks are fully documented, we might add).
@@ -8,9+10,9 @@ Copy `config.dist.php` to `config.php` and enter the connection information to y
## Against [LocalStack](https://localstack.cloud)
-This method is very useful for development.
+This method is very useful for development. It is the most faithful implementation of S3, but it does have some minor quirks not present in the real thing as a result of it running inside a Docker container.
-Install LocalStack [as per their documentation](https://docs.localstack.cloud/getting-started/installation/).
+Install LocalStack [per its documentation](https://docs.localstack.cloud/getting-started/installation/), or using its Docker Desktop Extension.
You will also need to install [`awslocal`](https://github.com/localstack/awscli-local) like so:
+Create a new bucket called `test` i.e. `awslocal s3 mb s3://test`
-Note that single- and dualstack tests result in the same URLs for all S3-compatible services, including LocalStack. These tests are essentially duplicates in this use case.
+The `config.dist.php` already has a configuration for LocalStack. Yes, the access and secret key can be any random string.
## Against Wasabi
-Wasabi nominally supports v4 signatures, but their implementation is actually _non-canonical_, as they only read the date from the optional `x-amz-date` header, without falling back to the standard HTTP `Date` header. We have added a workaround for this behaviour which necessitates testing with it.
+Wasabi nominally supports v4 signatures, but their implementation is actually _non-canonical_, as they only read the date from the optional `x-amz-date` header, without falling back to the standard HTTP `Date` header. We have changed the behaviour of the library to always go through the X-Amz-Date header as a result. Hence, the need to test with Wasabi.
+
+The Wasabi configuration block looks like this:
-Just like with Amazon S3 proper, copy `config.dist.php` to `config.php` and enter the connection information to your Wasabi storage. You will also need to set up the custom endpoint like so:
-**IMPORTANT!** The above endpoint will be different, depending on which region you've created your bucket in. The example above assumes the `eu-central-2` region. If you use the wrong region the tests _will_ fail!
+**❗Important**: The Endpoint and Region must match each other, and the region the bucket was crated in. In the example above, we have created a bucket in the `eu-central-2` region. If you use the wrong region and/or endpoint the tests _will_ fail!
## Against Synology C2
-Synology C2 is an S3-“compatible” storage service. It is not very “compatible” though, since they implemented Amazon's documentation of the v4 signatures instead of how the v4 signatures work in the real world (yeah, there's a very big difference). While Amazon S3 _in reality_ expects all dates to be formatted as per RFC1123, they document that they expect them to be formatted as per “ISO 8601” and they give their _completely wrong_ interpretation of what the “ISO 8601” format is. Synology did not catch that discrepancy, and they only expect the wrongly formatted dates which is totally NOT what S3 itself expects. Luckily, most third party implementations expect either format because they've caught the discrepancy between documentation and reality, therefore making it possible for us to come up with a viable workaround.
+Synology C2 is an S3-“compatible” storage service. It is not very “compatible” though, since they implemented Amazon's documentation of the v4 signatures instead of how the v4 signatures work in the real world (yeah, there's a very big difference). While Amazon S3 _in reality_ expects all dates to be formatted as per RFC1123, they document that they expect them to be formatted as per “ISO 8601”, and they give their _completely wrong_ interpretation of what the “ISO 8601” format is. Synology did not catch that discrepancy, and they only expect the wrongly formatted dates which is totally NOT what S3 itself expects. Luckily, most third party implementations expect either format because they've caught the discrepancy between documentation and reality, therefore making it possible for us to come up with a viable workaround.
And that's why we need to test with C2 as well, folks.
-Copy `config.dist.php` to `config.php` and enter the connection information to your Synology S3 service.
The endpoint URL is given in the Synology C2 Object Manager, next to each bucket. Note the part before `.s3.`. This is the **region** you need to use with v4 signatures. They do not document this anywhere.