- Add status checker + admin secure packages + upgrade enum + add sentry + upgrade to sitemap generator + bump to CRMV2 - Set customer role enum and user role enum - Update customer migration to set roles - phpcbf - faker local to fr - update lang - composer update - bump laravel ui - Redo all user crud - npm bump - Create admin command - rearrange views - redo all auth system - redo customer pro bo
190 lines
6 KiB
PHP
190 lines
6 KiB
PHP
<?php
|
|
|
|
namespace App\Lib\Helpers;
|
|
|
|
class ExceptionsHelper
|
|
{
|
|
/**
|
|
* Handle sentry event
|
|
*
|
|
* @param \Sentry\Event $event
|
|
* @return null|\Sentry\Event
|
|
*/
|
|
public static function sentryEventHandler(\Sentry\Event $event): ?\Sentry\Event
|
|
{
|
|
// Remove unwanted reports.
|
|
$event->setModules([]);
|
|
$event->setOsContext(null);
|
|
|
|
/** @var \Sentry\ExceptionDataBag[] */
|
|
$exceptionBag = [];
|
|
foreach ($event->getExceptions() as $exceptionDataBag) {
|
|
$exceptionBag[] = self::getAnonymizedSentryException($exceptionDataBag);
|
|
}
|
|
$event->setExceptions($exceptionBag);
|
|
return $event;
|
|
}
|
|
|
|
/**
|
|
* Anonimize Sentry Exception bag
|
|
*
|
|
* @param \Sentry\ExceptionDataBag $exceptionDataBag
|
|
* @return \Sentry\ExceptionDataBag
|
|
*/
|
|
private static function getAnonymizedSentryException(
|
|
\Sentry\ExceptionDataBag $exceptionDataBag
|
|
): \Sentry\ExceptionDataBag {
|
|
$exceptionDataBag->setValue(self::getAnonymizedMessage($exceptionDataBag->getValue()));
|
|
if ($stackTrace = $exceptionDataBag->getStacktrace()) {
|
|
$exceptionDataBag->setStacktrace(self::getAnonymizedSentryStackTrace($stackTrace));
|
|
}
|
|
return $exceptionDataBag;
|
|
}
|
|
|
|
/**
|
|
* Anonymise sentry stacktrace
|
|
*
|
|
* @param \Sentry\Stacktrace $stackTrace
|
|
* @return \Sentry\Stacktrace
|
|
*/
|
|
private static function getAnonymizedSentryStackTrace(\Sentry\Stacktrace $stackTrace): \Sentry\Stacktrace
|
|
{
|
|
/** @var \Sentry\Frame[] */
|
|
$frames = \array_reverse($stackTrace->getFrames(), true);
|
|
$i = \count($frames) - 1;
|
|
// * Remove all but keep first (index.php).
|
|
while ($i-- > 0) {
|
|
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
|
}
|
|
foreach ($frames as $index => $frame) {
|
|
$frame->setPostContext([]);
|
|
$frame->setPreContext([]);
|
|
$frame->setContextLine('');
|
|
$frame->setVars(self::getAnonymizedSentryParams($frame->getVars()));
|
|
$stackTrace->addFrame($frame);
|
|
if ($index === 0) {
|
|
$stackTrace->removeFrame(count($stackTrace->getFrames()) - 1);
|
|
}
|
|
}
|
|
return $stackTrace;
|
|
}
|
|
|
|
/**
|
|
* Get anonymized sentry params
|
|
*
|
|
* @param mixed[] $params
|
|
* @return string[]
|
|
*/
|
|
private static function getAnonymizedSentryParams(array $params): array
|
|
{
|
|
foreach ($params as &$param) {
|
|
$type = \strtolower(\gettype($param));
|
|
if (\is_string($param)) {
|
|
$type = \explode(' ', \trim($param))[0] ?? null;
|
|
}
|
|
switch ($type) {
|
|
case 'Lambda':
|
|
case 'Object':
|
|
continue 2;
|
|
case 'array':
|
|
$param = sprintf('Array(%d)', \count($param));
|
|
continue 2;
|
|
default:
|
|
if (\is_numeric($param)) {
|
|
$param = \ucfirst($type);
|
|
continue 2;
|
|
}
|
|
if (\is_string($param)) {
|
|
$param = sprintf('String(%d)', \strlen($param));
|
|
continue 2;
|
|
}
|
|
} //end switch
|
|
} //end foreach
|
|
return $params;
|
|
}
|
|
|
|
|
|
/**
|
|
* Anonymize at least Sql queries
|
|
*
|
|
* @param string $message
|
|
* @return string
|
|
*/
|
|
public static function getAnonymizedMessage(string $message): string
|
|
{
|
|
$message = \preg_replace('/^(.*)( \(SQL:.*\))$/', '$1', $message) ?? $message;
|
|
if ($sqlPos = \strpos($message, 'to use near')) {
|
|
$message = \mb_strcut($message, 0, $sqlPos);
|
|
}
|
|
return $message;
|
|
}
|
|
|
|
/**
|
|
* Anonymize stack trace
|
|
*
|
|
* @param \Throwable $e
|
|
* @return string
|
|
*/
|
|
public static function getAnonymizedStackTrace(\Throwable $e): string
|
|
{
|
|
$projectPath = \realpath(\sprintf('%s/../', \app_path()));
|
|
$traceStack = $e->getTrace();
|
|
$traceStr = '';
|
|
$maxStackStage = 0;
|
|
foreach ($traceStack as $stackStage => $stack) {
|
|
$maxStackStage = $stackStage;
|
|
$traceStr .= \sprintf(
|
|
'#%s %s(%d): ',
|
|
$stackStage,
|
|
str_replace($projectPath, '', $stack['file'] ?? ''),
|
|
$stack['line'] ?? ''
|
|
);
|
|
if (isset($stack['class'])) {
|
|
$traceStr .= "{$stack['class']}->{$stack['function']}(";
|
|
if (isset($stack['args'])) {
|
|
$traceStr .= self::handleArgs($stack);
|
|
}
|
|
$traceStr .= ")\n";
|
|
} elseif (isset($stack['function'])) {
|
|
$traceStr .= "{$stack['function']}(";
|
|
if (isset($stack['args'])) {
|
|
$traceStr .= self::handleArgs($stack);
|
|
}
|
|
$traceStr .= ")\n";
|
|
}
|
|
} //end foreach
|
|
$maxStackStage++;
|
|
$traceStr .= "#$maxStackStage {main}";
|
|
return $traceStr;
|
|
}
|
|
|
|
/**
|
|
* Handle Args
|
|
*
|
|
* @param array $stack
|
|
* @return string
|
|
*/
|
|
public static function handleArgs(array $stack): string
|
|
{
|
|
$traceArgs = '';
|
|
$argsCount = count($stack['args']);
|
|
for ($i = 0; $i < $argsCount; $i++) {
|
|
$type = \gettype($stack['args'][$i]);
|
|
switch ($type) {
|
|
case 'object':
|
|
$traceArgs .= sprintf('Object(%s)', \get_class($stack['args'][$i]));
|
|
break;
|
|
case 'array':
|
|
$traceArgs .= sprintf('Array(%d)', \count($stack['args'][$i]));
|
|
break;
|
|
case 'string':
|
|
$traceArgs .= sprintf('String(%d)', \strlen($stack['args'][$i]));
|
|
break;
|
|
default:
|
|
$traceArgs .= \gettype($stack['args'][$i]);
|
|
}
|
|
$traceArgs .= ($i !== ($argsCount - 1) ? ',' : '');
|
|
}
|
|
return $traceArgs;
|
|
}
|
|
}
|