[TASK] Re-work/simplify copyright header in PHP files - Part 1
[Packages/TYPO3.CMS.git] / typo3 / sysext / install / Classes / FolderStructure / DirectoryNode.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 directory
21 */
22 class DirectoryNode extends AbstractNode implements NodeInterface {
23
24 /**
25 * @var NULL|integer Default for directories is octal 02775 == decimal 1533
26 */
27 protected $targetPermission = '2775';
28
29 /**
30 * Implement constructor
31 *
32 * @param array $structure Structure array
33 * @param NodeInterface $parent Parent object
34 * @throws Exception\InvalidArgumentException
35 */
36 public function __construct(array $structure, NodeInterface $parent = NULL) {
37 if (is_null($parent)) {
38 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
39 'Node must have parent',
40 1366222203
41 );
42 }
43 $this->parent = $parent;
44
45 // Ensure name is a single segment, but not a path like foo/bar or an absolute path /foo
46 if (strstr($structure['name'], '/') !== FALSE) {
47 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
48 'Directory name must not contain forward slash',
49 1366226639
50 );
51 }
52 $this->name = $structure['name'];
53
54 if (isset($structure['targetPermission'])) {
55 $this->setTargetPermission($structure['targetPermission']);
56 }
57
58 if (array_key_exists('children', $structure)) {
59 $this->createChildren($structure['children']);
60 }
61 }
62
63 /**
64 * Get own status and status of child objects
65 *
66 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
67 */
68 public function getStatus() {
69 $result = array();
70 if (!$this->exists()) {
71 $status = new Status\WarningStatus();
72 $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' does not exist');
73 $status->setMessage('The Install Tool can try to create it');
74 $result[] = $status;
75 } else {
76 $result = $this->getSelfStatus();
77 }
78 $result = array_merge($result, $this->getChildrenStatus());
79 return $result;
80 }
81
82 /**
83 * Create a test file and delete again if directory exists
84 *
85 * @return boolean TRUE if test file creation was successful
86 */
87 public function isWritable() {
88 $result = TRUE;
89 if (!$this->exists()) {
90 $result = FALSE;
91 } elseif (!$this->canFileBeCreated()) {
92 $result = FALSE;
93 }
94 return $result;
95 }
96
97 /**
98 * Fix structure
99 *
100 * If there is nothing to fix, returns an empty array
101 *
102 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
103 */
104 public function fix() {
105 $result = $this->fixSelf();
106 foreach ($this->children as $child) {
107 /** @var $child NodeInterface */
108 $result = array_merge($result, $child->fix());
109 }
110 return $result;
111 }
112
113 /**
114 * Fix this directory:
115 *
116 * - create with correct permissions if it was not existing
117 * - if there is no "write" permissions, try to fix it
118 * - leave it alone otherwise
119 *
120 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
121 */
122 protected function fixSelf() {
123 $result = array();
124 if (!$this->exists()) {
125 $resultCreateDirectory = $this->createDirectory();
126 $result[] = $resultCreateDirectory;
127 if ($resultCreateDirectory instanceof \TYPO3\CMS\Install\Status\OkStatus &&
128 !$this->isPermissionCorrect()
129 ) {
130 $result[] = $this->fixPermission();
131 }
132 } elseif (!$this->isWritable()) {
133 // If directory is not writeable, we might have permissions to fix that
134 // Try it:
135 $result[] = $this->fixPermission();
136 } elseif (!$this->isDirectory()) {
137 $status = new Status\ErrorStatus();
138 $status->setTitle('Path ' . $this->getRelativePathBelowSiteRoot() . ' is not a directory');
139 $fileType = @filetype($this->getAbsolutePath());
140 if ($fileType) {
141 $status->setMessage(
142 'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a directory,' .
143 ' but is of type ' . $fileType . '. This cannot be fixed automatically. Please investigate.'
144 );
145 } else {
146 $status->setMessage(
147 'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a directory,' .
148 ' but is of unknown type, probably because an upper level directory does not exist. Please investigate.'
149 );
150 }
151 $result[] = $status;
152 }
153 return $result;
154 }
155
156 /**
157 * Create directory if not exists
158 *
159 * @throws Exception
160 * @return \TYPO3\CMS\Install\Status\StatusInterface
161 */
162 protected function createDirectory() {
163 if ($this->exists()) {
164 throw new Exception(
165 'Directory ' . $this->getAbsolutePath() . ' already exists',
166 1366740091
167 );
168 }
169 $result = @mkdir($this->getAbsolutePath());
170 if ($result === TRUE) {
171 $status = new Status\OkStatus();
172 $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' successfully created.');
173 } else {
174 $status = new Status\ErrorStatus();
175 $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' not created!');
176 $status->setMessage(
177 'The target directory 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 directory - used in root and directory node
186 *
187 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
188 */
189 protected function getSelfStatus() {
190 $result = array();
191 if (!$this->isDirectory()) {
192 $status = new Status\ErrorStatus();
193 $status->setTitle($this->getRelativePathBelowSiteRoot() . ' is not a directory');
194 $status->setMessage(
195 'Directory ' . $this->getRelativePathBelowSiteRoot() . ' should be a directory,' .
196 ' but is of type ' . filetype($this->getAbsolutePath())
197 );
198 $result[] = $status;
199 } elseif (!$this->isWritable()) {
200 $status = new Status\ErrorStatus();
201 $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' is not writable');
202 $status->setMessage(
203 'Path ' . $this->getAbsolutePath() . ' exists, but no file underneath it' .
204 ' can be created.'
205 );
206 $result[] = $status;
207 } elseif (!$this->isPermissionCorrect()) {
208 $status = new Status\NoticeStatus();
209 $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' permissions mismatch');
210 $status->setMessage(
211 'Default configured permissions are ' . $this->getTargetPermission() .
212 ' but current permissions are ' . $this->getCurrentPermission()
213 );
214 $result[] = $status;
215 } else {
216 $status = new Status\OkStatus();
217 $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot());
218 $status->setMessage(
219 'Is a directory with the configured permissions of ' . $this->getTargetPermission()
220 );
221 $result[] = $status;
222 }
223 return $result;
224 }
225
226 /**
227 * Get status of children
228 *
229 * @return array<\TYPO3\CMS\Install\Status\StatusInterface>
230 */
231 protected function getChildrenStatus() {
232 $result = array();
233 foreach ($this->children as $child) {
234 /** @var $child NodeInterface */
235 $result = array_merge($result, $child->getStatus());
236 }
237 return $result;
238 }
239
240 /**
241 * Create a test file and delete again - helper for isWritable
242 *
243 * @return boolean TRUE if test file creation was successful
244 */
245 protected function canFileBeCreated() {
246 $testFileName = uniqid('installToolTest_');
247 $result = @touch($this->getAbsolutePath() . '/' . $testFileName);
248 if ($result === TRUE) {
249 unlink($this->getAbsolutePath() . '/' . $testFileName);
250 }
251 return $result;
252 }
253
254 /**
255 * Checks if not is a directory
256 *
257 * @return boolean True if node is a directory
258 */
259 protected function isDirectory() {
260 $path = $this->getAbsolutePath();
261 return (!@is_link($path) && @is_dir($path));
262 }
263
264 /**
265 * Create children nodes - done in directory and root node
266 *
267 * @param array $structure Array of childs
268 * @throws Exception\InvalidArgumentException
269 */
270 protected function createChildren(array $structure) {
271 foreach ($structure as $child) {
272 if (!array_key_exists('type', $child)) {
273 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
274 'Child must have type',
275 1366222204
276 );
277 }
278 if (!array_key_exists('name', $child)) {
279 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
280 'Child must have name',
281 1366222205
282 );
283 }
284 $name = $child['name'];
285 foreach ($this->children as $existingChild) {
286 /** @var $existingChild NodeInterface */
287 if ($existingChild->getName() === $name) {
288 throw new \TYPO3\CMS\Install\FolderStructure\Exception\InvalidArgumentException(
289 'Child name must be unique',
290 1366222206
291 );
292 }
293 }
294 $this->children[] = new $child['type']($child, $this);
295 }
296 }
297 }