Path: blob/master/src/applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php
12241 views
<?php12/**3* Local disk storage engine. Keeps files on local disk. This engine is easy4* to set up, but it doesn't work if you have multiple web frontends!5*6* @task internal Internals7*/8final class PhabricatorLocalDiskFileStorageEngine9extends PhabricatorFileStorageEngine {101112/* -( Engine Metadata )---------------------------------------------------- */131415/**16* This engine identifies as "local-disk".17*/18public function getEngineIdentifier() {19return 'local-disk';20}2122public function getEnginePriority() {23return 5;24}2526public function canWriteFiles() {27$path = PhabricatorEnv::getEnvConfig('storage.local-disk.path');28$path = phutil_string_cast($path);29return (bool)strlen($path);30}313233/* -( Managing File Data )------------------------------------------------- */343536/**37* Write the file data to local disk. Returns the relative path as the38* file data handle.39* @task impl40*/41public function writeFile($data, array $params) {42$root = $this->getLocalDiskFileStorageRoot();4344// Generate a random, unique file path like "ab/29/1f918a9ac39201ff". We45// put a couple of subdirectories up front to avoid a situation where we46// have one directory with a zillion files in it, since this is generally47// bad news.48do {49$name = md5(mt_rand());50$name = preg_replace('/^(..)(..)(.*)$/', '\\1/\\2/\\3', $name);51if (!Filesystem::pathExists($root.'/'.$name)) {52break;53}54} while (true);5556$parent = $root.'/'.dirname($name);57if (!Filesystem::pathExists($parent)) {58execx('mkdir -p %s', $parent);59}6061AphrontWriteGuard::willWrite();62Filesystem::writeFile($root.'/'.$name, $data);6364return $name;65}666768/**69* Read the file data off local disk.70* @task impl71*/72public function readFile($handle) {73$path = $this->getLocalDiskFileStorageFullPath($handle);74return Filesystem::readFile($path);75}767778/**79* Deletes the file from local disk, if it exists.80* @task impl81*/82public function deleteFile($handle) {83$path = $this->getLocalDiskFileStorageFullPath($handle);84if (Filesystem::pathExists($path)) {85AphrontWriteGuard::willWrite();86Filesystem::remove($path);87}88}899091/* -( Internals )---------------------------------------------------------- */929394/**95* Get the configured local disk path for file storage.96*97* @return string Absolute path to somewhere that files can be stored.98* @task internal99*/100private function getLocalDiskFileStorageRoot() {101$root = PhabricatorEnv::getEnvConfig('storage.local-disk.path');102103if (!$root || $root == '/' || $root[0] != '/') {104throw new PhabricatorFileStorageConfigurationException(105pht(106"Malformed local disk storage root. You must provide an absolute ".107"path, and can not use '%s' as the root.",108'/'));109}110111return rtrim($root, '/');112}113114115/**116* Convert a handle into an absolute local disk path.117*118* @param string File data handle.119* @return string Absolute path to the corresponding file.120* @task internal121*/122private function getLocalDiskFileStorageFullPath($handle) {123// Make sure there's no funny business going on here. Users normally have124// no ability to affect the content of handles, but double-check that125// we're only accessing local storage just in case.126if (!preg_match('@^[a-f0-9]{2}/[a-f0-9]{2}/[a-f0-9]{28}\z@', $handle)) {127throw new Exception(128pht(129"Local disk filesystem handle '%s' is malformed!",130$handle));131}132$root = $this->getLocalDiskFileStorageRoot();133return $root.'/'.$handle;134}135136}137138139