Source of file DBFile.php
Size: 15,731 Bytes - Last Modified: 2021-12-23T10:27:40+00:00
/var/www/docs.ssmods.com/process/src/src/Storage/DBFile.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 | <?php namespace SilverStripe\Assets\Storage; use SilverStripe\Assets\File; use SilverStripe\Assets\ImageManipulation; use SilverStripe\Assets\Thumbnail; use SilverStripe\Control\Director; use SilverStripe\Core\Injector\Injector; use SilverStripe\ORM\FieldType\DBComposite; use SilverStripe\ORM\ValidationException; use SilverStripe\ORM\ValidationResult; use SilverStripe\Security\Permission; use SilverStripe\View\ViewableData; /** * Represents a file reference stored in a database * * @property string $Hash SHA of the file * @property string $Filename Name of the file, including directory * @property string $Variant Variant of the file */ class DBFile extends DBComposite implements AssetContainer, Thumbnail { use ImageManipulation; /** * List of allowed file categories. * * {@see File::$app_categories} * * @var array */ protected $allowedCategories = []; /** * List of image mime types supported by the image manipulations API * * {@see File::app_categories} for matching extensions. * * @config * @var array */ private static $supported_images = [ 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/gif', 'image/png', 'image/x-png', 'image/tiff', 'image/tif', 'image/x-tiff', 'image/x-tif', 'image/bmp', 'image/ms-bmp', 'image/x-bitmap', 'image/x-bmp', 'image/x-ms-bmp', 'image/x-win-bitmap', 'image/x-windows-bmp', 'image/x-xbitmap', 'image/x-ico', 'image/x-icon', 'image/vnd.microsoft.icon', 'image/vnd.adobe.photoshop', ]; /** * Create a new image manipulation * * @param string $name * @param array|string $allowed List of allowed file categories (not extensions), as per File::$app_categories */ public function __construct($name = null, $allowed = []) { parent::__construct($name); $this->setAllowedCategories($allowed); } /** * Determine if a valid non-empty image exists behind this asset, which is a format * compatible with image manipulations * * @return boolean */ public function getIsImage() { // Check file type $mime = $this->getMimeType(); return $mime && in_array($mime, $this->config()->supported_images); } /** * @return AssetStore */ protected function getStore() { return Injector::inst()->get(AssetStore::class); } private static $composite_db = [ "Hash" => "Varchar(255)", // SHA of the base content "Filename" => "Varchar(255)", // Path identifier of the base content "Variant" => "Varchar(255)", // Identifier of the variant to the base, if given ]; private static $casting = [ 'URL' => 'Varchar', 'AbsoluteURL' => 'Varchar', 'Basename' => 'Varchar', 'Title' => 'Varchar', 'MimeType' => 'Varchar', 'String' => 'Text', 'Tag' => 'HTMLFragment', 'getTag' => 'HTMLFragment', 'Size' => 'Varchar', 'AttributesHTML' => 'HTMLFragment', 'getAttributesHTML' => 'HTMLFragment', ]; public function scaffoldFormField($title = null, $params = null) { return null; } /** * Return a html5 tag of the appropriate for this file (normally img or a) * * @return string */ public function XML() { return $this->getTag() ?: ''; } /** * Return a html5 tag of the appropriate for this file (normally img or a) * * @return string */ public function getTag() { $template = $this->getFrontendTemplate(); if (empty($template)) { return ''; } return (string)$this->renderWith($template); } /** * Determine the template to render as on the frontend * * @return string Name of template */ public function getFrontendTemplate() { // Check that path is available $url = $this->getURL(); if (empty($url)) { return null; } // Image template for supported images if ($this->getIsImage()) { return 'DBFile_image'; } // Default download return 'DBFile_download'; } /** * Get trailing part of filename * * @return string */ public function getBasename() { if (!$this->exists()) { return null; } return basename($this->getSourceURL()); } /** * Get file extension * * @return string */ public function getExtension() { if (!$this->exists()) { return null; } return pathinfo($this->Filename, PATHINFO_EXTENSION); } /** * Alt title for this * * @return string */ public function getTitle() { // If customised, use the customised title if ($this->failover && ($title = $this->failover->Title)) { return $title; } // fallback to using base name return $this->getBasename(); } public function setFromLocalFile($path, $filename = null, $hash = null, $variant = null, $config = []) { $this->assertFilenameValid($filename ?: $path); $result = $this ->getStore() ->setFromLocalFile($path, $filename, $hash, $variant, $config); // Update from result if ($result) { $this->setValue($result); } return $result; } public function setFromStream($stream, $filename, $hash = null, $variant = null, $config = []) { $this->assertFilenameValid($filename); $result = $this ->getStore() ->setFromStream($stream, $filename, $hash, $variant, $config); // Update from result if ($result) { $this->setValue($result); } return $result; } public function setFromString($data, $filename, $hash = null, $variant = null, $config = []) { $this->assertFilenameValid($filename); $result = $this ->getStore() ->setFromString($data, $filename, $hash, $variant, $config); // Update from result if ($result) { $this->setValue($result); } return $result; } public function getStream() { if (!$this->exists()) { return null; } return $this ->getStore() ->getAsStream($this->Filename, $this->Hash, $this->Variant); } public function getString() { if (!$this->exists()) { return null; } return $this ->getStore() ->getAsString($this->Filename, $this->Hash, $this->Variant); } public function getURL($grant = true) { if (!$this->exists()) { return null; } $url = $this->getSourceURL($grant); $this->updateURL($url); $this->extend('updateURL', $url); return $url; } /** * Return URL for this image. Alias for getURL() * * @return string */ public function Link() { return $this->getURL(); } /** * Return absolute URL for this image. Alias for getAbsoluteURL() * * @return string */ public function AbsoluteLink() { return $this->getAbsoluteURL(); } /** * Get URL, but without resampling. * Note that this will return the url even if the file does not exist. * * @param bool $grant Ensures that the url for any protected assets is granted for the current user. * @return string */ public function getSourceURL($grant = true) { return $this ->getStore() ->getAsURL($this->Filename, $this->Hash, $this->Variant, $grant); } /** * Get the absolute URL to this resource * * @return string */ public function getAbsoluteURL() { if (!$this->exists()) { return null; } return Director::absoluteURL($this->getURL()); } public function getMetaData() { if (!$this->exists()) { return null; } return $this ->getStore() ->getMetadata($this->Filename, $this->Hash, $this->Variant); } public function getMimeType() { if (!$this->exists()) { return null; } return $this ->getStore() ->getMimeType($this->Filename, $this->Hash, $this->Variant); } public function getValue() { if (!$this->exists()) { return null; } return [ 'Filename' => $this->Filename, 'Hash' => $this->Hash, 'Variant' => $this->Variant ]; } public function getVisibility() { if (empty($this->Filename)) { return null; } return $this ->getStore() ->getVisibility($this->Filename, $this->Hash); } public function exists() { if (empty($this->Filename)) { return false; } return $this ->getStore() ->exists($this->Filename, $this->Hash, $this->Variant); } public function getFilename() { return $this->getField('Filename'); } public function getHash() { return $this->getField('Hash'); } public function getVariant() { return $this->getField('Variant'); } /** * Return file size in bytes. * * @return int */ public function getAbsoluteSize() { $metadata = $this->getMetaData(); if (isset($metadata['size'])) { return $metadata['size']; } return 0; } /** * Customise this object with an "original" record for getting other customised fields * * @param AssetContainer $original * @return $this */ public function setOriginal($original) { if ($original instanceof ViewableData) { $this->setFailover($original); } return $this; } /** * Get list of allowed file categories * * @return array */ public function getAllowedCategories() { return $this->allowedCategories; } /** * Assign allowed categories * * @param array|string $categories * @return $this */ public function setAllowedCategories($categories) { if (is_string($categories)) { $categories = preg_split('/\s*,\s*/', $categories); } $this->allowedCategories = (array)$categories; return $this; } /** * Gets the list of extensions (if limited) for this field. Empty list * means there is no restriction on allowed types. * * @return array */ protected function getAllowedExtensions() { $categories = $this->getAllowedCategories(); return File::get_category_extensions($categories); } /** * Validate that this DBFile accepts this filename as valid * * @param string $filename * @throws ValidationException * @return bool */ protected function isValidFilename($filename) { $extension = strtolower(File::get_file_extension($filename)); // Validate true if within the list of allowed extensions $allowed = $this->getAllowedExtensions(); if ($allowed) { return in_array($extension, $allowed); } // If no extensions are configured, fallback to global list $globalList = File::getAllowedExtensions(); if (in_array($extension, $globalList)) { return true; } // Only admins can bypass global rules return !File::config()->apply_restrictions_to_admin && Permission::check('ADMIN'); } /** * Check filename, and raise a ValidationException if invalid * * @param string $filename * @throws ValidationException */ protected function assertFilenameValid($filename) { $result = new ValidationResult(); $this->validate($result, $filename); if (!$result->isValid()) { throw new ValidationException($result); } } /** * Hook to validate this record against a validation result * * @param ValidationResult $result * @param string $filename Optional filename to validate. If omitted, the current value is validated. * @return bool Valid flag */ public function validate(ValidationResult $result, $filename = null) { if (empty($filename)) { $filename = $this->getFilename(); } if (empty($filename) || $this->isValidFilename($filename)) { return true; } $message = _t( 'SilverStripe\\Assets\\File.INVALIDEXTENSION_SHORT_EXT', 'Extension \'{extension}\' is not allowed', [ 'extension' => strtolower(File::get_file_extension($filename)) ] ); $result->addError($message); return false; } public function setField($field, $value, $markChanged = true) { // Catch filename validation on direct assignment if ($field === 'Filename' && $value) { $this->assertFilenameValid($value); } return parent::setField($field, $value, $markChanged); } /** * Returns the size of the file type in an appropriate format. * * @return string|false String value, or false if doesn't exist */ public function getSize() { $size = $this->getAbsoluteSize(); if ($size) { return File::format_size($size); } return false; } public function deleteFile() { if (!$this->Filename) { return false; } return $this ->getStore() ->delete($this->Filename, $this->Hash); } public function publishFile() { if ($this->Filename) { $this ->getStore() ->publish($this->Filename, $this->Hash); } } public function protectFile() { if ($this->Filename) { $this ->getStore() ->protect($this->Filename, $this->Hash); } } public function grantFile() { if ($this->Filename) { $this ->getStore() ->grant($this->Filename, $this->Hash); } } public function revokeFile() { if ($this->Filename) { $this ->getStore() ->revoke($this->Filename, $this->Hash); } } public function canViewFile() { return $this->Filename && $this ->getStore() ->canView($this->Filename, $this->Hash); } public function renameFile($newName) { if (!$this->Filename) { return null; } $newName = $this ->getStore() ->rename($this->Filename, $this->Hash, $newName); if ($newName) { $this->Filename = $newName; } return $newName; } public function copyFile($newName) { if (!$this->Filename) { return null; } return $this ->getStore() ->copy($this->Filename, $this->Hash, $newName); } } |