Spaces-API/spaces.php

528 lines
14 KiB
PHP

<?php
class SpacesConnect {
/*
An API wrapper for AWS, makes working with DigitalOcean's Spaces super easy.
Written by Devang Srivastava for Dev Uncoded.
Available under MIT License ( https://opensource.org/licenses/MIT )
*/
function __construct($access_key, $secret_key, $spaceName = "", $region = "nyc3", $host = "digitaloceanspaces.com") {
//Only pulled if an AWS class doesn't already exist.
$non_composer_aws_lib = dirname(__FILE__)."/aws/autoloader.php";
if(!empty($spaceName)) {
$endpoint = "https://".$spaceName.".".$region.".".$host;
}
else {
$endpoint = "https://".$region.".".$host;
}
if(!class_exists('Aws\S3\S3Client')) {
if(file_exists($non_composer_aws_lib)) {
require_once($non_composer_aws_lib);
}
else {
throw new SpacesAPIException(@json_encode(["error" => ["message" => "No AWS class loaded.", "code" => "no_aws_class", "type" => "init"]]));
}
}
try {
$this->client = Aws\S3\S3Client::factory(array(
'region' => $region,
'version' => 'latest',
'endpoint' => $endpoint,
'credentials' => array(
'key' => $access_key,
'secret' => $secret_key,
),
'bucket_endpoint' => true,
'signature_version' => 'v4-unsigned-body'
));
} catch (\Exception $e) {
$this->HandleAWSException($e);
}
$this->space = $spaceName;
$this->access_key = $access_key;
$this->secret_key = $secret_key;
$this->host = $host;
$this->region = $region;
}
/*
Creates a Space.
*/
function CreateSpace($spaceName, $region = "") {
if(empty($region)) {
$region = $this->region;
}
$current_space = $this->space;
try {
$this->SetSpace($spaceName);
$success = $this->client->createBucket(array('Bucket' => $spaceName));
$this->client->waitUntil('BucketExists', array('Bucket' => $spaceName));
$this->SetSpace($current_space);
return $this->ObjReturn($success->toArray());
} catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Lists all spaces owned by you in the region.
*/
function ListSpaces() {
$current_space = $this->space;
try {
$this->SetSpace(NULL);
$spaceList = $this->client->listBuckets();
$this->SetSpace($current_space);
return $this->ObjReturn($spaceList->toArray());
} catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Shorthand for SetSpace - Change your current Space, Region and/or Host.
*/
function ChangeSpace($spaceName, $region = "", $host = "") {
return SetSpace($spaceName, $region, $host);
}
/*
Changes your current Space, Region and/or Host.
*/
function SetSpace($spaceName, $region = "", $host = "") {
if(empty($region)) { $region = $this->region; }
if(empty($host)) { $host = $this->host; }
if(!empty($spaceName)) {
$endpoint = "https://".$spaceName.".".$region.".".$host;
$this->space = $spaceName;
} else {
$endpoint = "https://".$region.".".$host;
$this->space = "";
}
try {
$this->client = Aws\S3\S3Client::factory(array(
'region' => $region,
'version' => 'latest',
'endpoint' => $endpoint,
'credentials' => array(
'key' => $this->access_key,
'secret' => $this->secret_key,
),
'bucket_endpoint' => true,
'signature_version' => 'v4-unsigned-body'
));
return $this->ObjReturn(true);
} catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Fetches the current Space's name.
*/
function GetSpaceName() {
return $this->ObjReturn($this->space);
}
/*
Downloads the whole Space to a directory.
*/
function DownloadSpaceToDirectory($pathToDirectory) {
try {
$this->client->downloadBucket($pathToDirectory, $this->space);
return $this->ObjReturn(true);
} catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Deletes the current Space.
*/
function DestroyThisSpace() {
try {
$objects = $this->ListObjects();
foreach ($objects as $value) {
$key = $value["Key"];
$this->DeleteObject($key);
}
$this->client->deleteBucket(array('Bucket' => $this->space));
$this->client->waitUntil('BucketNotExists', array('Bucket' => $this->space));
return $this->ObjReturn(true);
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Lists all objects.
*/
function ListObjects($of_directory = "") {
try {
$objects = $this->client->getIterator('ListObjects', array(
'Bucket' => $this->space,
"Prefix" => $of_directory,
));
$objectArray = array();
foreach ($objects as $object) {
$objectArray[] = $object;
}
return $this->ObjReturn($objectArray);
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Checks whether an object exists.
*/
function DoesObjectExist($objectName) {
try {
return $this->ObjReturn($this->client->doesObjectExist($this->space, $objectName));
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Fetches an object's details.
*/
function GetObject($file_name = "") {
try {
$result = $this->client->getObject([
'Bucket' => $this->space,
'Key' => $file_name,
]);
return $this->ObjReturn($result->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Makes an object private, (restricted) access.
*/
function MakePrivate($file_path = "") {
try {
return $this->PutObjectACL($file_path, ["ACL" => "private"]);
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Makes an object public anyone can access.
*/
function MakePublic($file_path = "") {
try {
return $this->PutObjectACL($file_path, ["ACL" => "public-read"]);
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Deletes an object.
*/
function DeleteObject($file_path = "", $recursive = false) {
try {
if ($recursive) return $this->ObjReturn($this->client->deleteMatchingObjects(
$this->space,
$file_path
));
return $this->ObjReturn($this->client->deleteObject([
'Bucket' => $this->space,
'Key' => $file_path,
])->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Upload a file.
*/
function UploadFile($pathToFile, $access = "private", $save_as = "", $mime_type = "application/octet-stream") {
if(empty($save_as)) {
$save_as = $pathToFile;
}
if($access == "public") {
$access = "public-read";
}
$is_file = strlen($pathToFile) <= PHP_MAXPATHLEN && is_file($pathToFile);
if(!$is_file){
$file = $pathToFile;
}else{
$file = fopen($pathToFile, 'r+');
}
try {
$result = $this->client->putObject(array(
'Bucket' => $this->space,
'Key' => $save_as,
'Body' => $file,
'ACL' => $access,
'ContentType' => $mime_type
));
$this->client->waitUntil('ObjectExists', array(
'Bucket' => $this->space,
'Key' => $save_as
));
return $this->ObjReturn($result->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
} finally {
if ($is_file) {
fclose($file);
}
}
}
/*
Download a file.
*/
function DownloadFile($fileName, $destinationPath = false) {
try {
if(!$destinationPath) {
$result = $this->client->getObject(array(
'Bucket' => $this->space,
'Key' => $fileName,
));
return $result['Body'];
}else{
$result = $this->client->getObject(array(
'Bucket' => $this->space,
'Key' => $fileName,
'SaveAs' => $destinationPath
));
return $this->ObjReturn($result->toArray());
}
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Uploads all contents of a directory.
*/
function UploadDirectory($directory, $keyPrefix = "") {
try {
return $this->client->uploadDirectory($directory, $this->space, $keyPrefix);
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Lists the CORS policy of the Space.
*/
function ListCORS() {
try {
$cors = $this->client->getBucketCors([
'Bucket' => $this->space,
]);
return $this->ObjReturn($cors->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Updates the CORS policy of the Space.
*/
function PutCORS($cors_rules = "") {
if(empty($cors_rules)) {
$cors_rules = [
'AllowedMethods' => ['GET'],
'AllowedOrigins' => ['*'],
'ExposeHeaders' => ['Access-Control-Allow-Origin'],
];
}
try {
$result = $this->client->putBucketCors([
'Bucket' => $this->space,
'CORSConfiguration' => ['CORSRules' => [$cors_rules]]
]);
return $this->ObjReturn($result->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Fetches the ACL (Access Control Lists) of the Space.
*/
function ListSpaceACL() {
try {
$acl = $this->client->getBucketAcl([
'Bucket' => $this->space,
]);
return $this->ObjReturn($acl->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Updates the ACL (Access Control Lists) of the Space.
*/
function PutSpaceACL($params) {
try {
$acl = $this->client->putBucketAcl($params);
return $this->ObjReturn($acl->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Lists an object's ACL (Access Control Lists).
*/
function ListObjectACL($file) {
try {
$result = $this->client->getObjectAcl([
'Bucket' => $this->space,
'Key' => $file,
]);
return $this->ObjReturn($result->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Updates an object's ACL (Access Control Lists).
*/
function PutObjectACL($file, $acl) {
try {
$acl = array_merge(array("Bucket" => $this->space, "Key" => $file), $acl);
$result = $this->client->putObjectAcl($acl);
return $this->ObjReturn($result->toArray());
}
catch (\Exception $e) {
$this->HandleAWSException($e);
}
}
/*
Creates a temporary URL for a file (Mainly for accessing private files).
*/
function CreateTemporaryURL($file_name = "", $valid_for = "1 hour") {
$cmd = $this->client->getCommand('GetObject', [
'Bucket' => $this->space,
'Key' => $file_name
]);
$request = $this->client->createPresignedRequest($cmd, $valid_for);
return (string)$request->getUri();
}
/*
INTERNAL FUNCTION - Returns a standardized object.
*/
function ObjReturn($return) {
$return = @json_decode(@json_encode($return), true);
$return = $this->AWSTime($return);
return $return;
}
/*
INTERNAL FUNCTION - Converts all AWS time values to unix timestamps.
*/
function AWSTime($obj) {
$time_keys = ["LastModified", "CreationDate", "Expires", "last-modified", "date", "Expiration"];
if(is_array($obj)) {
foreach ($obj as $key => $value) {
if(is_array($obj[$key])) {
$obj[$key] = $this->AWSTime($obj[$key]);
}
else {
foreach ($time_keys as $time_key) {
if(array_key_exists($time_key, $obj) && !empty($obj[$time_key]) && !is_numeric($obj[$time_key])) {
$obj[$time_key] = strtotime($obj[$time_key]);
}
}
}
}
}
return $obj;
}
/*
INTERNAL FUNCTION - Checks whether an array has any keys.
*/
private function any_key_exists($keys, $arr) {
foreach ($keys as $key) {
if(array_key_exists($key, $arr)) {
return true;
}
}
return false;
}
/*
INTERNAL FUNCTION - Standardizes AWS errors.
*/
function HandleAWSException($e) {
if(get_class($e) == "Aws\S3\Exception\S3Exception") {
$error["error"] = [
"message" => $e->getAwsErrorMessage(),
"code" => $e->getAwsErrorCode(),
"type" => $e->getAwsErrorType(),
"http_code" => $e->getStatusCode(),
];
}
else {
throw $e;
}
throw new SpacesAPIException(@json_encode($error));
}
}
/*
INTERNAL FUNCTION - Throws error for catching.
*/
class SpacesAPIException extends \Exception {
public function __construct($message, $code = 0, Exception $previous = null) {
parent::__construct($message, $code, $previous);
}
public function GetError() {
$error = @json_decode($this->getMessage(), true);
return $error["error"];
}
}