Your IP : 127.0.0.1
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Framework\Setup;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Backup\Filesystem\Iterator\Filter;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\Filter\ExcludeFilter;
use Magento\Framework\App\State;
use Magento\Framework\App\ObjectManager;
/**
* Checks permissions to files and folders.
*/
class FilePermissions
{
/**
* @var Filesystem
*/
protected $filesystem;
/**
* @var DirectoryList
*/
protected $directoryList;
/**
* @var State
*/
private $state;
/**
* List of required writable directories for installation
*
* @var array
*/
protected $installationWritableDirectories = [];
/**
* List of recommended non-writable directories for application
*
* @var array
*/
protected $applicationNonWritableDirectories = [];
/**
* List of current writable directories for installation
*
* @var array
*/
protected $installationCurrentWritableDirectories = [];
/**
* List of current non-writable directories for application
*
* @var array
*/
protected $applicationCurrentNonWritableDirectories = [];
/**
* List of non-writable paths in a specified directory
*
* @var array
*/
protected $nonWritablePathsInDirectories = [];
/**
* @param Filesystem $filesystem
* @param DirectoryList $directoryList
* @param State $state
*/
public function __construct(
Filesystem $filesystem,
DirectoryList $directoryList,
State $state = null
) {
$this->filesystem = $filesystem;
$this->directoryList = $directoryList;
$this->state = $state ?: ObjectManager::getInstance()->get(State::class);
}
/**
* Retrieve list of required writable directories for installation
*
* @return array
*/
public function getInstallationWritableDirectories()
{
if (!$this->installationWritableDirectories) {
$data = [
DirectoryList::CONFIG,
DirectoryList::VAR_DIR,
DirectoryList::MEDIA,
DirectoryList::STATIC_VIEW,
];
if ($this->state->getMode() !== State::MODE_PRODUCTION) {
$data[] = DirectoryList::GENERATED;
}
foreach ($data as $code) {
$this->installationWritableDirectories[$code] = $this->directoryList->getPath($code);
}
}
return array_values($this->installationWritableDirectories);
}
/**
* Retrieve list of recommended non-writable directories for application
*
* @return array
*/
public function getApplicationNonWritableDirectories()
{
if (!$this->applicationNonWritableDirectories) {
$data = [
DirectoryList::CONFIG,
];
foreach ($data as $code) {
$this->applicationNonWritableDirectories[$code] = $this->directoryList->getPath($code);
}
}
return array_values($this->applicationNonWritableDirectories);
}
/**
* Retrieve list of currently writable directories for installation
*
* @return array
*/
public function getInstallationCurrentWritableDirectories()
{
if (!$this->installationCurrentWritableDirectories) {
foreach ($this->installationWritableDirectories as $code => $path) {
if ($this->isWritable($code)) {
if ($this->checkRecursiveDirectories($path)) {
$this->installationCurrentWritableDirectories[] = $path;
}
} else {
$this->nonWritablePathsInDirectories[$path] = [$path];
}
}
}
return $this->installationCurrentWritableDirectories;
}
/**
* Check all sub-directories and files except for generated/code and generated/metadata
*
* @param string $directory
* @return bool
*/
private function checkRecursiveDirectories($directory)
{
/** @var $directoryIterator \RecursiveIteratorIterator */
$directoryIterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
$noWritableFilesFolders = [
$this->directoryList->getPath(DirectoryList::GENERATED_CODE) . '/',
$this->directoryList->getPath(DirectoryList::GENERATED_METADATA) . '/',
];
$directoryIterator = new Filter($directoryIterator, $noWritableFilesFolders);
$directoryIterator = new ExcludeFilter(
$directoryIterator,
[
$this->directoryList->getPath(DirectoryList::SESSION) . '/',
]
);
$directoryIterator->setMaxDepth(1);
$foundNonWritable = false;
try {
foreach ($directoryIterator as $subDirectory) {
if (!$subDirectory->isWritable() && !$subDirectory->isLink()) {
$this->nonWritablePathsInDirectories[$directory][] = $subDirectory->getPathname();
$foundNonWritable = true;
}
}
} catch (\UnexpectedValueException $e) {
return false;
}
return !$foundNonWritable;
}
/**
* Retrieve list of currently non-writable directories for application
*
* @return array
*/
public function getApplicationCurrentNonWritableDirectories()
{
if (!$this->applicationCurrentNonWritableDirectories) {
foreach ($this->applicationNonWritableDirectories as $code => $path) {
if ($this->isNonWritable($code)) {
$this->applicationCurrentNonWritableDirectories[] = $path;
}
}
}
return $this->applicationCurrentNonWritableDirectories;
}
/**
* Checks if directory is writable by given directory code
*
* @param string $code
* @return bool
*/
protected function isWritable($code)
{
$directory = $this->filesystem->getDirectoryWrite($code);
return $this->isReadableDirectory($directory) && $directory->isWritable();
}
/**
* Checks if directory is non-writable by given directory code
*
* @param string $code
* @return bool
*/
protected function isNonWritable($code)
{
$directory = $this->filesystem->getDirectoryWrite($code);
return $this->isReadableDirectory($directory) && !$directory->isWritable();
}
/**
* Checks if directory exists and is readable
*
* @param \Magento\Framework\Filesystem\Directory\WriteInterface $directory
* @return bool
*/
protected function isReadableDirectory($directory)
{
if (!$directory->isExist() || !$directory->isDirectory() || !$directory->isReadable()) {
return false;
}
return true;
}
/**
* Checks writable paths for installation, returns associative array if input is true, else returns simple array
*
* @param bool $associative
* @return array
*/
public function getMissingWritablePathsForInstallation($associative = false)
{
$required = $this->getInstallationWritableDirectories();
$current = $this->getInstallationCurrentWritableDirectories();
$missingPaths = [];
foreach (array_diff($required, $current) as $missingPath) {
if (isset($this->nonWritablePathsInDirectories[$missingPath])) {
if ($associative) {
$missingPaths[$missingPath] = $this->nonWritablePathsInDirectories[$missingPath];
} else {
$missingPaths = array_merge(
$missingPaths,
$this->nonWritablePathsInDirectories[$missingPath]
);
}
}
}
if ($associative) {
$required = array_flip($required);
$missingPaths = array_merge($required, $missingPaths);
}
return $missingPaths;
}
/**
* Checks writable paths for database upgrade, returns array of directory paths that requires write permission
*
* @return array List of directories that requires write permission for database upgrade
*/
public function getMissingWritableDirectoriesForDbUpgrade()
{
$writableDirectories = [
DirectoryList::CONFIG,
DirectoryList::VAR_DIR
];
$requireWritePermission = [];
foreach ($writableDirectories as $code) {
if (!$this->isWritable($code)) {
$path = $this->directoryList->getPath($code);
if (!$this->checkRecursiveDirectories($path)) {
$requireWritePermission[] = $path;
}
}
}
return $requireWritePermission;
}
/**
* Checks writable directories for installation
*
* @deprecated 100.1.0 Use getMissingWritablePathsForInstallation()
* to get all missing writable paths required for install.
* @return array
*/
public function getMissingWritableDirectoriesForInstallation()
{
$required = $this->getInstallationWritableDirectories();
$current = $this->getInstallationCurrentWritableDirectories();
return array_diff($required, $current);
}
/**
* Checks non-writable directories for application
*
* @return array
*/
public function getUnnecessaryWritableDirectoriesForApplication()
{
$required = $this->getApplicationNonWritableDirectories();
$current = $this->getApplicationCurrentNonWritableDirectories();
return array_diff($required, $current);
}
}