Some security improvements 🔑 (#1503)

* Some security improvements 🔑

* Update .env.example

* Update Dev.php

* Update CHANGELOG.md

* Update Dev.php

* Update Ajax.php

* Update SqlDb.php

* Updated

* Updated

* Update Dev.php

* Update page_header.tpl

* Updated

* Updated

* Update CHANGELOG.md
This commit is contained in:
Roman Kelesidis 2024-06-10 16:55:55 +07:00 committed by GitHub
commit 0663f55e54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 117 additions and 83 deletions

View file

@ -1,5 +1,5 @@
# Common params # Common params
APP_ENV=local APP_ENV=production
APP_CRON_ENABLED=true APP_CRON_ENABLED=true
APP_DEMO_MODE=false APP_DEMO_MODE=false

View file

@ -6,8 +6,10 @@
**Merged pull requests:** **Merged pull requests:**
- Release 2.4.4 🦩 ([belomaxorka](https://github.com/belomaxorka)) - Release 2.4.4 🦩 ([belomaxorka](https://github.com/belomaxorka))
- Some security improvements 🔑 [\#1503](https://github.com/torrentpier/torrentpier/pull/1503) ([belomaxorka](https://github.com/belomaxorka))
- Some improvements for integrity checker [\#1501](https://github.com/torrentpier/torrentpier/pull/1501) ([belomaxorka](https://github.com/belomaxorka)) - Some improvements for integrity checker [\#1501](https://github.com/torrentpier/torrentpier/pull/1501) ([belomaxorka](https://github.com/belomaxorka))
- Minor improvements [\#1502](https://github.com/torrentpier/torrentpier/pull/1502) ([belomaxorka](https://github.com/belomaxorka)) - Minor improvements [\#1502](https://github.com/torrentpier/torrentpier/pull/1502) ([belomaxorka](https://github.com/belomaxorka))
- New Crowdin updates [\#1504](https://github.com/torrentpier/torrentpier/pull/1504) ([Exileum](https://github.com/Exileum))
## [v2.4.3](https://github.com/torrentpier/torrentpier/tree/v2.4.3) (2024-06-09) ## [v2.4.3](https://github.com/torrentpier/torrentpier/tree/v2.4.3) (2024-06-09)
[Full Changelog](https://github.com/torrentpier/torrentpier/compare/v2.4.2...v2.4.3) [Full Changelog](https://github.com/torrentpier/torrentpier/compare/v2.4.2...v2.4.3)

View file

@ -65,7 +65,6 @@ define('XS_TAG_ENDIF', 8);
define('XS_TAG_BEGINELSE', 11); define('XS_TAG_BEGINELSE', 11);
// Debug // Debug
define('APP_DEBUG', true); // enable application debug
define('SQL_DEBUG', true); // enable forum sql & cache debug define('SQL_DEBUG', true); // enable forum sql & cache debug
define('SQL_LOG_ERRORS', true); // all SQL_xxx options enabled only if SQL_DEBUG == TRUE define('SQL_LOG_ERRORS', true); // all SQL_xxx options enabled only if SQL_DEBUG == TRUE
define('SQL_BB_LOG_NAME', 'sql_error_bb'); // mysql log filename (Board) define('SQL_BB_LOG_NAME', 'sql_error_bb'); // mysql log filename (Board)

View file

@ -11,7 +11,7 @@ if (!defined('BB_ROOT')) {
die(basename(__FILE__)); die(basename(__FILE__));
} }
global $bb_cfg, $userdata, $template, $DBS, $lang; global $bb_cfg, $debug, $userdata, $template, $DBS, $lang;
if (!empty($template)) { if (!empty($template)) {
$template->assign_vars([ $template->assign_vars([
@ -25,7 +25,7 @@ if (!empty($template)) {
$template->pparse('page_footer'); $template->pparse('page_footer');
} }
$show_dbg_info = (APP_DEBUG && !(isset($_GET['pane']) && $_GET['pane'] == 'left')); $show_dbg_info = (!$debug->isProduction && !(isset($_GET['pane']) && $_GET['pane'] == 'left'));
if (!$bb_cfg['gzip_compress']) { if (!$bb_cfg['gzip_compress']) {
flush(); flush();

View file

@ -71,7 +71,7 @@ if (!empty($_COOKIE['explain'])) {
} }
} }
$sql_log = !empty($_COOKIE['sql_log']) ? \TorrentPier\Dev::get_sql_log() : false; $sql_log = !empty($_COOKIE['sql_log']) ? $debug->getSqlLog() : false;
if ($sql_log) { if ($sql_log) {
echo '<div class="sqlLog" id="sqlLog">' . $sql_log . '</div><!-- / sqlLog --><br clear="all" />'; echo '<div class="sqlLog" id="sqlLog">' . $sql_log . '</div><!-- / sqlLog --><br clear="all" />';

View file

@ -170,14 +170,16 @@ class Ajax
/** /**
* Send data * Send data
* *
* @return void
* @throws Exception * @throws Exception
*/ */
public function send() public function send(): void
{ {
global $debug;
$this->response['action'] = $this->action; $this->response['action'] = $this->action;
if (Dev::sql_dbg_enabled()) { if ($debug->sqlDebugAllowed()) {
$this->response['sql_log'] = Dev::get_sql_log(); $this->response['sql_log'] = $debug->getSqlLog();
} }
// sending output will be handled by $this->ob_handler() // sending output will be handled by $this->ob_handler()
@ -193,7 +195,9 @@ class Ajax
*/ */
public function ob_handler($contents): string public function ob_handler($contents): string
{ {
if (APP_DEBUG) { global $debug;
if (!$debug->isProduction) {
if ($contents) { if ($contents) {
$this->response['raw_output'] = $contents; $this->response['raw_output'] = $contents;
} }

View file

@ -37,7 +37,14 @@ class Dev
* *
* @var string * @var string
*/ */
public string $envType = 'local'; private string $envType;
/**
* In production mode
*
* @var bool
*/
public bool $isProduction = false;
/** /**
* Whoops instance * Whoops instance
@ -51,16 +58,20 @@ class Dev
*/ */
public function __construct() public function __construct()
{ {
$this->envType = env('APP_ENV', 'local'); $this->envType = env('APP_ENV', 'production');
$this->whoops = new Run; $this->whoops = new Run;
switch ($this->envType) { switch ($this->envType) {
case 'prod':
case 'production': case 'production':
ini_set('display_errors', 0); ini_set('display_errors', 0);
ini_set('display_startup_errors', 0); ini_set('display_startup_errors', 0);
$this->getWhoopsProduction(); $this->getWhoopsProduction();
$this->isProduction = true;
break; break;
case 'dev':
case 'local': case 'local':
case 'development':
ini_set('display_errors', 1); ini_set('display_errors', 1);
ini_set('display_startup_errors', 1); ini_set('display_startup_errors', 1);
$this->getWhoops(); $this->getWhoops();
@ -128,10 +139,6 @@ class Dev
*/ */
private function getWhoops(): void private function getWhoops(): void
{ {
if (!APP_DEBUG) {
return;
}
/** /**
* Show errors on page * Show errors on page
*/ */
@ -170,28 +177,28 @@ class Dev
* @return string * @return string
* @throws Exception * @throws Exception
*/ */
public static function get_sql_log(): string public function getSqlLog(): string
{ {
global $DBS, $CACHES, $datastore; global $DBS, $CACHES, $datastore;
$log = ''; $log = '';
foreach ($DBS->srv as $srv_name => $db_obj) { foreach ($DBS->srv as $srv_name => $db_obj) {
$log .= !empty($db_obj->dbg) ? self::get_sql_log_html($db_obj, "database: $srv_name [{$db_obj->engine}]") : ''; $log .= !empty($db_obj->dbg) ? $this->getSqlLogHtml($db_obj, "database: $srv_name [{$db_obj->engine}]") : '';
} }
foreach ($CACHES->obj as $cache_name => $cache_obj) { foreach ($CACHES->obj as $cache_name => $cache_obj) {
if (!empty($cache_obj->db->dbg)) { if (!empty($cache_obj->db->dbg)) {
$log .= self::get_sql_log_html($cache_obj->db, "cache: $cache_name [{$cache_obj->db->engine}]"); $log .= $this->getSqlLogHtml($cache_obj->db, "cache: $cache_name [{$cache_obj->db->engine}]");
} elseif (!empty($cache_obj->dbg)) { } elseif (!empty($cache_obj->dbg)) {
$log .= self::get_sql_log_html($cache_obj, "cache: $cache_name [{$cache_obj->engine}]"); $log .= $this->getSqlLogHtml($cache_obj, "cache: $cache_name [{$cache_obj->engine}]");
} }
} }
if (!empty($datastore->db->dbg)) { if (!empty($datastore->db->dbg)) {
$log .= self::get_sql_log_html($datastore->db, "cache: datastore [{$datastore->db->engine}]"); $log .= $this->getSqlLogHtml($datastore->db, "cache: datastore [{$datastore->db->engine}]");
} elseif (!empty($datastore->dbg)) { } elseif (!empty($datastore->dbg)) {
$log .= self::get_sql_log_html($datastore, "cache: datastore [{$datastore->engine}]"); $log .= $this->getSqlLogHtml($datastore, "cache: datastore [{$datastore->engine}]");
} }
return $log; return $log;
@ -202,9 +209,40 @@ class Dev
* *
* @return bool * @return bool
*/ */
public static function sql_dbg_enabled(): bool public function sqlDebugAllowed(): bool
{ {
return (SQL_DEBUG && APP_DEBUG && !empty($_COOKIE['sql_log'])); return (SQL_DEBUG && !$this->isProduction && !empty($_COOKIE['sql_log']));
}
/**
* Get SQL query html log
*
* @param object $db_obj
* @param string $log_name
*
* @return string
* @throws Exception
*/
private function getSqlLogHtml(object $db_obj, string $log_name): string
{
$log = '';
foreach ($db_obj->dbg as $i => $dbg) {
$id = "sql_{$i}_" . random_int(0, mt_getrandmax());
$sql = $this->shortQuery($dbg['sql'], true);
$time = sprintf('%.4f', $dbg['time']);
$perc = '[' . round($dbg['time'] * 100 / $db_obj->sql_timetotal) . '%]';
$info = !empty($dbg['info']) ? $dbg['info'] . ' [' . $dbg['src'] . ']' : $dbg['src'];
$log .= '<div onmouseout="$(this).removeClass(\'sqlHover\');" onmouseover="$(this).addClass(\'sqlHover\');" onclick="$(this).toggleClass(\'sqlHighlight\');" class="sqlLogRow" title="' . $info . '">'
. '<span style="letter-spacing: -1px;">' . $time . ' </span>'
. '<span class="copyElement" data-clipboard-target="#' . $id . '" title="Copy to clipboard" style="color: rgb(128,128,128); letter-spacing: -1px;">' . $perc . '</span>&nbsp;'
. '<span style="letter-spacing: 0;" id="' . $id . '">' . $sql . '</span>'
. '<span style="color: rgb(128,128,128);"> # ' . $info . ' </span>'
. '</div>';
}
return '<div class="sqlLogTitle">' . $log_name . '</div>' . $log;
} }
/** /**
@ -214,7 +252,7 @@ class Dev
* @param bool $esc_html * @param bool $esc_html
* @return string * @return string
*/ */
public static function short_query(string $sql, bool $esc_html = false): string public function shortQuery(string $sql, bool $esc_html = false): string
{ {
$max_len = 100; $max_len = 100;
$sql = str_compact($sql); $sql = str_compact($sql);
@ -227,40 +265,4 @@ class Dev
return $esc_html ? htmlCHR($sql, true) : $sql; return $esc_html ? htmlCHR($sql, true) : $sql;
} }
/**
* Get SQL query html log
*
* @param object $db_obj
* @param string $log_name
*
* @return string
* @throws Exception
*/
private static function get_sql_log_html(object $db_obj, string $log_name): string
{
$log = '';
foreach ($db_obj->dbg as $i => $dbg) {
$id = "sql_{$i}_" . random_int(0, mt_getrandmax());
$sql = self::short_query($dbg['sql'], true);
$time = sprintf('%.4f', $dbg['time']);
$perc = '[' . round($dbg['time'] * 100 / $db_obj->sql_timetotal) . '%]';
$info = !empty($dbg['info']) ? $dbg['info'] . ' [' . $dbg['src'] . ']' : $dbg['src'];
$log .= ''
. '<div onmouseout="$(this).removeClass(\'sqlHover\');" onmouseover="$(this).addClass(\'sqlHover\');" onclick="$(this).toggleClass(\'sqlHighlight\');" class="sqlLogRow" title="' . $info . '">'
. '<span style="letter-spacing: -1px;">' . $time . ' </span>'
. '<span class="copyElement" data-clipboard-target="#' . $id . '" title="Copy to clipboard" style="color: gray; letter-spacing: -1px;">' . $perc . '</span>'
. ' '
. '<span style="letter-spacing: 0;" id="' . $id . '">' . $sql . '</span>'
. '<span style="color: gray"> # ' . $info . ' </span>'
. '</div>'
. "\n";
}
return '
<div class="sqlLogTitle">' . $log_name . '</div>
' . $log . '
';
}
} }

View file

@ -23,12 +23,14 @@ class APCu extends Common
public function __construct($prefix = null) public function __construct($prefix = null)
{ {
global $debug;
if (!$this->is_installed()) { if (!$this->is_installed()) {
die("Error: $this->engine extension not installed"); die("Error: $this->engine extension not installed");
} }
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function get($name, $get_miss_key_callback = '', $ttl = 0) public function get($name, $get_miss_key_callback = '', $ttl = 0)

View file

@ -59,6 +59,8 @@ class Common
public function debug($mode, $cur_query = null) public function debug($mode, $cur_query = null)
{ {
global $debug;
if (!$this->dbg_enabled) { if (!$this->dbg_enabled) {
return; return;
} }
@ -69,7 +71,7 @@ class Common
switch ($mode) { switch ($mode) {
case 'start': case 'start':
$this->sql_starttime = utime(); $this->sql_starttime = utime();
$dbg['sql'] = Dev::short_query($cur_query ?? $this->cur_query); $dbg['sql'] = $debug->shortQuery($cur_query ?? $this->cur_query);
$dbg['src'] = $this->debug_find_source(); $dbg['src'] = $this->debug_find_source();
$dbg['file'] = $this->debug_find_source('file'); $dbg['file'] = $this->debug_find_source('file');
$dbg['line'] = $this->debug_find_source('line'); $dbg['line'] = $this->debug_find_source('line');

View file

@ -24,9 +24,11 @@ class File extends Common
public function __construct($dir, $prefix = null) public function __construct($dir, $prefix = null)
{ {
global $debug;
$this->dir = $dir; $this->dir = $dir;
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function get($name, $get_miss_key_callback = '', $ttl = 0) public function get($name, $get_miss_key_callback = '', $ttl = 0)

View file

@ -26,6 +26,8 @@ class Memcache extends Common
public function __construct($cfg, $prefix = null) public function __construct($cfg, $prefix = null)
{ {
global $debug;
if (!$this->is_installed()) { if (!$this->is_installed()) {
die("Error: $this->engine extension not installed"); die("Error: $this->engine extension not installed");
} }
@ -33,7 +35,7 @@ class Memcache extends Common
$this->cfg = $cfg; $this->cfg = $cfg;
$this->prefix = $prefix; $this->prefix = $prefix;
$this->memcache = new \Memcache(); $this->memcache = new \Memcache();
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function connect() public function connect()

View file

@ -26,6 +26,8 @@ class Redis extends Common
public function __construct($cfg, $prefix = null) public function __construct($cfg, $prefix = null)
{ {
global $debug;
if (!$this->is_installed()) { if (!$this->is_installed()) {
die("Error: $this->engine extension not installed"); die("Error: $this->engine extension not installed");
} }
@ -33,7 +35,7 @@ class Redis extends Common
$this->cfg = $cfg; $this->cfg = $cfg;
$this->prefix = $prefix; $this->prefix = $prefix;
$this->redis = new \Redis(); $this->redis = new \Redis();
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function connect() public function connect()

View file

@ -37,8 +37,10 @@ class SqliteCommon extends Common
public function __construct($cfg) public function __construct($cfg)
{ {
global $debug;
$this->cfg = array_merge($this->cfg, $cfg); $this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function connect() public function connect()

View file

@ -17,17 +17,19 @@ use TorrentPier\Dev;
*/ */
class APCu extends Common class APCu extends Common
{ {
public $prefix; public string $prefix;
public $engine = 'APCu'; public string $engine = 'APCu';
public function __construct($prefix = null) public function __construct($prefix = null)
{ {
global $debug;
if (!$this->is_installed()) { if (!$this->is_installed()) {
die("Error: $this->engine extension not installed"); die("Error: $this->engine extension not installed");
} }
$this->dbg_enabled = Dev::sql_dbg_enabled();
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function store($title, $var) public function store($title, $var)

View file

@ -139,6 +139,8 @@ class Common
public function debug($mode, $cur_query = null) public function debug($mode, $cur_query = null)
{ {
global $debug;
if (!$this->dbg_enabled) { if (!$this->dbg_enabled) {
return; return;
} }
@ -149,7 +151,7 @@ class Common
switch ($mode) { switch ($mode) {
case 'start': case 'start':
$this->sql_starttime = utime(); $this->sql_starttime = utime();
$dbg['sql'] = Dev::short_query($cur_query ?? $this->cur_query); $dbg['sql'] = $debug->shortQuery($cur_query ?? $this->cur_query);
$dbg['src'] = $this->debug_find_source(); $dbg['src'] = $this->debug_find_source();
$dbg['file'] = $this->debug_find_source('file'); $dbg['file'] = $this->debug_find_source('file');
$dbg['line'] = $this->debug_find_source('line'); $dbg['line'] = $this->debug_find_source('line');

View file

@ -23,9 +23,11 @@ class File extends Common
public function __construct($dir, $prefix = null) public function __construct($dir, $prefix = null)
{ {
global $debug;
$this->prefix = $prefix; $this->prefix = $prefix;
$this->dir = $dir; $this->dir = $dir;
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function store($title, $var) public function store($title, $var)

View file

@ -25,6 +25,8 @@ class Memcache extends Common
public function __construct($cfg, $prefix = null) public function __construct($cfg, $prefix = null)
{ {
global $debug;
if (!$this->is_installed()) { if (!$this->is_installed()) {
die("Error: $this->engine extension not installed"); die("Error: $this->engine extension not installed");
} }
@ -32,7 +34,7 @@ class Memcache extends Common
$this->cfg = $cfg; $this->cfg = $cfg;
$this->prefix = $prefix; $this->prefix = $prefix;
$this->memcache = new \Memcache(); $this->memcache = new \Memcache();
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function connect() public function connect()

View file

@ -25,13 +25,15 @@ class Redis extends Common
public function __construct($cfg, $prefix = null) public function __construct($cfg, $prefix = null)
{ {
global $debug;
if (!$this->is_installed()) { if (!$this->is_installed()) {
die("Error: $this->engine extension not installed"); die("Error: $this->engine extension not installed");
} }
$this->cfg = $cfg; $this->cfg = $cfg;
$this->redis = new \Redis(); $this->redis = new \Redis();
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
$this->prefix = $prefix; $this->prefix = $prefix;
} }

View file

@ -37,8 +37,10 @@ class SqliteCommon extends Common
public function __construct($cfg) public function __construct($cfg)
{ {
global $debug;
$this->cfg = array_merge($this->cfg, $cfg); $this->cfg = array_merge($this->cfg, $cfg);
$this->dbg_enabled = Dev::sql_dbg_enabled(); $this->dbg_enabled = $debug->sqlDebugAllowed();
} }
public function connect() public function connect()

View file

@ -57,10 +57,10 @@ class SqlDb
*/ */
public function __construct($cfg_values) public function __construct($cfg_values)
{ {
global $DBS; global $DBS, $debug;
$this->cfg = array_combine($this->cfg_keys, $cfg_values); $this->cfg = array_combine($this->cfg_keys, $cfg_values);
$this->dbg_enabled = (Dev::sql_dbg_enabled() || !empty($_COOKIE['explain'])); $this->dbg_enabled = ($debug->sqlDebugAllowed() || !empty($_COOKIE['explain']));
$this->do_explain = ($this->dbg_enabled && !empty($_COOKIE['explain'])); $this->do_explain = ($this->dbg_enabled && !empty($_COOKIE['explain']));
$this->slow_time = SQL_SLOW_QUERY_TIME; $this->slow_time = SQL_SLOW_QUERY_TIME;
@ -886,6 +886,8 @@ class SqlDb
*/ */
public function log_query($log_file = 'sql_queries') public function log_query($log_file = 'sql_queries')
{ {
global $debug;
$q_time = ($this->cur_query_time >= 10) ? round($this->cur_query_time, 0) : sprintf('%.4f', $this->cur_query_time); $q_time = ($this->cur_query_time >= 10) ? round($this->cur_query_time, 0) : sprintf('%.4f', $this->cur_query_time);
$msg = []; $msg = [];
$msg[] = round($this->sql_starttime); $msg[] = round($this->sql_starttime);
@ -893,7 +895,7 @@ class SqlDb
$msg[] = sprintf('%-6s', $q_time); $msg[] = sprintf('%-6s', $q_time);
$msg[] = sprintf('%05d', getmypid()); $msg[] = sprintf('%05d', getmypid());
$msg[] = $this->db_server; $msg[] = $this->db_server;
$msg[] = Dev::short_query($this->cur_query); $msg[] = $debug->shortQuery($this->cur_query);
$msg = implode(LOG_SEPR, $msg); $msg = implode(LOG_SEPR, $msg);
$msg .= ($info = $this->query_info()) ? ' # ' . $info : ''; $msg .= ($info = $this->query_info()) ? ' # ' . $info : '';
$msg .= ' # ' . $this->debug_find_source() . ' '; $msg .= ' # ' . $this->debug_find_source() . ' ';
@ -951,12 +953,14 @@ class SqlDb
* *
* @param $mode * @param $mode
* @param string $html_table * @param string $html_table
* @param string $row * @param array $row
* *
* @return bool|string * @return bool|string
*/ */
public function explain($mode, $html_table = '', $row = '') public function explain($mode, $html_table = '', array $row = [])
{ {
global $debug;
$query = str_compact($this->cur_query); $query = str_compact($this->cur_query);
// remove comments // remove comments
$query = preg_replace('#(\s*)(/\*)(.*)(\*/)(\s*)#', '', $query); $query = preg_replace('#(\s*)(/\*)(.*)(\*/)(\s*)#', '', $query);
@ -975,7 +979,7 @@ class SqlDb
$html_table = false; $html_table = false;
if ($result = mysqli_query($this->link, "EXPLAIN $query")) { if ($result = mysqli_query($this->link, "EXPLAIN $query")) {
while ($row = mysqli_fetch_assoc($result)) { while ($row = $this->sql_fetchrow($result)) {
$html_table = $this->explain('add_explain_row', $html_table, $row); $html_table = $this->explain('add_explain_row', $html_table, $row);
} }
} }
@ -1002,7 +1006,7 @@ class SqlDb
</tr> </tr>
<tr><td colspan="2">' . $this->explain_hold . '</td></tr> <tr><td colspan="2">' . $this->explain_hold . '</td></tr>
</table> </table>
<div class="sqlLog"><div id="' . $htid . '" class="sqlLogRow sqlExplain" style="padding: 0;">' . Dev::short_query($dbg['sql'], true) . '&nbsp;&nbsp;</div></div> <div class="sqlLog"><div id="' . $htid . '" class="sqlLogRow sqlExplain" style="padding: 0;">' . $debug->shortQuery($dbg['sql'], true) . '&nbsp;&nbsp;</div></div>
<br />'; <br />';
break; break;
@ -1024,8 +1028,6 @@ class SqlDb
return $html_table; return $html_table;
break;
case 'display': case 'display':
echo '<a name="explain"></a><div class="med">' . $this->explain_out . '</div>'; echo '<a name="explain"></a><div class="med">' . $this->explain_out . '</div>';
break; break;

View file

@ -3,6 +3,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge"> <meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="initial-scale=1.0">
<title><!-- IF HAVE_NEW_PM -->({HAVE_NEW_PM}) <!-- ENDIF --><!-- IF PAGE_TITLE -->{PAGE_TITLE} :: {SITENAME}<!-- ELSE -->{SITENAME}<!-- ENDIF --></title> <title><!-- IF HAVE_NEW_PM -->({HAVE_NEW_PM}) <!-- ENDIF --><!-- IF PAGE_TITLE -->{PAGE_TITLE} :: {SITENAME}<!-- ELSE -->{SITENAME}<!-- ENDIF --></title>
<meta name="application-name" content="{SITENAME}"/> <meta name="application-name" content="{SITENAME}"/>
<meta property="og:site_name" content="{SITENAME}"> <meta property="og:site_name" content="{SITENAME}">