ModCfg/Application/Model/Log/d3log.php

1665 lines
48 KiB
PHP

<?php
/**
* This Software is the property of Data Development and is protected
* by copyright law - it is NOT Freeware.
*
* Any unauthorized use of this software without a valid license
* is a violation of the license agreement and will be prosecuted by
* civil and criminal law.
*
* https://www.d3data.de
*
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
* @link http://www.oxidmodule.com
*/
namespace D3\ModCfg\Application\Model\Log;
use D3\ModCfg\Application\Model\d3bitmask;
use D3\ModCfg\Application\Model\d3database;
use D3\ModCfg\Application\Model\Configuration\d3_cfg_mod;
use D3\ModCfg\Application\Model\Parametercontainer\Registry as D3ModCfgRegistry;
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
use D3\ModCfg\Application\Model\Exception\d3_cfg_mod_exception;
use D3\ModCfg\Modules\Application\Controller\d3_oxshopcontrol_modcfg_extension;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Exception as DBALDriverException;
use Doctrine\DBAL\Query\QueryBuilder;
use Exception;
use OxidEsales\Eshop\Application\Model\Shop;
use OxidEsales\Eshop\Core\ConfigFile;
use OxidEsales\Eshop\Core\Exception\StandardException;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Request;
use OxidEsales\Eshop\Core\Model\BaseModel;
use OxidEsales\Eshop\Core\Email;
use OxidEsales\Eshop\Core\ShopControl;
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
use Doctrine\DBAL\Exception as DBALException;
use OxidEsales\EshopCommunity\Internal\Container\ContainerFactory;
use OxidEsales\EshopCommunity\Internal\Framework\Database\ConnectionProviderInterface;
use OxidEsales\EshopCommunity\Internal\Framework\Database\QueryBuilderFactoryInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerTrait;
class d3log extends BaseModel implements d3LogInterface
{
use LoggerTrait;
// single log levels
public const EMERGENCY = d3LogLevel::EMERGENCY; // Int 0, Bit 1
public const ALERT = d3LogLevel::ALERT; // Int 1, Bit 2
public const CRITICAL = d3LogLevel::CRITICAL; // Int 2, Bit 4
public const ERROR = d3LogLevel::ERROR; // Int 3 Bit 8
public const WARNING = d3LogLevel::WARNING; // Int 4 Bit 16
public const NOTICE = d3LogLevel::NOTICE; // Int 5 Bit 32
public const INFO = d3LogLevel::INFO; // Int 6 Bit 64
public const DEBUG = d3LogLevel::DEBUG; // Int 7 Bit 128
public const TEST = d3LogLevel::TEST; // Int 8 Bit 256
public const NONE = d3LogLevel::NONE; // Int 12 Bit 4096
// ranged log levels
public const ERROR_AND_ABOVE = d3LogLevel::ERROR_AND_ABOVE; // Bit 15;
public const WARNING_AND_ABOVE = d3LogLevel::WARNING_AND_ABOVE; // Bit 31;
public const NOTICE_AND_ABOVE = d3LogLevel::NOTICE_AND_ABOVE; // Bit 63;
public const INFO_AND_ABOVE = d3LogLevel::INFO_AND_ABOVE; // Bit 127;
public const ALL = d3LogLevel::ALL; // Bit 4095 // accept 3 additional levels
public $aLogTypes = [
'EMERGENCY' => d3LogLevel::EMERGENCY,
'ALERT' => d3LogLevel::ALERT,
'CRITICAL' => d3LogLevel::CRITICAL,
'ERROR' => d3LogLevel::ERROR,
'WARNING' => d3LogLevel::WARNING,
'NOTICE' => d3LogLevel::NOTICE,
'INFO' => d3LogLevel::INFO,
'DEBUG' => d3LogLevel::DEBUG,
'TEST' => d3LogLevel::TEST,
];
public $aLogGroups = [
'info' => [
'INFO' => true,
'NOTICE' => true,
'WARNING' => true,
'EMERGENCY' => true,
'ALERT' => true,
'CRITICAL' => true,
'ERROR' => true,
],
'notice' => [
'NOTICE' => true,
'WARNING' => true,
'EMERGENCY' => true,
'ALERT' => true,
'CRITICAL' => true,
'ERROR' => true,
],
'warning' => [
'WARNING' => true,
'EMERGENCY' => true,
'ALERT' => true,
'CRITICAL' => true,
'ERROR' => true,
],
'error' => [
'EMERGENCY' => true,
'ALERT' => true,
'CRITICAL' => true,
'ERROR' => true,
],
'none' => [
],
];
/**
* Object registry provides storage for shared objects
*
* @var array
*/
protected static $_aRegistry = [];
protected $_blStandAloneUse = false; // set this, if other libraries aren't available
protected $_sClassName = self::class;
protected $_sCoreTbl = 'd3log'; // bc
protected $_sCoreTable = 'd3log';
protected static $_sD3CoreTable = 'd3log';
public $_iLogType = d3LogLevel::EMERGENCY;
private string $_sLogSetId = 'd3modcfg_lib';
public $sModID;
public $sProfileID;
public $aD3TypeList = [];
public $aD3ModIdList = [];
public $aD3ClassList = [];
protected $_aSkipSaveFields = ['oxcounter', 'oxtimestamp'];
protected $_iInfoMailLogMessageLength = 40;
public $pwrsearchval;
/**
* Adds a new variable to the Registry.
*
* @param string $key Name of the variable
* @param mixed $value Value of the variable
*
* @return bool
*/
public static function set($key, $value)
{
self::$_aRegistry[$key] = $value;
return true;
}
/**
* Tests if given $key exists in registry
*
* @param string $key
*
* @return bool
*/
public static function has($key)
{
return isset(self::$_aRegistry[$key]);
}
/**
* Returns the value of the specified $key in the Registry.
*
* @param string $sModId
* @param int|null $iLogType
*
* @return d3log|false
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public static function get(string $sModId, ?int $iLogType = null)
{
if (Registry::get(ConfigFile::class)->getVar('iDebug')) {
startProfile(__METHOD__);
}
if (! self::isCallable()) {
return false;
}
if (self::has($sModId)) {
if (Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
return self::$_aRegistry[$sModId];
} else {
/** @var d3log $oLog */
$oLog =oxNew(d3log::class, $sModId);
if ($iLogType === false) {
$iLogType = $oLog->getLogType();
}
$oLog->setModId($sModId);
$oLog->setLogType($iLogType);
self::set($sModId, $oLog);
if (Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
return self::$_aRegistry[$sModId];
}
}
/**
* Returns the whole Registry as an array.
*
* @return array Whole Registry
*/
public static function getAll()
{
return self::$_aRegistry;
}
/**
* Removes a variable from the Registry.
*
* @param string $key Name of the variable
*
* @return bool
*/
public static function remove($key)
{
if (self::has($key)) {
unset(self::$_aRegistry[$key]);
return true;
}
return false;
}
/**
* Removes all variables from the Registry.
*
* @return void
*/
public static function removeAll()
{
self::$_aRegistry = [];
return;
}
/**
* constructor
*/
public function __construct()
{
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
startProfile(__METHOD__);
}
parent::__construct();
$this->init($this->_sCoreTable);
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
}
/**
* @param string $sModId
*
* @return d3log
*/
public function setModId($sModId)
{
$this->sModID = $sModId;
return $this;
}
/**
* @return string
*/
public function d3getModId()
{
return $this->sModID;
}
/**
* @param string $sProfileId
*
* @return d3log
*/
public function setProfileId($sProfileId)
{
$this->sProfileID = $sProfileId;
return $this;
}
/**
* @return string
*/
public function d3getProfileId()
{
return $this->sProfileID;
}
/**
* getLogType(d3log::INFO)
* getLogType(d3log::INFO, d3log::ERROR);
*
* @param int $iLogType1
* @param int|null $iLogType2
* @param int|null $iLogType3
*
* @return d3log
*/
public function setLogType($iLogType1, $iLogType2 = null, $iLogType3 = null)
{
$aArgs = func_get_args();
$bitmask = oxNew(d3bitmask::class);
unset($iLogType1);
unset($iLogType2);
unset($iLogType3);
$aLog = [];
foreach ($aArgs as $iLogType) {
// espacially for combined logtypes
foreach ($this->aLogTypes as $iGenLogType) {
if ($bitmask->isBitSet($iLogType, $this->getLogBit($iGenLogType))) {
$aLog[$this->getErrorModeName($iGenLogType)] = 1;
}
}
}
if (count($aLog)) {
$this->_iLogType = $this->getLogTypeByArray($aLog);
}
return $this;
}
/**
* @param int $range
*
* @return array
*/
public function getLogTypeListByRange($range = d3LogLevel::ALL)
{
$bitmask = oxNew(d3bitmask::class);
$types = [];
foreach ($this->aLogTypes as $iGenLogType) {
if ($bitmask->isBitSet($range, $this->getLogBit($iGenLogType))) {
$types[] = $this->getErrorModeName($iGenLogType);
}
}
return $types;
}
/**
* @return int
*/
public function getLogType()
{
return $this->_iLogType;
}
/**
* @param int $iLogType
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param string|null $sAction
* @param string|null $mText
* @param bool $blDie
*
* @return d3log
*/
public function log(
$iLogType = d3LogLevel::EMERGENCY,
$sClass = self::class,
$sFnc = __FUNCTION__,
$iLine = __LINE__,
$sAction = null,
$mText = null,
$blDie = false
) {
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
startProfile(__METHOD__);
}
try {
$sSessID = Registry::getSession()->getId();
$this->sModID ? $sModID = $this->sModID : $sModID = 'empty';
$mText = is_string($mText) ? $mText : print_r($mText, true);
//$this->sModID definiert den Namen des Moduls, das geloggt werden soll -> tabellenfeld oxmodid
// Beide Objektwerte sollten immer nach der Objekterstellung nach 'oxNew' gesetzt werden
if ($this->getErrorMode($iLogType)) {
$this->setId();
$aContent = [
'oxshopid' => Registry::getConfig()->getShopId(),
'oxsessid' => $sSessID,
'oxlogtype' => strtolower($this->getErrorModeName($iLogType)),
'oxtime' => date('Y-m-d H:i:s'),
'oxmodid' => $sModID,
'oxprofileid' => $this->d3getProfileId() ?: 'none',
'oxclass' => $sClass,
'oxfnc' => $sFnc,
'oxline' => $iLine,
'oxaction' => $sAction,
'oxtext' => $mText,
];
$this->assign($aContent);
$this->insert();
$this->_handleMailMessage();
D3ModCfgRegistry::getInstance()->add($this);
}
} catch (DBALException|DatabaseConnectionException|DatabaseErrorException|d3ShopCompatibilityAdapterException|d3_cfg_mod_exception $e) {
Registry::getLogger()->error($e->getMessage(), [$e]);
}
try {
$this->_handleDie($mText, $blDie);
} catch (StandardException $e) {
Registry::getLogger()->error($e->getMessage(), [$e]);
}
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
return $this;
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function emergency($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::EMERGENCY, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function alert($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::ALERT, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function critical($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::CRITICAL, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function error($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::ERROR, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function warning($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::WARNING, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function notice($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::NOTICE, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
*
* @return d3log
*/
public function info($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::INFO, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function debug($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::DEBUG, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param string $sClass
* @param string $sFnc
* @param int $iLine
* @param null $sAction
* @param null $mText
* @param bool $blDie
* @return d3log
*/
public function test($sClass = self::class, $sFnc = __FUNCTION__, $iLine = __LINE__, $sAction = null, $mText = null, $blDie = false)
{
return $this->log(d3LogLevel::TEST, $sClass, $sFnc, $iLine, $sAction, $mText, $blDie);
}
/**
* @param int $iLogType
*
* @return int
*/
public function getLogBit($iLogType)
{
return oxNew(d3bitmask::class)->getIntByBitPosition($iLogType);
}
/**
* @return array
*/
public function getErrorModes()
{
// $iError = $this->getLogType();
$aLogTypeStatus = [];
foreach ($this->aLogTypes as $sLogType => $iLogType) {
$aLogTypeStatus[$sLogType] = $this->getErrorMode($iLogType);
}
return $aLogTypeStatus;
}
/**
* @param int $iErrorMode
*
* @return bool
*/
public function getErrorMode($iErrorMode)
{
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
startProfile(__METHOD__);
}
$iError = $this->getLogType();
$iLogBit = $this->getLogBit($iErrorMode);
$blReturn = oxNew(d3bitmask::class)->isBitSet($iError, $iLogBit);
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
return $blReturn;
}
/**
* @param $sStatus
* @param $oSet
* @return bool
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function getLogStatus($sStatus, $oSet = false)
{
unset($oSet);
if (is_int($sStatus)) {
$flipped = array_flip($this->aLogTypes);
$sStatus = $flipped[$sStatus];
}
if ($this->getLogSet()->getValue('blLog_useExtendedLogging')) {
return $this->_getLogStatusExtended($sStatus);
} else {
if (strtoupper($sStatus) == 'DEBUG' ||
strtoupper($sStatus) == 'TEST'
) {
return $this->_getLogStatusExtended($sStatus);
}
$aLogLevelArray = $this->_convertLogLevelToModeArray($sStatus);
$aLogLevelKeys = array_keys($aLogLevelArray);
foreach ($this->getAllLogTypes() as $sErrorName => $iLogType) {
if (in_array($sErrorName, $aLogLevelKeys) && false == $this->getErrorMode($iLogType)) {
return false;
} elseif (false == in_array($sErrorName, $aLogLevelKeys) && $this->getErrorMode($iLogType)) {
return false;
}
}
return true;
}
}
/**
* @param string $sStatus
*
* @return bool
*/
protected function _getLogStatusExtended($sStatus)
{
$iErrorMode = $this->getErrorModeId($sStatus);
return $this->getErrorMode($iErrorMode);
}
/**
* @param int $iErrorMode
*
* @return string
*/
public function getErrorModeName($iErrorMode)
{
$aModTypeList = array_keys($this->aLogTypes);
return $aModTypeList[$iErrorMode];
}
/**
* @param string $sErrorName
*
* @return int
*/
public function getErrorModeId($sErrorName)
{
$aModTypeList = array_keys($this->aLogTypes);
$iErrorMode = array_search(strtoupper($sErrorName), $aModTypeList);
return $iErrorMode;
}
/**
* @param array $aErrorModes
*
* @return int
*/
public function getLogTypeByArray($aErrorModes = [])
{
$aErrorModes = $this->_resolveArrayByLogTypes($aErrorModes);
return oxNew(d3bitmask::class)->getIntByBitMask($aErrorModes);
}
/**
* @param array $aErrorModes
*
* @return array
*/
protected function _resolveArrayByLogTypes($aErrorModes)
{
$aNewTypeArray = [];
$aErrorModes = array_change_key_case($aErrorModes, CASE_UPPER);
foreach (array_keys($this->aLogTypes) as $sTypeName) {
if (isset($aErrorModes[strtoupper($sTypeName)])) {
$aNewTypeArray[$sTypeName] = $aErrorModes[strtoupper($sTypeName)];
} else {
$aNewTypeArray[$sTypeName] = false;
}
}
return $aNewTypeArray;
}
/**
* @param int $iType
*
* @return int
*/
public function addLogType($iType)
{
$this->setLogType(oxNew(d3bitmask::class)->addBit($this->getLogType(), $this->getLogBit($iType)));
return $this->getLogType();
}
/**
* @param int $iType
*
* @return int
*/
public function removeLogType($iType)
{
$this->setLogType(oxNew(d3bitmask::class)->removeBit($this->getLogType(), $this->getLogBit($iType)));
return $this->getLogType();
}
/**
* @return int|false
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function convertAdminLogSettings()
{
$aLog = [];
if ($this->getLogSet()->getValue('blLog_useExtendedLogging') &&
Registry::get(Request::class)->getRequestEscapedParameter('logtypes') &&
is_array(Registry::get(Request::class)->getRequestEscapedParameter('logtypes'))
) {
foreach (Registry::get(Request::class)->getRequestEscapedParameter('logtypes') as $iType => $blStatus) {
$aLog[$this->getErrorModeName($iType)] = (bool)$blStatus;
}
} elseif (Registry::get(Request::class)->getRequestEscapedParameter('loglevel') !== null) {
$aLog = $this->_convertLogLevelToModeArray(Registry::get(Request::class)->getRequestEscapedParameter('loglevel'));
$aLogTypes = Registry::get(Request::class)->getRequestEscapedParameter('logtypes');
/** set DEBUG mode */
if ($aLogTypes && is_array($aLogTypes) && isset($aLogTypes['7'])) {
$aLog['DEBUG'] = $aLogTypes['7'] ? true : false;
}
/** set TEST mode */
if ($aLogTypes && is_array($aLogTypes) && isset($aLogTypes['8'])) {
$aLog['TEST'] = $aLogTypes['8'] ? true : false;
}
} else {
return false;
}
if (count($aLog)) {
return $this->getLogTypeByArray($aLog);
}
return 0;
}
/**
* @param string $sLogLevel
*
* @return array
*/
protected function _convertLogLevelToModeArray($sLogLevel)
{
if (!$sLogLevel) {
return [];
}
$aLog = $this->aLogGroups[strtolower($sLogLevel)];
if (!is_array($aLog)) {
$aLog = [];
}
return $aLog;
}
/**
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws StandardException
* @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception
*/
public function setBacktraceLog()
{
$this->Log();
debug_print_backtrace();
}
/**
* @param bool $forceCoreTable
*
* @return string
*/
public function getSqlActiveSnippet($forceCoreTable = false)
{
unset($forceCoreTable);
return "1";
}
/**
* check, if mailsend has to be intitiated
* @return bool
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
protected function _checkMailMessage()
{
if ($this->_checkMailMessageSlot(1) || $this->_checkMailMessageSlot(2)) {
return true;
}
return false;
}
/**
* @param $iSlot
* @return bool
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
protected function _checkMailMessageSlot($iSlot)
{
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
startProfile(__METHOD__);
}
$sAdrFieldName = 'sLog_messageadr'.$iSlot;
$sErrLevelFieldName = 'sLog_messageerrlevel'.$iSlot;
$sTimeStampFieldName = 'sLog_messagetimestamp'.$iSlot;
if ($this->getLogSet()->getValue($sAdrFieldName) &&
$this->getLogSet()->getValue($sErrLevelFieldName) &&
(
false == $this->getLogSet()->getValue($sTimeStampFieldName) ||
($this->getLogSet()->getValue($sTimeStampFieldName) < $this->_getLastReqMailTimeStamp($iSlot))
)
) {
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
return true;
}
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
return false;
}
/**
* @return array
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function getUsedMailMessageSlots()
{
$sAdrBaseFieldName = 'sLog_messageadr';
$aSlots = [];
for ($i = 1; $i < 100; $i++) {
$sAdrFieldName = $sAdrBaseFieldName.$i;
if (strlen($this->getLogSet()->getValue($sAdrFieldName))) {
$aSlots[] = $i;
} else {
break;
};
}
return $aSlots;
}
/**
* get timestamp of last required mailsend time
* @param $iSlot
* @return int
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
protected function _getLastReqMailTimeStamp($iSlot)
{
$iDiff = match ($this->getLogSet()->getValue('sLog_messageintervaltype' . $iSlot)) {
'hour' => 60 * 60,
'day' => 60 * 60 * 24,
'minute' => 60,
default => 0,
};
$iDiff *= $this->getLogSet()->getValue('sLog_messageinterval' . $iSlot);
return time() - $iDiff;
}
/**
* send info mail to setted mail adresses
* @throws ContainerExceptionInterface
* @throws DBALDriverException
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws NotFoundExceptionInterface
* @throws StandardException
* @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception
*/
protected function _sendMailMessage()
{
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
startProfile(__METHOD__);
}
/** @var Connection $db */
$db = ContainerFactory::getInstance()->getContainer()->get(ConnectionProviderInterface::class)->get();
foreach ($this->getUsedMailMessageSlots() as $iSlotId) {
if ($this->_checkMailMessageSlot($iSlotId)) {
$aErrorStatus = $db->prepare($this->_getMailDataSelect($iSlotId))->executeQuery()->fetchAllAssociative();
if (count($aErrorStatus)) {
/** @var Email $oEMail */
$oEMail = oxNew(Email::class);
$this->_sendLogInfoMail(
$oEMail,
$this->getLogSet()->getValue('sLog_messageadr'.$iSlotId),
$this->_getMailSubject(),
$this->_getMailContent($aErrorStatus)
);
$this->getLogSet()->setValue('sLog_messagetimestamp'.$iSlotId, time());
$this->getLogSet()->save();
}
}
}
if ((bool) Registry::get(ConfigFile::class)->getVar('iDebug')) {
stopProfile(__METHOD__);
}
}
/**
* @param Email $oEmail
* @param $sTo
* @param $sSubject
* @param $sBody
*/
protected function _sendLogInfoMail($oEmail, $sTo, $sSubject, $sBody)
{
/** @var Shop $oShop */
$oShop = Registry::getConfig()->getActiveShop();
if (! ($sFromAddress = Registry::getConfig()->getConfigParam('sLogInfoMailFromAddress'))) {
$sFromAddress = $oShop->getFieldData('oxorderemail');
}
$oEmail->setFrom($sFromAddress, $oShop->__get('oxshops__oxname')->getRawValue());
$oEmail->setSmtp($oShop);
if (is_array($sTo)) {
foreach ($sTo as $sAddress) {
$oEmail->setRecipient($sAddress, "");
$oEmail->setReplyTo($sAddress, "");
}
} else {
$oEmail->setRecipient($sTo, "");
$oEmail->setReplyTo($sTo, "");
}
//may be changed later
$oEmail->isHTML(true);
$oEmail->setSubject($sSubject);
$oEmail->setBody($sBody);
$oEmail->send();
}
/**
* create select to get status overview from database
*
* @param int $iSlot mail send configuration slot
*
* @return string
* @throws ContainerExceptionInterface
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws NotFoundExceptionInterface
*/
protected function _getMailDataSelect($iSlot)
{
/** @var Connection $db */
$db = ContainerFactory::getInstance()->getContainer()->get(ConnectionProviderInterface::class)->get();
$sWhere = $this->getLogSet()->getValue('sLog_messagetimestamp' . $iSlot) ? "oxtime > " . $db->quote(
date('Y-m-d H:i:s', $this->getLogSet()->getValue('sLog_messagetimestamp' . $iSlot))
) . " " : '1 ';
$aLevelFilter = [];
switch ($this->getLogSet()->getValue('sLog_messageerrlevel' . $iSlot)) {
case 'warning':
$aLevelFilter = ['emergency', 'alert', 'critical', 'error', 'warning'];
break;
case 'error':
$aLevelFilter = ['emergency', 'alert', 'critical', 'error'];
break;
case 'critical':
$aLevelFilter = ['emergency', 'alert', 'critical'];
break;
case 'alert':
$aLevelFilter = ['emergency', 'alert'];
break;
case 'emergency':
$aLevelFilter = ['emergency'];
break;
}
if (count($aLevelFilter)) {
$sWhere .= ' AND oxlogtype IN ("' . implode('","', $aLevelFilter) . '") ';
}
$sSelect = "SELECT count(oxlogtype) as counter, oxlogtype, oxmodid, CONCAT(substr(oxtext, 1, ".$this->_iInfoMailLogMessageLength."),'...') as text
FROM " . $this->getViewName() . "
WHERE " . $sWhere . " AND oxlogtype IS NOT NULL
GROUP BY oxmodid, oxlogtype, text
ORDER BY FIELD(oxlogtype,".$this->getLogTypePriorityList4Query()."), counter DESC";
return $sSelect;
}
/**
* generate subject for owner info mail
*
* @return string
*/
protected function _getMailSubject()
{
/** @var Shop $oShop */
$oShop = Registry::getConfig()->getActiveShop();
$iDefaultLang = Registry::getConfig()->getConfigParam('sDefaultLang');
$oLang = Registry::getLang();
$sText = sprintf(
$oLang->translateString('D3_LOGMAIL_SUBJECT', $iDefaultLang, true),
$oShop->getFieldData('oxname'),
$oShop->getFieldData('oxurl')
);
return $sText;
}
/**
* generate content by database data for owner info mail
*
* @param array $aStatus status data
*
* @return string
*/
protected function _getMailContent($aStatus)
{
$iDefaultLang = Registry::getConfig()->getConfigParam('sDefaultLang');
$oLang = Registry::getLang();
$sText = $oLang->translateString('D3_LOGMAIL_HEADLINE', $iDefaultLang, true);
$sText .= "<br><br>";
$sText .= "<table style='border: 1px solid silver;'>";
foreach ($aStatus as $aUniqueStatus) {
$aUniqueStatus = array_change_key_case($aUniqueStatus, CASE_UPPER);
$sText .= "<tr><td>".$aUniqueStatus['COUNTER']."x</td>";
$sText .= "<td>".$aUniqueStatus['OXLOGTYPE']."</td>";
$sText .= "<td>".sprintf(
$oLang->translateString('D3_LOGMAIL_INMODULE', $iDefaultLang, true),
$aUniqueStatus['OXMODID']
)."</td>";
$sText .= "<td>".str_replace([chr(10), chr(13)], '', $aUniqueStatus['TEXT'])."</td></tr>";
}
$sText .= "</table>";
$sText .= "<br>";
$sText .= $oLang->translateString('D3_LOGMAIL_DESC', $iDefaultLang, true)."<br><br>";
$sText .= $oLang->translateString('D3_LOGMAIL_LEGENDE', $iDefaultLang, true);
$sText .= $oLang->translateString('D3_LOGTYPE_DESC', $iDefaultLang, true);
return $sText;
}
/**
* @param bool $blGetDebug
* @param bool $blGetTestMode
*
* @return array
*/
public function getAllLogTypes($blGetDebug = false, $blGetTestMode = false)
{
$aTypes = $this->aLogTypes;
if (false == $blGetDebug) {
unset($aTypes['DEBUG']);
}
if (false == $blGetTestMode) {
unset($aTypes['TEST']);
}
return $aTypes;
}
/**
* @param string $sModId
* @return array
* @throws ContainerExceptionInterface
* @throws DBALDriverException
* @throws DBALException
* @throws DatabaseConnectionException
* @throws NotFoundExceptionInterface
*/
public function getLogTypeList($sModId = '')
{
if (false == $this->aD3TypeList || false == count($this->aD3TypeList)) {
/** @var QueryBuilder $qb */
$qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
$qb->select('DISTINCT oxlogtype')
->from($this->getCoreTableName())
->orderBy('FIELD(oxlogtype,'.$this->getLogTypePriorityList4Query().')');
if ($sModId) {
$qb->where(
$qb->expr()->like('oxmodid', $qb->createNamedParameter('%'.$sModId.'%'))
);
}
$aRecords = $qb->execute()->fetchAllAssociative();
$this->aD3TypeList = [];
if (count($aRecords)) {
foreach ($aRecords as $aRecord) {
$aRecord = array_change_key_case($aRecord, CASE_UPPER);
$this->aD3TypeList[] = $aRecord['OXLOGTYPE'];
}
}
}
return $this->aD3TypeList;
}
public function getLogTypePriorityList()
{
return array_keys($this->aLogTypes);
}
/**
* @return string
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getLogTypePriorityList4Query(): string
{
/** @var Connection $db */
$db = ContainerFactory::getInstance()->getContainer()->get(ConnectionProviderInterface::class)->get();
return implode(',', array_map([$db, 'quote'], $this->getLogTypePriorityList()));
}
/**
* @param string $sModId
* @return array
* @throws ContainerExceptionInterface
* @throws DBALDriverException
* @throws DBALException
* @throws NotFoundExceptionInterface
*/
public function getModIdList($sModId = '')
{
if (false == $this->aD3ModIdList || false == count($this->aD3ModIdList)) {
/** @var QueryBuilder $qb */
$qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
$qb->select('DISTINCT oxmodid')
->from($this->getCoreTableName())
->orderBy('oxmodid');
if ($sModId) {
$qb->where($qb->expr()->like('oxmodid', $qb->createNamedParameter('%'.$sModId.'%')));
}
$aRecords = $qb->execute()->fetchAllAssociative();
$this->aD3ModIdList = [];
if (count($aRecords)) {
foreach ($aRecords as $aRecord) {
$aRecord = array_change_key_case($aRecord, CASE_UPPER);
$this->aD3ModIdList[] = $aRecord['OXMODID'];
}
}
}
return $this->aD3ModIdList;
}
/**
* @param string $sModId
* @return array
* @throws ContainerExceptionInterface
* @throws DBALDriverException
* @throws DBALException
* @throws NotFoundExceptionInterface
*/
public function getClassList($sModId = '')
{
if (false == $this->aD3ClassList || false == count($this->aD3ClassList)) {
/** @var QueryBuilder $qb */
$qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
$qb->select('DISTINCT oxclass')
->from($this->getCoreTableName())
->orderBy('oxclass');
if ($sModId) {
$qb->where($qb->expr()->like('oxmodid', $qb->createNamedParameter('%'.$sModId.'%')));
}
$aRecords = $qb->execute()->fetchAllAssociative();
$this->aD3ClassList = [];
if (count($aRecords)) {
foreach ($aRecords as $aRecord) {
$aRecord = array_change_key_case($aRecord, CASE_UPPER);
$this->aD3ClassList[] = $aRecord['OXCLASS'];
}
}
}
return $this->aD3ClassList;
}
/**
* @param bool $sModId
* @param bool $sType
* @param bool $sFromTime
* @param bool $sToTime
* @return QueryBuilder
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
protected function _getDelSql($sModId = false, $sType = false, $sFromTime = false, $sToTime = false): QueryBuilder
{
/** @var QueryBuilder $qb */
$qb = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
$qb->delete($this->getCoreTableName())
->where($qb->expr()->eq('oxshopid', $qb->createNamedParameter(Registry::getConfig()->getShopId())));
$sModId = $sModId ?: Registry::get(Request::class)->getRequestEscapedParameter('delete_oxmodid');
if ($sModId) {
$qb->andWhere($qb->expr()->eq('oxmodid', $qb->createNamedParameter($sModId)));
}
$sType = $sType ?: Registry::get(Request::class)->getRequestEscapedParameter('delete_oxtype');
if ($sType) {
$qb->andWhere($qb->expr()->eq('oxlogtype', $qb->createNamedParameter($sType)));
}
$sFromTime = $sFromTime ?: Registry::get(Request::class)->getRequestEscapedParameter('delete_oxfromtime');
if ($sFromTime) {
$qb->andWhere($qb->expr()->gt('oxtime', $qb->createNamedParameter($sFromTime)));
}
$sToTime = $sToTime ?: Registry::get(Request::class)->getRequestEscapedParameter('delete_oxtotime');
if ($sToTime) {
$qb->andWhere($qb->expr()->lt('oxtime', $qb->createNamedParameter($sToTime)));
}
return $qb;
}
/**
* @param bool $sModId
* @param bool $sType
* @param bool $sFromTime
* @param bool $sToTime
* @return int
* @throws ContainerExceptionInterface
* @throws DBALException
* @throws NotFoundExceptionInterface
*/
public function delLog($sModId = false, $sType = false, $sFromTime = false, $sToTime = false)
{
$sql = $this->_getDelSql($sModId, $sType, $sFromTime, $sToTime);
return $sql->execute();
}
/**
* @return array
*/
public function getSearchableFields()
{
$aSkipFields = ['oxid'];
$aFields = array_diff(array_keys($this->_aFieldNames), $aSkipFields);
return $aFields;
}
/**
* get logging modcfg object
*
* @return d3_cfg_mod
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function getLogSet()
{
return d3_cfg_mod::get($this->_sLogSetId);
}
/**
* register an error handler
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public function registerErrorHandler()
{
if (class_exists(d3_cfg_mod::class) && d3_cfg_mod::isCallable()) {
try {
if ($this->getLogSet()->getId() && $this->getLogSet()->getValue('blLog_enableErrorReporting')) {
register_shutdown_function([$this, 'd3logShutDown']);
// E_USER_ERROR will catched twice, no additional handling needed
set_error_handler([$this, 'd3logError'], E_ALL ^ E_USER_ERROR);
}
} catch (Exception $e) {
unset($e);
return;
}
}
}
/**
* log fatal error shutdowns
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws StandardException
* @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception
*/
public function d3logShutDown()
{
$aError = error_get_last();
if (is_array($aError) && isset($aError['message'])) {
$this->d3logError($aError['type'], $aError['message'], $aError['file'], $aError['line']);
}
}
/**
* @param $errno
* @param $errstr
* @param $errfile
* @param $errline
* @return bool
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws StandardException
* @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception
*/
public function d3logError($errno, $errstr, $errfile, $errline)
{
$sClass = null;
$sFunction = null;
$sLine = null;
$sContent = null;
if (self::_d3extractClassName($errfile) == self::class) {
$aTrace = debug_backtrace();
$sClass = $aTrace[1]['class'] ?: self::_d3extractClassName($aTrace[1]['file']);
$sFunction = $aTrace[1]['function'];
$sLine = $aTrace[1]['line'];
foreach (array_keys($aTrace) as $key) {
if ($aTrace[$key]['object']) {
unset($aTrace[$key]['object']);
}
}
$sContent = trim(strip_tags($errstr)) . "\n\n";
$sContent .= print_r($aTrace, true);
} else {
$sClass = self::_d3extractClassName($errfile);
$sFunction = 'unknown';
$sLine = $errline;
$sContent = trim($errstr);
}
$this->Log(
self::_d3getErrorStatus($errno),
$sClass,
$sFunction,
$sLine,
'ErrorReporting',
$sContent . PHP_EOL . print_r($_REQUEST, true)
);
return false;
}
/**
* @param $errno
*
* @return int
*/
private function _d3getErrorStatus($errno)
{
$sErrState = null;
switch ((int)$errno) {
case E_NOTICE:
case E_USER_NOTICE:
$sErrState = d3LogLevel::NOTICE;
break;
case E_WARNING:
case E_USER_WARNING:
$sErrState = d3LogLevel::WARNING;
break;
case E_ERROR:
case E_RECOVERABLE_ERROR:
case E_USER_ERROR:
$sErrState = d3LogLevel::EMERGENCY;
break;
case E_STRICT:
$sErrState = d3LogLevel::WARNING;
break;
case null:
$sErrState = d3LogLevel::NONE;
break;
default:
$sErrState = d3LogLevel::ERROR;
}
if (version_compare(PHP_VERSION, '5.3', '>')) {
switch ((int)$errno) {
case E_DEPRECATED:
case E_USER_DEPRECATED:
$sErrState = d3LogLevel::WARNING;
break;
}
}
return $sErrState;
}
/**
* @param $sFile
*
* @return string
*/
private function _d3extractClassName($sFile)
{
$sFile = basename($sFile);
$iEnd = strrpos($sFile, '.');
return substr($sFile, 0, $iEnd);
}
/**
* show profiling
*/
public function d3GetProfiling()
{
$view = Registry::getConfig()->getActiveView();
/** @var d3_oxshopcontrol_modcfg_extension $oShopControl */
$oShopControl = oxNew(ShopControl::class);
$oShopControl->d3StopMonitoring($view);
}
/**
* check, if modcfg can get items
*
* @return bool
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
*/
public static function isCallable()
{
if (class_exists(d3database::class) &&
($oD3DataBase = d3database::getInstance()) &&
$oD3DataBase->checkTableExist(self::$_sD3CoreTable)
) {
return true;
}
return false;
}
/**
* @param $sLogType
*
* @return string
*/
public function getLogTypeTranslation($sLogType)
{
$sTranslationIdent = "D3_LOGTYPE_" . strtoupper($sLogType);
$sTranslation = Registry::getLang()->translateString($sTranslationIdent);
if ($sTranslation == $sTranslationIdent) {
return $sLogType;
} else {
return $sTranslation;
}
}
/**
* @param string $sBaseModId
* @return string
* @throws DatabaseConnectionException
*/
public function d3BuildExportQuery($sBaseModId = '')
{
$aWhere = [];
$sModId = Registry::get(Request::class)->getRequestEscapedParameter('export_oxmodid');
if ($sModId) {
$aWhere['oxmodid'] = $sModId;
Registry::getConfig()->getActiveView()->addTplParam('oxmodid', $sModId);
}
$sTime = Registry::get(Request::class)->getRequestEscapedParameter('export_oxtime');
if ($sTime) {
$aWhere['oxtime'] = date('Y-m-d H:i:s', strtotime($sTime));
Registry::getConfig()->getActiveView()->addTplParam('oxtime', $sTime);
}
$sSessid = trim(Registry::get(Request::class)->getRequestEscapedParameter('export_oxsessid'));
if ($sSessid) {
$aWhere['oxsessid'] = $sSessid;
Registry::getConfig()->getActiveView()->addTplParam('oxsessid', $sSessid);
}
$sClass = trim(Registry::get(Request::class)->getRequestEscapedParameter('export_oxclass'));
if ($sClass) {
$aWhere['oxclass'] = $sClass;
Registry::getConfig()->getActiveView()->addTplParam('oxclass', $sClass);
}
$sSelect = $this->buildSelectString($aWhere);
/** @var Connection $db */
$db = ContainerFactory::getInstance()->getContainer()->get(ConnectionProviderInterface::class)->get();
$aSearch = ['oxtime ='];
$aReplace = ['oxtime >'];
if ($sBaseModId) {
$aSearch[] = ' where 1 ';
$aReplace[] = ' where 1 AND oxmodid LIKE '.$db->quote('%'.$sBaseModId.'%');
}
$sSelect = str_replace($aSearch, $aReplace, $sSelect);
return $sSelect;
}
/**
* @throws DBALException
* @throws DatabaseConnectionException
* @throws DatabaseErrorException
* @throws StandardException
* @throws d3ShopCompatibilityAdapterException
* @throws d3_cfg_mod_exception
*/
protected function _handleMailMessage()
{
if (false == $this->_blStandAloneUse) {
if ($this->_checkMailMessage()) {
$this->_sendMailMessage();
}
}
}
/**
* @param $mText
* @param $blDie
*/
protected function _handleDie($mText, $blDie)
{
if ($blDie) {
die($mText);
}
}
/**
* @param string $sModId
*
* @return string
* @throws DatabaseConnectionException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function getItemCount($sModId = '')
{
$oQB = ContainerFactory::getInstance()->getContainer()->get(QueryBuilderFactoryInterface::class)->create();
$oQB->select('count(*)')
->from($this->getCoreTableName())
->setMaxResults(1)
;
if ($sModId) {
$oQB->where('oxmodid LIKE '.$oQB->createNamedParameter('%' . $sModId . '%'));
}
return $oQB->execute()->fetchOne();
}
}