1150 lines
36 KiB
PHP
1150 lines
36 KiB
PHP
<?php
|
|
/**
|
|
* TNT OFFICIAL MODULE FOR PRESTASHOP.
|
|
*
|
|
* @author GFI Informatique <www.gfi.world>
|
|
* @copyright 2016-2019 GFI Informatique, 2016-2019 TNT
|
|
* @license https://opensource.org/licenses/MIT MIT License
|
|
*/
|
|
|
|
require_once _PS_MODULE_DIR_.'tntofficiel/libraries/TNTOfficiel_ClassLoader.php';
|
|
|
|
class TNTOfficiel_Logstack
|
|
{
|
|
/**
|
|
* @var bool Is debugging enabled ?
|
|
* _PS_MODE_DEV_ should be false to catch all error.
|
|
*/
|
|
private static $boolEnabled = false;
|
|
/**
|
|
* @var array List of allowed client IP. No client IP means all allowed.
|
|
*/
|
|
private static $arrRemoteIPAddressAllowed = array();
|
|
|
|
/**
|
|
* @var int Backtrace maximum items. 0 to disable backtrace.
|
|
*/
|
|
private static $intBackTraceMaxDeepDefault = 0;
|
|
private static $intBackTraceMaxDeepException = 64;
|
|
private static $intBackTraceMaxDeepError = 64;
|
|
|
|
/**
|
|
* @var bool Backtrace arguments detail at maximum.
|
|
*/
|
|
private static $boolBackTraceArgsDetail = false;
|
|
|
|
/**
|
|
* @var array Error type and message pattern to exclude.
|
|
*/
|
|
private static $arrPHPErrorExclude = array(
|
|
'E_WARNING' => array(
|
|
'/^filemtime\(\): stat failed for/ui',
|
|
'/^file_exists\(\): open_basedir restriction in effect\./ui',
|
|
'/^mkdir\(\): File exists /ui'
|
|
),
|
|
'E_USER_DEPRECATED' => array(
|
|
'/^AdminMarketing is a deprecated tab since version /ui',
|
|
'/^AdminCarrierWizard is a deprecated tab since version /ui',
|
|
'/^The Swift_Transport_MailTransport class is deprecated since version /ui',
|
|
'/^Fetching the "[^"]++" private service or alias is deprecated since Symfony /ui',
|
|
),
|
|
'E_NOTICE' => array(
|
|
'/^(ArrayObject::)?serialize\(\): "[\S\s]+?" returned as member variable from __sleep\(\) but does not exist$/ui'
|
|
)
|
|
);
|
|
|
|
|
|
|
|
/**
|
|
* @var array PHP Errors constant name list.
|
|
*/
|
|
private static $arrPHPErrorNames = array(
|
|
'E_ERROR',
|
|
'E_RECOVERABLE_ERROR',
|
|
'E_WARNING',
|
|
'E_PARSE',
|
|
'E_NOTICE',
|
|
'E_STRICT',
|
|
'E_DEPRECATED', // PHP 5.3+
|
|
'E_CORE_ERROR',
|
|
'E_CORE_WARNING',
|
|
'E_COMPILE_ERROR',
|
|
'E_COMPILE_WARNING',
|
|
'E_USER_ERROR',
|
|
'E_USER_WARNING',
|
|
'E_USER_NOTICE',
|
|
'E_USER_DEPRECATED' // PHP 5.3+
|
|
);
|
|
/**
|
|
* @var array PHP Errors map. Dynamically generated using getPHPErrorType().
|
|
*/
|
|
private static $arrPHPErrorMap = null;
|
|
|
|
/**
|
|
* @var array JSON Errors constant name list. PHP 5.3.0+.
|
|
*/
|
|
private static $arrJSONErrorNames = array(
|
|
'JSON_ERROR_NONE',
|
|
'JSON_ERROR_DEPTH',
|
|
'JSON_ERROR_STATE_MISMATCH',
|
|
'JSON_ERROR_CTRL_CHAR',
|
|
'JSON_ERROR_SYNTAX',
|
|
'JSON_ERROR_UTF8', // PHP 5.3.3+
|
|
'JSON_ERROR_RECURSION', // PHP 5.5.0+
|
|
'JSON_ERROR_INF_OR_NAN', // PHP 5.5.0+
|
|
'JSON_ERROR_UNSUPPORTED_TYPE', // PHP 5.5.0+
|
|
);
|
|
/**
|
|
* @var array JSON Errors map. PHP 5.3.0+.
|
|
*/
|
|
private static $arrJSONErrorMap = null;
|
|
|
|
|
|
/**
|
|
* @var bool
|
|
*/
|
|
private static $boolHandlerRegistered = false;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
private static $strRoot = null;
|
|
/**
|
|
* @var string
|
|
*/
|
|
private static $strFileName = null;
|
|
|
|
|
|
/**
|
|
* Prevent Construct.
|
|
*/
|
|
final private function __construct()
|
|
{
|
|
trigger_error(sprintf('%s() %s is static.', __FUNCTION__, get_class($this)), E_USER_ERROR);
|
|
}
|
|
|
|
/**
|
|
* Check if client IP address allowed to use debug.
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function isClientIPAddressAllowed()
|
|
{
|
|
$strRemoteIPAddress = array_key_exists('REMOTE_ADDR', $_SERVER) ? $_SERVER['REMOTE_ADDR'] : null;
|
|
|
|
$boolIPAllowed = count(TNTOfficiel_Logstack::$arrRemoteIPAddressAllowed) === 0
|
|
|| in_array($strRemoteIPAddress, TNTOfficiel_Logstack::$arrRemoteIPAddressAllowed, true) === true;
|
|
|
|
return $boolIPAllowed;
|
|
}
|
|
|
|
/**
|
|
* Encode to JSON.
|
|
*
|
|
* @param array $arrDebugInfo
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function encJSON($arrDebugInfo, $boolArgPetty = true)
|
|
{
|
|
$flagJSONEncode = 0;
|
|
if ($boolArgPetty === true) {
|
|
$flagJSONEncode |= defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0;
|
|
}
|
|
$flagJSONEncode |= defined('JSON_UNESCAPED_UNICODE') ? JSON_UNESCAPED_UNICODE : 0;
|
|
$flagJSONEncode |= defined('JSON_UNESCAPED_SLASHES') ? JSON_UNESCAPED_SLASHES : 0;
|
|
|
|
// PHP < 5.3 return null if second parameter is used.
|
|
return $flagJSONEncode === 0 ? json_encode($arrDebugInfo) : json_encode($arrDebugInfo, $flagJSONEncode);
|
|
}
|
|
|
|
/**
|
|
* Get PHP Error name from value.
|
|
*
|
|
* @param int $intArgType
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getPHPErrorType($intArgType)
|
|
{
|
|
// Generate constant name mapping.
|
|
if (TNTOfficiel_Logstack::$arrPHPErrorMap === null) {
|
|
TNTOfficiel_Logstack::$arrPHPErrorMap = array();
|
|
foreach (TNTOfficiel_Logstack::$arrPHPErrorNames as $strPHPErrorTypeName) {
|
|
if (defined($strPHPErrorTypeName)) {
|
|
// Get constant value.
|
|
$intPHPErrorType = constant($strPHPErrorTypeName);
|
|
TNTOfficiel_Logstack::$arrPHPErrorMap[ $intPHPErrorType ] = $strPHPErrorTypeName;
|
|
}
|
|
}
|
|
}
|
|
|
|
$strPHPErrorType = (string)$intArgType;
|
|
if (array_key_exists($intArgType, TNTOfficiel_Logstack::$arrPHPErrorMap)) {
|
|
$strPHPErrorType = TNTOfficiel_Logstack::$arrPHPErrorMap[ $intArgType ];
|
|
}
|
|
|
|
return $strPHPErrorType;
|
|
}
|
|
|
|
|
|
/**
|
|
* Get JSON Error name from value.
|
|
*
|
|
* @param int $intArgType
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getJSONErrorType($intArgType)
|
|
{
|
|
// Generate constant name mapping.
|
|
if (TNTOfficiel_Logstack::$arrJSONErrorMap === null) {
|
|
TNTOfficiel_Logstack::$arrJSONErrorMap = array();
|
|
foreach (TNTOfficiel_Logstack::$arrJSONErrorNames as $strJSONErrorTypeName) {
|
|
if (defined($strJSONErrorTypeName)) {
|
|
// Get constant value.
|
|
$intJSONErrorType = constant($strJSONErrorTypeName);
|
|
TNTOfficiel_Logstack::$arrJSONErrorMap[ $intJSONErrorType ] = $strJSONErrorTypeName;
|
|
}
|
|
}
|
|
}
|
|
|
|
$strJSONErrorType = (string)$intArgType;
|
|
if (array_key_exists($intArgType, TNTOfficiel_Logstack::$arrJSONErrorMap)) {
|
|
$strJSONErrorType = TNTOfficiel_Logstack::$arrJSONErrorMap[ $intArgType ];
|
|
}
|
|
|
|
return $strJSONErrorType;
|
|
}
|
|
|
|
/**
|
|
* Capture an Error.
|
|
*
|
|
* @param int $intArgType
|
|
* @param string $strArgMessage
|
|
* @param string|null $strArgFile
|
|
* @param int $intArgLine
|
|
* @param array $arrArgContext
|
|
* @param bool $boolArgIsLast
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function captureError(
|
|
$intArgType,
|
|
$strArgMessage,
|
|
$strArgFile = null,
|
|
$intArgLine = 0,
|
|
$arrArgContext = array(),
|
|
$boolArgIsLast = false
|
|
) {
|
|
$arrLogError = array(
|
|
'type' => $boolArgIsLast ? 'LastError' : 'Error'
|
|
);
|
|
|
|
if ($strArgFile !== null) {
|
|
$arrLogError['file'] = $strArgFile;
|
|
$arrLogError['line'] = $intArgLine;
|
|
}
|
|
|
|
if ($boolArgIsLast) {
|
|
$arrLogError['trace'] = array();
|
|
}
|
|
|
|
$strPHPErrorType = TNTOfficiel_Logstack::getPHPErrorType($intArgType);
|
|
$arrLogError['msg'] = 'Type '.$strPHPErrorType.': '.$strArgMessage;
|
|
|
|
if (array_key_exists($strPHPErrorType, TNTOfficiel_Logstack::$arrPHPErrorExclude)
|
|
&& is_array(TNTOfficiel_Logstack::$arrPHPErrorExclude[$strPHPErrorType])
|
|
) {
|
|
if (count(TNTOfficiel_Logstack::$arrPHPErrorExclude[$strPHPErrorType]) === 0) {
|
|
return false;
|
|
}
|
|
foreach (TNTOfficiel_Logstack::$arrPHPErrorExclude[$strPHPErrorType] as $strPattern) {
|
|
if (preg_match($strPattern, $strArgMessage) === 1) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
TNTOfficiel_Logstack::stack($arrLogError, TNTOfficiel_Logstack::$intBackTraceMaxDeepError);
|
|
|
|
// Internal error handler continues (displays/log error, …)
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Capture last Error.
|
|
* Useful at script end for E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE, …
|
|
*/
|
|
public static function captureLastError()
|
|
{
|
|
$arrPHPLastError = error_get_last();
|
|
|
|
if (is_array($arrPHPLastError)) {
|
|
TNTOfficiel_Logstack::captureError(
|
|
$arrPHPLastError['type'],
|
|
$arrPHPLastError['message'],
|
|
$arrPHPLastError['file'],
|
|
$arrPHPLastError['line'],
|
|
array(),
|
|
true
|
|
);
|
|
}
|
|
|
|
// PHP 5.3.0+
|
|
if (function_exists('json_last_error')) {
|
|
$intTypeJSONLastError = json_last_error();
|
|
$strJSONLastErrorType = TNTOfficiel_Logstack::getJSONErrorType($intTypeJSONLastError);
|
|
if ($strJSONLastErrorType !== 'JSON_ERROR_NONE') {
|
|
// PHP 5.5.0+
|
|
$strJSONLastErrorMessage = function_exists('json_last_error_msg') ? json_last_error_msg() : 'N/A';
|
|
TNTOfficiel_Logstack::captureError(
|
|
$strJSONLastErrorType,
|
|
$strJSONLastErrorMessage,
|
|
null,
|
|
0,
|
|
array(),
|
|
true
|
|
);
|
|
}
|
|
}
|
|
|
|
// PHP 5.3.0+
|
|
if (function_exists('date_get_last_errors')) {
|
|
$arrTypeDateLastError = date_get_last_errors();
|
|
if (is_array($arrTypeDateLastError)) {
|
|
if (array_key_exists('errors', $arrTypeDateLastError)
|
|
&& count($arrTypeDateLastError['errors']) > 0
|
|
) {
|
|
$strDateLastErrorType = 'DATE_ERROR';
|
|
$strDateLastErrorMessage = TNTOfficiel_Logstack::encJSON($arrTypeDateLastError['errors']);
|
|
TNTOfficiel_Logstack::captureError(
|
|
$strDateLastErrorType,
|
|
$strDateLastErrorMessage,
|
|
null,
|
|
0,
|
|
array(),
|
|
true
|
|
);
|
|
}
|
|
if (array_key_exists('warnings', $arrTypeDateLastError)
|
|
&& count($arrTypeDateLastError['warnings']) > 0
|
|
) {
|
|
$strDateLastErrorType = 'DATE_WARNING';
|
|
$strDateLastErrorMessage = TNTOfficiel_Logstack::encJSON($arrTypeDateLastError['warnings']);
|
|
TNTOfficiel_Logstack::captureError(
|
|
$strDateLastErrorType,
|
|
$strDateLastErrorMessage,
|
|
null,
|
|
0,
|
|
array(),
|
|
true
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Capture an Exception.
|
|
*
|
|
* @param Exception $objArgException
|
|
*/
|
|
public static function captureException($objArgException, $boolArgReturn = false)
|
|
{
|
|
$arrLogException = array(
|
|
'type' => 'Exception'
|
|
);
|
|
|
|
if ($objArgException->getFile() !== null) {
|
|
$arrLogException['file'] = $objArgException->getFile();
|
|
$arrLogException['line'] = $objArgException->getLine();
|
|
}
|
|
|
|
$arrLogException['msg'] = 'Code '.$objArgException->getCode().': '.$objArgException->getMessage();
|
|
$arrLogException['trace'] = $objArgException->getTrace();
|
|
|
|
return TNTOfficiel_Logstack::stack(
|
|
$arrLogException,
|
|
TNTOfficiel_Logstack::$intBackTraceMaxDeepException,
|
|
$boolArgReturn
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Capture connection status.
|
|
*/
|
|
public static function captureConnectionStatus()
|
|
{
|
|
// is non normal connection status.
|
|
$intStatus = connection_status();
|
|
// connection_aborted()
|
|
if ($intStatus & 1) {
|
|
TNTOfficiel_Logstack::stack(array(
|
|
'type' => 'Shutdown',
|
|
'msg' => sprintf('Connection was aborted by user.')
|
|
));
|
|
}
|
|
if ($intStatus & 2) {
|
|
TNTOfficiel_Logstack::stack(array(
|
|
'type' => 'Shutdown',
|
|
'msg' => sprintf('Script exceeded maximum execution time.')
|
|
));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Capture output buffer status.
|
|
*/
|
|
public static function captureOutPutBufferStatus()
|
|
{
|
|
$msg = 'Output was not sent yet.';
|
|
|
|
// is output buffer was sent
|
|
$strOutputBufferFile = null;
|
|
$intOutputBufferLine = null;
|
|
$boolOutputBufferSent = headers_sent($strOutputBufferFile, $intOutputBufferLine);
|
|
if ($boolOutputBufferSent) {
|
|
$msg = sprintf('Output was sent in \'%s\' on line %s.', $strOutputBufferFile, $intOutputBufferLine);
|
|
}
|
|
|
|
TNTOfficiel_Logstack::stack(array(
|
|
'type' => 'Shutdown',
|
|
'msg' => $msg,
|
|
'headers' => headers_list(),
|
|
'level' => ob_get_level()
|
|
), 0);
|
|
}
|
|
|
|
/**
|
|
* Capture at shutdown.
|
|
*/
|
|
public static function captureAtShutdown()
|
|
{
|
|
TNTOfficiel_Logstack::captureLastError();
|
|
TNTOfficiel_Logstack::captureConnectionStatus();
|
|
TNTOfficiel_Logstack::captureOutPutBufferStatus();
|
|
TNTOfficiel_Logstack::addLogContent('{}]');
|
|
}
|
|
|
|
|
|
/**
|
|
* Register capture handlers once.
|
|
*/
|
|
public static function registerHandlers()
|
|
{
|
|
/*
|
|
$mxdPrevExceptionHandler = true;
|
|
while ($mxdPrevExceptionHandler !== null) {
|
|
// Get previous error handler.
|
|
$mxdPrevExceptionHandler = set_error_handler(array('TNTOfficiel_Logstack', 'captureError'));
|
|
restore_error_handler();
|
|
//
|
|
if ($mxdPrevExceptionHandler !== null) {
|
|
// Remove previous error handler like ControllerCore::myErrorHandler().
|
|
restore_error_handler();
|
|
}
|
|
}
|
|
set_error_handler(array('TNTOfficiel_Logstack', 'captureError'));
|
|
|
|
$mxdPrevExceptionHandler = true;
|
|
while ($mxdPrevExceptionHandler !== null) {
|
|
// Get previous exception handler.
|
|
$mxdPrevExceptionHandler = set_exception_handler(array('TNTOfficiel_Logstack', 'captureException'));
|
|
restore_exception_handler();
|
|
//
|
|
if ($mxdPrevExceptionHandler !== null) {
|
|
// Remove previous exception handler.
|
|
restore_exception_handler();
|
|
}
|
|
}
|
|
set_exception_handler(array('TNTOfficiel_Logstack', 'captureException'));
|
|
*/
|
|
|
|
if (TNTOfficiel_Logstack::$boolHandlerRegistered !== true) {
|
|
TNTOfficiel_Logstack::$boolHandlerRegistered = true;
|
|
set_error_handler(array('TNTOfficiel_Logstack', 'captureError'));
|
|
set_exception_handler(array('TNTOfficiel_Logstack', 'captureException'));
|
|
register_shutdown_function(array('TNTOfficiel_Logstack', 'captureAtShutdown'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the script start time.
|
|
*
|
|
* @return float
|
|
*/
|
|
public static function getStartTime()
|
|
{
|
|
return (float)(array_key_exists('REQUEST_TIME_FLOAT', $_SERVER) ? $_SERVER['REQUEST_TIME_FLOAT'] :
|
|
$_SERVER['REQUEST_TIME']);
|
|
}
|
|
|
|
|
|
/**
|
|
* Set log root directory.
|
|
*
|
|
* @param string $strArgRoot
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function setRootDirectory($strArgRoot)
|
|
{
|
|
TNTOfficiel_Logstack::$strRoot = null;
|
|
|
|
$strRealpath = realpath($strArgRoot);
|
|
|
|
// If not a writable directory.
|
|
if ($strRealpath === false || !is_dir($strRealpath) || !is_writable($strRealpath)) {
|
|
return false;
|
|
}
|
|
|
|
// Add final separator.
|
|
if (Tools::substr($strRealpath, -1) !== DIRECTORY_SEPARATOR) {
|
|
$strRealpath .= DIRECTORY_SEPARATOR;
|
|
}
|
|
|
|
// Save.
|
|
TNTOfficiel_Logstack::$strRoot = $strRealpath;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get log filename.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getFilename()
|
|
{
|
|
// If root directory is defined, but not the filename.
|
|
if (TNTOfficiel_Logstack::$strRoot !== null && TNTOfficiel_Logstack::$strFileName === null) {
|
|
// Get Optional IP folder.
|
|
$strClientIPFolder = '';
|
|
if (array_key_exists('REMOTE_ADDR', $_SERVER)) {
|
|
$strClientIPFolder = preg_replace('/[^a-z0-9_]+/ui', '-', $_SERVER['REMOTE_ADDR']).DIRECTORY_SEPARATOR;
|
|
}
|
|
// Create folder.
|
|
TNTOfficiel_Tools::makeDirectory(TNTOfficiel_Logstack::$strRoot.$strClientIPFolder);
|
|
// Check.
|
|
if (!is_dir(TNTOfficiel_Logstack::$strRoot.$strClientIPFolder)) {
|
|
$strClientIPFolder = '';
|
|
}
|
|
|
|
$floatScriptTime = TNTOfficiel_Logstack::getStartTime();
|
|
$strTimeStampExport = var_export($floatScriptTime, true);
|
|
$strTimeStampMaxWidth = preg_replace('/^([0-9]+(?:\.[0-9]{1,6}))[0-9]*$/ui', '$1', $strTimeStampExport);
|
|
$strTimeStampNum = preg_replace('/\./ui', '', $strTimeStampMaxWidth);
|
|
$strTimeStamp = sprintf('%-016s', $strTimeStampNum);
|
|
|
|
$strShopFullContextID = 'G'.(int)Shop::getContextShopGroupID().'S'.(int)Shop::getContextShopID();
|
|
|
|
$strFileName = $strTimeStamp.'-'.$strShopFullContextID.'-'
|
|
.preg_replace('/[^a-z0-9_]+/ui', '-', parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
|
|
|
|
TNTOfficiel_Logstack::$strFileName = TNTOfficiel_Logstack::$strRoot.$strClientIPFolder.$strFileName.'.json';
|
|
}
|
|
|
|
return TNTOfficiel_Logstack::$strFileName;
|
|
}
|
|
|
|
/**
|
|
* Create log file if do not exist.
|
|
* Log global info at creation.
|
|
*
|
|
* @param string $strArgDebugInfo
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function addLogContent($strArgDebugInfo = '')
|
|
{
|
|
$strFileName = TNTOfficiel_Logstack::getFilename();
|
|
|
|
if ($strFileName === null) {
|
|
return false;
|
|
}
|
|
|
|
// If file don't already exist.
|
|
if (!file_exists($strFileName)) {
|
|
$arrDebugInfo = array(
|
|
'type' => 'Intro',
|
|
'uri' => array_key_exists('REQUEST_URI', $_SERVER) ? $_SERVER['REQUEST_URI'] : null,
|
|
'referer' => array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : null,
|
|
'client' => array_key_exists('REMOTE_ADDR', $_SERVER) ? $_SERVER['REMOTE_ADDR'] : null,
|
|
'post' => $_POST,
|
|
'get' => $_GET,
|
|
'cookie' => $_COOKIE,
|
|
'config' => array(
|
|
'php' => TNTOfficiel_Logstack::getPHPConfig(),
|
|
'ps' => TNTOfficiel_Logstack::getPSConfig()
|
|
)
|
|
);
|
|
|
|
$strDebugInfo = '['.TNTOfficiel_Logstack::encJSON($arrDebugInfo).',';
|
|
|
|
$strArgDebugInfo = $strDebugInfo.$strArgDebugInfo;
|
|
}
|
|
|
|
touch($strFileName);
|
|
chmod($strFileName, 0660);
|
|
|
|
return file_put_contents($strFileName, $strArgDebugInfo, FILE_APPEND) > 0;
|
|
}
|
|
|
|
public static function dumpItem($args)
|
|
{
|
|
$t = $args;
|
|
if (!is_scalar($args) && !($args === null)) {
|
|
$t = '('.gettype($args).')';
|
|
if (is_object($args)) {
|
|
$t .= get_class($args);
|
|
}
|
|
}
|
|
|
|
$u = $args;
|
|
if (!is_scalar($args) && !($args === null)) {
|
|
// Detecting circular reference, etc ...
|
|
try {
|
|
serialize($args);
|
|
} catch (Exception $e) {
|
|
return $t;
|
|
}
|
|
|
|
$strArgsJSON = TNTOfficiel_Logstack::encJSON($args, false);
|
|
// If unable to encode.
|
|
if (Tools::strlen($strArgsJSON) == 0) {
|
|
return $t;
|
|
} else {
|
|
return $t.preg_replace('/"/ui', '`', $strArgsJSON);
|
|
}
|
|
}
|
|
|
|
return $u;
|
|
}
|
|
|
|
public static function dumpArgs($args)
|
|
{
|
|
try {
|
|
$arrCallerArgsDeep = array();
|
|
foreach ($args as $k => $mxdTraceArg) {
|
|
$arrCallerArgsDeep[ $k ] = TNTOfficiel_Logstack::dumpItem($mxdTraceArg);
|
|
}
|
|
$args = $arrCallerArgsDeep;
|
|
} catch (Exception $e) {
|
|
$args = TNTOfficiel_Logstack::dumpItem($args);
|
|
}
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* Append stack info.
|
|
*
|
|
* @param array|null $arrArg
|
|
* @param int|null $intArgBackTraceMaxDeep
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function stack($arrArg = null, $intArgBackTraceMaxDeep = null, $boolArgReturn = false)
|
|
{
|
|
$intBackTraceMaxDeep = TNTOfficiel_Logstack::$intBackTraceMaxDeepDefault;
|
|
if ( $intArgBackTraceMaxDeep >= 0 ) {
|
|
$intBackTraceMaxDeep = $intArgBackTraceMaxDeep;
|
|
}
|
|
|
|
if ($boolArgReturn !== true) {
|
|
// If not enabled or client IP not allowed.
|
|
if (TNTOfficiel_Logstack::$boolEnabled !== true || TNTOfficiel_Logstack::isClientIPAddressAllowed() !== true) {
|
|
return;
|
|
}
|
|
|
|
// Set default path.
|
|
//TNTOfficiel_Logstack::setRootDirectory(_PS_ROOT_DIR_.'/log/');
|
|
TNTOfficiel_Logstack::setRootDirectory(
|
|
_PS_MODULE_DIR_.TNTOfficiel::MODULE_NAME.DIRECTORY_SEPARATOR.TNTOfficiel::PATH_LOG
|
|
);
|
|
|
|
// Register handlers if not.
|
|
TNTOfficiel_Logstack::registerHandlers();
|
|
}
|
|
|
|
if (!is_array($arrArg)) {
|
|
$arrArg = array('raw' => $arrArg);
|
|
}
|
|
|
|
// If message, file and line exist, then concat.
|
|
if (array_key_exists('msg', $arrArg)
|
|
&& array_key_exists('file', $arrArg)
|
|
&& array_key_exists('line', $arrArg)
|
|
) {
|
|
$arrArg['msg'] .= ' \''.$arrArg['file'].'\' on line '.$arrArg['line'];
|
|
unset($arrArg['file']);
|
|
unset($arrArg['line']);
|
|
}
|
|
|
|
// If no backtrace and auto backtrace set.
|
|
if ($intBackTraceMaxDeep > 0
|
|
&& (!array_key_exists('trace', $arrArg) || !is_array($arrArg['trace']))
|
|
) {
|
|
// Get current one.
|
|
$arrArg['trace'] = debug_backtrace();
|
|
// TODO : remove all trace from this current method.
|
|
// Remove trace from this current method.
|
|
array_shift($arrArg['trace']);
|
|
}
|
|
|
|
// Process backtrace.
|
|
if (array_key_exists('trace', $arrArg) && is_array($arrArg['trace'])) {
|
|
// Final backtrace.
|
|
$arrTraceStack = array();
|
|
|
|
// Get each trace, deeper first.
|
|
while ($arrTrace = array_shift($arrArg['trace'])) {
|
|
$intDeepIndex = count($arrTraceStack);
|
|
// Get stack with maximum items.
|
|
if ($intDeepIndex >= $intBackTraceMaxDeep) {
|
|
break;
|
|
}
|
|
|
|
// function
|
|
if (array_key_exists('class', $arrTrace) && is_string($arrTrace['class'])) {
|
|
// Exclude this class.
|
|
if (in_array($arrTrace['class'], array(__CLASS__), true)) {
|
|
continue;
|
|
}
|
|
$arrTrace['function'] = $arrTrace['class'].$arrTrace['type'].$arrTrace['function'];
|
|
}
|
|
// file
|
|
if (array_key_exists('file', $arrTrace) && is_string($arrTrace['file'])) {
|
|
$arrTrace['file'] = '\''.$arrTrace['file'].'\' on line '.$arrTrace['line'];
|
|
} else {
|
|
$arrTrace['file'] = '[Internal]';
|
|
}
|
|
|
|
// arguments
|
|
$arrCallerArgs = array();
|
|
if (array_key_exists('args', $arrTrace) && is_array($arrTrace['args'])) {
|
|
foreach ($arrTrace['args'] as $k => $mxdTraceArg) {
|
|
if (is_scalar($mxdTraceArg) || $mxdTraceArg === null) {
|
|
$arrCallerArgs[ $k ] = $mxdTraceArg;
|
|
} else {
|
|
$arrCallerArgs[ $k ] = '('.gettype($mxdTraceArg).')';
|
|
if (is_object($mxdTraceArg)) {
|
|
$arrCallerArgs[ $k ] .= get_class($mxdTraceArg);
|
|
}
|
|
}
|
|
}
|
|
$arrTrace['function'] .= '('.count($arrCallerArgs).')';
|
|
}
|
|
|
|
unset($arrTrace['line']);
|
|
unset($arrTrace['class']);
|
|
unset($arrTrace['type']);
|
|
unset($arrTrace['object']);
|
|
|
|
if ($boolArgReturn === true
|
|
|| TNTOfficiel_Logstack::$boolBackTraceArgsDetail === true
|
|
) {
|
|
if (array_key_exists('args', $arrTrace)) {
|
|
$arrTrace['args'] = TNTOfficiel_Logstack::dumpArgs($arrTrace['args']);
|
|
}
|
|
} else {
|
|
$arrTrace['args'] = $arrCallerArgs;
|
|
}
|
|
|
|
// If no arguments.
|
|
if (count($arrCallerArgs) === 0) {
|
|
// Remove key (no line output).
|
|
unset($arrTrace['args']);
|
|
}
|
|
|
|
// Add trace.
|
|
$arrTraceStack[ $intDeepIndex ] = $arrTrace;
|
|
}
|
|
|
|
// Save processed backtrace.
|
|
$arrArg['trace'] = $arrTraceStack;
|
|
|
|
// Remove backtrace key if empty.
|
|
if (count($arrArg['trace']) === 0) {
|
|
unset($arrArg['trace']);
|
|
}
|
|
}
|
|
|
|
// Append time and memory consumption.
|
|
$arrArg += array(
|
|
'time' => microtime(true) - TNTOfficiel_Logstack::getStartTime(),
|
|
'mem' => memory_get_peak_usage() / 1024 / 1024,
|
|
);
|
|
|
|
// List of sorted selected key.
|
|
$arrKeyExistSort = array_intersect_key(array_flip(
|
|
array('time', 'mem', 'type', 'msg', 'file', 'line', 'raw', 'dump', 'trace')
|
|
), $arrArg);
|
|
// List of unsorted key left.
|
|
$arrKeyUnExistUnSort = array_diff_key($arrArg, $arrKeyExistSort);
|
|
// Append unsorted list to sorted.
|
|
$arrArg = array_merge($arrKeyExistSort, $arrArg) + $arrKeyUnExistUnSort;
|
|
|
|
$strDebugInfo = TNTOfficiel_Logstack::encJSON($arrArg).',';
|
|
$strDebugInfo = preg_replace('/}\s*,\s*{/ui', '},{', $strDebugInfo);
|
|
|
|
if ($boolArgReturn !== true) {
|
|
TNTOfficiel_Logstack::addLogContent($strDebugInfo);
|
|
}
|
|
|
|
return $strDebugInfo;
|
|
}
|
|
|
|
/**
|
|
* Append log info.
|
|
*
|
|
* @param array|null $arrArg
|
|
* @param int|null $intArgBackTraceMaxDeep
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function log($arrArg = null, $intArgBackTraceMaxDeep = null, $boolArgReturn = false)
|
|
{
|
|
$intBackTraceMaxDeep = TNTOfficiel_Logstack::$intBackTraceMaxDeepDefault;
|
|
if ( $intArgBackTraceMaxDeep > 0 ) {
|
|
$intBackTraceMaxDeep = $intArgBackTraceMaxDeep;
|
|
}
|
|
|
|
if ($arrArg === null & $intBackTraceMaxDeep === 0) {
|
|
return '';
|
|
}
|
|
|
|
return TNTOfficiel_Logstack::stack($arrArg, $intBackTraceMaxDeep, $boolArgReturn);
|
|
}
|
|
|
|
/**
|
|
* Append dump info.
|
|
*
|
|
* @param array|null $arrArg
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function dump($arrArg = null, $boolArgReturn = false)
|
|
{
|
|
return TNTOfficiel_Logstack::stack(array('dump' => $arrArg), 0, $boolArgReturn);
|
|
}
|
|
|
|
/**
|
|
* Append trace info.
|
|
*
|
|
* @param null $intArgBackTraceMaxDeep
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function trace($intArgBackTraceMaxDeep = null, $boolArgReturn = false)
|
|
{
|
|
$intBackTraceMaxDeep = TNTOfficiel_Logstack::$intBackTraceMaxDeepException;
|
|
if ( $intArgBackTraceMaxDeep > 0 ) {
|
|
$intBackTraceMaxDeep = $intArgBackTraceMaxDeep;
|
|
}
|
|
|
|
return TNTOfficiel_Logstack::stack(array(), $intBackTraceMaxDeep, $boolArgReturn);
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public static function getPHPConfig()
|
|
{
|
|
/*
|
|
* User
|
|
*/
|
|
|
|
$arrUser = posix_getpwuid(posix_geteuid());
|
|
|
|
/*
|
|
* Environment
|
|
*/
|
|
|
|
$arrEnv = array(
|
|
'http_proxy' => getenv('http_proxy'),
|
|
'https_proxy' => getenv('https_proxy'),
|
|
'ftp_proxy' => getenv('ftp_proxy')
|
|
);
|
|
|
|
/*
|
|
* Constant
|
|
*/
|
|
|
|
$arrPHPConstants = array(
|
|
'PHP_OS' => PHP_OS,
|
|
'PHP_VERSION' => PHP_VERSION,
|
|
'PHP_SAPI' => PHP_SAPI,
|
|
'PHP_INT_SIZE (bits)' => PHP_INT_SIZE * 8
|
|
);
|
|
|
|
/*
|
|
* Extension
|
|
*/
|
|
|
|
$arrPHPExtensions = array_intersect_key(array_flip(get_loaded_extensions()), array(
|
|
'curl' => true,
|
|
'soap' => true,
|
|
'session' => true,
|
|
'mcrypt' => true,
|
|
'mhash' => true,
|
|
'mbstring' => true,
|
|
'iconv' => true,
|
|
'zip' => true,
|
|
'zlib' => true,
|
|
'dom' => true,
|
|
'xml' => true,
|
|
'SimpleXML' => true,
|
|
'Zend OPcache' => true,
|
|
'ionCube Loader' => true
|
|
));
|
|
|
|
/*
|
|
* Configuration
|
|
*/
|
|
|
|
$arrPHPConfiguration = array_intersect_key(ini_get_all(null, false), array(
|
|
// php
|
|
'magic_quotes' => 'Off',
|
|
'magic_quotes_gpc' => 'Off',
|
|
'max_input_vars' => '8192',
|
|
// core - file uploads
|
|
'upload_max_filesize' => '4M',
|
|
// core - language options
|
|
'disable_functions' => '',
|
|
'disable_classes' => '',
|
|
// core - paths and directories
|
|
'open_basedir' => '',
|
|
// core - data handling
|
|
'register_globals' => 'Off',
|
|
// safe mode
|
|
'safe_mode' => '',
|
|
'safe_mode_gid' => '',
|
|
'safe_mode_exec_dir' => '',
|
|
'safe_mode_include_dir' => '',
|
|
// filesystem
|
|
'allow_url_fopen' => 'On',
|
|
'allow_url_include' => 'Off',
|
|
'default_socket_timeout' => '60',
|
|
// opcache
|
|
'opcache.enable' => 'true'
|
|
));
|
|
|
|
if (array_key_exists('open_basedir', $arrPHPConfiguration)) {
|
|
$arrPHPConfiguration['open_basedir'] = explode(PATH_SEPARATOR, $arrPHPConfiguration['open_basedir']);
|
|
}
|
|
|
|
/*
|
|
* Time
|
|
*/
|
|
|
|
$arrPHPTime = array(
|
|
'date_default_timezone_set' => date_default_timezone_get(),
|
|
'date.timezone' => ini_get('date.timezone'),
|
|
'date' => date('Y-m-d H:i:s P T (e)'),
|
|
);
|
|
|
|
|
|
return array(
|
|
'user' => $arrUser,
|
|
'env' => $arrEnv,
|
|
'constants' => $arrPHPConstants,
|
|
'extensions' => $arrPHPExtensions,
|
|
'configuration' => $arrPHPConfiguration,
|
|
'time' => $arrPHPTime
|
|
);
|
|
}
|
|
|
|
public static function getPSConfig()
|
|
{
|
|
/*
|
|
* Constant
|
|
*/
|
|
|
|
//$__constants = get_defined_constants(true);
|
|
$arrPSConstant = array(
|
|
'_PS_VERSION_' => _PS_VERSION_,
|
|
'_PS_JQUERY_VERSION_' => _PS_JQUERY_VERSION_,
|
|
|
|
'_PS_MODE_DEV_' => _PS_MODE_DEV_,
|
|
'_PS_DEBUG_PROFILING_' => _PS_DEBUG_PROFILING_,
|
|
|
|
'_PS_MAGIC_QUOTES_GPC_' => _PS_MAGIC_QUOTES_GPC_,
|
|
'_PS_USE_SQL_SLAVE_' => _PS_USE_SQL_SLAVE_,
|
|
|
|
'_PS_CACHE_ENABLED_' => _PS_CACHE_ENABLED_,
|
|
'_PS_CACHING_SYSTEM_' => _PS_CACHING_SYSTEM_,
|
|
|
|
'_PS_DEFAULT_THEME_NAME_' => _PS_DEFAULT_THEME_NAME_,
|
|
'_PS_THEME_DIR_' => _PS_THEME_DIR_,
|
|
//'_PS_THEME_OVERRIDE_DIR_' => _PS_THEME_OVERRIDE_DIR_,
|
|
//'_PS_THEME_MOBILE_DIR_' => _PS_THEME_MOBILE_DIR_,
|
|
//'_PS_THEME_MOBILE_OVERRIDE_DIR_' => _PS_THEME_MOBILE_OVERRIDE_DIR_,
|
|
//'_PS_THEME_TOUCHPAD_DIR_' => _PS_THEME_TOUCHPAD_DIR_
|
|
|
|
'_PS_CACHE_CA_CERT_FILE_' => _PS_CACHE_CA_CERT_FILE_
|
|
);
|
|
|
|
/*
|
|
* Context
|
|
*/
|
|
|
|
$flagShopContext = Shop::getContext();
|
|
$arrConstShopContext = array();
|
|
|
|
if ($flagShopContext & Shop::CONTEXT_SHOP) {
|
|
$arrConstShopContext[] = 'Shop::CONTEXT_SHOP';
|
|
}
|
|
if ($flagShopContext & Shop::CONTEXT_GROUP) {
|
|
$arrConstShopContext[] = 'Shop::CONTEXT_GROUP';
|
|
}
|
|
if ($flagShopContext & Shop::CONTEXT_ALL) {
|
|
$arrConstShopContext[] = 'Shop::CONTEXT_ALL';
|
|
}
|
|
|
|
$arrPSContext = array(
|
|
'Context::getContext()->shop->id' => Context::getContext()->shop->id,
|
|
'Context::getContext()->shop->id_shop_group' => Context::getContext()->shop->id_shop_group,
|
|
'Shop::getContext()' => $arrConstShopContext,
|
|
'Shop::isFeatureActive()' => Shop::isFeatureActive(),
|
|
'Shop::getContextShopGroupID()' => (int)Shop::getContextShopGroupID(),
|
|
'Shop::getContextShopID()' => (int)Shop::getContextShopID()
|
|
);
|
|
|
|
/*
|
|
* Configuration
|
|
*/
|
|
|
|
$arrPSConfig = Configuration::getMultiple(array(
|
|
|
|
/*
|
|
* Carrier
|
|
*/
|
|
|
|
/* Shipping */
|
|
|
|
'PS_SHIPPING_HANDLING',
|
|
'PS_SHIPPING_FREE_PRICE',
|
|
'PS_SHIPPING_FREE_WEIGHT',
|
|
|
|
'PS_CARRIER_DEFAULT',
|
|
'PS_CARRIER_DEFAULT_SORT',
|
|
'PS_CARRIER_DEFAULT_ORDER',
|
|
|
|
|
|
/*
|
|
* Localization
|
|
*/
|
|
|
|
/* Localization */
|
|
|
|
'PS_LANG_DEFAULT',
|
|
'PS_COUNTRY_DEFAULT',
|
|
'PS_CURRENCY_DEFAULT',
|
|
|
|
'PS_WEIGHT_UNIT', // kg
|
|
'PS_DISTANCE_UNIT',
|
|
'PS_VOLUME_UNIT',
|
|
'PS_DIMENSION_UNIT',
|
|
|
|
'PS_LOCALE_LANGUAGE',
|
|
'PS_LOCALE_COUNTRY',
|
|
|
|
/* Country */
|
|
|
|
'PS_RESTRICT_DELIVERED_COUNTRIES',
|
|
|
|
/* Taxes */
|
|
|
|
'PS_TAX',
|
|
'PS_TAX_DISPLAY',
|
|
'PS_TAX_ADDRESS_TYPE',
|
|
'PS_USE_ECOTAX',
|
|
'PS_ECOTAX_TAX_RULES_GROUP_ID',
|
|
|
|
|
|
/*
|
|
* Preferences
|
|
*/
|
|
|
|
/* General */
|
|
|
|
'PS_SSL_ENABLED',
|
|
'PS_SSL_ENABLED_EVERYWHERE',
|
|
'PS_PRICE_ROUND_MODE',
|
|
'PS_ROUND_TYPE',
|
|
'PS_PRICE_DISPLAY_PRECISION',
|
|
'PS_MULTISHOP_FEATURE_ACTIVE',
|
|
// PS 1.6.1.16+
|
|
'PS_API_KEY',
|
|
|
|
/* Order */
|
|
|
|
// General
|
|
//'PS_ORDER_PROCESS_TYPE',
|
|
'PS_GUEST_CHECKOUT_ENABLED',
|
|
'PS_DISALLOW_HISTORY_REORDERING',
|
|
'PS_PURCHASE_MINIMUM',
|
|
'PS_SHIP_WHEN_AVAILABLE',
|
|
'PS_CONDITIONS',
|
|
// Multi-Shipping (deprecated)
|
|
'PS_ALLOW_MULTISHIPPING',
|
|
// Gift Wrapping
|
|
'PS_GIFT_WRAPPING',
|
|
'PS_GIFT_WRAPPING_PRICE',
|
|
'PS_GIFT_WRAPPING_TAX_RULES_GROUP',
|
|
'PS_RECYCLABLE_PACK',
|
|
|
|
/* Product */
|
|
|
|
'PS_ATTRIBUTE_ANCHOR_SEPARATOR',
|
|
'PS_ORDER_OUT_OF_STOCK',
|
|
'PS_STOCK_MANAGEMENT',
|
|
'PS_ADVANCED_STOCK_MANAGEMENT',
|
|
|
|
/* Customer */
|
|
|
|
'PS_REGISTRATION_PROCESS_TYPE',
|
|
'PS_ONE_PHONE_AT_LEAST',
|
|
'PS_B2B_ENABLE',
|
|
|
|
/* SEO & URL */
|
|
|
|
'PS_REWRITING_SETTINGS',
|
|
'PS_ALLOW_ACCENTED_CHARS_URL',
|
|
'PS_CANONICAL_REDIRECT',
|
|
|
|
/* Stores */
|
|
'PS_SHOP_NAME',
|
|
'PS_SHOP_EMAIL',
|
|
'PS_SHOP_PHONE',
|
|
|
|
|
|
/*
|
|
* Advanced Parameters
|
|
*/
|
|
|
|
/* Performance */
|
|
|
|
'PS_DISABLE_OVERRIDES',
|
|
|
|
'PS_CSS_THEME_CACHE',
|
|
'PS_JS_THEME_CACHE',
|
|
'PS_HTML_THEME_COMPRESSION',
|
|
'PS_JS_HTML_THEME_COMPRESSION',
|
|
'PS_JS_DEFER',
|
|
'PS_HTACCESS_CACHE_CONTROL',
|
|
|
|
'PS_CIPHER_ALGORITHM',
|
|
|
|
));
|
|
|
|
return array(
|
|
'constants' => $arrPSConstant,
|
|
'context' => $arrPSContext,
|
|
'configuration' => $arrPSConfig
|
|
);
|
|
}
|
|
}
|