Subida del módulo y tema de PrestaShop

This commit is contained in:
Kaloyan
2026-04-09 18:31:51 +02:00
parent 12c253296f
commit 16b3ff9424
39262 changed files with 7418797 additions and 0 deletions

10
tools/profiling/.htaccess Normal file
View File

@@ -0,0 +1,10 @@
# Apache 2.2
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
# Apache 2.4
<IfModule mod_authz_core.c>
Require all denied
</IfModule>

View File

@@ -0,0 +1,129 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
abstract class Controller extends ControllerCore
{
protected $profiler = null;
/**
* @var string|null
*/
public $outPutHtml;
public function __construct()
{
$this->profiler = Profiler::getInstance();
$this->profiler->stamp('config');
parent::__construct();
$this->profiler->stamp('__construct');
}
public function run()
{
$this->init();
$this->profiler->stamp('init');
if ($this->checkAccess()) {
$this->profiler->stamp('checkAccess');
if (!$this->content_only && ($this->display_header || !empty($this->className))) {
$this->setMedia();
$this->profiler->stamp('setMedia');
}
$this->postProcess();
$this->profiler->stamp('postProcess');
if (!$this->content_only && ($this->display_header || !empty($this->className))) {
$this->initHeader();
$this->profiler->stamp('initHeader');
}
$this->initContent();
$this->profiler->stamp('initContent');
if (!$this->content_only && ($this->display_footer || !empty($this->className))) {
$this->initFooter();
$this->profiler->stamp('initFooter');
}
if ($this->ajax) {
$action = Tools::toCamelCase(Tools::getValue('action'), true);
if (!empty($action) && method_exists($this, 'displayAjax' . $action)) {
$this->{'displayAjax' . $action}();
} elseif (method_exists($this, 'displayAjax')) {
$this->displayAjax();
}
return;
}
} else {
$this->initCursedPage();
}
echo $this->displayProfiling();
}
/**
* Display profiling
* If it's a migrated page, we change the outPutHtml content, otherwise
* we display the profiling at the end of the page.
*
* @return string
*/
public function displayProfiling(): string
{
$content = '';
if (!empty($this->redirect_after)) {
$this->context->smarty->assign(
[
'redirectAfter' => $this->redirect_after,
]
);
$content .= $this->context->smarty->fetch(__DIR__ . '/templates/redirect.tpl');
} else {
// Call original display method
ob_start();
$this->display();
$displayOutput = ob_get_clean();
if (empty($displayOutput) && isset($this->outPutHtml)) {
$displayOutput = $this->outPutHtml;
}
$content .= $displayOutput;
$this->profiler->stamp('display');
}
// Process all profiling data
$this->profiler->processData();
// Add some specific style for profiling information
$this->context->smarty->assign(
$this->profiler->getSmartyVariables()
);
if (strpos($content, '{$content}') === false) {
return str_replace(
'</html>',
$this->context->smarty->fetch(__DIR__ . '/templates/profiling.tpl') . '</html>',
$content
);
}
if (isset($this->outPutHtml)) {
$this->outPutHtml = str_replace(
'{$content}',
'{$content}' . $this->context->smarty->fetch(__DIR__ . '/templates/profiling.tpl'),
$content
);
}
// Return empty string since we change the outPutHtml
return '';
}
}

109
tools/profiling/Db.php Normal file
View File

@@ -0,0 +1,109 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
abstract class Db extends DbCore
{
/**
* Add SQL_NO_CACHE in SELECT queries
*
* @var bool
*/
public $disableCache = true;
/**
* Total of queries
*
* @var int
*/
public $count = 0;
/**
* List of queries
*
* @var array
*/
public $queries = [];
/**
* List of uniq queries (replace numbers by XX)
*
* @var array
*/
public $uniqQueries = [];
/**
* List of tables
*
* @var array
*/
public $tables = [];
/**
* Execute the query and log some informations
*
* @see DbCore::query()
*/
public function query($sql)
{
$explain = false;
if (preg_match('/^\s*explain\s+/i', $sql)) {
$explain = true;
}
if (!$explain) {
$uniqSql = preg_replace('/[\'"][a-f0-9]{32}[\'"]/', 'XX', $sql);
$uniqSql = preg_replace('/[0-9]+/', 'XX', $uniqSql);
if (!isset($this->uniqQueries[$uniqSql])) {
$this->uniqQueries[$uniqSql] = 0;
}
++$this->uniqQueries[$uniqSql];
// No cache for query
if ($this->disableCache && !stripos($sql, 'SQL_NO_CACHE')) {
$sql = preg_replace('/^\s*select\s+/i', 'SELECT SQL_NO_CACHE ', trim($sql));
}
// Get tables in query
preg_match_all('/(from|join)\s+`?' . _DB_PREFIX_ . '([a-z0-9_-]+)/ui', $sql, $matches);
foreach ($matches[2] as $table) {
if (!isset($this->tables[$table])) {
$this->tables[$table] = 0;
}
++$this->tables[$table];
}
$start = microtime(true);
}
// Execute query
$result = parent::query($sql);
if (!$explain) {
$end = microtime(true);
$stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
while (preg_match('@[/\\\\]classes[/\\\\]db[/\\\\]@i', $stack[0]['file'])) {
array_shift($stack);
}
$stack_light = [];
foreach ($stack as $call) {
$stack_light[] = [
'file' => $call['file'] ?? 'undefined',
'line' => $call['line'] ?? 'undefined',
'function' => $call['function'],
];
}
$this->queries[] = [
'query' => $sql,
'time' => $end - $start,
'stack' => $stack_light,
];
}
return $result;
}
}

75
tools/profiling/Hook.php Normal file
View File

@@ -0,0 +1,75 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
declare(strict_types=1);
class Hook extends HookCore
{
public static function coreCallHook($module, $method, $params)
{
$timeStart = microtime(true);
$memoryStart = memory_get_usage();
$result = parent::coreCallHook($module, $method, $params);
Profiler::getInstance()->interceptHook(
substr($method, 4),
[
'module' => $module->name,
'params' => $params,
'time' => microtime(true) - $timeStart,
'memory' => memory_get_usage() - $memoryStart,
]
);
Profiler::getInstance()->interceptModule(
[
'module' => $module->name,
'method' => $method,
'time' => microtime(true) - $timeStart,
'memory' => memory_get_usage() - $memoryStart,
]
);
return $result;
}
public static function coreRenderWidget($module, $registeredHookName, $params)
{
$timeStart = microtime(true);
$memoryStart = memory_get_usage();
$result = parent::coreRenderWidget($module, $registeredHookName, $params);
/*
* It's not a hook which has been triggered but
* it's a widget
*/
if (empty($registeredHookName)) {
$registeredHookName = 'renderWidget';
}
Profiler::getInstance()->interceptHook(
$registeredHookName,
[
'module' => $module->name . ' (widget)',
'params' => $params,
'time' => microtime(true) - $timeStart,
'memory' => memory_get_usage() - $memoryStart,
]
);
Profiler::getInstance()->interceptModule(
[
'module' => $module->name,
'method' => $registeredHookName,
'time' => microtime(true) - $timeStart,
'memory' => memory_get_usage() - $memoryStart,
]
);
return $result;
}
}

View File

@@ -0,0 +1,28 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
declare(strict_types=1);
class Module extends ModuleCore
{
protected static function coreLoadModule($moduleName)
{
$timeStart = microtime(true);
$memoryStart = memory_get_usage();
$result = parent::coreLoadModule($moduleName);
Profiler::getInstance()->interceptModule(
[
'module' => $moduleName,
'method' => '__construct',
'time' => microtime(true) - $timeStart,
'memory' => memory_get_usage() - $memoryStart,
]
);
return $result;
}
}

View File

@@ -0,0 +1,38 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
abstract class ObjectModel extends ObjectModelCore
{
public static $debug_list = [];
public function __construct($id = null, $id_lang = null, $id_shop = null, $translator = null)
{
parent::__construct($id, $id_lang, $id_shop, $translator);
$classname = get_class($this);
if (!isset(self::$debug_list[$classname])) {
self::$debug_list[$classname] = [];
}
$class_list = ['ObjectModel', 'ObjectModelCore', $classname, $classname . 'Core'];
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
foreach ($backtrace as $trace_id => $row) {
if (!isset($backtrace[$trace_id]['class']) || !in_array($backtrace[$trace_id]['class'], $class_list)) {
break;
}
}
if (!isset($trace_id)) {
return;
}
--$trace_id;
self::$debug_list[$classname][] = [
'file' => $backtrace[$trace_id]['file'] ?? '',
'line' => $backtrace[$trace_id]['line'] ?? 0,
'function' => $backtrace[$trace_id]['function'] ?? 0,
'id' => $id,
];
}
}

View File

@@ -0,0 +1,356 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
declare(strict_types=1);
class Profiler
{
/** @var array */
protected $hooksPerfs = [];
/** @var array */
protected $modulesPerfs = [];
/** @var array */
protected $profiler = [];
/** @var array */
protected $globalVarSize = [];
/** @var array */
protected $queries = [];
/** @var int */
protected $totalFilesize = 0;
/** @var int */
protected $totalGlobalVarSize = 0;
/** @var float */
protected $totalQueryTime = 0;
/** @var float */
protected $totalModulesTime = 0;
/** @var int */
protected $totalModulesMemory = 0;
/** @var float */
protected $totalHooksTime = 0;
/** @var int */
protected $totalHooksMemory = 0;
/** @var float */
protected $startTime = 0;
/** @var int */
protected $totalCacheSize = 0;
protected static $instance = null;
private function __construct()
{
global $start_time;
if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
$this->startTime = (float) $_SERVER['REQUEST_TIME_FLOAT'];
} elseif (!empty($start_time)) {
$this->startTime = $start_time;
} else {
$this->startTime = microtime(true);
}
}
/**
* Return profiler instance
*
* @return self
*/
public static function getInstance()
{
if (static::$instance === null) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Sort array by query time
*
* @param array $a
* @param array $b
*
* @return int
*/
public function sortByQueryTime(array $a, array $b): int
{
if ($a['time'] == $b['time']) {
return 0;
}
return ($a['time'] > $b['time']) ? -1 : 1;
}
/**
* Stamp the profiling
*
* @param string $block
*/
public function stamp(string $block)
{
$this->profiler[] = [
'block' => $block,
'memory_usage' => memory_get_usage(),
'peak_memory_usage' => memory_get_peak_usage(),
'time' => microtime(true),
];
}
/**
* Get var size
*
* @param mixed $var
*/
private function getVarSize($var)
{
$start_memory = memory_get_usage();
try {
$tmp = Tools::unSerialize(serialize($var));
} catch (Exception $e) {
$tmp = $this->getVarData($var);
}
$size = memory_get_usage() - $start_memory;
return $size;
}
/**
* Get var data
*
* @param mixed $var
*
* @return string|object|array
*/
private function getVarData($var)
{
if (is_object($var)) {
return $var;
}
if (is_array($var)) {
return $var;
}
return (string) $var;
}
/**
* Intercept hook and register its data
*
* @param string $hookName
* @param array $params
*/
public function interceptHook(string $hookName, array $params)
{
if (empty($this->hooksPerfs[$hookName])) {
$this->hooksPerfs[$hookName] = [
'time' => 0,
'memory' => 0,
'modules' => [],
];
}
$this->hooksPerfs[$hookName]['time'] += $params['time'];
$this->hooksPerfs[$hookName]['memory'] += $params['memory'];
$this->hooksPerfs[$hookName]['modules'][] = $params;
$this->totalHooksMemory += $params['memory'];
$this->totalHooksTime += $params['time'];
}
/**
* Intercept module
*
* @param array $params
*/
public function interceptModule(array $params)
{
$this->modulesPerfs[$params['module']][] = $params;
$this->totalModulesTime += $params['time'];
$this->totalModulesMemory += $params['memory'];
}
/**
* Process all data such as Global vars and
* database queries
*/
public function processData()
{
// Including a lot of files uses memory
foreach (get_included_files() as $file) {
if (file_exists($file)) {
$this->totalFilesize += filesize($file);
}
}
foreach ($GLOBALS as $key => $value) {
if ($key === 'GLOBALS') {
continue;
}
$this->totalGlobalVarSize += ($size = $this->getVarSize($value));
if ($size > 1024) {
$this->globalVarSize[$key] = round($size / 1024);
}
}
arsort($this->globalVarSize);
$cache = Cache::retrieveAll();
$this->totalCacheSize = $this->getVarSize($cache);
// Sum querying time
/* @phpstan-ignore-next-line */
$queries = Db::getInstance()->queries;
uasort($queries, [$this, 'sortByQueryTime']);
foreach ($queries as $id => $data) {
$this->totalQueryTime += $data['time'];
$queryRow = [
'time' => $data['time'],
'query' => $data['query'],
'location' => str_replace('\\', '/', substr($data['stack'][0]['file'], strlen(_PS_ROOT_DIR_))) . ':' . $data['stack'][0]['line'],
'filesort' => false,
'rows' => 1,
'group_by' => false,
'stack' => [],
'id' => $id,
];
if (preg_match('/^\s*select\s+/i', $data['query'])) {
$explain = Db::getInstance()->executeS('explain ' . $data['query']);
if (isset($explain[0]['Extra']) && stristr($explain[0]['Extra'], 'filesort')) {
$queryRow['filesort'] = true;
}
if (is_array($explain)) {
foreach ($explain as $row) {
$queryRow['rows'] *= (int) $row['rows'];
}
} else {
$queryRow['rows'] = 'N/A';
}
if (stristr($data['query'], 'group by') && !preg_match('/(avg|count|min|max|group_concat|sum)\s*\(/i', $data['query'])) {
$queryRow['group_by'] = true;
}
}
array_shift($data['stack']);
foreach ($data['stack'] as $call) {
$queryRow['stack'][] = str_replace('\\', '/', substr($call['file'], strlen(_PS_ROOT_DIR_))) . ':' . $call['line'] . ' (' . $call['function'] . ')';
}
$this->queries[] = $queryRow;
}
/* @phpstan-ignore-next-line */
uasort(ObjectModel::$debug_list, function ($a, $b) { return (count($a) < count($b)) ? 1 : -1; });
/* @phpstan-ignore-next-line */
arsort(Db::getInstance()->tables);
/* @phpstan-ignore-next-line */
arsort(Db::getInstance()->uniqQueries);
uasort($this->hooksPerfs, [$this, 'sortByQueryTime']);
}
/**
* Format performance details for modules
*
* @return array
*/
public function getFormattedModulePerfs(): array
{
$formattedOutput = [];
foreach ($this->modulesPerfs as $moduleName => $perfs) {
$formattedOutput[$moduleName] = [
'total_time' => array_reduce(
$perfs,
function ($res, $item) {
return $res + $item['time'];
},
0
),
'total_memory' => array_reduce(
$perfs,
function ($res, $item) {
return $res + $item['memory'];
},
0
),
'details' => $perfs,
];
}
return $formattedOutput;
}
/**
* Prepare and return smarty variables
*
* @return array
*/
public function getSmartyVariables(): array
{
/* @phpstan-ignore-next-line */
$doublesQueries = Db::getInstance()->uniqQueries;
/* @phpstan-ignore-next-line */
$tableStress = Db::getInstance()->tables;
return [
'summary' => [
'loadTime' => empty($this->profiler) ? null : $this->profiler[count($this->profiler) - 1]['time'] - $this->startTime,
'queryTime' => round(1000 * $this->totalQueryTime),
'nbQueries' => count($this->queries),
'peakMemoryUsage' => empty($this->profiler) ? null : $this->profiler[count($this->profiler) - 1]['peak_memory_usage'],
'globalVarSize' => $this->globalVarSize,
'includedFiles' => count(get_included_files()),
'totalFileSize' => $this->totalFilesize,
'totalCacheSize' => $this->totalCacheSize,
'totalGlobalVarSize' => $this->totalGlobalVarSize,
],
'configuration' => [
'psVersion' => _PS_VERSION_,
'phpVersion' => PHP_VERSION,
'mysqlVersion' => Db::getInstance()->getVersion(),
'memoryLimit' => ini_get('memory_limit'),
'maxExecutionTime' => ini_get('max_execution_time'),
'smartyCache' => Configuration::get('PS_SMARTY_CACHE'),
'smartyCompilation' => Configuration::get('PS_SMARTY_FORCE_COMPILE'),
],
'run' => [
'startTime' => $this->startTime,
'profiler' => $this->profiler,
],
'hooks' => [
'perfs' => $this->hooksPerfs,
'totalHooksTime' => $this->totalHooksTime,
'totalHooksMemory' => $this->totalHooksMemory,
],
'modules' => [
'perfs' => $this->getFormattedModulePerfs(),
'totalHooksTime' => $this->totalModulesTime,
'totalHooksMemory' => $this->totalModulesMemory,
],
'stopwatchQueries' => $this->queries,
'doublesQueries' => $doublesQueries,
'tableStress' => $tableStress,
'objectmodel' => ObjectModel::$debug_list,
'files' => get_included_files(),
];
}
}

86
tools/profiling/Tools.php Normal file
View File

@@ -0,0 +1,86 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
class Tools extends ToolsCore
{
public static function redirect($url, $base_uri = __PS_BASE_URI__, ?Link $link = null, $headers = null)
{
if (!$link) {
$link = Context::getContext()->link;
}
if (!preg_match('@^https?://@i', $url) && $link) {
if (strpos($url, $base_uri) === 0) {
$url = substr($url, strlen($base_uri));
}
if (strpos($url, 'index.php?controller=') === 0) {
$url = substr($url, strlen('index.php?controller='));
if (Configuration::get('PS_REWRITING_SETTINGS')) {
$url = static::strReplaceFirst('&', '?', $url);
}
}
$explode = explode('?', $url);
// don't use ssl if url is home page, used when logout for example
$use_ssl = !empty($url);
$url = $link->getPageLink($explode[0], $use_ssl);
if (isset($explode[1])) {
$url .= '?' . $explode[1];
}
}
// Send additional headers
if ($headers) {
if (!is_array($headers)) {
$headers = [$headers];
}
foreach ($headers as $header) {
header($header);
}
}
Context::getContext()->controller->setRedirectAfter($url);
}
public static function getDefaultControllerClass()
{
if (isset(Context::getContext()->employee) && Validate::isLoadedObject(Context::getContext()->employee) && isset(Context::getContext()->employee->default_tab)) {
$default_controller = Tab::getClassNameById((int) Context::getContext()->employee->default_tab);
}
if (empty($default_controller)) {
$default_controller = 'AdminDashboard';
}
$controllers = Dispatcher::getControllers([_PS_ADMIN_CONTROLLER_DIR_, _PS_OVERRIDE_DIR_ . 'controllers/admin/']);
if (!isset($controllers[strtolower($default_controller)])) {
$default_controller = 'adminnotfound';
}
$controller_class = $controllers[strtolower($default_controller)];
return $controller_class;
}
public static function redirectLink($url)
{
static::redirect($url);
}
public static function redirectAdmin($url)
{
if (!is_object(Context::getContext()->controller)) {
try {
$controller = Controller::getController(static::getDefaultControllerClass());
$controller->setRedirectAfter($url);
$controller->run();
Context::getContext()->controller = $controller;
die;
} catch (PrestaShopException $e) {
$e->displayMessage();
}
} else {
Context::getContext()->controller->setRedirectAfter($url);
}
}
}

14
tools/profiling/index.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
/**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*/
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Location: ../');
exit;

View File

@@ -0,0 +1,50 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="col-4">
<table class="table table-condensed">
<tr>
<td>PrestaShop Version</td>
<td>{$configuration.psVersion}</td>
</tr>
<tr>
<td>PHP Version</td>
<td>{$configuration.phpVersion}</td>
</tr>
<tr>
<td>MySQL Version</td>
<td>{$configuration.mysqlVersion}</td>
</tr>
<tr>
<td>Memory Limit</td>
<td>{$configuration.memoryLimit}</td>
</tr>
<tr>
<td>Max Execution Time</td>
<td>{$configuration.maxExecutionTime}s</td>
</tr>
<tr>
<td>Smarty Cache</td>
<td>
{if $configuration.smartyCache}
<span class="success">enabled</span>
{else}
<span class="error">disabled</span>
{/if}
</td>
</tr>
<tr>
<td>Smarty Compilation</td>
<td>
{if $configuration.smartyCompilation == 0}
<span class="success">never recompile</span>
{elseif $configuration.smartyCompilation == 1}
<span class="warning">auto</span>
{else}
<span class="red">force compile</span>
{/if}
</td>
</tr>
</table>
</div>

View File

@@ -0,0 +1,24 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="row">
<h2>
<a name="doubles">Doubles</a>
</h2>
<table class="table table-condensed">
{foreach $doublesQueries as $q => $nb}
{if $nb > 1}
<tr>
<td>
{sql_queries data=$nb}
</td>
<td class="pre">
<pre>{$q}</pre>
</td>
</tr>
{/if}
{/foreach}
</table>
</div>

View File

@@ -0,0 +1,31 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="row">
<h2>
<a name="includedFiles">
Included Files
</a>
</h2>
<table class="table table-condensed">
<tr>
<th>#</th>
<th>Filename</th>
</tr>
{foreach $files as $i => $file}
{$file = str_replace('\\', '/', str_replace(_PS_ROOT_DIR_, '', $file))}
{if (strpos($file, '/tools/profiling/') !== 0)}
<tr>
<td>
{$i}
</td>
<td>
{$file}
</td>
</tr>
{/if}
{/foreach}
</table>
</div>

View File

@@ -0,0 +1,16 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{include file="./functions/load-time.tpl"}
{include file="./functions/memory.tpl"}
{include file="./functions/mysql-version.tpl"}
{include file="./functions/objectmodel.tpl"}
{include file="./functions/peak-memory.tpl"}
{include file="./functions/php-version.tpl"}
{include file="./functions/rows-browsed.tpl"}
{include file="./functions/sql-queries.tpl"}
{include file="./functions/table.tpl"}
{include file="./functions/time.tpl"}
{include file="./functions/total-queries.tpl"}
{include file="./functions/total-querying-time.tpl"}

View File

@@ -0,0 +1,14 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=load_time}
{if $data > 1.6}
<span class="danger">{round($data * 1000)}</span>
{elseif $data > 0.8}
<span class="warning">{round($data * 1000)}</span>
{else}
<span class="success">{sprintf('%01.3f', $data * 1000)}</span>
{/if}
ms
{/function}

View File

@@ -0,0 +1,17 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=memory}
{$data = round($data / 1048576, 2)}
{if $data > 3}
<span class="danger">{$data|string_format:"%0.2f"}</span>
{elseif $data > 1}
<span class="warning">{$data|string_format:"%0.2f"}</span>
{elseif round($data, 2) > 0}
<span class="success">{$data|string_format:"%0.2f"}</span>
{else}
<span class="success">-</span>
{/if}
Mb
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=mysql_version}
{if version_compare($version, '5.6') < 0}
<span class="danger">{$data} (Upgrade strongly recommended)</span>
{elseif version_compare($version, '5.7') < 0}
<span class="warning">{$data} (Consider upgrading)</span>
{else}
<span class="success">{$data} (OK)</span>
{/if}
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=objectmodel}
{if $data > 50}
<span class="danger">{$data}</span>
{elseif $data > 10}
<span class="warning">{$data}</span>
{else}
<span class="success">{$data}</span>
{/if}
{/function}

View File

@@ -0,0 +1,16 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=peak_memory}
{$data = round($data / 1048576, 2)}
{if $data > 16}
<span class="danger">{$data|string_format:"%0.1f"}</span>
{elseif $data > 12}
<span class="warning">{$data|string_format:"%0.1f"}</span>
{else}
<span class="success">{$data|string_format:"%0.1f"}</span>
{/if}
Mb
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=php_version}
{if version_compare($version, '8.1') <= 0}
<span class="danger">{$data} (Upgrade strongly recommended)</span>
{elseif version_compare($version, '8.2') <= 0}
<span class="warning">{$data} (Consider upgrading)</span>
{else}
<span class="success">{$data} (OK)</span>
{/if}
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=rows_browsed}
{if $data > 400}
<span class="danger">{$data} rows browsed</span>
{elseif $data > 100}
<span class="warning">{$data} rows browsed</span>
{else}
<span class="success">{$data} rows browsed</span>
{/if}
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=sql_queries}
{if $data > 150}
<span class="danger">{$data} queries</span>
{elseif $data > 100}
<span class="warning">{$data} queries</span>
{else}
<span class="success">{$data} queries</span>
{/if}
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=table}
{if $data > 30}
<span class="danger">{$data}</span>
{elseif $data > 20}
<span class="warning">{$data}</span>
{else}
<span class="success">{$data}</span>
{/if}
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=time}
{if $data > 4}
<span class="danger">{$data}</span>
{elseif $data > 2}
<span class="warning">{$data}</span>
{else}
<span class="success">{$data}</span>
{/if}
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=total_queries}
{if $data >= 100}
<span class="danger">{$data}</span>
{elseif $data >= 50}
<span class="warning">{$data}</span>
{else}
<span class="success">{$data}</span>
{/if}
{/function}

View File

@@ -0,0 +1,13 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{function name=total_querying_time}
{if $data >= 100}
<span class="danger">{$data}</span>
{elseif $data >= 50}
<span class="warning">{$data}</span>
{else}
<span class="success">{$data}</span>
{/if}
{/function}

View File

@@ -0,0 +1,53 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="col-5">
<table class="table table-condensed">
<thead>
<tr>
<th>Hook</th>
<th>Time</th>
<th>Memory Usage</th>
</tr>
</thead>
<tbody>
{foreach $hooks.perfs as $hook => $hooksPerfs}
<tr>
<td>
<a href="javascript:void(0);" onclick="$('.{$hook}_modules_details').toggle();">{$hook}</a>
</td>
<td>
{load_time data=$hooksPerfs['time']}
</td>
<td>
{memory data=$hooksPerfs['memory']}
</td>
</tr>
{foreach $hooksPerfs['modules'] as $perfs}
<tr class="{$hook}_modules_details" style="background-color:#EFEFEF;display:none">
<td>
=&gt; {$perfs['module']}
</td>
<td>
{load_time data=$perfs['time']}
</td>
<td>
{memory data=$perfs['memory']}
</td>
</tr>
{/foreach}
{/foreach}
</tbody>
<tfoot>
<tr>
<th><b>{$hooks.perfs|count} hook(s)</b></th>
<th>{load_time data=$hooks.totalHooksTime}</th>
<th>{memory data=$hooks.totalHooksMemory}</th>
</tr>
</tfoot>
</table>
</div>

View File

@@ -0,0 +1,28 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div id="profiling-links">
<span>Profiling</span>
<ol>
<li>
<a href="#summary">Summary</a>
</li>
<li>
<a href="#stopwatch">Stopwatch SQL</a>
</li>
<li>
<a href="#doubles">Doubles</a>
</li>
<li>
<a href="#tables">Tables stress</a>
</li>
<li>
<a href="#objectModels">ObjectModel instances</a>
</li>
<li>
<a href="#includedFiles">Included Files</a>
</li>
</ol>
</div>

View File

@@ -0,0 +1,75 @@
{**
* 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)
*}
<div class="col-5">
<table class="table table-condensed">
<thead>
<tr>
<th>Module</th>
<th>Time</th>
<th>Memory Usage</th>
</tr>
</thead>
<tbody>
{foreach $modules.perfs as $moduleName => $perfs}
<tr>
<td>
<a href="javascript:void(0);" onclick="$('.{$moduleName}_modules_details').toggle();">{$moduleName}</a>
</td>
</td>
<td>
{load_time data=$perfs['total_time']}
</td>
<td>
{memory data=$perfs['total_memory']}
</td>
</tr>
{foreach $perfs['details'] as $perfs}
<tr class="{$moduleName}_modules_details" style="background-color:#EFEFEF;display:none">
<td>
{$perfs['method']}
</td>
<td>
{load_time data=$perfs['time']}
</td>
<td>
{memory data=$perfs['memory']}
</td>
</tr>
{/foreach}
{/foreach}
</tbody>
<tfoot>
<tr>
<th><b>{$modules.perfs|count} module(s)</b></th>
<th>{load_time data=$modules.totalHooksTime}</th>
<th>{memory data=$modules.totalHooksMemory}</th>
</tr>
</tfoot>
</table>
</div>

View File

@@ -0,0 +1,38 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="row">
<h2>
<a name="objectModels">
ObjectModel instances
</a>
</h2>
<table class="table table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Instances</th>
<th>Source</th>
</tr>
</thead>
<tbody>
{foreach $objectmodel as $class => $info}
<tr>
<td>{$class}</td>
<td>
{objectmodel data=count($info)}
</td>
<td>
{foreach $info as $trace}
{str_replace([_PS_ROOT_DIR_, '\\'], ['', '/'], $trace['file'])}:{$trace['line']} ({$trace['function']}) [id: {$trace['id']}]
<br />
{/foreach}
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>

View File

@@ -0,0 +1,25 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
{include file="./functions.tpl"}
{include file="./styles.tpl"}
<div id="prestashop-profiling" class="container">
{include file="./links.tpl"}
<div class="row">
{include file="./summary.tpl" summary=$summary}
{include file="./configuration.tpl" configuration=$configuration}
{include file="./run.tpl" run=$run}
</div>
<div class="row">
{include file="./hooks.tpl" hooks=$hooks}
{include file="./modules.tpl" modules=$modules}
</div>
{include file="./stopwatch.tpl" stopwatchQueries=$stopwatchQueries}
{include file="./doubles.tpl" doublesQueries=$doublesQueries}
{include file="./table-stress.tpl" tableStress=$tableStress}
{include file="./objectmodel.tpl" objectmodel=$objectmodel}
{include file="./files.tpl" files=$files}
</div>

View File

@@ -0,0 +1,21 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<html>
<head>
<meta charset="utf-8" />
<script src="//code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="container" style="width:100%">
<div class="row">
<div class="col-lg-12">
<h2>Caught redirection to <a href="{$redirectAfter}">{$redirectAfter}</a></h2>
</div>
</div>
</div>
</body>
</html>

View File

@@ -0,0 +1,37 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="col-4">
<table class="table table-condensed">
<thead>
<tr>
<th>&nbsp;</th>
<th>Time</th>
<th>Cumulated Time</th>
<th>Memory Usage</th>
<th>Memory Peak Usage</th>
</tr>
</thead>
<tbody>
{assign var="last" value=['time' => $run.startTime, 'memory_usage' => 0]}
{foreach from=$run.profiler item=row}
{if $row['block'] == 'checkAccess' && $row['time'] == $last['time']}
{continue}
{/if}
<tr>
<td>{$row['block']}</td>
<td>{load_time data=($row['time'] - $last['time'])}</td>
<td>{load_time data=($row['time'] - $run.startTime)}</td>
<td>{memory data=($row['memory_usage'] - $last['memory_usage'])}</td>
<td>{peak_memory data=($row['peak_memory_usage'])}</td>
</tr>
{assign var="last" value=$row}
{/foreach}
</tbody>
</table>
</div>

View File

@@ -0,0 +1,58 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="row">
<h2>
<a name="stopwatch">
Stopwatch SQL - {$summary.nbQueries} queries
</a>
</h2>
<table class="table table-condensed table-bordered sortable">
<thead>
<tr>
<th>#</th>
<th>Query</th>
<th>Time (ms)</th>
<th>Rows</th>
<th>Filesort</th>
<th>Group By</th>
<th>Location</th>
</tr>
</thead>
<tbody>
{foreach $stopwatchQueries as $data}
{$callstack = implode('<br>', $data['stack'])}
{$callstack_md5 = md5($callstack)}
<tr>
<td>{$data['id']}</td>
<td class="pre" style="max-width: 60vw"><pre>{preg_replace("/(^[\s]*)/m", "", htmlspecialchars($data['query'], ENT_NOQUOTES, 'utf-8', false))}</pre></td>
<td data-value="{sprintf('%01.6f', $data['time'])}">
{load_time data=($data['time'])}
</td>
<td>{$data['rows']}</td>
<td data-value="{$data['filesort']}">
{if $data['filesort']}
<span class="danger">Yes</span>
{/if}
</td>
<td data-value="{$data['group_by']}">
{if $data['group_by']}
<span class="danger"">Yes</span>
{/if}
</td>
<td data-value="{$data['location']}">
<a href="javascript:void(0);" onclick="$('#callstack_{$callstack_md5}').toggle();">{$data['location']}</a>
<div id="callstack_{$callstack_md5}" style="display:none">
{foreach $data['stack'] as $stack}
{$stack}<br/>
{/foreach}
</div>
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>

View File

@@ -0,0 +1,166 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<style>
#prestashop-profiling {
max-width: 100%;
padding: 20px;
}
.ps_back-office.page-sidebar #prestashop-profiling {
margin-left: 210px;
}
.ps_back-office.page-sidebar-closed #prestashop-profiling {
margin-left: 50px;
}
.ps_back-office #prestashop-profiling {
clear: both;
padding: 10px;
margin-bottom: 50px;
}
#prestashop-profiling * {
box-sizing:border-box;
-moz-box-sizing:border-box;
}
#prestashop-profiling .table {
width: 100%;
}
#prestashop-profiling .table td,
#prestashop-profiling .table th {
padding: 6.4px;
padding: .4rem;
vertical-align: top;
border-top: 1px solid #bbcdd2;
vertical-align: middle;
text-align: left;
}
#prestashop-profiling .table th {
padding-top: 0.625rem;
padding-bottom: 0.625rem;
}
#prestashop-profiling .table thead th {
border-bottom: .125rem solid #25b9d7;
}
#prestashop-profiling .table tfoot th {
border-top: .125rem solid #25b9d7;
}
#prestashop-profiling .sortable thead th {
cursor:pointer;
}
#prestashop-profiling .table td .pre {
padding: 6px;
margin-right: 10px;
overflow: auto;
display: block;
color: #777;
font-size: 12px;
line-height: 1.42857;
word-break: break-all;
word-wrap: break-word;
background-color: whitesmoke;
border: 1px solid #cccccc;
max-width: 960px;
}
#prestashop-profiling .row {
clear: both;
margin-bottom: 20px;
}
#prestashop-profiling .col-4 {
float: left;
padding: 0 10px;
width: 33%;
}
@media (max-width: 1200px) {
#prestashop-profiling .col-4 {
width: 50%;
}
}
@media (max-width: 600px) {
#prestashop-profiling .col-4 {
width: 100%;
}
}
#prestashop-profiling .col-5 {
float: left;
padding: 0 10px;
width: 40%;
}
@media (max-width: 1200px) {
#prestashop-profiling .col-5 {
width: 50%;
}
}
@media (max-width: 600px) {
#prestashop-profiling .col-5 {
width: 100%;
}
}
#prestashop-profiling .col-2 {
float: left;
padding: 0 10px;
width: 20%;
}
@media (max-width: 1200px) {
#prestashop-profiling .col-2 {
width: 20%;
}
}
@media (max-width: 600px) {
#prestashop-profiling .col-2 {
width: 100%;
}
}
#profiling-links {
display: flex;
width: fit-content;
position: fixed;
top: 0;
right: 0;
transform: translateX(calc(100% - 38px));
padding: 10px;
background: #EEE;
z-index: 10000;
transition: transform ease-in-out .2s;
}
#profiling-links:hover {
left: unset;
transform: translateX(0);
}
#profiling-links span {
writing-mode: vertical-rl;
text-orientation: mixed;
}
#profiling-links ol {
padding-left: 25px;
}
.success {
color: green;
}
.danger {
color: red;
}
.warning {
color: #EF8B00;
}
</style>
<script type="text/javascript" src="https://cdn.rawgit.com/drvic10k/bootstrap-sortable/1.11.2/Scripts/bootstrap-sortable.js"></script>

View File

@@ -0,0 +1,73 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="col-4" id="summary">
<table class="table table-condensed">
<tr>
<td>
Load Time
</td>
<td>
{load_time data=$summary.loadTime}
</td>
</tr>
<tr>
<td>Querying Time</td>
<td>
{total_querying_time data=$summary.queryTime} ms
</td>
</tr>
<tr>
<td>
Queries
</td>
<td>
{total_queries data=$summary.nbQueries}
</td>
</tr>
<tr>
<td>
Memory Peak Usage
</td>
<td>
{peak_memory data=$summary.peakMemoryUsage}
</td>
</tr>
<tr>
<td>
Included Files
</td>
<td>
{$summary.includedFiles} files - {memory data=$summary.totalFileSize}
</td>
</tr>
<tr>
<td>
PrestaShop Cache
</td>
<td>
{memory data=$summary.totalCacheSize}
</td>
</tr>
<tr>
<td>
<a href="javascript:void(0);" onclick="$('.global_vars_detail').toggle();">Global vars</a>
</td>
<td>
{memory data=$summary.totalGlobalVarSize}
</td>
</tr>
{foreach $summary.globalVarSize as $global=>$size}
<tr class="global_vars_detail" style="display:none">
<td>
- global ${$global}
</td>
<td>
{$size}k
</td>
</tr>
{/foreach}
</table>
</div>

View File

@@ -0,0 +1,16 @@
{**
* For the full copyright and license information, please view the
* docs/licenses/LICENSE.txt file that was distributed with this source code.
*}
<div class="row">
<h2><a name="tables">Tables stress</a></h2>
<table class="table table-condensed">
{foreach $tableStress as $table => $nb}
<tr>
<td>
{table data=$nb} {$table}
</td>
</tr>
{/foreach}
</table>
</div>