Files
2019-11-17 19:14:07 +01:00

258 lines
8.4 KiB
PHP

<?php
/*
* 2007-2018 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/osl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
* @author PrestaShop SA <contact@prestashop.com>
* @copyright 2007-2018 PrestaShop SA
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
namespace PrestaShop\Module\AutoUpgrade\UpgradeTools;
use PrestaShop\Module\AutoUpgrade\Tools14;
class FilesystemAdapter
{
private $restoreFilesFilename;
private $fileFilter;
private $autoupgradeDir;
private $adminSubDir;
private $prodRootDir;
/**
* Somes elements to find in a folder.
* If one of them cannot be found, we can consider that the release is invalid.
*
* @var array
*/
private $releaseFileChecks = array(
'files' => array(
'index.php',
'config/defines.inc.php',
),
'folders' => array(
'classes',
'controllers',
),
);
public function __construct(FileFilter $fileFilter, $restoreFilesFilename,
$autoupgradeDir, $adminSubDir, $prodRootDir)
{
$this->fileFilter = $fileFilter;
$this->restoreFilesFilename = $restoreFilesFilename;
$this->autoupgradeDir = $autoupgradeDir;
$this->adminSubDir = $adminSubDir;
$this->prodRootDir = $prodRootDir;
}
/**
* Delete directory and subdirectories.
*
* @param string $dirname Directory name
*/
public static function deleteDirectory($dirname, $delete_self = true)
{
return Tools14::deleteDirectory($dirname, $delete_self);
}
public function listFilesInDir($dir, $way = 'backup', $list_directories = false)
{
$list = array();
$dir = rtrim($dir, '/') . DIRECTORY_SEPARATOR;
$allFiles = false;
if (is_dir($dir) && is_readable($dir)) {
$allFiles = scandir($dir);
}
if (!is_array($allFiles)) {
return $list;
}
foreach ($allFiles as $file) {
$fullPath = $dir . $file;
// skip broken symbolic links
if (is_link($fullPath) && !is_readable($fullPath)) {
continue;
}
if ($this->isFileSkipped($file, $fullPath, $way)) {
continue;
}
if (is_dir($fullPath)) {
$list = array_merge($list, $this->listFilesInDir($fullPath, $way, $list_directories));
if ($list_directories) {
$list[] = $fullPath;
}
} else {
$list[] = $fullPath;
}
}
return $list;
}
/**
* this function list all files that will be remove to retrieve the filesystem states before the upgrade.
*
* @return array of files to delete
*/
public function listFilesToRemove()
{
$prev_version = preg_match('#auto-backupfiles_V([0-9.]*)_#', $this->restoreFilesFilename, $matches);
if ($prev_version) {
$prev_version = $matches[1];
}
// if we can't find the diff file list corresponding to _PS_VERSION_ and prev_version,
// let's assume to remove every files
$toRemove = $this->listFilesInDir($this->prodRootDir, 'restore', true);
// if a file in "ToRemove" has been skipped during backup,
// just keep it
foreach ($toRemove as $key => $file) {
$filename = substr($file, strrpos($file, '/') + 1);
$toRemove[$key] = preg_replace('#^/admin#', $this->adminSubDir, $file);
// this is a really sensitive part, so we add an extra checks: preserve everything that contains "autoupgrade"
if ($this->isFileSkipped($filename, $file, 'backup') || strpos($file, $this->autoupgradeDir)) {
unset($toRemove[$key]);
}
}
return $toRemove;
}
/**
* Retrieve a list of sample files to be deleted from the release.
*
* @param array $directoryList
*
* @return array Files to remove from the release
*/
public function listSampleFilesFromArray(array $directoryList)
{
$res = array();
foreach ($directoryList as $directory) {
$res = array_merge($res, $this->listSampleFiles($directory['path'], $directory['filter']));
}
return $res;
}
/**
* listSampleFiles will make a recursive call to scandir() function
* and list all file which match to the $fileext suffixe (this can be an extension or whole filename).
*
* @param string $dir directory to look in
* @param string $fileext suffixe filename
*
* @return array of files
*/
public function listSampleFiles($dir, $fileext = '.jpg')
{
$res = array();
$dir = rtrim($dir, '/') . DIRECTORY_SEPARATOR;
$toDel = false;
if (is_dir($dir) && is_readable($dir)) {
$toDel = scandir($dir);
}
// copied (and kind of) adapted from AdminImages.php
if (is_array($toDel)) {
foreach ($toDel as $file) {
if ($file[0] != '.') {
if (preg_match('#' . preg_quote($fileext, '#') . '$#i', $file)) {
$res[] = $dir . $file;
} elseif (is_dir($dir . $file)) {
$res = array_merge($res, $this->listSampleFiles($dir . $file, $fileext));
}
}
}
}
return $res;
}
/**
* bool _skipFile : check whether a file is in backup or restore skip list.
*
* @param string $file : current file or directory name eg:'.svn' , 'settings.inc.php'
* @param string $fullpath : current file or directory fullpath eg:'/home/web/www/prestashop/app/config/parameters.php'
* @param string $way : 'backup' , 'upgrade'
* @param string $temporaryWorkspace : If needed, another folder than the shop root can be used (used for releases)
*/
public function isFileSkipped($file, $fullpath, $way = 'backup', $temporaryWorkspace = null)
{
$fullpath = str_replace('\\', '/', $fullpath); // wamp compliant
$rootpath = str_replace(
'\\',
'/',
(null !== $temporaryWorkspace) ? $temporaryWorkspace : $this->prodRootDir
);
if (in_array($file, $this->fileFilter->getExcludeFiles())) {
return true;
}
$ignoreList = array();
if ('backup' === $way) {
$ignoreList = $this->fileFilter->getFilesToIgnoreOnBackup();
} elseif ('restore' === $way) {
$ignoreList = $this->fileFilter->getFilesToIgnoreOnRestore();
} elseif ('upgrade' === $way) {
$ignoreList = $this->fileFilter->getFilesToIgnoreOnUpgrade();
}
foreach ($ignoreList as $path) {
$path = str_replace(DIRECTORY_SEPARATOR . 'admin', DIRECTORY_SEPARATOR . $this->adminSubDir, $path);
if ($fullpath === $rootpath . $path) {
return true;
}
}
// by default, don't skip
return false;
}
/**
* Check a directory has some files available in every release of PrestaShop.
*
* @param string $path Workspace to check
*
* @return bool
*/
public function isReleaseValid($path)
{
foreach ($this->releaseFileChecks as $type => $elements) {
foreach ($elements as $element) {
$fullPath = $path . DIRECTORY_SEPARATOR . $element;
if ('files' === $type && !is_file($fullPath)) {
return false;
}
if ('folders' === $type && !is_dir($fullPath)) {
return false;
}
}
}
return true;
}
}