Spaces-API/spaces.php
Bakr Alsharif 7e23a96a6a
Allow uploading files from URL
When uploading files from a URL, and if the server closes the connection directly after sending the file, then the resource will be invalid and an exception will be thrown when trying to close it. The supposed fix is to check if the resource is valid.
2020-12-18 19:33:08 +03:00

368 lines
8.3 KiB
PHP

<?php
/*
Makes interacting with DigitalOcean Spaces super easy.
*/
/*
A helper function just to tidy everything up a bit.
*/
function Spaces($accessKey, $secretKey, $host = "digitaloceanspaces.com") { return new Spaces($accessKey, $secretKey, $host); }
/*
We're all Devs here, right?
If not, this creates a class that can be called to connect to your Spaces instaces.
*/
class Spaces {
private $accessKey;
private $secretKey;
private $host;
/*
Takes your secrets.
*/
function __construct($accessKey, $secretKey, $host = "digitaloceanspaces.com") {
$this->accessKey = $accessKey;
$this->secretKey = $secretKey;
$this->host = $host;
//Load the underlying AWS class.
if(!class_exists("Aws\S3\S3Client")) { require_once(dirname(__FILE__)."/aws/aws-autoloader.php"); }
//Create an S3 instance.
$this->s3 = new \Aws\S3\S3Client([
"version" => "2006-03-01",
"region" => "us-east-1",
"endpoint" => "https://ams3.".$host,
"credentials" => ["key" => $accessKey, "secret" => $secretKey],
"ua_append" => "SociallyDev-Spaces-API/2"
]);
}
/*
Lists all your Spaces.
*/
function listSpaces() {
return SpacesResult($this->s3->listBuckets())["Buckets"];
}
/*
Creates a single Space instance.
Automatically figures out the region if not provided.
*/
function space($name, $region = "ams3") {
return new Space($name, $region, $this->accessKey, $this->secretKey, $this->host);
}
/*
Creates a new Space & returns a Space instance.
*/
function create($name, $region, $privacy = "private") {
$space = $this->space($name, $region);
$space->create($privacy);
return $space;
}
}
/*
Handles single Space operations.
*/
class Space {
/*
Stores the arguments needed.
Also creates another S3 instance for this region.
*/
function __construct($name, $region, $accessKey, $secretKey, $host) {
$this->name = $name;
//$this->region = $region;
$this->s3 = new \Aws\S3\S3Client([
"version" => "2006-03-01",
"region" => "us-east-1",
"endpoint" => "https://".$region.".".$host,
"credentials" => ["key" => $accessKey, "secret" => $secretKey],
"ua_append" => "SociallyDev-Spaces-API/2"
]);
}
/*
Creates this Space.
*/
function create($privacy = "private") {
if($privacy == "public") { $privacy = "public-read"; }
return $this->s3->createBucket([
"ACL" => $privacy,
"Bucket" => $this->name
])->toArray()["@metadata"]["effectiveUri"];
}
/*
Deletes this Space.
*/
function destroy() {
$this->s3->deleteMatchingObjects($this->name, "", "(.*?)");
$this->s3->deleteBucket(["Bucket" => $this->name]);
return true;
}
/*
Downloads entire Space to a directory.
*/
function downloadToDirectory($directory, $filesStartingAs = "") {
$this->s3->downloadBucket($directory, $this->name, $filesStartingAs);
return true;
}
/*
Uploads an entire directory to Space.
*/
function uploadDirectory($directory, $prependPrefix = "") {
$this->s3->uploadDirectory($directory, $this->name, $prependPrefix);
return true;
}
/*
Uploads text.
*/
function upload($text, $saveAs, $privacy = "private") {
if($privacy == "public") { $privacy = "public-read"; }
return SpacesResult($this->s3->upload($this->name, $saveAs, $text, $privacy));
}
/*
Uploads a file.
*/
function uploadFile($filePath, $saveAs = "", $privacy = "private") {
if(empty($saveAs)) { $saveAs = $filePath; }
if($privacy == "public") { $privacy = "public-read"; }
$content = fopen($filePath, "r");
$result = $this->s3->upload($this->name, $saveAs, $content, $privacy);
if(is_resource($content)) { fclose($content); }
return SpacesResult($result);
}
/*
Downloads a file.
*/
function downloadFile($file, $saveTo = false) {
if(!$saveTo) {
//Directly return file content.
return $this->s3->getObject(["Bucket" => $this->name, "Key" => $file])["Body"]->getContents();
}
//Save to a file on disk.
return SpacesResult($this->s3->getObject(["Bucket" => $this->name, "Key" => $file, "SaveAs" => $saveTo]));
}
/*
Copies a file.
*/
function copyFile($filePath, $saveAs, $toSpace = "", $privacy = "private") {
if(!$toSpace) { $toSpace = $this->name; }
if($privacy == "public") { $privacy = "public-read"; }
return SpacesResult($this->s3->copy($this->name, $filePath, $toSpace, $saveAs, $privacy));
}
/*
Lists all files.
*/
function listFiles($ofFolder = "", $autoIterate = true, $continueAfter = null) {
$data = $this->s3->listObjectsV2(["Bucket" => $this->name, "Prefix" => $ofFolder, "MaxKeys" => 1000, "FetchOwner" => false, "ContinuationToken" => $continueAfter]);
$result = SpacesResult($data);
if($autoIterate && $data["NextContinuationToken"]) {
$result["Contents"] = array_merge($result["Contents"], $this->listFiles($ofFolder, true, $data["NextContinuationToken"]));
}
if($autoIterate) { return $result["Contents"]; }
return $result;
}
/*
Checks if a file exists.
*/
function fileExists($path) {
return $this->s3->doesObjectExist($this->name, $path);
}
/*
Gets info on a file.
*/
function fileInfo($path) {
return SpacesResult($this->s3->headObject([
"Bucket" => $this->name,
"Key" => $path
]));
}
/*
Creates a non-signed view/download URL.
*/
function url($path) {
return $this->s3->getObjectUrl($this->name, $path);
}
/*
Creates a signed view/download URL.
*/
function signedURL($path, $validFor = "15 minutes") {
return (string) $this->s3->createPresignedRequest($this->s3->getCommand("GetObject", ["Bucket" => $this->name, "Key" => $path]), $validFor)->getUri();
}
/*
Deletes multiple files.
*/
function deleteFolder($prefixOrPath) {
$this->s3->deleteMatchingObjects($this->name, $prefixOrPath);
return true;
}
/*
Deletes a single file.
*/
function deleteFile($path) {
$this->s3->deleteObject([
"Bucket" => $this->name,
"Key" => $path
]);
return true;
}
/*
Changes a file's ACL (Privacy).
*/
function filePrivacy($file, $privacy) {
if($privacy == "public") { $privacy = "public-read"; }
$this->s3->putObjectAcl(["Bucket" => $this->name, "Key" => $file, "ACL" => $privacy]);
return true;
}
/*
Changes this Space's ACL (Privacy).
*/
function privacy($privacy) {
if($privacy == "public") { $privacy = "public-read"; }
$this->s3->putBucketAcl(["Bucket" => $this->name, "ACL" => $privacy]);
return true;
}
/*
Gets this Space's CORS rules.
*/
function getCORS() {
return SpacesResult($this->s3->getBucketCors(["Bucket" => $this->name]))["CORSRules"];
}
/*
Sets this Space's CORS rules.
*/
function setCORS($rules = []) {
foreach ($rules as $ogKey => $rule) {
foreach ($rule as $key => $value) {
if($key == "headers") { $rules[$ogKey]["AllowedHeaders"] = $value; }
else if($key == "methods") { $rules[$ogKey]["AllowedMethods"] = $value; }
else if($key == "origins") { $rules[$ogKey]["AllowedOrigins"] = $value; }
else if($key == "exposeHeaders" || $key == "expose") { $rules[$ogKey]["ExposeHeaders"] = $value; }
else if($key == "max") { $rules[$ogKey]["MaxAgeSeconds"] = $value; }
}
}
$this->s3->putBucketCors(["Bucket" => $this->name, "CORSConfiguration" => ["CORSRules" => $rules]]);
return true;
}
/*
Gets bucket lifecycle rules.
*/
function getLifecycleRules() {
return $this->s3->getBucketLifecycle(["Bucket" => $this->name]);
}
/*
Sets bucket lifecycle rules.
NOTE: Currently not used as it kept throwing "MalformedXML error".
*/
function setLifecycleRules($rules) {
return $this->s3->putBucketLifecycle(["Bucket" => $this->name, "LifecycleConfiguration" => ["Rules" => $rules]]);
}
}
/*
Handles creating a standard result.
*/
function SpacesResult($data) {
if(gettype($data) == "object" && get_class($data) == "Aws\Result") { $data = $data->toArray(); }
foreach ($data as $key => $value) {
if(is_array($value)) {
$data[$key] = SpacesResult($value);
continue;
}
if(gettype($value) == "object" && get_class($value) == "Aws\Api\DateTimeResult") {
$data[$key] = strtotime($value);
}
}
return $data;
}