[TASK] Re-work/simplify copyright header in PHP files - Part 1
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / FolderStructure / FileNode.php
1 <?php
2 namespace TYPO3\CMS\Install\FolderStructure;
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\Install\Status;
18
19 /**
20 * A file
21 */
22 class FileNode extends AbstractNode implements NodeInterface {
23
24 /**
25 * @var NULL|integer Default for files is octal 0664 == decimal 436
26 */
27 protected $targetPermission = '0664';
28
29 /**
30 * @var string|NULL Target content of file. If NULL, target content is ignored
31 */
32 protected $targetContent = NULL;
33
34 /**
35 * Implement constructor
36 *
37 * @param array $structure Structure array
38 * @param NodeInterface $parent Parent object
39 * @throws Exception\InvalidArgumentException
40 */
41 public function __construct(array $structure, NodeInterface $parent = NULL) {
42 if (is_null($parent)) {
43 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
44 'File node must have parent',
45 1366927513
46 );
47 }
48 $this->parent = $parent;
49
50 // Ensure name is a single segment, but not a path like foo/bar or an absolute path /foo
51 if (strstr($structure['name'], '/') !== FALSE) {
52 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
53 'File name must not contain forward slash',
54 1366222207
55 );
56 }
57 $this->name = $structure['name'];
58
59 if (isset($structure['targetPermission'])) {
60 $this->setTargetPermission($structure['targetPermission']);
61 }
62
63 if (isset($structure['targetContent']) && isset($structure['targetContentFile'])) {
64 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
65 'Either targetContent or targetContentFile can be set, but not both',
66 1380364361
67 );
68 }
69
70 if (isset($structure['targetContent'])) {
71 $this->targetContent = $structure['targetContent'];
72 }
73 if (isset($structure['targetContentFile'])) {
74 if (!is_readable($structure['targetContentFile'])) {
75 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
76 'targetContentFile ' . $structure['targetContentFile'] . ' does not exist or is not readable',
77 1380364362
78 );
79 }
80 $this->targetContent = file_get_contents($structure['targetContentFile']);
81 }
82 }
83
84 /**
85 * Get own status
86 * Returns warning if file not exists
87 * Returns error if file exists but content is not as expected (can / shouldn't be fixed)
88 *
89 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
90 */
91 public function getStatus() {
92 $result = array();
93 if (!$this->exists()) {
94 $status = new Status\WarningStatus();
95 $status->setTitle('File ' . $this->getRelativePathBelowSiteRoot() . ' does not exist');
96 $status->setMessage('By using "Try to fix errors" we can try to create it');
97 $result[] = $status;
98 } else {
99 $result = $this->getSelfStatus();
100 }
101 return $result;
102 }
103
104 /**
105 * Fix structure
106 *
107 * If there is nothing to fix, returns an empty array
108 *
109 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
110 */
111 public function fix() {
112 $result = $this->fixSelf();
113 return $result;
114 }
115
116 /**
117 * Fix this node: create if not there, fix permissions
118 *
119 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
120 */
121 protected function fixSelf() {
122 $result = array();
123 if (!$this->exists()) {
124 $resultCreateFile = $this->createFile();
125 $result[] = $resultCreateFile;
126 if ($resultCreateFile instanceof \TYPO3\CMS\Install\Status\OkStatus
127 && !is_null($this->targetContent)
128 ) {
129 $result[] = $this->setContent();
130 if (!$this->isPermissionCorrect()) {
131 $result[] = $this->fixPermission();
132 }
133 }
134 } elseif (!$this->isFile()) {
135 $status = new Status\ErrorStatus();
136 $status->setTitle('Path ' . $this->getRelativePathBelowSiteRoot() . ' is not a file');
137 $fileType = @filetype($this->getAbsolutePath());
138 if ($fileType) {
139 $status->setMessage(
140 'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a file,' .
141 ' but is of type ' . $fileType . '. This cannot be fixed automatically. Please investigate.'
142 );
143 } else {
144 $status->setMessage(
145 'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a file,' .
146 ' but is of unknown type, probably because an upper level directory does not exist. Please investigate.'
147 );
148 }
149 $result[] = $status;
150 } elseif (!$this->isPermissionCorrect()) {
151 $result[] = $this->fixPermission();
152 }
153 return $result;
154 }
155
156 /**
157 * Create file if not exists
158 *
159 * @throws Exception
160 * @return \TYPO3\CMS\Install\Status\StatusInterface
161 */
162 protected function createFile() {
163 if ($this->exists()) {
164 throw new Exception(
165 'File ' . $this->getRelativePathBelowSiteRoot() . ' already exists',
166 1367048077
167 );
168 }
169 $result = @touch($this->getAbsolutePath());
170 if ($result === TRUE) {
171 $status = new Status\OkStatus();
172 $status->setTitle('File ' . $this->getRelativePathBelowSiteRoot() . ' successfully created.');
173 } else {
174 $status = new Status\ErrorStatus();
175 $status->setTitle('File ' . $this->getRelativePathBelowSiteRoot() . ' not created!');
176 $status->setMessage(
177 'The target file could not be created. There is probably a' .
178 ' group or owner permission problem on the parent directory.'
179 );
180 }
181 return $status;
182 }
183
184 /**
185 * Get status of file
186 *
187 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
188 */
189 protected function getSelfStatus() {
190 $result = array();
191 if (!$this->isFile()) {
192 $status = new Status\ErrorStatus();
193 $status->setTitle($this->getRelativePathBelowSiteRoot() . ' is not a file');
194 $status->setMessage(
195 'Path ' . $this->getAbsolutePath() . ' should be a file,' .
196 ' but is of type ' . filetype($this->getAbsolutePath())
197 );
198 $result[] = $status;
199 } elseif (!$this->isWritable()) {
200 $status = new Status\NoticeStatus();
201 $status->setTitle('File ' . $this->getRelativePathBelowSiteRoot() . ' is not writable');
202 $status->setMessage(
203 'File ' . $this->getRelativePathBelowSiteRoot() . ' exists, but is not writeable.'
204 );
205 $result[] = $status;
206 } elseif (!$this->isPermissionCorrect()) {
207 $status = new Status\NoticeStatus();
208 $status->setTitle('File ' . $this->getRelativePathBelowSiteRoot() . ' permissions mismatch');
209 $status->setMessage(
210 'Default configured permissions are ' . $this->getTargetPermission() .
211 ' but file permissions are ' . $this->getCurrentPermission()
212 );
213 $result[] = $status;
214 }
215 if ($this->isFile() && !$this->isContentCorrect()) {
216 $status = new Status\NoticeStatus();
217 $status->setTitle('File ' . $this->getRelativePathBelowSiteRoot() . ' content differs');
218 $status->setMessage(
219 'File content is not identical to default content. This file may have been changed manually.' .
220 ' The Install Tool will not overwrite the current version!'
221 );
222 $result[] = $status;
223 } else {
224 $status = new Status\OkStatus();
225 $status->setTitle('File ' . $this->getRelativePathBelowSiteRoot());
226 $status->setMessage(
227 'Is a file with the default content and configured permissions of ' . $this->getTargetPermission()
228 );
229 $result[] = $status;
230 }
231 return $result;
232 }
233
234 /**
235 * Compare current file content with target file content
236 *
237 * @throws Exception If file does not exist
238 * @return boolean TRUE if current and target file content are identical
239 */
240 protected function isContentCorrect() {
241 $absolutePath = $this->getAbsolutePath();
242 if (is_link($absolutePath) || !is_file($absolutePath)) {
243 throw new Exception(
244 'File ' . $absolutePath . ' must exist',
245 1367056363
246 );
247 }
248 $result = FALSE;
249 if (is_null($this->targetContent)) {
250 $result = TRUE;
251 } else {
252 $targetContentHash = md5($this->targetContent);
253 $currentContentHash = md5(file_get_contents($absolutePath));
254 if ($targetContentHash === $currentContentHash) {
255 $result = TRUE;
256 }
257 }
258 return $result;
259 }
260
261 /**
262 * Sets content of file to target content
263 *
264 * @throws Exception If file does not exist
265 * @return \TYPO3\CMS\Install\Status\StatusInterface
266 */
267 protected function setContent() {
268 $absolutePath = $this->getAbsolutePath();
269 if (is_link($absolutePath) || !is_file($absolutePath)) {
270 throw new Exception(
271 'File ' . $absolutePath . ' must exist',
272 1367060201
273 );
274 }
275 if (is_null($this->targetContent)) {
276 throw new Exception(
277 'Target content not defined for ' . $absolutePath,
278 1367060202
279 );
280 }
281 $result = @file_put_contents($absolutePath, $this->targetContent);
282 if ($result !== FALSE) {
283 $status = new Status\OkStatus();
284 $status->setTitle('Set content to ' . $this->getRelativePathBelowSiteRoot());
285 } else {
286 $status = new Status\ErrorStatus();
287 $status->setTitle('Setting content to ' . $this->getRelativePathBelowSiteRoot() . ' failed');
288 $status->setMessage('Setting content of the file failed for unknown reasons.');
289 }
290 return $status;
291 }
292
293 /**
294 * Checks if not is a file
295 *
296 * @return boolean
297 */
298 protected function isFile() {
299 $path = $this->getAbsolutePath();
300 return (!is_link($path) && is_file($path));
301 }
302 }