JEMBOT MAWOT Bypass Shell
<?php
/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* 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.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* 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 https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/
namespace PrestaShop\PrestaShop\Adapter\Module\Configuration;
use Doctrine\DBAL\Connection;
use Exception;
use PrestaShop\PrestaShop\Adapter\Configuration;
use PrestaShop\PrestaShop\Core\Module\ModuleRepository;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Process\Exception\InvalidArgumentException;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
/**
* This class allow system users and developers to configure their module
* with a single config file.
*
* Use validate() to check everything is ready to run.
* Use configure() to run the configuration with the provided parameters.
*/
class ModuleSelfConfigurator
{
/**
* @var string|null the module name
*/
protected $module;
/**
* @var string|null
*/
protected $configFile;
/**
* @var array
*/
protected $configs = [];
/**
* @var string
*/
protected $defaultConfigFile = 'self_config.yml';
/**
* @var ModuleRepository
*/
protected $moduleRepository;
/**
* @var Configuration
*/
protected $configuration;
/**
* @var Connection
*/
protected $connection;
/**
* @var Filesystem
*/
protected $filesystem;
public function __construct(
ModuleRepository $moduleRepository,
Configuration $configuration,
Connection $connection,
Filesystem $filesystem
) {
$this->module = null;
$this->configFile = null;
$this->moduleRepository = $moduleRepository;
$this->configuration = $configuration;
$this->connection = $connection;
$this->filesystem = $filesystem;
}
/**
* Alias for $module setter.
*
* @param string $name
*
* @return $this
*/
public function module($name)
{
return $this->setModule($name);
}
/**
* Set the module to be updated with its name.
*
* @param string $name
*
* @return $this
*
* @throws UnexpectedTypeException
*/
public function setModule($name)
{
if (!is_string($name)) {
throw new UnexpectedTypeException($name, 'string');
}
$this->module = $name;
return $this;
}
/**
* If defined, get the config file path or if possible, guess it.
*
* @return string|null
*
* @throws InvalidArgumentException
*/
public function getFile()
{
// If set, return it
if ($this->configFile) {
return $this->configFile;
}
// If we do not know in which module to search, we cannot go further
if (!$this->module) {
return null;
}
// Find and store the first config file we find
$files = Finder::create()
->files()
->in(_PS_MODULE_DIR_ . $this->module)
->name($this->defaultConfigFile);
foreach ($files as $file) {
$this->configFile = $file->getRealPath();
return $this->configFile;
}
return null;
}
/**
* Alias for config file setter.
*
* @param string $filepath
*
* @return $this
*/
public function file($filepath)
{
return $this->setFile($filepath);
}
/**
* Set the config file to parse.
*
* @param string $filepath
*
* @return $this
*
* @throws UnexpectedTypeException
*/
public function setFile($filepath)
{
if (!is_string($filepath)) {
throw new UnexpectedTypeException($filepath, 'string');
}
$this->configFile = $filepath;
return $this;
}
/**
* In order to prevent some failure, we can check all pre-requesites are respected.
* Any error will be reported in the array.
*
* @return array
*/
public function validate()
{
$errors = [];
if ($this->module === null) {
$errors[] = 'Module name not specified';
}
try {
$file = $this->getFile();
} catch (InvalidArgumentException $e) {
$errors[] = $e->getMessage();
$file = null;
}
if ($file === null) {
$errors[] = 'No config file to apply';
} elseif (!file_exists($file)) {
$errors[] = 'Specified config file is not found';
} else {
try {
$config = $this->loadYmlFile($file);
} catch (ParseException $e) {
$errors[] = $e->getMessage();
}
if (empty($config)) {
$errors[] = 'Parsed config file is empty';
}
}
if (!$this->module || !$this->moduleRepository->getModule($this->module)->hasValidInstance()) {
$errors[] = 'The module specified is invalid';
}
return $errors;
}
/**
* Launch the self configuration with all the context previously set!
*
* @return bool
*/
public function configure()
{
if (count($this->validate())) {
return false;
}
$config = $this->loadYmlFile($this->getFile());
$this->runConfigurationStep($config);
$this->runFilesStep($config);
$this->runSqlStep($config);
$this->runPhpStep($config);
return true;
}
// PROTECTED ZONE
/**
* Helper function which adds the relative path from the YML config file.
* Do not alter URLs.
*
* @param string $file
*
* @return string
*/
protected function convertRelativeToAbsolutePaths($file)
{
// If we do not deal with any kind of URL, add the path to the YML config file
if (!filter_var($file, FILTER_VALIDATE_URL)) {
$file = dirname($this->getFile()) . '/' . $file;
}
return $file;
}
/**
* Finds and returns filepath from a config key in the YML config file.
* Can be a string of a value of "file" key.
*
* @param array|string $data
*
* @return string
*
* @throws Exception if file data not provided
*/
protected function extractFilePath($data)
{
if (is_scalar($data)) {
$file = $data;
} elseif (is_array($data) && !empty($data['file'])) {
$file = $data['file'];
} else {
throw new Exception('Missing file path');
}
return $this->convertRelativeToAbsolutePaths($file);
}
/**
* Require a PHP file and instanciate the class of the same name in it.
*
* @param string $file
*
* @return object
*/
protected function loadPhpFile($file)
{
// Load file
require_once $file;
// Load class of same name as the file
$className = pathinfo($file, PATHINFO_FILENAME);
return new $className();
}
/**
* Parse and return the YML content.
*
* @param string $file
*
* @return array
*/
protected function loadYmlFile($file)
{
if (array_key_exists($file, $this->configs)) {
return $this->configs[$file];
}
$this->configs[$file] = Yaml::parse(file_get_contents($file));
return $this->configs[$file];
}
/**
* Run configuration for "configuration" step.
*
* @param array $config
*/
protected function runConfigurationStep($config)
{
if (empty($config['configuration'])) {
return;
}
if (array_key_exists('update', $config['configuration'])) {
$this->runConfigurationUpdate($config['configuration']['update']);
}
if (array_key_exists('delete', $config['configuration'])) {
$this->runConfigurationDelete($config['configuration']['delete']);
}
}
/**
* Run configuration for "file" step.
*
* @param array $config
*/
protected function runFilesStep($config)
{
if (empty($config['files'])) {
return;
}
foreach ($config['files'] as $copy) {
if (empty($copy['source'])) {
throw new Exception('Missing source file');
}
if (empty($copy['dest'])) {
throw new Exception('Missing destination file');
}
// If we get a relative path from the yml, add the original path
foreach (['source', 'dest'] as $prop) {
$copy[$prop] = $this->convertRelativeToAbsolutePaths($copy[$prop]);
}
$this->filesystem->copy(
$copy['source'],
$copy['dest']
);
}
}
/**
* Run configuration for "php" step.
*
* @param array $config
*/
protected function runPhpStep($config)
{
if (empty($config['php'])) {
return;
}
foreach ($config['php'] as $data) {
$file = $this->extractFilePath($data);
$module = $this->moduleRepository->getModule($this->module);
$params = !empty($data['params']) ? $data['params'] : [];
$this->loadPhpFile($file)->run($module, $params);
}
}
/**
* Run configuration for "sql" step.
*
* @param array $config
*/
protected function runSqlStep($config)
{
if (empty($config['sql'])) {
return;
}
// Avoid unconsistant state with transactions
$this->connection->beginTransaction();
try {
foreach ($config['sql'] as $data) {
$this->runSqlFile($data);
}
$this->connection->commit();
} catch (Exception $e) {
$this->connection->rollBack();
throw $e;
}
}
/**
* Subtask of Sql step. Get and prepare all SQL requests from a file.
*
* @param array $data
*/
protected function runSqlFile($data)
{
$content = file_get_contents($this->extractFilePath($data));
foreach (explode(';', $content) as $sql) {
$sql = trim($sql);
if (empty($sql)) {
continue;
}
// Set _DB_PREFIX_
$sql = str_replace(
[
'PREFIX_',
'DB_NAME',
],
[
$this->configuration->get('_DB_PREFIX_'),
$this->configuration->get('_DB_NAME_'),
],
$sql
);
$stmt = $this->connection->prepare($sql);
$stmt->execute();
}
}
/**
* Subtask of configuration step, for all configuration key to update.
*
* @param array $config
*
* @throws Exception
*/
protected function runConfigurationUpdate($config)
{
foreach ($config as $key => $data) {
if (is_array($data) && isset($data['value'])) {
$value = $data['value'];
} elseif (is_scalar($data)) {
// string / integer / decimal / bool
$value = $data;
} else {
throw new Exception(sprintf('No value given for key %s', $key));
}
$this->configuration->set($key, $value);
}
}
/**
* Subtask of configuration step, for all configuration keys to delete.
*
* @param array $config
*/
protected function runConfigurationDelete($config)
{
foreach ($config as $key) {
$this->configuration->remove($key);
}
}
}
xxxxx1.0, XXX xxxx