[CLEANUP] File object
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Resource / File.php
1 <?php
2 namespace TYPO3\CMS\Core\Resource;
3
4 /*
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18
19 /**
20 * File representation in the file abstraction layer.
21 *
22 */
23 class File extends AbstractFile {
24
25 /**
26 * @var bool
27 */
28 protected $metaDataLoaded = FALSE;
29
30 /**
31 * @var array
32 */
33 protected $metaDataProperties = array();
34
35 /**
36 * Set to TRUE while this file is being indexed - used to prevent some endless loops
37 *
38 * @var bool
39 */
40 protected $indexingInProgress = FALSE;
41
42 /**
43 * Contains the names of all properties that have been update since the
44 * instantiation of this object
45 *
46 * @var array
47 */
48 protected $updatedProperties = array();
49
50 /**
51 * Constructor for a file object. Should normally not be used directly, use
52 * the corresponding factory methods instead.
53 *
54 * @param array $fileData
55 * @param ResourceStorage $storage
56 * @param array $metaData
57 */
58 public function __construct(array $fileData, ResourceStorage $storage, array $metaData = array()) {
59 $this->identifier = $fileData['identifier'];
60 $this->name = $fileData['name'];
61 $this->properties = $fileData;
62 $this->storage = $storage;
63 if (!empty($metaData)) {
64 $this->metaDataLoaded = TRUE;
65 $this->metaDataProperties = $metaData;
66 }
67 }
68
69 /*******************************
70 * VARIOUS FILE PROPERTY GETTERS
71 *******************************/
72 /**
73 * Returns a property value
74 *
75 * @param string $key
76 * @return mixed Property value
77 */
78 public function getProperty($key) {
79 if (parent::hasProperty($key)) {
80 return parent::getProperty($key);
81 } else {
82 $metaData = $this->_getMetaData();
83 return isset($metaData[$key]) ? $metaData[$key] : NULL;
84 }
85 }
86
87 /**
88 * Checks if the file has a (metadata) property which
89 * can be retrieved by "getProperty"
90 *
91 * @param string $key
92 * @return bool
93 */
94 public function hasProperty($key) {
95 if (!parent::hasProperty($key)) {
96 return array_key_exists($key, $this->_getMetaData());
97 }
98 return TRUE;
99 }
100
101
102 /**
103 * Returns the properties of this object.
104 *
105 * @return array
106 */
107 public function getProperties() {
108 return array_merge(parent::getProperties(), array_diff_key($this->_getMetaData(), parent::getProperties()));
109 }
110
111 /**
112 * Returns the MetaData
113 *
114 * @return array
115 * @internal
116 */
117 public function _getMetaData() {
118 if (!$this->metaDataLoaded) {
119 $this->loadMetaData();
120 }
121 return $this->metaDataProperties;
122 }
123
124 /******************
125 * CONTENTS RELATED
126 ******************/
127 /**
128 * Get the contents of this file
129 *
130 * @return string File contents
131 */
132 public function getContents() {
133 return $this->getStorage()->getFileContents($this);
134 }
135
136 /**
137 * Gets SHA1 hash.
138 *
139 * @return string
140 */
141 public function getSha1() {
142 if (empty($this->properties['sha1'])) {
143 $this->properties['sha1'] = parent::getSha1();
144 }
145 return $this->properties['sha1'];
146 }
147
148 /**
149 * Replace the current file contents with the given string
150 *
151 * @param string $contents The contents to write to the file.
152 * @return File The file object (allows chaining).
153 */
154 public function setContents($contents) {
155 $this->getStorage()->setFileContents($this, $contents);
156 return $this;
157 }
158
159 /***********************
160 * INDEX RELATED METHODS
161 ***********************/
162 /**
163 * Returns TRUE if this file is indexed
164 *
165 * @return bool|NULL
166 */
167 public function isIndexed() {
168 return TRUE;
169 }
170
171 /**
172 * Loads MetaData from Repository
173 * @return void
174 */
175 protected function loadMetaData() {
176 if (!$this->indexingInProgress) {
177 $this->indexingInProgress = TRUE;
178 $this->metaDataProperties = $this->getMetaDataRepository()->findByFile($this);
179 $this->metaDataLoaded = TRUE;
180 $this->indexingInProgress = FALSE;
181 }
182
183 }
184
185 /**
186 * Updates the properties of this file, e.g. after re-indexing or moving it.
187 * By default, only properties that exist as a key in the $properties array
188 * are overwritten. If you want to explicitly unset a property, set the
189 * corresponding key to NULL in the array.
190 *
191 * NOTE: This method should not be called from outside the File Abstraction Layer (FAL)!
192 *
193 * @param array $properties
194 * @return void
195 * @internal
196 */
197 public function updateProperties(array $properties) {
198 // Setting identifier and name to update values; we have to do this
199 // here because we might need a new identifier when loading
200 // (and thus possibly indexing) a file.
201 if (isset($properties['identifier'])) {
202 $this->identifier = $properties['identifier'];
203 }
204 if (isset($properties['name'])) {
205 $this->name = $properties['name'];
206 }
207
208 if ($this->properties['uid'] != 0 && isset($properties['uid'])) {
209 unset($properties['uid']);
210 }
211 foreach ($properties as $key => $value) {
212 if ($this->properties[$key] !== $value) {
213 if (!in_array($key, $this->updatedProperties)) {
214 $this->updatedProperties[] = $key;
215 }
216 $this->properties[$key] = $value;
217 }
218 }
219 // If the mime_type property should be updated and it was changed also update the type.
220 if (array_key_exists('mime_type', $properties) && in_array('mime_type', $this->updatedProperties)) {
221 $this->updatedProperties[] = 'type';
222 unset($this->properties['type']);
223 $this->getType();
224 }
225 if (array_key_exists('storage', $properties) && in_array('storage', $this->updatedProperties)) {
226 $this->storage = ResourceFactory::getInstance()->getStorageObject($properties['storage']);
227 }
228 }
229
230 /**
231 * Updates MetaData properties
232 *
233 * @internal Do not use outside the FileAbstraction Layer classes
234 *
235 * @param array $properties
236 * @return void
237 */
238 public function _updateMetaDataProperties(array $properties) {
239 $this->metaDataProperties = array_merge($this->metaDataProperties, $properties);
240 }
241
242 /**
243 * Returns the names of all properties that have been updated in this record
244 *
245 * @return array
246 */
247 public function getUpdatedProperties() {
248 return $this->updatedProperties;
249 }
250
251 /****************************************
252 * STORAGE AND MANAGEMENT RELATED METHODS
253 ****************************************/
254 /**
255 * Check if a file operation (= action) is allowed for this file
256 *
257 * @param string $action, can be read, write, delete
258 * @return bool
259 */
260 public function checkActionPermission($action) {
261 return $this->getStorage()->checkFileActionPermission($action, $this);
262 }
263
264 /*****************
265 * SPECIAL METHODS
266 *****************/
267 /**
268 * Creates a MD5 hash checksum based on the combined identifier of the file,
269 * the files' mimetype and the systems' encryption key.
270 * used to generate a thumbnail, and this hash is checked if valid
271 *
272 * @return string the MD5 hash
273 */
274 public function calculateChecksum() {
275 return md5(
276 $this->getCombinedIdentifier() . '|' .
277 $this->getMimeType() . '|' .
278 $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']
279 );
280 }
281
282 /**
283 * Returns a modified version of the file.
284 *
285 * @param string $taskType The task type of this processing
286 * @param array $configuration the processing configuration, see manual for that
287 * @return ProcessedFile The processed file
288 */
289 public function process($taskType, array $configuration) {
290 return $this->getStorage()->processFile($this, $taskType, $configuration);
291 }
292
293 /**
294 * Returns an array representation of the file.
295 * (This is used by the generic listing module vidi when displaying file records.)
296 *
297 * @return array Array of main data of the file. Don't rely on all data to be present here, it's just a selection of the most relevant information.
298 */
299 public function toArray() {
300 $array = array(
301 'id' => $this->getCombinedIdentifier(),
302 'name' => $this->getName(),
303 'extension' => $this->getExtension(),
304 'type' => $this->getType(),
305 'mimetype' => $this->getMimeType(),
306 'size' => $this->getSize(),
307 'url' => $this->getPublicUrl(),
308 'indexed' => TRUE,
309 'uid' => $this->getUid(),
310 'permissions' => array(
311 'read' => $this->checkActionPermission('read'),
312 'write' => $this->checkActionPermission('write'),
313 'delete' => $this->checkActionPermission('delete')
314 ),
315 'checksum' => $this->calculateChecksum()
316 );
317 foreach ($this->properties as $key => $value) {
318 $array[$key] = $value;
319 }
320 $stat = $this->getStorage()->getFileInfo($this);
321 foreach ($stat as $key => $value) {
322 $array[$key] = $value;
323 }
324 return $array;
325 }
326
327 /**
328 * @return bool
329 */
330 public function isMissing() {
331 return (bool)$this->getProperty('missing');
332 }
333
334 /**
335 * @param bool $missing
336 */
337 public function setMissing($missing) {
338 $this->updateProperties(array('missing' => $missing ? 1 : 0));
339 }
340
341 /**
342 * Returns a publicly accessible URL for this file
343 * When file is marked as missing or deleted no url is returned
344 *
345 * WARNING: Access to the file may be restricted by further means, e.g. some
346 * web-based authentication. You have to take care of this yourself.
347 *
348 * @param bool $relativeToCurrentScript Determines whether the URL returned should be relative to the current script, in case it is relative at all (only for the LocalDriver)
349 *
350 * @return string
351 */
352 public function getPublicUrl($relativeToCurrentScript = FALSE) {
353 if ($this->isMissing() || $this->deleted) {
354 return FALSE;
355 } else {
356 return $this->getStorage()->getPublicUrl($this, $relativeToCurrentScript);
357 }
358 }
359
360 /**
361 * @return \TYPO3\CMS\Core\Resource\Index\MetaDataRepository
362 */
363 protected function getMetaDataRepository() {
364 return GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Index\MetaDataRepository::class);
365 }
366
367 /**
368 * @return \TYPO3\CMS\Core\Resource\Index\FileIndexRepository
369 */
370 protected function getFileIndexRepository() {
371 return GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Index\FileIndexRepository::class);
372 }
373
374 /**
375 * @return void
376 * @internal Only for usage in Indexer
377 */
378 public function setIndexingInProgess($indexingState) {
379 $this->indexingInProgress = (bool)$indexingState;
380 }
381
382 /**
383 * @param $key
384 * @internal Only for use in Repositories and indexer
385 * @return mixed
386 */
387 public function _getPropertyRaw($key) {
388 return parent::getProperty($key);
389 }
390
391 }