[TASK] Re-work/simplify copyright header in PHP files - Part 2
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / Updates / FileIdentifierHashUpdate.php
1 <?php
2 namespace TYPO3\CMS\Install\Updates;
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\Resource\ResourceStorage;
18 use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
19
20 /**
21 * Class FileIdentifierHashUpdate adds IdentifierHashes
22 */
23 class FileIdentifierHashUpdate extends AbstractUpdate {
24
25 /**
26 * @var string
27 */
28 protected $title = 'Add the file identifier hash to existing sys_file records and update the settings for local storages';
29
30 /**
31 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
32 */
33 protected $db;
34
35 /**
36 * @var array
37 */
38 protected $sqlQueries = array();
39
40 /**
41 * @var ResourceStorage[]
42 */
43 protected $storages;
44
45 /**
46 * @var \TYPO3\CMS\Core\Resource\StorageRepository
47 */
48 protected $storageRepository;
49
50 /**
51 * Creates this object
52 */
53 public function __construct() {
54 $this->db = $GLOBALS['TYPO3_DB'];
55 }
56
57 /**
58 * Initialize the storage repository.
59 */
60 public function init() {
61 $this->storageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
62 $this->storages = $this->storageRepository->findAll();
63 // Add default storage for core files
64 $this->storages[] = \TYPO3\CMS\Core\Resource\ResourceFactory::getInstance()->getStorageObject(0);
65 }
66
67 /**
68 * Checks if an update is needed.
69 *
70 * @param string &$description The description for the update
71 * @return boolean TRUE if an update is needed, FALSE otherwise
72 */
73 public function checkForUpdate(&$description) {
74 $description = 'Add file identifier hash to sys_file records, where it is missing. Additionally upgrade storage configurations.';
75 $unhashedFileCount = $this->db->exec_SELECTcountRows(
76 'uid',
77 'sys_file',
78 'identifier_hash = "" OR folder_hash = ""'
79 );
80
81 $unmigratedStorageCount = $this->db->exec_SELECTcountRows(
82 'uid',
83 'sys_file_storage',
84 'driver = "Local" AND configuration NOT LIKE "%caseSensitive%"'
85 );
86
87 return $unhashedFileCount > 0 || $unmigratedStorageCount > 0;
88 }
89
90 /**
91 * Performs the database update.
92 *
93 * @param array &$dbQueries Queries done in this update
94 * @param mixed &$customMessages Custom messages
95 * @return boolean TRUE on success, FALSE on error
96 */
97 public function performUpdate(array &$dbQueries, &$customMessages) {
98 $this->init();
99 foreach ($this->storages as $storage) {
100 $dbQueries = array_merge($dbQueries, $this->updateIdentifierHashesForStorage($storage));
101 }
102
103 $dbQueries = array_merge($dbQueries, $this->migrateStorages());
104
105 $this->markWizardAsDone();
106 return TRUE;
107 }
108
109 /**
110 * @return array
111 */
112 protected function migrateStorages() {
113 $dbQueries = array();
114 $unmigratedStorages = $this->db->exec_SELECTgetRows(
115 'uid, configuration',
116 'sys_file_storage',
117 'driver = "Local" AND configuration NOT LIKE "%caseSensitive%"'
118 );
119
120 /** @var $flexObj \TYPO3\CMS\Core\Configuration\FlexForm\FlexFormTools */
121 $flexObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Configuration\\FlexForm\\FlexFormTools');
122
123
124 foreach ($unmigratedStorages as $storage) {
125 $flexFormXml = $storage['configuration'];
126 $configurationArray = \TYPO3\CMS\Core\Utility\GeneralUtility::xml2array($flexFormXml);
127
128 $caseSensitive = $this->testCaseSensitivity(
129 $configurationArray['data']['sDEF']['lDEF']['pathType']['vDEF'] == 'relative' ?
130 PATH_site . $configurationArray['data']['sDEF']['lDEF']['basePath']['vDEF'] :
131 $configurationArray['data']['sDEF']['lDEF']['basePath']['vDEF']
132 );
133 $configurationArray['data']['sDEF']['lDEF']['caseSensitive'] = array('vDEF' => $caseSensitive);
134
135 $configuration = $flexObj->flexArray2Xml($configurationArray);
136 $dbQueries[] = $query = $this->db->UPDATEquery(
137 'sys_file_storage',
138 'uid=' . $storage['uid'],
139 array(
140 'configuration' => $configuration
141 )
142 );
143 $this->db->sql_query($query);
144 }
145 return $dbQueries;
146 }
147
148 /**
149 * Creates file identifier hashes for a single storage.
150 *
151 * @param ResourceStorage $storage The storage to update
152 * @return array The executed database queries
153 */
154 protected function updateIdentifierHashesForStorage(ResourceStorage $storage) {
155 $queries = array();
156
157 if (!ExtensionManagementUtility::isLoaded('dbal')) {
158 // if DBAL is not loaded, we're using MySQL and can thus use their
159 // SHA1() function
160 if ($storage->usesCaseSensitiveIdentifiers()) {
161 $updateCall = 'SHA1(identifier)';
162 } else {
163 $updateCall = 'SHA1(LOWER(identifier))';
164 }
165 $queries[] = $query = sprintf(
166 'UPDATE sys_file SET identifier_hash = %s WHERE storage=%d',
167 $updateCall,
168 $storage->getUid()
169 );
170 $this->db->sql_query($query);
171
172 // folder hashes cannot be done with one call: so do it manually
173 $files = $this->db->exec_SELECTgetRows('uid, storage, identifier', 'sys_file',
174 sprintf('storage=%d AND folder_hash=""', $storage->getUid())
175 );
176
177 foreach ($files as $file) {
178 $folderHash = $storage->hashFileIdentifier($storage->getFolderIdentifierFromFileIdentifier($file['identifier']));
179
180 $queries[] = $query = $this->db->UPDATEquery(
181 'sys_file',
182 'uid=' . $file['uid'],
183 array(
184 'folder_hash' => $folderHash
185 )
186 );
187
188 $this->db->sql_query($query);
189 }
190 } else {
191 // manually hash the identifiers when using DBAL
192 $files = $this->db->exec_SELECTgetRows('uid, storage, identifier', 'sys_file',
193 sprintf('storage=%d AND identifier_hash=""', $storage->getUid())
194 );
195
196 foreach ($files as $file) {
197 $hash = $storage->hashFileIdentifier($file['identifier']);
198 $folderHash = $storage->hashFileIdentifier($storage->getFolderIdentifierFromFileIdentifier($file['identifier']));
199
200 $queries[] = $query = $this->db->UPDATEquery(
201 'sys_file',
202 'uid=' . $file['uid'],
203 array(
204 'identifier_hash' => $hash,
205 'folder_hash' => $folderHash
206 )
207 );
208
209 $this->db->sql_query($query);
210 }
211 }
212
213 return $queries;
214 }
215
216
217 /**
218 * Test if the local filesystem is case sensitive
219 *
220 * @param $absolutePath
221 * @return boolean
222 */
223 protected function testCaseSensitivity($absolutePath) {
224 $caseSensitive = TRUE;
225 $path = rtrim($absolutePath, '/') . '/aAbB';
226 $testFileExists = file_exists($path);
227
228 // create test file
229 if (!$testFileExists) {
230 @touch($path);
231 }
232
233 // do the actual sensitivity check
234 if (file_exists(strtoupper($path)) && file_exists(strtolower($path))) {
235 $caseSensitive = FALSE;
236 }
237
238 // clean filesystem
239 if (!$testFileExists) {
240 @unlink($path);
241 }
242
243 return $caseSensitive;
244 }
245 }