Path: blob/master/src/applications/files/engine/PhabricatorS3FileStorageEngine.php
12241 views
<?php12/**3* Amazon S3 file storage engine. This engine scales well but is relatively4* high-latency since data has to be pulled off S3.5*6* @task internal Internals7*/8final class PhabricatorS3FileStorageEngine9extends PhabricatorFileStorageEngine {101112/* -( Engine Metadata )---------------------------------------------------- */131415/**16* This engine identifies as `amazon-s3`.17*/18public function getEngineIdentifier() {19return 'amazon-s3';20}2122public function getEnginePriority() {23return 100;24}2526public function canWriteFiles() {27$bucket = PhabricatorEnv::getEnvConfig('storage.s3.bucket');28$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');29$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');30$endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint');31$region = PhabricatorEnv::getEnvConfig('amazon-s3.region');3233return ($bucket !== null && strlen($bucket) &&34$access_key !== null && strlen($access_key) &&35$secret_key !== null && strlen($secret_key) &&36$endpoint !== null && strlen($endpoint) &&37$region !== null && strlen($region));38}394041/* -( Managing File Data )------------------------------------------------- */424344/**45* Writes file data into Amazon S3.46*/47public function writeFile($data, array $params) {48$s3 = $this->newS3API();4950// Generate a random name for this file. We add some directories to it51// (e.g. 'abcdef123456' becomes 'ab/cd/ef123456') to make large numbers of52// files more browsable with web/debugging tools like the S3 administration53// tool.54$seed = Filesystem::readRandomCharacters(20);55$parts = array();56$parts[] = 'phabricator';5758$instance_name = PhabricatorEnv::getEnvConfig('cluster.instance');59if ($instance_name !== null && strlen($instance_name)) {60$parts[] = $instance_name;61}6263$parts[] = substr($seed, 0, 2);64$parts[] = substr($seed, 2, 2);65$parts[] = substr($seed, 4);6667$name = implode('/', $parts);6869AphrontWriteGuard::willWrite();70$profiler = PhutilServiceProfiler::getInstance();71$call_id = $profiler->beginServiceCall(72array(73'type' => 's3',74'method' => 'putObject',75));7677$s378->setParametersForPutObject($name, $data)79->resolve();8081$profiler->endServiceCall($call_id, array());8283return $name;84}858687/**88* Load a stored blob from Amazon S3.89*/90public function readFile($handle) {91$s3 = $this->newS3API();9293$profiler = PhutilServiceProfiler::getInstance();94$call_id = $profiler->beginServiceCall(95array(96'type' => 's3',97'method' => 'getObject',98));99100$result = $s3101->setParametersForGetObject($handle)102->resolve();103104$profiler->endServiceCall($call_id, array());105106return $result;107}108109110/**111* Delete a blob from Amazon S3.112*/113public function deleteFile($handle) {114$s3 = $this->newS3API();115116AphrontWriteGuard::willWrite();117$profiler = PhutilServiceProfiler::getInstance();118$call_id = $profiler->beginServiceCall(119array(120'type' => 's3',121'method' => 'deleteObject',122));123124$s3125->setParametersForDeleteObject($handle)126->resolve();127128$profiler->endServiceCall($call_id, array());129}130131132/* -( Internals )---------------------------------------------------------- */133134135/**136* Retrieve the S3 bucket name.137*138* @task internal139*/140private function getBucketName() {141$bucket = PhabricatorEnv::getEnvConfig('storage.s3.bucket');142if (!$bucket) {143throw new PhabricatorFileStorageConfigurationException(144pht(145"No '%s' specified!",146'storage.s3.bucket'));147}148return $bucket;149}150151/**152* Create a new S3 API object.153*154* @task internal155*/156private function newS3API() {157$access_key = PhabricatorEnv::getEnvConfig('amazon-s3.access-key');158$secret_key = PhabricatorEnv::getEnvConfig('amazon-s3.secret-key');159$region = PhabricatorEnv::getEnvConfig('amazon-s3.region');160$endpoint = PhabricatorEnv::getEnvConfig('amazon-s3.endpoint');161162return id(new PhutilAWSS3Future())163->setAccessKey($access_key)164->setSecretKey(new PhutilOpaqueEnvelope($secret_key))165->setRegion($region)166->setEndpoint($endpoint)167->setBucket($this->getBucketName());168}169170}171172173