* @copyright 2007-2014 PrestaShop SA
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
* International Registered Trademark & Property of PrestaShop SA
*/
function developpementErrorHandler($errno, $errstr, $errfile, $errline)
{
if (!(error_reporting() & $errno))
return;
switch($errno)
{
case E_ERROR:
echo '[PHP Error #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_WARNING:
echo '[PHP Warning #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_PARSE:
echo '[PHP Parse #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_NOTICE:
echo '[PHP Notice #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_CORE_ERROR:
echo '[PHP Core #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_CORE_WARNING:
echo '[PHP Core warning #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_COMPILE_ERROR:
echo '[PHP Compile #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_COMPILE_WARNING:
echo '[PHP Compile warning #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_USER_ERROR:
echo '[PHP Error #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_USER_WARNING:
echo '[PHP User warning #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_USER_NOTICE:
echo '[PHP User notice #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_STRICT:
echo '[PHP Strict #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
case E_RECOVERABLE_ERROR:
echo '[PHP Recoverable error #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
break;
default:
echo '[PHP Unknown error #'.$errno.'] '.$errstr.' ('.$errfile.', line '.$errline.')';
}
die;
return true;
}
abstract class Controller extends ControllerCore
{
public $_memory = array();
public $_time = array();
private static $_footer = true;
public static function disableParentCalls()
{
self::$_footer = false;
}
private function displayMemoryColor($n)
{
$n /= 1048576;
if ($n > 3)
return ''.sprintf('%0.2f', $n).'';
if ($n > 1)
return ''.sprintf('%0.2f', $n).'';
return ''.sprintf('%0.2f', $n).'';
}
private function displayPeakMemoryColor($n)
{
$n /= 1048576;
if ($n > 16)
return ''.sprintf('%0.1f', $n).'';
if ($n > 12)
return ''.sprintf('%0.1f', $n).'';
return ''.sprintf('%0.1f', $n).'';
}
private function displaySQLQueries($n)
{
if ($n > 150)
return ''.$n.' queries';
if ($n > 100)
return ''.$n.' queries';
return ''.$n.' quer'.($n == 1 ? 'y' : 'ies').'';
}
private function displayRowsBrowsed($n)
{
if ($n > 400)
return ''.$n.' rows browsed';
if ($n > 100)
return ''.$n.' rows browsed';
return ''.$n.' row'.($n == 1 ? '' : 's').' browsed';
}
private function displayLoadTimeColor($n, $kikoo = false)
{
if ($n > 1)
return ''.round($n * 1000).''.($kikoo ? ' ms
You\'d better run your shop on a toaster' : '');
if ($n > 0.5)
return ''.round($n * 1000).''.($kikoo ? ' ms
I hope it is a shared hosting' : '');
return ''.round($n * 1000).''.($kikoo ? ' ms
Good boy! That\'s what I call a webserver!' : '');
}
private function getTimeColor($n)
{
if ($n > 4)
return 'style="color:red"';
if ($n > 2)
return 'style="color:orange"';
return 'style="color:green"';
}
private function getQueryColor($n)
{
if ($n > 5)
return 'style="color:red"';
if ($n > 2)
return 'style="color:orange"';
return 'style="color:green"';
}
private function getTableColor($n)
{
if ($n > 30)
return 'style="color:red"';
if ($n > 20)
return 'style="color:orange"';
return 'style="color:green"';
}
private function getObjectModelColor($n)
{
if ($n > 50)
return 'style="color:red"';
if ($n > 10)
return 'style="color:orange"';
return 'style="color:green"';
}
public function __construct()
{
//set_error_handler('developpementErrorHandler');
ini_set('html_errors', 'on');
ini_set('display_errors', 'on');
error_reporting(E_ALL | E_STRICT);
if (!self::$_footer)
return;
$this->_memory['config'] = memory_get_usage();
$this->_mempeak['config'] = memory_get_peak_usage();
$this->_time['config'] = microtime(true);
parent::__construct();
$this->_memory['constructor'] = memory_get_usage();
$this->_mempeak['constructor'] = memory_get_peak_usage();
$this->_time['constructor'] = microtime(true);
}
public function run()
{
$this->init();
$this->_memory['init'] = memory_get_usage();
$this->_mempeak['init'] = memory_get_peak_usage();
$this->_time['init'] = microtime(true);
if ($this->checkAccess())
{
$this->_memory['checkAccess'] = memory_get_usage();
$this->_mempeak['checkAccess'] = memory_get_peak_usage();
$this->_time['checkAccess'] = microtime(true);
if (!$this->content_only && ($this->display_header || (isset($this->className) && $this->className)))
$this->setMedia();
$this->_memory['setMedia'] = memory_get_usage();
$this->_mempeak['setMedia'] = memory_get_peak_usage();
$this->_time['setMedia'] = microtime(true);
// postProcess handles ajaxProcess
$this->postProcess();
$this->_memory['postProcess'] = memory_get_usage();
$this->_mempeak['postProcess'] = memory_get_peak_usage();
$this->_time['postProcess'] = microtime(true);
if (!empty($this->redirect_after))
$this->redirect();
if (!$this->content_only && ($this->display_header || (isset($this->className) && $this->className)))
$this->initHeader();
$this->_memory['initHeader'] = memory_get_usage();
$this->_mempeak['initHeader'] = memory_get_peak_usage();
$this->_time['initHeader'] = microtime(true);
$this->initContent();
$this->_memory['initContent'] = memory_get_usage();
$this->_mempeak['initContent'] = memory_get_peak_usage();
$this->_time['initContent'] = microtime(true);
if (!$this->content_only && ($this->display_footer || (isset($this->className) && $this->className)))
$this->initFooter();
$this->_memory['initFooter'] = memory_get_usage();
$this->_mempeak['initFooter'] = memory_get_peak_usage();
$this->_time['initFooter'] = microtime(true);
// default behavior for ajax process is to use $_POST[action] or $_GET[action]
// then using displayAjax[action]
if ($this->ajax)
{
$action = Tools::getValue('action');
if (!empty($action) && method_exists($this, 'displayAjax'.Tools::toCamelCase($action)))
$this->{'displayAjax'.$action}();
elseif (method_exists($this, 'displayAjax'))
$this->displayAjax();
}
else
$this->displayDebug();
}
else
{
$this->initCursedPage();
$this->displayDebug();
}
}
function ini_get_display_errors()
{
$a = 'display_errors';
$b = ini_get($a);
switch (strtolower($b))
{
case 'on':
case 'yes':
case 'true':
return 'assert.active' !== $a;
case 'stdout':
case 'stderr':
return 'display_errors' === $a;
default:
return (bool)(int)$b;
}
}
private function sizeofvar($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;
}
private function getVarData($var)
{
if (is_object($var))
return $var;
return (string)$var;
}
public function displayDebug()
{
global $start_time;
$this->display();
$this->_memory['display'] = memory_get_usage();
$this->_mempeak['display'] = memory_get_peak_usage();
$this->_time['display'] = microtime(true);
if (!$this->ini_get_display_errors())
return;
$memory_peak_usage = memory_get_peak_usage();
$hr = '
';
$totalSize = 0;
foreach (get_included_files() as $file)
$totalSize += filesize($file);
$totalQueryTime = 0;
foreach (Db::getInstance()->queries as $data)
$totalQueryTime += $data['time'];
$executedModules = Hook::getExecutedModules();
$hooktime = Hook::getHookTime();
arsort($hooktime);
$totalHookTime = 0;
foreach ($hooktime as $time)
$totalHookTime += $time;
$hookMemoryUsage = Hook::getHookMemoryUsage();
arsort($hookMemoryUsage);
$totalHookMemoryUsage = 0;
foreach ($hookMemoryUsage as $usage)
$totalHookMemoryUsage += $usage;
$globalSize = array();
$totalGlobalSize = 0;
foreach ($GLOBALS as $key => $value)
if ($key != 'GLOBALS')
{
$totalGlobalSize += ($size = $this->sizeofvar($value));
if ($size > 1024)
$globalSize[$key] = round($size / 1024, 1);
}
arsort($globalSize);
$cache = Cache::retrieveAll();
$totalCacheSize = $this->sizeofvar($cache);
echo '
';
echo '
Load time: '.$this->displayLoadTimeColor($this->_time['display'] - $start_time, true).'
';
if (self::$_footer){
echo '
';
echo 'Execution | Load time (ms) |
';
$last_time = $start_time;
foreach ($this->_time as $k => $time)
{
echo ''.$k.' | '.$this->displayLoadTimeColor($time - $last_time).' |
';
$last_time = $time;
}
echo '
';
}
echo '
Hook processing: '.$this->displayLoadTimeColor($totalHookTime).' ms / '.$this->displayMemoryColor($totalHookMemoryUsage).' Mb
'.(int)count($executedModules).' methods called in '.(int)count(array_unique($executedModules)).' modules
';
echo '
';
echo 'Hook | Processing |
';
foreach ($hooktime as $hook => $time)
echo ''.$hook.' | '.$this->displayMemoryColor($hookMemoryUsage[$hook]).' Mb in '.$this->displayLoadTimeColor($time).' ms |
';
echo '
Memory peak usage: '.$this->displayPeakMemoryColor($memory_peak_usage).' Mb
';
if (self::$_footer)
{
echo '
';
echo 'Execution | Memory (Mb) | Total (Mb) |
';
$last_memory = 0;
foreach ($this->_memory as $k => $memory)
{
echo ''.$k.' | '.$this->displayMemoryColor($memory - $last_memory).' | '.$this->displayPeakMemoryColor($this->_mempeak[$k]).' |
';
$last_memory = $memory;
}
echo '
';
}
echo '
';
echo '
Total cache size (in Cache class): '.$this->displayMemoryColor($totalCacheSize).' Mb
DB type: '.get_class(Db::getInstance()).'
SQL Queries: '.$this->displaySQLQueries(count(Db::getInstance()->queries)).'
Time spent querying: '.$this->displayLoadTimeColor($totalQueryTime).' ms
Included files: '.sizeof(get_included_files()).'
Size of included files: '.$this->displayMemoryColor($totalSize).' Mb
Globals (> 1 Ko only): '.round($totalGlobalSize / 1024).' Ko
';
foreach ($globalSize as $global => $size)
echo '- '.$global.' ≈ '.$size.' Ko
';
echo '
';
$array_queries = array();
$queries = Db::getInstance()->queries;
uasort($queries, 'prestashop_querytime_sort');
foreach ($queries as $data)
{
$query_row = array(
'time' => $data['time'],
'query' => $data['query'],
'location' => $data['stack'][0]['file'].':'.$data['stack'][0]['line'],
'filesort' => false,
'rows' => 1,
'group_by' => false,
'stack' => $data['stack']
);
if (preg_match('/^\s*select\s+/i', $data['query']))
{
$explain = Db::getInstance()->executeS('explain '.$data['query']);
if (stristr($explain[0]['Extra'], 'filesort'))
$query_row['filesort'] = true;
foreach ($explain as $row)
$query_row['rows'] *= $row['rows'];
if (stristr($data['query'], 'group by') && !preg_match('/(avg|count|min|max|group_concat|sum)\s*\(/i', $data['query']))
$query_row['group_by'] = true;
}
$array_queries[] = $query_row;
}
echo '
';
echo '
Stopwatch (with SQL_NO_CACHE) (total = '.count(Db::getInstance()->queries).')';
$i = 1;
echo '
Query |
Time (ms) |
Rows |
Filesort |
Group By |
Location |
';
foreach ($array_queries as $data)
{
$echo_stack = '';
array_shift($data['stack']);
foreach ($data['stack'] as $call)
$echo_stack .= 'from '.str_replace('\\', '/', substr($call['file'], strlen(_PS_ROOT_DIR_))).':'.$call['line'].'
';
echo '';
echo ''.preg_replace("/(^[\s]*)/m", "", htmlspecialchars($data['query'], ENT_NOQUOTES, 'utf-8', false)).' | ';
echo 'getTimeColor($data['time'] * 1000).'>'.round($data['time'] * 1000, 3).' | ';
echo ''.$data['rows'].' | ';
echo ''.($data['filesort'] ? 'Yes' : '').' | ';
echo ''.($data['group_by'] ? 'Yes' : '').' | ';
echo 'in '.$data['location'].'
'.$echo_stack.' | ';
echo '
';
}
echo '
';
$queries = Db::getInstance()->uniqQueries;
arsort($queries);
$count = count(Db::getInstance()->uniqQueries);
foreach ($queries as $q => &$nb)
if ($nb == 1)
$count--;
if ($count)
echo '
Tables stress
';
$tables = Db::getInstance()->tables;
arsort($tables);
foreach ($tables as $table => $nb)
echo 'getTableColor($nb).'>'.$nb.' '.$table.' |
';
echo '
';
if (isset(ObjectModel::$debug_list))
{
echo '
ObjectModel instances';
$list = ObjectModel::$debug_list;
uasort($list, create_function('$a,$b', 'return (count($a) < count($b)) ? 1 : -1;'));
$i = 0;
echo '
Name | Instance | Source |
';
foreach ($list as $class => $info)
{
echo ''.$class.' | ';
echo 'getObjectModelColor(count($info)).'>'.count($info).' | ';
echo '';
foreach ($info as $trace)
echo ltrim(str_replace(array(_PS_ROOT_DIR_, '\\'), array('', '/'), $trace['file']), '/').' ['.$trace['line'].'] ';
echo ' |
';
$i++;
}
echo '
';
}
// List of included files
echo '
Included files
';
$i = 1;
echo '# | Filename |
';
foreach (get_included_files() as $file)
{
$file = ltrim(str_replace('\\', '/', str_replace(_PS_ROOT_DIR_, '', $file)), '/');
$file = ''.dirname($file).'/'.basename($file).'';
echo ''.$i.' | '.$file.' |
';
$i++;
}
echo '
';
}
}
function prestashop_querytime_sort($a, $b)
{
if ($a['time'] == $b['time'])
return 0;
return ($a['time'] > $b['time']) ? -1 : 1;
}