name; } /** * Get target permission * * Make sure to call octdec on the value when passing this to chmod * * @return string Permissions as a 4 character octal string, i.e. 2775 or 0644 */ protected function getTargetPermission() { return $this->targetPermission ?? ''; } /** * Set target permission * * @param string $permission Permissions as a 4 character octal string, i.e. 2775 or 0644 */ protected function setTargetPermission($permission) { // Normalize the permission string to "4 characters", padding with leading "0" if necessary: $permission = substr($permission, 0, 4); $permission = str_pad($permission, 4, '0', STR_PAD_LEFT); $this->targetPermission = $permission; } /** * Get children * * @return array */ protected function getChildren() { return $this->children; } /** * Get parent * * @return NodeInterface|null */ protected function getParent() { return $this->parent; } /** * Get absolute path of node * * @return string */ public function getAbsolutePath() { return $this->getParent()->getAbsolutePath() . '/' . $this->name; } /** * Current node is writable if parent is writable * * @return bool TRUE if parent is writable */ public function isWritable() { return $this->getParent()->isWritable(); } /** * Checks if node exists. * Returns TRUE if it is there, even if it is only a link. * Does not check the type! * * @return bool */ protected function exists() { if (@is_link($this->getAbsolutePath())) { return true; } return @file_exists($this->getAbsolutePath()); } /** * Fix permission if they are not equal to target permission * * @throws Exception */ protected function fixPermission(): FlashMessage { if ($this->isPermissionCorrect()) { return new FlashMessage( '', 'Permission on ' . $this->getAbsolutePath() . ' is already ok.' ); } $result = @chmod($this->getAbsolutePath(), (int)octdec($this->getTargetPermission())); if ($result === true) { return new FlashMessage( '', 'Fixed permission on ' . $this->getRelativePathBelowSiteRoot() . '.' ); } return new FlashMessage( 'Permissions could not be changed to ' . $this->getTargetPermission() . '. This only is a problem if files and folders within this node cannot be written.', 'Permission change on ' . $this->getRelativePathBelowSiteRoot() . ' not successful', ContextualFeedbackSeverity::NOTICE ); } /** * Checks if current permission are identical to target permission * * @return bool */ protected function isPermissionCorrect() { if ($this->isWindowsOs()) { return true; } if ($this->getCurrentPermission() === $this->getTargetPermission()) { return true; } return false; } /** * Get current permission of node * * @return string eg. 2775 for dirs, 0664 for files */ protected function getCurrentPermission() { $permissions = decoct((int)fileperms($this->getAbsolutePath())); return substr($permissions, -4); } /** * Returns TRUE if OS is windows * * @return bool TRUE on windows */ protected function isWindowsOs() { return Environment::isWindows(); } /** * Cut off project path from given path * * @param string $path Given path * @return string Relative path, but beginning with / * @throws Exception\InvalidArgumentException */ protected function getRelativePathBelowSiteRoot($path = null) { if ($path === null) { $path = $this->getAbsolutePath(); } $projectPath = Environment::getProjectPath(); if (strpos($path, $projectPath, 0) !== 0) { throw new InvalidArgumentException( 'Public path is not first part of given path', 1366398198 ); } $relativePath = substr($path, strlen($projectPath), strlen($path)); // Add a forward slash again, so we don't end up with an empty string if ($relativePath === '') { $relativePath = '/'; } return $relativePath; } }