Changeset View
Changeset View
Standalone View
Standalone View
src/applications/files/storage/PhabricatorFile.php
Show All 31 Lines | final class PhabricatorFile extends PhabricatorFileDAO | ||||
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'; | ||||
const METADATA_INTEGRITY = 'integrity'; | |||||
protected $name; | protected $name; | ||||
protected $mimeType; | protected $mimeType; | ||||
protected $byteSize; | protected $byteSize; | ||||
protected $authorPHID; | protected $authorPHID; | ||||
protected $secretKey; | protected $secretKey; | ||||
protected $contentHash; | protected $contentHash; | ||||
protected $metadata = array(); | protected $metadata = array(); | ||||
▲ Show 20 Lines • Show All 271 Lines • ▼ Show 20 Lines | private static function buildFromFileData($data, array $params = array()) { | ||||
$format->setFile($file); | $format->setFile($file); | ||||
$properties = $format->newStorageProperties(); | $properties = $format->newStorageProperties(); | ||||
$file->setStorageFormat($format->getStorageFormatKey()); | $file->setStorageFormat($format->getStorageFormatKey()); | ||||
$file->setStorageProperties($properties); | $file->setStorageProperties($properties); | ||||
$data_handle = null; | $data_handle = null; | ||||
$engine_identifier = null; | $engine_identifier = null; | ||||
$integrity_hash = null; | |||||
$exceptions = array(); | $exceptions = array(); | ||||
foreach ($engines as $engine) { | foreach ($engines as $engine) { | ||||
$engine_class = get_class($engine); | $engine_class = get_class($engine); | ||||
try { | try { | ||||
list($engine_identifier, $data_handle) = $file->writeToEngine( | $result = $file->writeToEngine( | ||||
$engine, | $engine, | ||||
$data, | $data, | ||||
$params); | $params); | ||||
list($engine_identifier, $data_handle, $integrity_hash) = $result; | |||||
// We stored the file somewhere so stop trying to write it to other | // We stored the file somewhere so stop trying to write it to other | ||||
// places. | // places. | ||||
break; | break; | ||||
} catch (PhabricatorFileStorageConfigurationException $ex) { | } catch (PhabricatorFileStorageConfigurationException $ex) { | ||||
// If an engine is outright misconfigured (or misimplemented), raise | // If an engine is outright misconfigured (or misimplemented), raise | ||||
// that immediately since it probably needs attention. | // that immediately since it probably needs attention. | ||||
throw $ex; | throw $ex; | ||||
} catch (Exception $ex) { | } catch (Exception $ex) { | ||||
Show All 14 Lines | private static function buildFromFileData($data, array $params = array()) { | ||||
$file->setByteSize(strlen($data)); | $file->setByteSize(strlen($data)); | ||||
$hash = self::hashFileContent($data); | $hash = self::hashFileContent($data); | ||||
$file->setContentHash($hash); | $file->setContentHash($hash); | ||||
$file->setStorageEngine($engine_identifier); | $file->setStorageEngine($engine_identifier); | ||||
$file->setStorageHandle($data_handle); | $file->setStorageHandle($data_handle); | ||||
$file->setIntegrityHash($integrity_hash); | |||||
$file->readPropertiesFromParameters($params); | $file->readPropertiesFromParameters($params); | ||||
if (!$file->getMimeType()) { | if (!$file->getMimeType()) { | ||||
$tmp = new TempFile(); | $tmp = new TempFile(); | ||||
Filesystem::writeFile($tmp, $data); | Filesystem::writeFile($tmp, $data); | ||||
$file->setMimeType(Filesystem::getMimeType($tmp)); | $file->setMimeType(Filesystem::getMimeType($tmp)); | ||||
} | } | ||||
Show All 30 Lines | if (!$this->getID() || !$this->getStorageHandle()) { | ||||
pht("You can not migrate a file which hasn't yet been saved.")); | pht("You can not migrate a file which hasn't yet been saved.")); | ||||
} | } | ||||
$data = $this->loadFileData(); | $data = $this->loadFileData(); | ||||
$params = array( | $params = array( | ||||
'name' => $this->getName(), | 'name' => $this->getName(), | ||||
); | ); | ||||
list($new_identifier, $new_handle) = $this->writeToEngine( | list($new_identifier, $new_handle, $integrity_hash) = $this->writeToEngine( | ||||
$engine, | $engine, | ||||
$data, | $data, | ||||
$params); | $params); | ||||
$old_engine = $this->instantiateStorageEngine(); | $old_engine = $this->instantiateStorageEngine(); | ||||
$old_identifier = $this->getStorageEngine(); | $old_identifier = $this->getStorageEngine(); | ||||
$old_handle = $this->getStorageHandle(); | $old_handle = $this->getStorageHandle(); | ||||
$this->setStorageEngine($new_identifier); | $this->setStorageEngine($new_identifier); | ||||
$this->setStorageHandle($new_handle); | $this->setStorageHandle($new_handle); | ||||
$this->setIntegrityHash($integrity_hash); | |||||
$this->save(); | $this->save(); | ||||
if (!$make_copy) { | if (!$make_copy) { | ||||
$this->deleteFileDataIfUnused( | $this->deleteFileDataIfUnused( | ||||
$old_engine, | $old_engine, | ||||
$old_identifier, | $old_identifier, | ||||
$old_handle); | $old_handle); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | private function writeToEngine( | ||||
$key = $this->getStorageFormat(); | $key = $this->getStorageFormat(); | ||||
$format = id(clone PhabricatorFileStorageFormat::requireFormat($key)) | $format = id(clone PhabricatorFileStorageFormat::requireFormat($key)) | ||||
->setFile($this); | ->setFile($this); | ||||
$data_iterator = array($data); | $data_iterator = array($data); | ||||
$formatted_iterator = $format->newWriteIterator($data_iterator); | $formatted_iterator = $format->newWriteIterator($data_iterator); | ||||
$formatted_data = $this->loadDataFromIterator($formatted_iterator); | $formatted_data = $this->loadDataFromIterator($formatted_iterator); | ||||
$integrity_hash = $engine->newIntegrityHash($formatted_data, $format); | |||||
$data_handle = $engine->writeFile($formatted_data, $params); | $data_handle = $engine->writeFile($formatted_data, $params); | ||||
if (!$data_handle || strlen($data_handle) > 255) { | if (!$data_handle || strlen($data_handle) > 255) { | ||||
// This indicates an improperly implemented storage engine. | // This indicates an improperly implemented storage engine. | ||||
throw new PhabricatorFileStorageConfigurationException( | throw new PhabricatorFileStorageConfigurationException( | ||||
pht( | pht( | ||||
"Storage engine '%s' executed %s but did not return a valid ". | "Storage engine '%s' executed %s but did not return a valid ". | ||||
"handle ('%s') to the data: it must be nonempty and no longer ". | "handle ('%s') to the data: it must be nonempty and no longer ". | ||||
"than 255 characters.", | "than 255 characters.", | ||||
$engine_class, | $engine_class, | ||||
'writeFile()', | 'writeFile()', | ||||
$data_handle)); | $data_handle)); | ||||
} | } | ||||
$engine_identifier = $engine->getEngineIdentifier(); | $engine_identifier = $engine->getEngineIdentifier(); | ||||
if (!$engine_identifier || strlen($engine_identifier) > 32) { | if (!$engine_identifier || strlen($engine_identifier) > 32) { | ||||
throw new PhabricatorFileStorageConfigurationException( | throw new PhabricatorFileStorageConfigurationException( | ||||
pht( | pht( | ||||
"Storage engine '%s' returned an improper engine identifier '{%s}': ". | "Storage engine '%s' returned an improper engine identifier '{%s}': ". | ||||
"it must be nonempty and no longer than 32 characters.", | "it must be nonempty and no longer than 32 characters.", | ||||
$engine_class, | $engine_class, | ||||
$engine_identifier)); | $engine_identifier)); | ||||
} | } | ||||
return array($engine_identifier, $data_handle); | return array($engine_identifier, $data_handle, $integrity_hash); | ||||
} | } | ||||
/** | /** | ||||
* Download a remote resource over HTTP and save the response body as a file. | * Download a remote resource over HTTP and save the response body as a file. | ||||
* | * | ||||
* This method respects `security.outbound-blacklist`, and protects against | * This method respects `security.outbound-blacklist`, and protects against | ||||
* HTTP redirection (by manually following "Location" headers and verifying | * HTTP redirection (by manually following "Location" headers and verifying | ||||
▲ Show 20 Lines • Show All 685 Lines • ▼ Show 20 Lines | public function getIsProfileImage() { | ||||
return idx($this->metadata, self::METADATA_PROFILE); | return idx($this->metadata, self::METADATA_PROFILE); | ||||
} | } | ||||
public function setIsProfileImage($value) { | public function setIsProfileImage($value) { | ||||
$this->metadata[self::METADATA_PROFILE] = $value; | $this->metadata[self::METADATA_PROFILE] = $value; | ||||
return $this; | return $this; | ||||
} | } | ||||
public function setIntegrityHash($integrity_hash) { | |||||
$this->metadata[self::METADATA_INTEGRITY] = $integrity_hash; | |||||
return $this; | |||||
} | |||||
public function getIntegrityHash() { | |||||
return idx($this->metadata, self::METADATA_INTEGRITY); | |||||
} | |||||
/** | /** | ||||
* Write the policy edge between this file and some object. | * Write the policy edge between this file and some object. | ||||
* | * | ||||
* @param phid Object PHID to attach to. | * @param phid Object PHID to attach to. | ||||
* @return this | * @return this | ||||
*/ | */ | ||||
public function attachToObject($phid) { | public function attachToObject($phid) { | ||||
$edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST; | $edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST; | ||||
▲ Show 20 Lines • Show All 314 Lines • Show Last 20 Lines |