TYPO3CMS  8
 All Classes Namespaces Files Functions Variables Pages
DirectoryNode.php
Go to the documentation of this file.
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 
18 use TYPO3\CMS\Install\Status;
19 
23 class DirectoryNode extends AbstractNode implements NodeInterface
24 {
28  protected $targetPermission = '2775';
29 
37  public function __construct(array $structure, NodeInterface $parent = null)
38  {
39  if (is_null($parent)) {
40  throw new Exception\InvalidArgumentException(
41  'Node must have parent',
42  1366222203
43  );
44  }
45  $this->parent = $parent;
46 
47  // Ensure name is a single segment, but not a path like foo/bar or an absolute path /foo
48  if (strstr($structure['name'], '/') !== false) {
49  throw new Exception\InvalidArgumentException(
50  'Directory name must not contain forward slash',
51  1366226639
52  );
53  }
54  $this->name = $structure['name'];
55 
56  if (isset($structure['targetPermission'])) {
57  $this->setTargetPermission($structure['targetPermission']);
58  }
59 
60  if (array_key_exists('children', $structure)) {
61  $this->createChildren($structure['children']);
62  }
63  }
64 
70  public function getStatus()
71  {
72  $result = [];
73  if (!$this->exists()) {
74  $status = new Status\WarningStatus();
75  $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' does not exist');
76  $status->setMessage('The Install Tool can try to create it');
77  $result[] = $status;
78  } else {
79  $result = $this->getSelfStatus();
80  }
81  $result = array_merge($result, $this->getChildrenStatus());
82  return $result;
83  }
84 
90  public function isWritable()
91  {
92  $result = true;
93  if (!$this->exists()) {
94  $result = false;
95  } elseif (!$this->canFileBeCreated()) {
96  $result = false;
97  }
98  return $result;
99  }
100 
108  public function fix()
109  {
110  $result = $this->fixSelf();
111  foreach ($this->children as $child) {
113  $result = array_merge($result, $child->fix());
114  }
115  return $result;
116  }
117 
127  protected function fixSelf()
128  {
129  $result = [];
130  if (!$this->exists()) {
131  $resultCreateDirectory = $this->createDirectory();
132  $result[] = $resultCreateDirectory;
133  if ($resultCreateDirectory instanceof Status\OkStatus &&
134  !$this->isPermissionCorrect()
135  ) {
136  $result[] = $this->fixPermission();
137  }
138  } elseif (!$this->isWritable()) {
139  // If directory is not writable, we might have permissions to fix that
140  // Try it:
141  $result[] = $this->fixPermission();
142  } elseif (!$this->isDirectory()) {
143  $status = new Status\ErrorStatus();
144  $status->setTitle('Path ' . $this->getRelativePathBelowSiteRoot() . ' is not a directory');
145  $fileType = @filetype($this->getAbsolutePath());
146  if ($fileType) {
147  $status->setMessage(
148  'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a directory,' .
149  ' but is of type ' . $fileType . '. This cannot be fixed automatically. Please investigate.'
150  );
151  } else {
152  $status->setMessage(
153  'The target ' . $this->getRelativePathBelowSiteRoot() . ' should be a directory,' .
154  ' but is of unknown type, probably because an upper level directory does not exist. Please investigate.'
155  );
156  }
157  $result[] = $status;
158  }
159  return $result;
160  }
161 
168  protected function createDirectory()
169  {
170  if ($this->exists()) {
171  throw new Exception(
172  'Directory ' . $this->getAbsolutePath() . ' already exists',
173  1366740091
174  );
175  }
176  $result = @mkdir($this->getAbsolutePath());
177  if ($result === true) {
178  $status = new Status\OkStatus();
179  $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' successfully created.');
180  } else {
181  $status = new Status\ErrorStatus();
182  $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' not created!');
183  $status->setMessage(
184  'The target directory could not be created. There is probably a' .
185  ' group or owner permission problem on the parent directory.'
186  );
187  }
188  return $status;
189  }
190 
196  protected function getSelfStatus()
197  {
198  $result = [];
199  if (!$this->isDirectory()) {
200  $status = new Status\ErrorStatus();
201  $status->setTitle($this->getRelativePathBelowSiteRoot() . ' is not a directory');
202  $status->setMessage(
203  'Directory ' . $this->getRelativePathBelowSiteRoot() . ' should be a directory,' .
204  ' but is of type ' . filetype($this->getAbsolutePath())
205  );
206  $result[] = $status;
207  } elseif (!$this->isWritable()) {
208  $status = new Status\ErrorStatus();
209  $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' is not writable');
210  $status->setMessage(
211  'Path ' . $this->getAbsolutePath() . ' exists, but no file underneath it' .
212  ' can be created.'
213  );
214  $result[] = $status;
215  } elseif (!$this->isPermissionCorrect()) {
216  $status = new Status\NoticeStatus();
217  $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot() . ' permissions mismatch');
218  $status->setMessage(
219  'Default configured permissions are ' . $this->getTargetPermission() .
220  ' but current permissions are ' . $this->getCurrentPermission()
221  );
222  $result[] = $status;
223  } else {
224  $status = new Status\OkStatus();
225  $status->setTitle('Directory ' . $this->getRelativePathBelowSiteRoot());
226  $status->setMessage(
227  'Is a directory with the configured permissions of ' . $this->getTargetPermission()
228  );
229  $result[] = $status;
230  }
231  return $result;
232  }
233 
239  protected function getChildrenStatus()
240  {
241  $result = [];
242  foreach ($this->children as $child) {
244  $result = array_merge($result, $child->getStatus());
245  }
246  return $result;
247  }
248 
254  protected function canFileBeCreated()
255  {
256  $testFileName = StringUtility::getUniqueId('installToolTest_');
257  $result = @touch($this->getAbsolutePath() . '/' . $testFileName);
258  if ($result === true) {
259  unlink($this->getAbsolutePath() . '/' . $testFileName);
260  }
261  return $result;
262  }
263 
269  protected function isDirectory()
270  {
271  $path = $this->getAbsolutePath();
272  return !@is_link($path) && @is_dir($path);
273  }
274 
281  protected function createChildren(array $structure)
282  {
283  foreach ($structure as $child) {
284  if (!array_key_exists('type', $child)) {
285  throw new Exception\InvalidArgumentException(
286  'Child must have type',
287  1366222204
288  );
289  }
290  if (!array_key_exists('name', $child)) {
291  throw new Exception\InvalidArgumentException(
292  'Child must have name',
293  1366222205
294  );
295  }
296  $name = $child['name'];
297  foreach ($this->children as $existingChild) {
299  if ($existingChild->getName() === $name) {
300  throw new Exception\InvalidArgumentException(
301  'Child name must be unique',
302  1366222206
303  );
304  }
305  }
306  $this->children[] = new $child['type']($child, $this);
307  }
308  }
309 }
__construct(array $structure, NodeInterface $parent=null)