Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Sanitizer
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 5
272
0.00% covered (danger)
0.00%
0 / 1
 sanitizeStackTrace
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 applyCatchAllPatterns
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
2
 applySpecificPatterns
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
90
 replaceQuoted
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
 replace
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace BO\Slim\Helper;
4
5final class Sanitizer
6{
7    public static function sanitizeStackTrace(string $trace): string
8    {
9        $trace = self::applyCatchAllPatterns($trace);
10
11        return self::applySpecificPatterns($trace);
12    }
13
14    protected static function applyCatchAllPatterns(string $trace): string
15    {
16        $trace = self::replace('/mysql:dbname=[^;]+;host=[^;]+;port=\d+/', 'mysql:dbname=***;host=***;port=***', $trace);
17        $trace = self::replace('/sqlite:[^;]+/', 'sqlite:***', $trace);
18
19        $trace = self::replace('/[^:\s]+:[^@\s]+@[^:\s]+:\d+/', '***:***@***:***', $trace);
20        $trace = self::replace('/[^:\s]+:[^@\s]+@[^:\s]+/', '***:***@***', $trace);
21
22        $trace = self::replace('/port=\d+/', 'port=***', $trace);
23        $trace = self::replace('/:\d+(\/|$)/', ':***$1', $trace);
24
25        $trace = self::replace('/@[\d\.]+/', '@***', $trace); // IP addresses
26        $trace = self::replace('/@[a-zA-Z0-9\-\.]+/', '@***', $trace); // Hostnames
27        $trace = self::replace('/host=[a-zA-Z0-9\-\.]+/', 'host=***', $trace); // Hostnames in connection strings
28        $trace = self::replace('/host=\d+\.\d+\.\d+\.\d+/', 'host=***', $trace); // IP addresses in connection strings
29
30        $trace = self::replace('/dbname=[a-zA-Z0-9\-_]+/', 'dbname=***', $trace);
31        $trace = self::replace('/database \'[a-zA-Z0-9\-_]+\'/', 'database \'***\'', $trace);
32
33        $trace = self::replace('/user=\'[^\']+\'/', 'user=\'***\'', $trace);
34        $trace = self::replace('/user=[^;]+/', 'user=***', $trace);
35
36        $trace = self::replace('/password=\'[^\']+\'/', 'password=\'***\'', $trace);
37        $trace = self::replace('/password=[^;]+/', 'password=***', $trace);
38
39        $trace = self::replace('/Access denied for user \'[^\']+\'@\'[^\']+\'/', 'Access denied for user \'***\'@\'***\'', $trace);
40        $trace = self::replace('/Access denied for user [^@]+@[^\s]+/', 'Access denied for user ***@***', $trace);
41
42        return $trace;
43    }
44
45    protected static function applySpecificPatterns(string $trace): string
46    {
47        if (defined('\App::DB_PASSWORD')) {
48            $trace = self::replaceQuoted(\App::DB_PASSWORD, $trace);
49        }
50        if (defined('\App::DB_USER')) {
51            $trace = self::replaceQuoted(\App::DB_USER, $trace);
52        }
53        if (defined('\App::DB_HOST')) {
54            $trace = self::replaceQuoted(\App::DB_HOST, $trace);
55        }
56        if (defined('\App::DB_NAME')) {
57            $trace = self::replaceQuoted(\App::DB_NAME, $trace);
58        }
59        if (defined('\App::DB_PORT')) {
60            $port = \App::DB_PORT;
61            if (is_int($port)) {
62                $port = (string) $port;
63            }
64            if (is_string($port) && $port !== '') {
65                $encodedPort = preg_quote($port, '/');
66                $trace = self::replace('/' . $encodedPort . '/', '***', $trace);
67                $trace = self::replace('/' . preg_quote(urlencode($port), '/') . '/', '***', $trace);
68                $trace = self::replace('/\'' . $encodedPort . '\'/', '\'***\'', $trace);
69                $trace = self::replace('/port=' . $encodedPort . '/', 'port=***', $trace);
70                $trace = self::replace('/port=' . preg_quote(urlencode($port), '/') . '/', 'port=***', $trace);
71            }
72        }
73
74        return $trace;
75    }
76
77    protected static function replaceQuoted(mixed $value, string $trace): string
78    {
79        if (!is_string($value) || $value === '') {
80            return $trace;
81        }
82        $encoded = preg_quote($value, '/');
83        $trace = self::replace('/' . $encoded . '/', '***', $trace);
84        $trace = self::replace('/' . preg_quote(urlencode($value), '/') . '/', '***', $trace);
85        $trace = self::replace('/\'' . $encoded . '\'/', '\'***\'', $trace);
86
87        return $trace;
88    }
89
90    protected static function replace(string $pattern, string $replacement, string $subject): string
91    {
92        if ($pattern === '') {
93            return $subject;
94        }
95        return preg_replace($pattern, $replacement, $subject) ?? $subject;
96    }
97}