Changeset View
Changeset View
Standalone View
Standalone View
src/applications/files/storage/PhabricatorFile.php
Show All 24 Lines | implements | ||||
PhabricatorApplicationTransactionInterface, | PhabricatorApplicationTransactionInterface, | ||||
PhabricatorTokenReceiverInterface, | PhabricatorTokenReceiverInterface, | ||||
PhabricatorSubscribableInterface, | PhabricatorSubscribableInterface, | ||||
PhabricatorFlaggableInterface, | PhabricatorFlaggableInterface, | ||||
PhabricatorPolicyInterface, | PhabricatorPolicyInterface, | ||||
PhabricatorDestructibleInterface, | PhabricatorDestructibleInterface, | ||||
PhabricatorConduitResultInterface, | PhabricatorConduitResultInterface, | ||||
PhabricatorIndexableInterface, | PhabricatorIndexableInterface, | ||||
PhabricatorNgramsInterface { | PhabricatorNgramsInterface, | ||||
PhabricatorSpacesInterface { | |||||
const METADATA_IMAGE_WIDTH = 'width'; | const METADATA_IMAGE_WIDTH = 'width'; | ||||
const METADATA_IMAGE_HEIGHT = 'height'; | const METADATA_IMAGE_HEIGHT = 'height'; | ||||
const METADATA_CAN_CDN = 'canCDN'; | const METADATA_CAN_CDN = 'canCDN'; | ||||
const METADATA_BUILTIN = 'builtin'; | const METADATA_BUILTIN = 'builtin'; | ||||
const METADATA_PARTIAL = 'partial'; | const METADATA_PARTIAL = 'partial'; | ||||
const METADATA_PROFILE = 'profile'; | const METADATA_PROFILE = 'profile'; | ||||
const METADATA_STORAGE = 'storage'; | const METADATA_STORAGE = 'storage'; | ||||
Show All 15 Lines | final class PhabricatorFile extends PhabricatorFileDAO | ||||
protected $storageEngine; | protected $storageEngine; | ||||
protected $storageFormat; | protected $storageFormat; | ||||
protected $storageHandle; | protected $storageHandle; | ||||
protected $ttl; | protected $ttl; | ||||
protected $isExplicitUpload = 1; | protected $isExplicitUpload = 1; | ||||
protected $viewPolicy = PhabricatorPolicies::POLICY_USER; | protected $viewPolicy = PhabricatorPolicies::POLICY_USER; | ||||
protected $spacePHID; | |||||
protected $isPartial = 0; | protected $isPartial = 0; | ||||
protected $isDeleted = 0; | protected $isDeleted = 0; | ||||
private $objects = self::ATTACHABLE; | private $objects = self::ATTACHABLE; | ||||
private $objectPHIDs = self::ATTACHABLE; | private $objectPHIDs = self::ATTACHABLE; | ||||
private $originalFile = self::ATTACHABLE; | private $originalFile = self::ATTACHABLE; | ||||
private $transforms = self::ATTACHABLE; | private $transforms = self::ATTACHABLE; | ||||
public static function initializeNewFile() { | public static function initializeNewFile(PhabricatorUser $actor) { | ||||
$app = id(new PhabricatorApplicationQuery()) | $app = id(new PhabricatorApplicationQuery()) | ||||
->setViewer(PhabricatorUser::getOmnipotentUser()) | ->setViewer(PhabricatorUser::getOmnipotentUser()) | ||||
->withClasses(array('PhabricatorFilesApplication')) | ->withClasses(array('PhabricatorFilesApplication')) | ||||
->executeOne(); | ->executeOne(); | ||||
$view_policy = $app->getPolicy( | $view_policy = $app->getPolicy( | ||||
FilesDefaultViewCapability::CAPABILITY); | FilesDefaultViewCapability::CAPABILITY); | ||||
return id(new PhabricatorFile()) | return id(new PhabricatorFile()) | ||||
->setViewPolicy($view_policy) | ->setViewPolicy($view_policy) | ||||
->setSpacePHID($actor->getDefaultSpacePHID()) | |||||
->setIsPartial(0) | ->setIsPartial(0) | ||||
->attachOriginalFile(null) | ->attachOriginalFile(null) | ||||
->attachObjects(array()) | ->attachObjects(array()) | ||||
->attachObjectPHIDs(array()); | ->attachObjectPHIDs(array()); | ||||
} | } | ||||
protected function getConfiguration() { | protected function getConfiguration() { | ||||
return array( | return array( | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | public static function newFromPHPUpload($spec, array $params = array()) { | ||||
$file_name = nonempty( | $file_name = nonempty( | ||||
idx($params, 'name'), | idx($params, 'name'), | ||||
idx($spec, 'name')); | idx($spec, 'name')); | ||||
$params = array( | $params = array( | ||||
'name' => $file_name, | 'name' => $file_name, | ||||
) + $params; | ) + $params; | ||||
// TODO | |||||
Lint: TODO Comment: This comment has a TODO. | |||||
return self::newFromFileData($file_data, $params); | return self::newFromFileData($file_data, $params); | ||||
} | } | ||||
public static function newFromXHRUpload($data, array $params = array()) { | public static function newFromXHRUpload($data, array $params = array()) { | ||||
// TODO | |||||
Lint: TODO Comment This comment has a TODO. Lint: TODO Comment: This comment has a TODO. | |||||
return self::newFromFileData($data, $params); | return self::newFromFileData($data, $params); | ||||
} | } | ||||
public static function newFileFromContentHash($hash, array $params) { | public static function newFileFromContentHash($hash, array $params, PhabricatorUser $actor) { | ||||
Lint: Line Too Long This line is 95 characters long, but the convention is 80 characters. Lint: Line Too Long: This line is 95 characters long, but the convention is 80 characters. | |||||
if ($hash === null) { | if ($hash === null) { | ||||
return null; | return null; | ||||
} | } | ||||
// Check to see if a file with same hash already exists. | // Check to see if a file with same hash already exists. | ||||
$file = id(new PhabricatorFile())->loadOneWhere( | $file = id(new PhabricatorFile())->loadOneWhere( | ||||
'contentHash = %s LIMIT 1', | 'contentHash = %s LIMIT 1', | ||||
$hash); | $hash); | ||||
if (!$file) { | if (!$file) { | ||||
return null; | return null; | ||||
} | } | ||||
$copy_of_storage_engine = $file->getStorageEngine(); | $copy_of_storage_engine = $file->getStorageEngine(); | ||||
$copy_of_storage_handle = $file->getStorageHandle(); | $copy_of_storage_handle = $file->getStorageHandle(); | ||||
$copy_of_storage_format = $file->getStorageFormat(); | $copy_of_storage_format = $file->getStorageFormat(); | ||||
$copy_of_storage_properties = $file->getStorageProperties(); | $copy_of_storage_properties = $file->getStorageProperties(); | ||||
$copy_of_byte_size = $file->getByteSize(); | $copy_of_byte_size = $file->getByteSize(); | ||||
$copy_of_mime_type = $file->getMimeType(); | $copy_of_mime_type = $file->getMimeType(); | ||||
$new_file = self::initializeNewFile(); | $new_file = self::initializeNewFile($actor); | ||||
$new_file->setByteSize($copy_of_byte_size); | $new_file->setByteSize($copy_of_byte_size); | ||||
$new_file->setContentHash($hash); | $new_file->setContentHash($hash); | ||||
$new_file->setStorageEngine($copy_of_storage_engine); | $new_file->setStorageEngine($copy_of_storage_engine); | ||||
$new_file->setStorageHandle($copy_of_storage_handle); | $new_file->setStorageHandle($copy_of_storage_handle); | ||||
$new_file->setStorageFormat($copy_of_storage_format); | $new_file->setStorageFormat($copy_of_storage_format); | ||||
$new_file->setStorageProperties($copy_of_storage_properties); | $new_file->setStorageProperties($copy_of_storage_properties); | ||||
$new_file->setMimeType($copy_of_mime_type); | $new_file->setMimeType($copy_of_mime_type); | ||||
$new_file->copyDimensions($file); | $new_file->copyDimensions($file); | ||||
$new_file->readPropertiesFromParameters($params); | $new_file->readPropertiesFromParameters($params); | ||||
$new_file->saveAndIndex(); | $new_file->saveAndIndex(); | ||||
return $new_file; | return $new_file; | ||||
} | } | ||||
public static function newChunkedFile( | public static function newChunkedFile( | ||||
PhabricatorFileStorageEngine $engine, | PhabricatorFileStorageEngine $engine, | ||||
$length, | $length, | ||||
array $params) { | array $params, | ||||
PhabricatorUser $actor) { | |||||
$file = self::initializeNewFile(); | $file = self::initializeNewFile($actor); | ||||
$file->setByteSize($length); | $file->setByteSize($length); | ||||
// NOTE: Once we receive the first chunk, we'll detect its MIME type and | // NOTE: Once we receive the first chunk, we'll detect its MIME type and | ||||
// update the parent file if a MIME type hasn't been provided. This matters | // update the parent file if a MIME type hasn't been provided. This matters | ||||
// for large media files like video. | // for large media files like video. | ||||
$mime_type = idx($params, 'mime-type'); | $mime_type = idx($params, 'mime-type'); | ||||
if (!strlen($mime_type)) { | if (!strlen($mime_type)) { | ||||
Show All 26 Lines | public static function newChunkedFile( | ||||
$file->setIsPartial(1); | $file->setIsPartial(1); | ||||
$file->readPropertiesFromParameters($params); | $file->readPropertiesFromParameters($params); | ||||
return $file; | return $file; | ||||
} | } | ||||
private static function buildFromFileData($data, array $params = array()) { | private static function buildFromFileData( | ||||
Lint: Default Parameters Arguments with default values must be at the end of the argument list. Lint: Default Parameters: Arguments with default values must be at the end of the argument list. | |||||
$data, | |||||
array $params = array(), | |||||
PhabricatorUser $actor) { | |||||
if (isset($params['storageEngines'])) { | if (isset($params['storageEngines'])) { | ||||
$engines = $params['storageEngines']; | $engines = $params['storageEngines']; | ||||
} else { | } else { | ||||
$size = strlen($data); | $size = strlen($data); | ||||
$engines = PhabricatorFileStorageEngine::loadStorageEngines($size); | $engines = PhabricatorFileStorageEngine::loadStorageEngines($size); | ||||
if (!$engines) { | if (!$engines) { | ||||
throw new Exception( | throw new Exception( | ||||
pht( | pht( | ||||
'No configured storage engine can store this file. See '. | 'No configured storage engine can store this file. See '. | ||||
'"Configuring File Storage" in the documentation for '. | '"Configuring File Storage" in the documentation for '. | ||||
'information on configuring storage engines.')); | 'information on configuring storage engines.')); | ||||
} | } | ||||
} | } | ||||
assert_instances_of($engines, 'PhabricatorFileStorageEngine'); | assert_instances_of($engines, 'PhabricatorFileStorageEngine'); | ||||
if (!$engines) { | if (!$engines) { | ||||
throw new Exception(pht('No valid storage engines are available!')); | throw new Exception(pht('No valid storage engines are available!')); | ||||
} | } | ||||
$file = self::initializeNewFile(); | $file = self::initializeNewFile($actor); | ||||
$aes_type = PhabricatorFileAES256StorageFormat::FORMATKEY; | $aes_type = PhabricatorFileAES256StorageFormat::FORMATKEY; | ||||
$has_aes = PhabricatorKeyring::getDefaultKeyName($aes_type); | $has_aes = PhabricatorKeyring::getDefaultKeyName($aes_type); | ||||
if ($has_aes !== null) { | if ($has_aes !== null) { | ||||
$default_key = PhabricatorFileAES256StorageFormat::FORMATKEY; | $default_key = PhabricatorFileAES256StorageFormat::FORMATKEY; | ||||
} else { | } else { | ||||
$default_key = PhabricatorFileRawStorageFormat::FORMATKEY; | $default_key = PhabricatorFileRawStorageFormat::FORMATKEY; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | try { | ||||
// Do nothing. | // Do nothing. | ||||
} | } | ||||
$file->saveAndIndex(); | $file->saveAndIndex(); | ||||
return $file; | return $file; | ||||
} | } | ||||
public static function newFromFileData($data, array $params = array()) { | public static function newFromFileData( | ||||
Lint: Default Parameters Arguments with default values must be at the end of the argument list. Lint: Default Parameters: Arguments with default values must be at the end of the argument list. | |||||
$data, | |||||
array $params = array(), | |||||
PhabricatorUser $actor) { | |||||
$hash = self::hashFileContent($data); | $hash = self::hashFileContent($data); | ||||
if ($hash !== null) { | if ($hash !== null) { | ||||
$file = self::newFileFromContentHash($hash, $params); | $file = self::newFileFromContentHash($hash, $params, $actor); | ||||
if ($file) { | if ($file) { | ||||
return $file; | return $file; | ||||
} | } | ||||
} | } | ||||
return self::buildFromFileData($data, $params); | return self::buildFromFileData($data, $params); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | while (true) { | ||||
$default_name = id(new PhutilUTF8StringTruncator()) | $default_name = id(new PhutilUTF8StringTruncator()) | ||||
->setMaximumBytes(64) | ->setMaximumBytes(64) | ||||
->truncateString($default_name); | ->truncateString($default_name); | ||||
$params = $params + array( | $params = $params + array( | ||||
'name' => $default_name, | 'name' => $default_name, | ||||
); | ); | ||||
// TODO | |||||
Lint: TODO Comment This comment has a TODO. Lint: TODO Comment: This comment has a TODO. | |||||
return self::newFromFileData($body, $params); | return self::newFromFileData($body, $params); | ||||
} | } | ||||
} catch (Exception $ex) { | } catch (Exception $ex) { | ||||
if ($redirects) { | if ($redirects) { | ||||
throw new PhutilProxyException( | throw new PhutilProxyException( | ||||
pht( | pht( | ||||
'Failed to fetch remote URI "%s" after following %s redirect(s) '. | 'Failed to fetch remote URI "%s" after following %s redirect(s) '. | ||||
'(%s): %s', | '(%s): %s', | ||||
▲ Show 20 Lines • Show All 501 Lines • ▼ Show 20 Lines | foreach ($builtins as $key => $builtin) { | ||||
$params = array( | $params = array( | ||||
'name' => $builtin->getBuiltinDisplayName(), | 'name' => $builtin->getBuiltinDisplayName(), | ||||
'canCDN' => true, | 'canCDN' => true, | ||||
'builtin' => $key, | 'builtin' => $key, | ||||
); | ); | ||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); | ||||
try { | try { | ||||
// TODO | |||||
Lint: TODO Comment This comment has a TODO. Lint: TODO Comment: This comment has a TODO. | |||||
$file = self::newFromFileData($data, $params); | $file = self::newFromFileData($data, $params); | ||||
} catch (AphrontDuplicateKeyQueryException $ex) { | } catch (AphrontDuplicateKeyQueryException $ex) { | ||||
$file = id(new PhabricatorFileQuery()) | $file = id(new PhabricatorFileQuery()) | ||||
->setViewer(PhabricatorUser::getOmnipotentUser()) | ->setViewer(PhabricatorUser::getOmnipotentUser()) | ||||
->withBuiltinKeys(array($key)) | ->withBuiltinKeys(array($key)) | ||||
->executeOne(); | ->executeOne(); | ||||
if (!$file) { | if (!$file) { | ||||
throw new Exception( | throw new Exception( | ||||
▲ Show 20 Lines • Show All 420 Lines • ▼ Show 20 Lines | switch ($capability) { | ||||
'file.'); | 'file.'); | ||||
break; | break; | ||||
} | } | ||||
return $out; | return $out; | ||||
} | } | ||||
/* -( PhabricatorSpacesInterface )----------------------------------------- */ | |||||
public function getSpacePHID() { | |||||
return $this->spacePHID; | |||||
} | |||||
/* -( PhabricatorSubscribableInterface Implementation )-------------------- */ | /* -( PhabricatorSubscribableInterface Implementation )-------------------- */ | ||||
public function isAutomaticallySubscribed($phid) { | public function isAutomaticallySubscribed($phid) { | ||||
return ($this->authorPHID == $phid); | return ($this->authorPHID == $phid); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 65 Lines • Show Last 20 Lines |
This comment has a TODO.