mirror of
https://github.com/SociallyDev/Spaces-API.git
synced 2025-08-20 05:13:42 -07:00
Version 3 release. Major re-write
This commit is contained in:
parent
127ad7e14a
commit
f9b49002c7
1507 changed files with 6592 additions and 94204 deletions
7
SpacesAPI/Exceptions/AuthenticationException.php
Normal file
7
SpacesAPI/Exceptions/AuthenticationException.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class AuthenticationException extends Exception {}
|
9
SpacesAPI/Exceptions/FileDoesntExistException.php
Normal file
9
SpacesAPI/Exceptions/FileDoesntExistException.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class FileDoesntExistException extends Exception
|
||||
{
|
||||
}
|
9
SpacesAPI/Exceptions/SpaceDoesntExistException.php
Normal file
9
SpacesAPI/Exceptions/SpaceDoesntExistException.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class SpaceDoesntExistException extends Exception
|
||||
{
|
||||
}
|
7
SpacesAPI/Exceptions/SpaceExistsException.php
Normal file
7
SpacesAPI/Exceptions/SpaceExistsException.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class SpaceExistsException extends Exception {}
|
9
SpacesAPI/Exceptions/SpacesException.php
Normal file
9
SpacesAPI/Exceptions/SpacesException.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class SpacesException extends Exception
|
||||
{
|
||||
}
|
266
SpacesAPI/File.php
Normal file
266
SpacesAPI/File.php
Normal file
|
@ -0,0 +1,266 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI;
|
||||
|
||||
use SpacesAPI\Exceptions\FileDoesntExistException;
|
||||
|
||||
/**
|
||||
* Represents a single file
|
||||
*
|
||||
* You wouldn't normally instantiate this class directly,
|
||||
* Rather obtain an instance from `\SpacesAPI\Space::list()`, `\SpacesAPI\Spaces::file()`, `\SpacesAPI\Spaces::uploadText()` or `\SpacesAPI\Spaces::uploadFile()`
|
||||
*
|
||||
* @property string $expiration
|
||||
* @property string $e_tag
|
||||
* @property int $last_modified
|
||||
* @property string $content_type
|
||||
* @property int $content_length
|
||||
*/
|
||||
class File
|
||||
{
|
||||
use StringFunctions;
|
||||
|
||||
/**
|
||||
* @var \SpacesAPI\Space
|
||||
*/
|
||||
private $space;
|
||||
|
||||
/**
|
||||
* The name of the current space
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $space_name;
|
||||
|
||||
/**
|
||||
* @var \Aws\S3\S3Client
|
||||
*/
|
||||
private $s3;
|
||||
|
||||
private $_expiration;
|
||||
private $_e_tag;
|
||||
private $_filename;
|
||||
private $_last_modified;
|
||||
private $_content_type;
|
||||
private $_content_length;
|
||||
|
||||
/**
|
||||
* @param \SpacesAPI\Space $space
|
||||
* @param string $filename
|
||||
* @param array $info
|
||||
*
|
||||
* @throws \SpacesAPI\Exceptions\FileDoesntExistException
|
||||
*/
|
||||
public function __construct(Space $space, string $filename, array $info = [])
|
||||
{
|
||||
$this->space = $space;
|
||||
$this->space_name = $space->getName();
|
||||
$this->s3 = $space->getS3Client();
|
||||
$this->_filename = $filename;
|
||||
|
||||
if (!$this->s3->doesObjectExist($this->space_name, $filename)) {
|
||||
throw new FileDoesntExistException("File $filename doesn't exist");
|
||||
}
|
||||
|
||||
if (count($info) > 0) {
|
||||
$this->setFileInfo($info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic getter to make the properties read-only
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
if (!property_exists($this, "_$name")) {
|
||||
trigger_error("Undefined property: SpacesAPI\File::$name", E_USER_NOTICE);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->{"_$name"}) {
|
||||
$this->fetchFileInfo();
|
||||
}
|
||||
|
||||
return $this->{"_$name"};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $info
|
||||
*/
|
||||
private function setFileInfo(array $info): void
|
||||
{
|
||||
foreach ($info as $_property => $value) {
|
||||
$property = "_" . $this->pascalCaseToCamelCase($_property);
|
||||
|
||||
if ($property == 'size') {
|
||||
$property = 'content_length';
|
||||
}
|
||||
|
||||
if (property_exists($this, $property)) {
|
||||
$this->$property = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function fetchFileInfo(): void
|
||||
{
|
||||
$this->setFileInfo(
|
||||
Result::parse(
|
||||
$this->s3->headObject([
|
||||
"Bucket" => $this->space_name,
|
||||
"Key" => $this->_filename,
|
||||
])
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this file publicly accessible
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isPublic(): bool
|
||||
{
|
||||
$acl = Result::parse(
|
||||
$this->s3->getObjectAcl([
|
||||
"Bucket" => $this->space_name,
|
||||
"Key" => $this->_filename,
|
||||
])
|
||||
);
|
||||
|
||||
return (
|
||||
isset($acl['Grants'][0]['Grantee']['URI']) &&
|
||||
$acl['Grants'][0]['Grantee']['URI'] == "http://acs.amazonaws.com/groups/global/AllUsers" &&
|
||||
$acl['Grants'][0]['Permission'] == "READ"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a file public or privately accessible
|
||||
*
|
||||
* @param bool $public
|
||||
*/
|
||||
private function updatePrivacy(bool $public): void
|
||||
{
|
||||
$this->s3->putObjectAcl([
|
||||
"Bucket" => $this->space_name,
|
||||
"Key" => $this->_filename,
|
||||
"ACL" => ($public) ? "public-read" : "private",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make file publicly accessible
|
||||
*/
|
||||
public function makePublic(): void
|
||||
{
|
||||
$this->updatePrivacy(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make file non-publicly accessible
|
||||
*/
|
||||
public function makePrivate(): void
|
||||
{
|
||||
$this->updatePrivacy(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file contents as a string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContents(): string
|
||||
{
|
||||
return $this->s3->getObject([
|
||||
"Bucket" => $this->space_name,
|
||||
"Key" => $this->_filename,
|
||||
])["Body"]->getContents();
|
||||
}
|
||||
|
||||
/**
|
||||
* Download the file to a local location
|
||||
*
|
||||
* @param string $saveAs
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function download(string $saveAs): void
|
||||
{
|
||||
$this->s3->getObject([
|
||||
"Bucket" => $this->space_name,
|
||||
"Key" => $this->_filename,
|
||||
"SaveAs" => $saveAs,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the file on the space
|
||||
*
|
||||
* @param string $newFilename
|
||||
* @param false $public
|
||||
*
|
||||
* @return \SpacesAPI\File
|
||||
*/
|
||||
public function copy(string $newFilename, bool $public = false): File
|
||||
{
|
||||
$this->s3->copy(
|
||||
$this->space_name,
|
||||
$this->_filename,
|
||||
$this->space_name,
|
||||
$newFilename,
|
||||
($public) ? 'public-read' : 'private'
|
||||
);
|
||||
|
||||
return new self($this->space, $newFilename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the public URL
|
||||
* This URL will not work if the file is private
|
||||
*
|
||||
* @return string
|
||||
* @see getSignedURL
|
||||
*
|
||||
*/
|
||||
public function getURL(): string
|
||||
{
|
||||
return $this->s3->getObjectUrl($this->space_name, $this->_filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a signed URL, which will work for private files
|
||||
*
|
||||
* @param string|\DateTime|int $validFor Can be any string recognised by strtotime(), an instance of DateTime or a unix timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSignedURL($validFor = "15 minutes"): string
|
||||
{
|
||||
return (string)$this->s3->createPresignedRequest(
|
||||
$this->s3->getCommand("GetObject", [
|
||||
"Bucket" => $this->space_name,
|
||||
"Key" => $this->_filename,
|
||||
]),
|
||||
$validFor
|
||||
)->getUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently delete this file
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
$this->s3->deleteObject([
|
||||
"Bucket" => $this->space_name,
|
||||
"Key" => $this->_filename,
|
||||
]);
|
||||
}
|
||||
}
|
37
SpacesAPI/Result.php
Normal file
37
SpacesAPI/Result.php
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI;
|
||||
|
||||
use Aws\Api\DateTimeResult;
|
||||
|
||||
/**
|
||||
* AWS Results parser
|
||||
*/
|
||||
class Result
|
||||
{
|
||||
/**
|
||||
* Convert AWS result object into plain, multidimensional array
|
||||
*
|
||||
* @param $data
|
||||
*
|
||||
* @return array|mixed
|
||||
*/
|
||||
public static function parse($data) {
|
||||
if (gettype($data) == "object" && get_class($data) == \Aws\Result::class) {
|
||||
$data = $data->toArray();
|
||||
}
|
||||
|
||||
foreach ($data as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$data[$key] = self::parse($value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (gettype($value) == "object" && get_class($value) == DateTimeResult::class) {
|
||||
$data[$key] = strtotime($value);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
352
SpacesAPI/Space.php
Normal file
352
SpacesAPI/Space.php
Normal file
|
@ -0,0 +1,352 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI;
|
||||
|
||||
use Aws\S3\Exception\S3Exception;
|
||||
use Aws\S3\S3Client;
|
||||
use SpacesAPI\Exceptions\SpaceDoesntExistException;
|
||||
|
||||
/**
|
||||
* Represents a space once connected/created
|
||||
*
|
||||
* You wouldn't normally instantiate this class directly,
|
||||
* Rather obtain an instance from `\SpacesAPI\Spaces::space()` or `\SpacesAPI\Spaces::create()`
|
||||
*/
|
||||
class Space
|
||||
{
|
||||
/**
|
||||
* AWS S3 client
|
||||
*
|
||||
* @var \Aws\S3\S3Client
|
||||
*/
|
||||
private $s3;
|
||||
|
||||
/**
|
||||
* The name of the current space
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* Load a space
|
||||
*
|
||||
* You wouldn't normally call this directly,
|
||||
* rather obtain an instance from `\SpacesAPI\Spaces::space()` or `\SpacesAPI\Spaces::create()`
|
||||
*
|
||||
* @param \Aws\S3\S3Client $s3 An authenticated S3Client instance
|
||||
* @param string $name Space name
|
||||
*
|
||||
* @throws \SpacesAPI\Exceptions\SpaceDoesntExistException
|
||||
*/
|
||||
public function __construct(S3Client $s3, string $name)
|
||||
{
|
||||
$this->s3 = $s3;
|
||||
$this->name = $name;
|
||||
|
||||
if (!$this->s3->doesBucketExist($name)) {
|
||||
throw new SpaceDoesntExistException("Space '$this->name' does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current AWS S3 client instance
|
||||
*
|
||||
* For internal library use
|
||||
*
|
||||
* @return \Aws\S3\S3Client
|
||||
*/
|
||||
public function getS3Client(): S3Client
|
||||
{
|
||||
return $this->s3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this space
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update space privacy
|
||||
*
|
||||
* @param bool $public
|
||||
*/
|
||||
private function updatePrivacy(bool $public): void
|
||||
{
|
||||
$this->s3->putBucketAcl([
|
||||
"Bucket" => $this->name,
|
||||
"ACL" => ($public) ? "public-read" : "private",
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable file listing
|
||||
*/
|
||||
public function makePublic(): void
|
||||
{
|
||||
$this->updatePrivacy(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable file listing
|
||||
*/
|
||||
public function makePrivate(): void
|
||||
{
|
||||
$this->updatePrivacy(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is file listing enabled?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isPublic(): bool
|
||||
{
|
||||
$acl = Result::parse($this->s3->getBucketAcl(["Bucket" => $this->name]));
|
||||
|
||||
return (
|
||||
isset($acl['Grants'][0]['Grantee']['URI']) &&
|
||||
$acl['Grants'][0]['Grantee']['URI'] == "http://acs.amazonaws.com/groups/global/AllUsers" &&
|
||||
$acl['Grants'][0]['Permission'] == "READ"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy/Delete this space, along with all files
|
||||
*/
|
||||
public function destroy(): void
|
||||
{
|
||||
$this->s3->deleteMatchingObjects($this->name, "", "(.*?)");
|
||||
$this->s3->deleteBucket(["Bucket" => $this->name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CORS configuration for the space
|
||||
*
|
||||
* @return array|null An array of CORS rules or null if no rules exist
|
||||
*/
|
||||
public function getCORS(): ?array
|
||||
{
|
||||
try {
|
||||
return Result::parse(
|
||||
$this->s3->getBucketCors([
|
||||
"Bucket" => $this->name,
|
||||
])
|
||||
)['CORSRules'];
|
||||
} catch (S3Exception $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CORS rules, removing the origin specified
|
||||
*
|
||||
* @param string $origin
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getCORSRemovingOrigin(string $origin): array
|
||||
{
|
||||
if (!$CORSRules = $this->getCORS()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
foreach ($CORSRules as $i => $cors) {
|
||||
if ($cors['AllowedOrigins'][0] == $origin) {
|
||||
array_splice($CORSRules, $i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return $CORSRules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CORS rules
|
||||
*
|
||||
* @param array $rules
|
||||
*/
|
||||
private function putCORS(array $rules): void
|
||||
{
|
||||
$this->s3->putBucketCors([
|
||||
"Bucket" => $this->name,
|
||||
"CORSConfiguration" => [
|
||||
"CORSRules" => $rules,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an origin to the CORS settings on this space
|
||||
*
|
||||
* @param string $origin eg `http://example.com`
|
||||
* @param array $methods Array items must be one of `GET`, `PUT`, `DELETE`, `POST` and `HEAD`
|
||||
* @param int $maxAge Access Control Max Age
|
||||
* @param array $headers Allowed Headers
|
||||
*/
|
||||
public function addCORSOrigin(string $origin, array $methods, int $maxAge = 0, array $headers = []): void
|
||||
{
|
||||
$rules = $this->getCORSRemovingOrigin($origin);
|
||||
|
||||
$this->putCORS(
|
||||
array_merge($rules, [
|
||||
[
|
||||
"AllowedHeaders" => $headers,
|
||||
"AllowedMethods" => $methods,
|
||||
"AllowedOrigins" => [$origin],
|
||||
"MaxAgeSeconds" => $maxAge,
|
||||
],
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an origin from the CORS settings on this space
|
||||
*
|
||||
* @param string $origin eg `http://example.com`
|
||||
*/
|
||||
public function removeCORSOrigin(string $origin): void
|
||||
{
|
||||
$rules = $this->getCORSRemovingOrigin($origin);
|
||||
|
||||
if (empty($rules)) {
|
||||
$this->removeAllCORSOrigins();
|
||||
} else {
|
||||
$this->putCORS($rules);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all CORS rules
|
||||
*/
|
||||
public function removeAllCORSOrigins(): void
|
||||
{
|
||||
$this->s3->deleteBucketCors([
|
||||
'Bucket' => $this->name,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* List all files in the space (recursively)
|
||||
*
|
||||
* @param string $directory The directory to list files in. Empty string for root directory
|
||||
* @param string|null $continuationToken Used internally to work around request limits (1000 files per request)
|
||||
*
|
||||
* @return array
|
||||
* @throws \SpacesAPI\Exceptions\FileDoesntExistException
|
||||
*/
|
||||
public function listFiles(string $directory = "", ?string $continuationToken = null): array
|
||||
{
|
||||
$data = Result::parse(
|
||||
$this->s3->listObjectsV2([
|
||||
"Bucket" => $this->name,
|
||||
"Prefix" => $directory,
|
||||
"MaxKeys" => 1000,
|
||||
// "StartAfter" => 0, // For skipping files, maybe for future limit/skip ability
|
||||
"FetchOwner" => false,
|
||||
"ContinuationToken" => $continuationToken,
|
||||
])
|
||||
);
|
||||
|
||||
if (!isset($data['Contents'])) {
|
||||
return ['files' => []];
|
||||
}
|
||||
|
||||
$files = [
|
||||
'files' => $data['Contents'],
|
||||
];
|
||||
|
||||
foreach ($files['files'] as $index => $fileInfo) {
|
||||
$files['files'][$index] = new File($this, $fileInfo['Key'], $fileInfo);
|
||||
}
|
||||
|
||||
if (isset($data["NextContinuationToken"]) && $data["NextContinuationToken"] != "") {
|
||||
$files = array_merge($files['files'], $this->listFiles($directory, $data["NextContinuationToken"])['files']);
|
||||
}
|
||||
|
||||
return $files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a string of text to file
|
||||
*
|
||||
* @param string $text The text to upload
|
||||
* @param string $filename The filepath/name to save to
|
||||
* @param array $params Any extra parameters. [See here](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property)
|
||||
*
|
||||
* @return \SpacesAPI\File
|
||||
*/
|
||||
public function uploadText(string $text, string $filename, array $params = []): File
|
||||
{
|
||||
$this->s3->upload($this->name, $filename, $text, 'private', $params);
|
||||
return new File($this, $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a file
|
||||
*
|
||||
* @param string $filepath The path to the file, including the filename. Relative and absolute paths are accepted.
|
||||
* @param string|null $filename The remote filename. If `null`, the local filename will be used.
|
||||
*
|
||||
* @return \SpacesAPI\File
|
||||
*/
|
||||
public function uploadFile(string $filepath, ?string $filename = null): File
|
||||
{
|
||||
$this->s3->putObject([
|
||||
'Bucket' => $this->name,
|
||||
'Key' => ($filename) ?: basename($filepath),
|
||||
'SourceFile' => $filepath,
|
||||
]);
|
||||
|
||||
return new File($this, ($filename) ?: basename($filepath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of \SpacesAPI\File for a given filename
|
||||
*
|
||||
* @param string $filename
|
||||
*
|
||||
* @return \SpacesAPI\File
|
||||
* @throws \SpacesAPI\Exceptions\FileDoesntExistException Thrown if the file doesn't exist
|
||||
*/
|
||||
public function file(string $filename): File
|
||||
{
|
||||
return new File($this, $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively upload an entire directory
|
||||
*
|
||||
* @param string $local The local directory to upload
|
||||
* @param string|null $remote The remote directory to place the files in. `null` to place in the root
|
||||
*/
|
||||
public function uploadDirectory(string $local, ?string $remote = null): void
|
||||
{
|
||||
$this->s3->uploadDirectory($local, $this->name, $remote);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively download an entire directory.
|
||||
*
|
||||
* @param string $local The local directory to save the directories/files in
|
||||
* @param string|null $remote The remote directory to download. `null` to download the entire space
|
||||
*/
|
||||
public function downloadDirectory(string $local, ?string $remote = null): void
|
||||
{
|
||||
$this->s3->downloadBucket($local, $this->name, $remote);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an entire directory, including its contents
|
||||
*
|
||||
* @param string $path The directory to delete
|
||||
*/
|
||||
public function deleteDirectory(string $path): void
|
||||
{
|
||||
$this->s3->deleteMatchingObjects($this->name, $path);
|
||||
}
|
||||
}
|
105
SpacesAPI/Spaces.php
Normal file
105
SpacesAPI/Spaces.php
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI;
|
||||
|
||||
use Aws\S3\Exception\S3Exception;
|
||||
use Aws\S3\S3Client;
|
||||
use SpacesAPI\Exceptions\AuthenticationException;
|
||||
use SpacesAPI\Exceptions\SpaceExistsException;
|
||||
|
||||
/**
|
||||
* Represents the connection to Digital Ocean spaces.
|
||||
* The entry point for managing spaces.
|
||||
*
|
||||
* Instantiate your connection with `new \SpacesAPI\Spaces("access-key", "secret-key", "region")`
|
||||
*
|
||||
* Obtain your access and secret keys from the [DigitalOcean Applications & API dashboard](https://cloud.digitalocean.com/account/api/tokens)
|
||||
*/
|
||||
class Spaces
|
||||
{
|
||||
/**
|
||||
* @var \Aws\S3\S3Client
|
||||
*/
|
||||
private $s3;
|
||||
|
||||
/**
|
||||
* Initialise the API
|
||||
*
|
||||
* @param string $accessKey Digital Ocean API access key
|
||||
* @param string $secretKey Digital Ocean API secret key
|
||||
* @param string $region Region, defaults to ams3
|
||||
* @param string $host API endpoint, defaults to digitaloceanspaces.com
|
||||
*
|
||||
* @throws \SpacesAPI\Exceptions\AuthenticationException Authentication failed
|
||||
*/
|
||||
public function __construct(string $accessKey, string $secretKey, string $region = "ams3", string $host = "digitaloceanspaces.com")
|
||||
{
|
||||
$this->s3 = new S3Client([
|
||||
"version" => "latest",
|
||||
"region" => "us-east-1",
|
||||
"endpoint" => "https://$region.$host",
|
||||
"credentials" => ["key" => $accessKey, "secret" => $secretKey],
|
||||
"ua_append" => "SociallyDev-Spaces-API/2",
|
||||
]);
|
||||
|
||||
try {
|
||||
$this->s3->headBucket(["Bucket" => 'auth-check']);
|
||||
} catch (S3Exception $e) {
|
||||
if ($e->getStatusCode() == 403) {
|
||||
throw new AuthenticationException("Authentication failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List all your spaces
|
||||
*
|
||||
* @return array An array of \SpacesAPI\Space instances
|
||||
*/
|
||||
public function list(): array
|
||||
{
|
||||
$spaces = [];
|
||||
|
||||
foreach (Result::parse($this->s3->listBuckets()['Buckets']) as $bucket) {
|
||||
$spaces[] = new Space($this->s3, $bucket['Name']);
|
||||
}
|
||||
|
||||
return $spaces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new space
|
||||
*
|
||||
* @param string $name The name of the new space
|
||||
* @param bool $public Enable file listing. Default `false`
|
||||
*
|
||||
* @return \SpacesAPI\Space The newly created space
|
||||
* @throws \SpacesAPI\Exceptions\SpaceExistsException The named space already exists
|
||||
*/
|
||||
public function create(string $name, bool $public = false): Space
|
||||
{
|
||||
try {
|
||||
$this->s3->createBucket([
|
||||
"ACL" => ($public) ? "public-read" : "private",
|
||||
"Bucket" => $name,
|
||||
]);
|
||||
} catch (S3Exception $e) {
|
||||
throw new SpaceExistsException($e->getAwsErrorMessage());
|
||||
}
|
||||
|
||||
return new Space($this->s3, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use an existing space
|
||||
*
|
||||
* @param string $name The name of the space
|
||||
*
|
||||
* @return \SpacesAPI\Space The loaded space
|
||||
* @throws \SpacesAPI\Exceptions\SpaceDoesntExistException The named space doesn't exist
|
||||
*/
|
||||
public function space(string $name): Space
|
||||
{
|
||||
return new Space($this->s3, $name);
|
||||
}
|
||||
}
|
11
SpacesAPI/StringFunctions.php
Normal file
11
SpacesAPI/StringFunctions.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace SpacesAPI;
|
||||
|
||||
trait StringFunctions
|
||||
{
|
||||
public function pascalCaseToCamelCase(string $name): string
|
||||
{
|
||||
return strtolower(preg_replace("/([a-z])([A-Z])/", "$1_$2", $name));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue