1019 lines
31 KiB
PHP
1019 lines
31 KiB
PHP
<?php
|
|
// $Header: /cvsroot/phptsmadmin/phpTSMadmin/lib/functions.php,v 1.37 2009/04/19 04:03:05 wurley Exp $
|
|
|
|
/**
|
|
* A collection of common generic functions used throughout the application.
|
|
*
|
|
* @author Deon George
|
|
* @package phpTSMadmin
|
|
*/
|
|
|
|
/**
|
|
* @package phpTSMadmin
|
|
* @subpackage Functions
|
|
*/
|
|
|
|
define('HTDOCDIR',sprintf('%s/',realpath(LIBDIR.'../htdocs/')));
|
|
define('LANGDIR',sprintf('%s/',realpath(LIBDIR.'../locale/')));
|
|
define('CONFDIR',sprintf('%s/',realpath(LIBDIR.'../config')));
|
|
define('HOOKSDIR',sprintf('%s/',realpath(LIBDIR.'../hooks/')));
|
|
define('CSSDIR','css/');
|
|
define('IMGDIR','images/');
|
|
define('JSDIR','js/');
|
|
|
|
/**
|
|
* Supplimental functions
|
|
* This list is a list of supplimental functions that are used throughout
|
|
* this application. The order here IS important - so that files that refer to
|
|
* functions defined in other files need to be listed after those files.
|
|
*/
|
|
$app['function_files'] = array(
|
|
LIBDIR.'session_functions.php',
|
|
# Datasource functions
|
|
LIBDIR.'ds.php',
|
|
LIBDIR.'tsm_classes.php',
|
|
# Functions for rendering the page
|
|
LIBDIR.'page.php'
|
|
);
|
|
|
|
if (file_exists(LIBDIR.'functions.custom.php'))
|
|
array_push($app['function_files'],LIBDIR.'functions.custom.php');
|
|
|
|
/**
|
|
* Loads class definition
|
|
*/
|
|
function __autoload($className) {
|
|
if (defined('DEBUG_ENABLED') && DEBUG_ENABLED)
|
|
debug_log('Call to autoload (%s)',1,__FILE__,__LINE__,__METHOD__,$className);
|
|
|
|
if (file_exists(HOOKSDIR."classes/$className.php"))
|
|
require_once(HOOKSDIR."classes/$className.php");
|
|
elseif (file_exists(LIBDIR."$className.php"))
|
|
require_once(LIBDIR."$className.php");
|
|
elseif (file_exists(LIBDIR."ds_$className.php"))
|
|
require_once(LIBDIR."ds_$className.php");
|
|
else
|
|
system_message(array(
|
|
'title'=>_('Generic Error'),
|
|
'body'=>sprintf('%s: %s [%s]',
|
|
__METHOD__,_('Called to load a class that cant be found'),$className),
|
|
'type'=>'error'));
|
|
}
|
|
|
|
/**
|
|
* Strips all slashes from the specified array in place (pass by ref).
|
|
* @param Array The array to strip slashes from, typically one of
|
|
* $_GET, $_POST, or $_COOKIE.
|
|
*/
|
|
function array_stripslashes(&$array) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s)',1,__FILE__,__LINE__,__METHOD__,$array);
|
|
|
|
if (is_array($array))
|
|
while (list($key) = each($array))
|
|
if (is_array($array[$key]) && $key != $array)
|
|
array_stripslashes($array[$key]);
|
|
else
|
|
$array[$key] = stripslashes($array[$key]);
|
|
}
|
|
|
|
/**
|
|
* Compatibility Functions
|
|
* These functions exist, so that a standard function can be used in new applications, and they
|
|
* map to already defined functions in older applications.
|
|
*/
|
|
|
|
/**
|
|
* If gettext is not available in PHP, then this will provide compatibility for it.
|
|
*/
|
|
if (! function_exists('_')) {
|
|
function _($msg) {
|
|
return $msg;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generic Utility Functions
|
|
*/
|
|
|
|
/**
|
|
* Custom error handling function.
|
|
* When a PHP error occurs, PHP will call this function rather than printing
|
|
* the typical PHP error string. This provides the application the ability to
|
|
* format an error message so that it looks better.
|
|
* Optionally, it can present a link so that a user can search/submit bugs.
|
|
* This function is not to be called directly. It is exclusively for the use of
|
|
* PHP internally. If this function is called by PHP from within a context
|
|
* where error handling has been disabled (ie, from within a function called
|
|
* with "@" prepended), then this function does nothing.
|
|
*
|
|
* @param int The PHP error number that occurred (ie, E_ERROR, E_WARNING, E_PARSE, etc).
|
|
* @param string The PHP error string provided (ie, "Warning index "foo" is undefined)
|
|
* @param string The file in which the PHP error ocurred.
|
|
* @param int The line number on which the PHP error ocurred
|
|
* @see set_error_handler
|
|
*/
|
|
function app_error_handler($errno,$errstr,$file,$lineno) {
|
|
if (defined('DEBUG_ENABLED') && DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s,%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$errno,$errstr,$file,$lineno);
|
|
|
|
/**
|
|
* error_reporting will be 0 if the error context occurred
|
|
* within a function call with '@' preprended (ie, @ldap_bind() );
|
|
* So, don't report errors if the caller has specifically
|
|
* disabled them with '@'
|
|
*/
|
|
if (ini_get('error_reporting') == 0 || error_reporting() == 0)
|
|
return;
|
|
|
|
$file = basename($file);
|
|
$caller = basename($_SERVER['PHP_SELF']);
|
|
$errtype = '';
|
|
|
|
switch ($errno) {
|
|
case E_STRICT: $errtype = 'E_STRICT'; break;
|
|
case E_ERROR: $errtype = 'E_ERROR'; break;
|
|
case E_WARNING: $errtype = 'E_WARNING'; break;
|
|
case E_PARSE: $errtype = 'E_PARSE'; break;
|
|
case E_NOTICE: $errtype = 'E_NOTICE'; break;
|
|
case E_CORE_ERROR: $errtype = 'E_CORE_ERROR'; break;
|
|
case E_CORE_WARNING: $errtype = 'E_CORE_WARNING'; break;
|
|
case E_COMPILE_ERROR: $errtype = 'E_COMPILE_ERROR'; break;
|
|
case E_COMPILE_WARNING: $errtype = 'E_COMPILE_WARNING'; break;
|
|
case E_USER_ERROR: $errtype = 'E_USER_ERROR'; break;
|
|
case E_USER_WARNING: $errtype = 'E_USER_WARNING'; break;
|
|
case E_USER_NOTICE: $errtype = 'E_USER_NOTICE'; break;
|
|
case E_ALL: $errtype = 'E_ALL'; break;
|
|
|
|
default: $errtype = sprintf('%s: %s',_('Unrecognized error number'),$errno);
|
|
}
|
|
|
|
# Take out extra spaces in error strings.
|
|
$errstr = preg_replace('/\s+/',' ',$errstr);
|
|
|
|
if ($errno == E_NOTICE) {
|
|
$body = '<table class="notice">';
|
|
$body .= sprintf('<tr><td>%s:</td><td><b>%s</b> (<b>%s</b>)</td></tr>',_('Error'),$errstr,$errtype);
|
|
$body .= sprintf('<tr><td>%s:</td><td><b>%s</b> %s <b>%s</b>, %s <b>%s</b></td></tr>',
|
|
_('File'),$file,_('line'),$lineno,_('caller'),$caller);
|
|
$body .= sprintf('<tr><td>Versions:</td><td>APP: <b>%s</b>, PHP: <b>%s</b>, SAPI: <b>%s</b></td></tr>',
|
|
app_version(),phpversion(),php_sapi_name());
|
|
$body .= sprintf('<tr><td>Web server:</td><td><b>%s</b></td></tr>',isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : 'SCRIPT');
|
|
|
|
if (function_exists('get_href'))
|
|
$body .= sprintf('<tr><td colspan="2"><a href="%s" target="_blank"><center>%s.</center></a></td></tr>',
|
|
get_href('search_bug',"&summary_keyword=".rawurlencode($errstr)),
|
|
_('Please check and see if this bug has been reported'));
|
|
$body .= '</table>';
|
|
|
|
system_message(array(
|
|
'title'=>_('You found a non-fatal application bug!'),
|
|
'body'=>$body,
|
|
'type'=>'error'));
|
|
|
|
return;
|
|
}
|
|
|
|
# If this is a more serious error, call the error call.
|
|
error(sprintf('%s: %s',$errtype,$errstr),'error',null,true,true);
|
|
}
|
|
|
|
/**
|
|
* Returns the application name.
|
|
*/
|
|
function app_name() {
|
|
if (isset($_SESSION[APPCONFIG]))
|
|
return $_SESSION[APPCONFIG]->getValue('app','name',false);
|
|
else
|
|
return 'Application name NOT set';
|
|
}
|
|
|
|
/**
|
|
* Returns the application version currently running. The version
|
|
* is read from the file named VERSION.
|
|
*
|
|
* @return string The current version as read from the VERSION file.
|
|
*/
|
|
function app_version() {
|
|
static $CACHE = null;
|
|
|
|
if ($CACHE)
|
|
return $CACHE;
|
|
|
|
$version_file = realpath(LIBDIR.'../VERSION');
|
|
if (! file_exists($version_file))
|
|
$CACHE = 'UNKNOWN';
|
|
|
|
else {
|
|
$f = fopen($version_file,'r');
|
|
$version = trim(fread($f, filesize($version_file)));
|
|
fclose($f);
|
|
|
|
# We use cvs_prefix, because CVS will translate this on checkout otherwise.
|
|
$cvs_prefix = '\$Name:';
|
|
|
|
$CACHE = preg_replace('/^'.$cvs_prefix.' RELEASE-([0-9_]+)\s*\$$/','$1',$version);
|
|
$CACHE = preg_replace('/_/','.',$CACHE);
|
|
|
|
# Check if we are a CVS copy.
|
|
if (preg_match('/^'.$cvs_prefix.'?\s*\$$/',$CACHE))
|
|
$CACHE = 'CVS';
|
|
|
|
# Check if we are special CVS branch
|
|
elseif (preg_match('/^'.$cvs_prefix.'?\s*([a-zA-Z]+)?\s*\$$/',$CACHE,$match))
|
|
$CACHE = $match[1];
|
|
|
|
# If return is still the same as version, then the tag is not one we expect.
|
|
elseif ($CACHE == $version)
|
|
$CACHE = 'UNKNOWN';
|
|
}
|
|
|
|
if (defined('DEBUG_ENABLED') && DEBUG_ENABLED)
|
|
debug_log('Entered with (), Returning (%s)',1,__FILE__,__LINE__,__METHOD__,$CACHE);
|
|
|
|
return $CACHE;
|
|
}
|
|
|
|
/**
|
|
* This function will convert the browser two character language into the
|
|
* default 5 character language, where the country portion should NOT be
|
|
* assumed to be upper case characters of the first two characters.
|
|
*/
|
|
function auto_lang($lang) {
|
|
switch ($lang) {
|
|
case 'ja': return 'ja_JP';
|
|
case 'cs': return 'cs_CZ';
|
|
default: return sprintf('%s_%s',$lang,strtoupper($lang));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes sure that the config file is properly setup.
|
|
*/
|
|
function check_config($config_file) {
|
|
# Read in config_default.php
|
|
require_once LIBDIR.'config_default.php';
|
|
|
|
# Make sure their PHP version is current enough
|
|
if (strcmp(phpversion(),REQUIRED_PHP_VERSION) < 0)
|
|
system_message(array(
|
|
'title'=>_('Incorrect version of PHP'),
|
|
'body'=>sprintf('This application requires PHP version %s or greater.<br /><small>(You are using %s)</small>',
|
|
REQUIRED_PHP_VERSION,phpversion()),
|
|
'type'=>'error'));
|
|
|
|
$config = new Config;
|
|
|
|
if (file_exists(LIBDIR.'config_custom.php') && is_readable(LIBDIR.'config_custom.php'))
|
|
include LIBDIR.'config_custom.php';
|
|
|
|
ob_start();
|
|
require $config_file;
|
|
$str = '';
|
|
if (ob_get_level()) {
|
|
$str = ob_get_contents();
|
|
ob_end_clean();
|
|
}
|
|
|
|
if ($str) {
|
|
$str = strip_tags($str);
|
|
$matches = array();
|
|
preg_match('/(.*):\s+(.*):.*\s+on line (\d+)/',$str,$matches);
|
|
|
|
if (isset($matches[1]) && isset($matches[2]) && isset($matches[3])) {
|
|
$error_type = $matches[1];
|
|
$error = $matches[2];
|
|
$line_num = $matches[3];
|
|
|
|
$file = file($config_file);
|
|
|
|
$body = '<h3 class="title">Config file ERROR</h3>';
|
|
$body .= sprintf('<h3 class="subtitle">%s (%s) on line %s</h3>',$error_type,$error,$line_num);
|
|
|
|
$body .= '<center>';
|
|
$body .= sprintf('Looks like your config file has an ERROR on line %s.<br />',$line_num);
|
|
$body .= 'Here is a snippet around that line <br />';
|
|
$body .= '<br />'."\n";
|
|
|
|
$body .= '<div style="text-align: left; font-family: monospace; margin-left: 80px; margin-right: 80px; border: 1px solid black; padding: 10px;">';
|
|
|
|
for ($i = $line_num-9; $i<$line_num+5; $i++) {
|
|
if ($i+1 == $line_num)
|
|
$body .= '<div style="color:red;background:#fdd">';
|
|
|
|
if ($i < 0)
|
|
continue;
|
|
|
|
$body .= sprintf('<b>%s</b>: %s<br />',$i+1,$file[$i]);
|
|
|
|
if ($i+1 == $line_num)
|
|
$body .= '</div>';
|
|
}
|
|
|
|
$body .= '</div>';
|
|
$body .= '<br />';
|
|
$body .= 'Hint: Sometimes these errors are caused by lines <b>preceding</b> the line reported.';
|
|
$body .= '</center>';
|
|
|
|
$block = new block();
|
|
$block->SetBody($body);
|
|
$www['page'] = new page();
|
|
$www['page']->block_add('body',$block);
|
|
$www['page']->display();
|
|
|
|
die();
|
|
}
|
|
}
|
|
|
|
# Process our friendly attributes.
|
|
if (isset($friendly_attrs))
|
|
$config->getFriendlyAttrs($friendly_attrs);
|
|
|
|
# Check for server definitions.
|
|
if (! isset($servers) || count($servers->GetServerList()) == 0)
|
|
error(_('Your config.php is missing Server Definitions. Please see the sample file config/config.php.example.'),'error','index.php',true);
|
|
|
|
$config->setServers($servers);
|
|
|
|
# Check the memory limit parameter.
|
|
if (ini_get('memory_limit') < $config->getValue('session','memorylimit'))
|
|
system_message(array(
|
|
'title'=>_('Memory Limit low.'),
|
|
'body'=> sprintf('Your php memory limit is low - currently %s, you should increase it to atleast %s. This is normally controlled in /etc/php.ini.',ini_get('memory_limit'),$config->getValue('session','memorylimit')),
|
|
'type'=>'error'));
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Commands available in the control_panel of the page
|
|
*
|
|
* @return array
|
|
*/
|
|
function cmd_control_pane($type) {
|
|
switch ($type) {
|
|
case 'main' :
|
|
return array(
|
|
'home'=>array(
|
|
'title'=>_('Home'),
|
|
'link'=>sprintf('href="index.php" title="%s"',_('Home')),
|
|
'image'=>sprintf('<img src="%s/home-big.png" alt="%s" />',IMGDIR,_('Home'))),
|
|
|
|
'purge'=>array(
|
|
'title'=>_('Purge caches'),
|
|
'link'=>sprintf('href="cmd.php?cmd=purge_cache" onclick="return displayAJ(\'BODY\',\'cmd=purge_cache\',\'%s\');" title="%s"',
|
|
_('Clearing cache'),_('Purge caches')),
|
|
'image'=>sprintf('<img src="%s/trash-big.png" alt="%s" />',IMGDIR,_('Purge caches'))),
|
|
|
|
'appearance:hide_debug_info'=>array(
|
|
'title'=>_('Show Cache'),
|
|
'link'=>sprintf('href="cmd.php?cmd=show_cache" onclick="return displayAJ(\'BODY\',\'cmd=show_cache\',\'%s\');" title="%s"',
|
|
_('Loading'),_('Show Cache'),_('Show Cache')),
|
|
'image'=>sprintf('<img src="%s/debug-cache.png" alt="%s" />',IMGDIR,_('Show Cache'))),
|
|
);
|
|
break;
|
|
|
|
case 'top' :
|
|
return array();
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function dumps the $variable for debugging purposes
|
|
*
|
|
* @param string|array Variable to dump
|
|
* @param boolean Whether to stop execution or not.
|
|
*/
|
|
function debug_dump($variable,$die=false,$onlydebugaddr=false) {
|
|
if ($onlydebugaddr &&
|
|
isset($_SESSION[APPCONFIG]) && $_SESSION[APPCONFIG]->getValue('debug','addr') &&
|
|
$_SERVER['HTTP_X_FORWARDED_FOR'] != $_SESSION[APPCONFIG]->getValue('debug','addr') &&
|
|
$_SERVER['REMOTE_ADDR'] != $_SESSION[APPCONFIG]->getValue('debug','addr'))
|
|
return;
|
|
|
|
$backtrace = debug_backtrace();
|
|
$caller['class'] = isset($backtrace[0]['class']) ? $backtrace[0]['class'] : 'N/A';
|
|
$caller['function'] = isset($backtrace[0]['function']) ? $backtrace[0]['function'] : 'N/A';
|
|
$caller['file'] = isset($backtrace[0]['file']) ? $backtrace[0]['file'] : 'N/A';
|
|
$caller['line'] = isset($backtrace[0]['line']) ? $backtrace[0]['line'] : 'N/A';
|
|
$caller['debug'] = $variable;
|
|
|
|
print '<PRE>';
|
|
print_r($caller);
|
|
print '</PRE>';
|
|
|
|
if ($die)
|
|
die();
|
|
}
|
|
|
|
/**
|
|
* This function generates a backtrace
|
|
*
|
|
* @param boolean Whether to stop execution or not.
|
|
*/
|
|
function debug_dump_backtrace($msg='Calling BackTrace',$die=false) {
|
|
error($msg,'note',null,$die,true);
|
|
}
|
|
|
|
/**
|
|
* Send a debug as a sys message
|
|
*/
|
|
function debug_sysmsg($msg) {
|
|
system_message(array('title'=>_('Debug'),'body'=>$msg,'type'=>'debug'));
|
|
}
|
|
|
|
/**
|
|
* Debug Logging to Syslog
|
|
*
|
|
* The global debug level is turned on in your configuration file by setting:
|
|
* <code>
|
|
* $config->custom->debug['level'] = 255;
|
|
* </code>
|
|
* together with atleast one output direction (currently file and syslog are supported).
|
|
* <code>
|
|
* $config->custom->debug['file'] = '/tmp/app_debug.log';
|
|
* $config->custom->debug['syslog'] = true;
|
|
* </code>
|
|
*
|
|
* The debug level is turned into binary, then if the message levels bit is on
|
|
* the message will be sent to the debug log. (Thus setting your debug level to 255,
|
|
* all bits on, will results in all messages being printed.)
|
|
*
|
|
* The message level bits are defined here.
|
|
* 0( 1) = Entry/Return results from function calls.
|
|
* 1( 2) = Configuration Processing
|
|
* 2( 4) = Template Processing
|
|
* 3( 8) = Schema Processing
|
|
* 4( 16) = Server Communication
|
|
* 5( 32) = Menu Processing
|
|
* 7( 64) = Other non generic messages
|
|
* 8(128) = Page Processing
|
|
* @param string Message to send to syslog
|
|
* @param int Log bit number for this message.
|
|
* @see syslog.php
|
|
*/
|
|
function debug_log($msg,$level=0) {
|
|
global $debug_file;
|
|
|
|
# Temporary, to catch when these are not set in the function arguments.
|
|
$file = __FILE__;
|
|
$line = __LINE__;
|
|
$method = __METHOD__;
|
|
|
|
# In case we are called before we are fully initialised or if debugging is not set.
|
|
if (! isset($_SESSION[APPCONFIG]) || ! ($_SESSION[APPCONFIG]->getValue('debug','file')
|
|
|| $_SESSION[APPCONFIG]->getValue('debug','syslog')))
|
|
return false;
|
|
|
|
$debug_level = $_SESSION[APPCONFIG]->getValue('debug','level');
|
|
if (! $debug_level || (! ($level & $debug_level)))
|
|
return;
|
|
|
|
$debugaddr = false;
|
|
if ($_SESSION[APPCONFIG]->getValue('debug','addr')) {
|
|
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && $_SERVER['HTTP_X_FORWARDED_FOR'] == $_SESSION[APPCONFIG]->getValue('debug','addr'))
|
|
$debugaddr = true;
|
|
|
|
elseif ($_SERVER['REMOTE_ADDR'] == $_SESSION[APPCONFIG]->getValue('debug','addr'))
|
|
$debugaddr = true;
|
|
} else $debugaddr = true;
|
|
|
|
if (! $debugaddr)
|
|
return;
|
|
|
|
# If we are limiting debug to a browser, then check that
|
|
$caller = basename( $_SERVER['PHP_SELF'] );
|
|
|
|
if (func_num_args() > 2) {
|
|
$args = func_get_args();
|
|
array_shift($args);
|
|
array_shift($args);
|
|
|
|
# This is temporary, until we change all the debug_log statements.
|
|
if (is_string($args[0]) && preg_match('/.php$/',$args[0])) {
|
|
$file = array_shift($args);
|
|
$line = array_shift($args);
|
|
$method = array_shift($args);
|
|
}
|
|
|
|
$fargs = array();
|
|
foreach ($args as $key) {
|
|
if (is_array($key) || is_object($key))
|
|
array_push($fargs,serialize($key));
|
|
else
|
|
array_push($fargs,$key);
|
|
}
|
|
$msg = vsprintf($msg, array_values($fargs));
|
|
}
|
|
|
|
if (function_exists('stopwatch'))
|
|
$timer = stopwatch();
|
|
else
|
|
$timer = null;
|
|
|
|
$debug_message = sprintf('[%2.3f] %3s-%s(%04s): %s: %s',$timer,$level,basename($file),$line,$method,substr($msg,0,200));
|
|
|
|
if ($debug_file || $_SESSION[APPCONFIG]->getValue('debug','file')) {
|
|
if (! $debug_file)
|
|
$debug_file = fopen($_SESSION[APPCONFIG]->getValue('debug','file'),
|
|
$_SESSION[APPCONFIG]->getValue('debug','append') ? 'a' : 'w');
|
|
|
|
fwrite($debug_file,$debug_message."\n");
|
|
}
|
|
|
|
if ($_SESSION[APPCONFIG]->getValue('debug','syslog'))
|
|
syslog_notice($debug_message);
|
|
|
|
return syslog_notice( sprintf('%s(%s): %s',$caller,$level,$msg) );
|
|
}
|
|
|
|
/**
|
|
* Display an error message in the system message panel of the page.
|
|
*/
|
|
function error($msg,$type='note',$redirect=null,$fatal=false,$backtrace=false) {
|
|
global $www;
|
|
static $counter;
|
|
|
|
# Just a check to see that we are called right.
|
|
if (! isset($www['page']) && ! $fatal)
|
|
die("Function error called incorrectly [$msg]");
|
|
|
|
# If the error is fatal, we'll need to stop here.
|
|
if (! isset($www['page']))
|
|
$www['page'] = new page();
|
|
|
|
if ($fatal)
|
|
$www['page']->setsysmsg(array('title'=>_('Error'),'body'=>$msg,'type'=>$type));
|
|
else
|
|
system_message(array('title'=>_('Error'),'body'=>$msg,'type'=>$type),$redirect);
|
|
|
|
# Spin loop detection
|
|
if ($counter++ > 20) {
|
|
debug_dump('Spin loop detection.');
|
|
debug_dump(array('msg'=>$msg,'session'=>$_SESSION['sysmsg'],'www'=>$www),1);
|
|
}
|
|
|
|
# Do we have a backtrace to display?
|
|
if ($backtrace) {
|
|
$backtraceblock = new block();
|
|
$backtraceblock->SetTitle('PHP Debug Backtrace');
|
|
|
|
$body = '<table class="result_table">';
|
|
$body .= "\n";
|
|
|
|
foreach (debug_backtrace() as $error => $line) {
|
|
$_SESSION['backtrace'][$error]['file'] = isset($line['file']) ? $line['file'] : 'unknown';
|
|
$_SESSION['backtrace'][$error]['line'] = isset($line['line']) ? $line['line'] : 'unknown';
|
|
$body .= sprintf('<tr class="hightlight"><td colspan="2"><b><small>%s</small></b></td><td>%s (%s)</td></tr>',
|
|
_('File'),isset($line['file']) ? $line['file'] : $last['file'],isset($line['line']) ? $line['line'] : '');
|
|
|
|
$_SESSION['backtrace'][$error]['function'] = $line['function'];
|
|
$body .= sprintf('<tr><td> </td><td><b><small>%s</small></b></td><td><small>%s',
|
|
_('Function'),$line['function']);
|
|
|
|
if (isset($line['args'])) {
|
|
$display = strlen(serialize($line['args'])) < 50 ? serialize($line['args']) : substr(serialize($line['args']),0,50).'...<TRUNCATED>';
|
|
$_SESSION['backtrace'][$error]['args'] = $line['args'];
|
|
if (file_exists(LIBDIR.'../tools/unserialize.php'))
|
|
$body .= sprintf(' (<a href="%s?index=%s" target="backtrace">%s</a>)',
|
|
'../tools/unserialize.php',$error,$display);
|
|
else
|
|
$body .= sprintf(' (%s)',$display);
|
|
}
|
|
$body .= '</small></td></tr>';
|
|
$body .= "\n";
|
|
|
|
if (isset($line['file']))
|
|
$last['file'] = $line['file'];
|
|
}
|
|
|
|
$body .= '</table>';
|
|
$body .= "\n";
|
|
$backtraceblock->SetBody($body);
|
|
|
|
$www['page']->block_add('body',$backtraceblock);
|
|
}
|
|
|
|
if ($fatal) {
|
|
$www['page']->display(array('menu'=>false));
|
|
die();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the result of a form variable, with optional default
|
|
*
|
|
* @return The form GET/REQUEST/SESSION/POST variable value or its default
|
|
*/
|
|
function get_request($attr,$type='POST',$die=false,$default=null) {
|
|
switch($type) {
|
|
case 'GET':
|
|
$value = isset($_GET[$attr]) ? (is_array($_GET[$attr]) ? $_GET[$attr] : rawurldecode($_GET[$attr])) : $default;
|
|
break;
|
|
|
|
case 'REQUEST':
|
|
$value = isset($_REQUEST[$attr]) ? (is_array($_REQUEST[$attr]) ? $_REQUEST[$attr] : rawurldecode($_REQUEST[$attr])) : $default;
|
|
break;
|
|
|
|
case 'SESSION':
|
|
$value = isset($_SESSION[$attr]) ? (is_array($_SESSION[$attr]) ? $_SESSION[$attr] : rawurldecode($_SESSION[$attr])) : $default;
|
|
break;
|
|
|
|
case 'POST':
|
|
default:
|
|
$value = isset($_POST[$attr]) ? (is_array($_POST[$attr]) ? $_POST[$attr] : rawurldecode($_POST[$attr])) : $default;
|
|
break;
|
|
}
|
|
|
|
if ($die && is_null($value))
|
|
system_message(array(
|
|
'title'=>_('Generic Error'),
|
|
'body'=>sprintf('%s: Called "%s" without "%s" using "%s"',
|
|
basename($_SERVER['PHP_SELF']),get_request('cmd','REQUEST'),$attr,$type),
|
|
'type'=>'error'),
|
|
'index.php');
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Record a system message.
|
|
* This function can be used as an alternative to generate a system message, if page hasnt yet been defined.
|
|
*/
|
|
function system_message($msg,$redirect=null) {
|
|
if (! is_array($msg))
|
|
return null;
|
|
|
|
if (! isset($msg['title']) && ! isset($msg['body']))
|
|
return null;
|
|
|
|
if (! isset($msg['type']))
|
|
$msg['type'] = 'info';
|
|
|
|
if (! isset($_SESSION['sysmsg']) || ! is_array($_SESSION['sysmsg']))
|
|
$_SESSION['sysmsg'] = array();
|
|
|
|
# Try and detect if we are in a redirect loop
|
|
if (get_request('redirect','GET') && $msg['type'] != 'debug') {
|
|
foreach ($_SESSION['sysmsg'] as $detail) {
|
|
if ($msg == $detail && ! isset($detail['special'])) {
|
|
debug_dump($_SESSION['sysmsg']);
|
|
debug_dump_backtrace('Redirect Loop Detected',true);
|
|
}
|
|
}
|
|
}
|
|
|
|
array_push($_SESSION['sysmsg'],$msg);
|
|
|
|
if ($redirect) {
|
|
if (preg_match('/\?/',$redirect))
|
|
$redirect .= '&';
|
|
else
|
|
$redirect .= '?';
|
|
$redirect .= 'redirect=true';
|
|
|
|
# Check if we were an ajax request, and only render the ajax message
|
|
if (get_request('meth','REQUEST') == 'ajax')
|
|
$redirect .= '&meth=ajax';
|
|
|
|
header("Location: $redirect");
|
|
die();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Other Functions
|
|
*/
|
|
|
|
/**
|
|
* Encryption using blowfish algorithm
|
|
*
|
|
* @param string Original data
|
|
* @param string The secret
|
|
* @return string The encrypted result
|
|
* @author lem9 (taken from the phpMyAdmin source)
|
|
*/
|
|
function blowfish_encrypt($data,$secret=null) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$data,$secret);
|
|
|
|
# If our secret is null or blank, get the default.
|
|
if ($secret === null || ! trim($secret))
|
|
$secret = $_SESSION[APPCONFIG]->getValue('session','blowfish');
|
|
|
|
# If the secret isnt set, then just return the data.
|
|
if (! trim($secret))
|
|
return $data;
|
|
|
|
if (file_exists(LIBDIR.'blowfish.php'))
|
|
require_once LIBDIR.'blowfish.php';
|
|
else
|
|
return $data;
|
|
|
|
$pma_cipher = new Horde_Cipher_blowfish;
|
|
$encrypt = '';
|
|
|
|
for ($i=0; $i<strlen($data); $i+=8) {
|
|
$block = substr($data, $i, 8);
|
|
|
|
if (strlen($block) < 8)
|
|
$block = full_str_pad($block,8,"\0", 1);
|
|
|
|
$encrypt .= $pma_cipher->encryptBlock($block, $secret);
|
|
}
|
|
return base64_encode($encrypt);
|
|
}
|
|
|
|
/**
|
|
* Decryption using blowfish algorithm
|
|
*
|
|
* @param string Encrypted data
|
|
* @param string The secret
|
|
* @return string Original data
|
|
* @author lem9 (taken from the phpMyAdmin source)
|
|
*/
|
|
function blowfish_decrypt($encdata,$secret=null) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$encdata,$secret);
|
|
|
|
# This cache gives major speed up for stupid callers :)
|
|
static $CACHE = array();
|
|
|
|
if (isset($CACHE[$encdata]))
|
|
return $CACHE[$encdata];
|
|
|
|
# If our secret is null or blank, get the default.
|
|
if ($secret === null || ! trim($secret))
|
|
$secret = $_SESSION[APPCONFIG]->getValue('session','blowfish');
|
|
|
|
# If the secret isnt set, then just return the data.
|
|
if (! trim($secret))
|
|
return $encdata;
|
|
|
|
if (file_exists(LIBDIR.'blowfish.php'))
|
|
require_once LIBDIR.'blowfish.php';
|
|
else
|
|
return $data;
|
|
|
|
$pma_cipher = new Horde_Cipher_blowfish;
|
|
$decrypt = '';
|
|
$data = base64_decode($encdata);
|
|
|
|
for ($i=0; $i<strlen($data); $i+=8)
|
|
$decrypt .= $pma_cipher->decryptBlock(substr($data, $i, 8), $secret);
|
|
|
|
$return = trim($decrypt);
|
|
$CACHE[$encdata] = $return;
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* String padding
|
|
*
|
|
* @param string Input string
|
|
* @param integer Length of the result
|
|
* @param string The filling string
|
|
* @param integer Padding mode
|
|
* @return string The padded string
|
|
*/
|
|
function full_str_pad($input,$pad_length,$pad_string='',$pad_type=0) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s,%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$input,$pad_length,$pad_string,$pad_type);
|
|
|
|
$str = '';
|
|
$length = $pad_length - strlen($input);
|
|
|
|
if ($length > 0) { // str_repeat doesn't like negatives
|
|
if ($pad_type == STR_PAD_RIGHT) { // STR_PAD_RIGHT == 1
|
|
$str = $input.str_repeat($pad_string, $length);
|
|
} elseif ($pad_type == STR_PAD_BOTH) { // STR_PAD_BOTH == 2
|
|
$str = str_repeat($pad_string, floor($length/2));
|
|
$str .= $input;
|
|
$str .= str_repeat($pad_string, ceil($length/2));
|
|
} else { // defaults to STR_PAD_LEFT == 0
|
|
$str = str_repeat($pad_string, $length).$input;
|
|
}
|
|
|
|
} else { // if $length is negative or zero we don't need to do anything
|
|
$str = $input;
|
|
}
|
|
return $str;
|
|
}
|
|
|
|
/**
|
|
* Returns the cached array of application server resources.
|
|
*
|
|
* Note that internally, this function utilizes a two-layer cache,
|
|
* one in memory using a static variable for multiple calls within
|
|
* the same page load, and one in a session for multiple calls within
|
|
* the same user session (spanning multiple page loads).
|
|
*
|
|
* @return Returns the cached attributed requested,
|
|
* or null if there is nothing cached..
|
|
*/
|
|
function get_cached_item($index,$item,$subitem='null') {
|
|
# Set default return
|
|
$return = null;
|
|
|
|
# Check config to make sure session-based caching is enabled.
|
|
if ($_SESSION[APPCONFIG]->getValue('cache',$item)) {
|
|
|
|
global $CACHE;
|
|
if (isset($CACHE[$index][$item][$subitem])) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Returning MEMORY cached [%s] (%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$item,$subitem);
|
|
|
|
$return = $CACHE[$index][$item][$subitem];
|
|
|
|
} elseif (isset($_SESSION['cache'][$index][$item][$subitem])) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Returning SESSION cached [%s] (%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$item,$subitem);
|
|
|
|
$return = $_SESSION['cache'][$index][$item][$subitem];
|
|
$CACHE[$index][$item][$subitem] = $return;
|
|
}
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s), Returning (%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$index,$item,$subitem,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Caches the specified $item for the specified $index.
|
|
*
|
|
* Returns true on success of false on failure.
|
|
*/
|
|
function set_cached_item($index,$item,$subitem='null',$data) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s,%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$index,$item,$subitem,$data);
|
|
|
|
# Check config to make sure session-based caching is enabled.
|
|
if ($_SESSION[APPCONFIG]->getValue('cache',$item)) {
|
|
global $CACHE;
|
|
|
|
$CACHE[$index][$item][$subitem] = $data;
|
|
$_SESSION['cache'][$index][$item][$subitem] = $data;
|
|
return true;
|
|
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Deletes the cache for a specified $item for the specified $index
|
|
*/
|
|
function del_cached_item($index,$item,$subitem='null') {
|
|
global $CACHE;
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$index,$item,$subitem);
|
|
|
|
# Check config to make sure session-based caching is enabled.
|
|
if (isset($_SESSION['cache'][$index][$item][$subitem]))
|
|
unset($_SESSION['cache'][$index][$item][$subitem]);
|
|
|
|
if (isset($CACHE[$index][$item][$subitem]))
|
|
unset($CACHE[$index][$item][$subitem]);
|
|
}
|
|
|
|
/**
|
|
* Utility wrapper for setting cookies, which takes into consideration
|
|
* application configuration values. On success, true is returned. On
|
|
* failure, false is returned.
|
|
*
|
|
* @param string The name of the cookie to set.
|
|
* @param string The value of the cookie to set.
|
|
* @param int (optional) The duration in seconds of this cookie. If unspecified, $cookie_time is used from config.php
|
|
* @param string (optional) The directory value of this cookie (see php.net/setcookie)
|
|
* @return boolean
|
|
*/
|
|
function set_cookie($name,$val,$expire=null,$dir=null) {
|
|
# Set default return
|
|
$return = false;
|
|
|
|
if ($expire == null) {
|
|
$cookie_time = $_SESSION[APPCONFIG]->getValue('session','cookie_time');
|
|
$expire = $cookie_time == 0 ? null : time() + $cookie_time;
|
|
}
|
|
|
|
if ($dir == null)
|
|
$dir = dirname($_SERVER['PHP_SELF']);
|
|
|
|
if (@setcookie($name,$val,$expire,$dir)) {
|
|
$_COOKIE[$name] = $val;
|
|
$return = true;
|
|
}
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s,%s), Returning (%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$name,$val,$expire,$dir,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Get a customized file for a server
|
|
* We don't need any caching, because it's done by PHP
|
|
*
|
|
* @param int The ID of the server
|
|
* @param string The requested filename
|
|
*
|
|
* @return string The customized filename, if exists, or the standard one
|
|
*/
|
|
function get_custom_file($index,$filename,$path) {
|
|
# Set default return
|
|
$return = $path.$filename;
|
|
$server = $_SESSION[APPCONFIG]->getServer($index);
|
|
|
|
$custom = $server->getValue('custom','pages_prefix');
|
|
if (! is_null($custom) && is_file(realpath($path.$custom.$filename)))
|
|
$return = $path.$custom.$filename;
|
|
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s), Returning (%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$index,$filename,$path,$return);
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Sort a multi dimensional array.
|
|
*
|
|
* @param array Multi demension array passed by reference
|
|
* @param string Comma delimited string of sort keys.
|
|
* @param boolean Whether to reverse sort.
|
|
* @return array Sorted multi demension array.
|
|
*/
|
|
function masort(&$data,$sortby,$rev=0) {
|
|
if (DEBUG_ENABLED)
|
|
debug_log('Entered with (%s,%s,%s)',1,__FILE__,__LINE__,__METHOD__,
|
|
$data,$sortby,$rev);
|
|
|
|
# if the array to sort is null or empty
|
|
if (! $data) return;
|
|
|
|
static $CACHE = array();
|
|
|
|
if (empty($CACHE[$sortby])) {
|
|
$code = "\$c=0;\n";
|
|
foreach (explode(',',$sortby) as $key) {
|
|
$code .= "if (is_object(\$a) || is_object(\$b)) {\n";
|
|
$code .= " if (\$a->$key != \$b->$key)\n";
|
|
|
|
if ($rev)
|
|
$code .= " return (\$a->$key < \$b->$key ? 1 : -1);\n";
|
|
else
|
|
$code .= " return (\$a->$key > \$b->$key ? 1 : -1);\n";
|
|
|
|
$code .= "} else {\n";
|
|
|
|
$code .= "if ((! isset(\$a['$key'])) && (! isset(\$b['$key']))) return 0;\n";
|
|
$code .= "if ((! isset(\$a['$key'])) && isset(\$b['$key'])) return -1;\n";
|
|
$code .= "if (isset(\$a['$key']) && (! isset(\$b['$key']))) return 1;\n";
|
|
|
|
|
|
$code .= "if (is_numeric(\$a['$key']) && is_numeric(\$b['$key'])) {\n";
|
|
|
|
$code .= " if (\$a['$key'] != \$b['$key'])\n";
|
|
if ($rev)
|
|
$code .= " return (\$a['$key'] < \$b['$key'] ? 1 : -1);\n";
|
|
else
|
|
$code .= " return (\$a['$key'] > \$b['$key'] ? 1 : -1);\n";
|
|
|
|
$code .= "} else {\n";
|
|
|
|
if ($rev)
|
|
$code .= " if ( (\$c = strcasecmp(\$b['$key'],\$a['$key'])) != 0 ) return \$c;\n";
|
|
else
|
|
$code .= " if ( (\$c = strcasecmp(\$a['$key'],\$b['$key'])) != 0 ) return \$c;\n";
|
|
$code .= "}}\n";
|
|
}
|
|
$code .= 'return $c;';
|
|
$CACHE[$sortby] = create_function('$a, $b',$code);
|
|
}
|
|
|
|
uasort($data,$CACHE[$sortby]);
|
|
}
|
|
|
|
/**
|
|
* Is compression enabled for output
|
|
*/
|
|
function isCompress() {
|
|
return (isset($_SESSION[APPCONFIG]) && $_SESSION[APPCONFIG]->getValue('appearance','compress')
|
|
&& ! ini_get('zlib.output_compression')
|
|
&& eregi('gzip',$_SERVER['HTTP_ACCEPT_ENCODING']));
|
|
}
|
|
?>
|