Passed
Push — master ( 3e34f7...90252a )
by Waaaaaaaaaa
05:57
created

Payload::detectAndCleanUtf8()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 2
nop 1
dl 0
loc 12
ccs 0
cts 9
cp 0
crap 12
rs 9.9666
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
namespace Logfile;
4
5
use Throwable;
6
7
class Payload implements DataInterface
8
{
9
    use DataTrait;
10
11
    protected $message;
12
13
    protected $id;
14
15
    protected $context;
16
17
    public function __construct(string $message, string $id)
18
    {
19
        $this->message = $message;
20
        $this->id = $id;
21
    }
22
23
    public function setContext(array $context): void
24
    {
25
        $this->context = $context;
26
    }
27
28
    public function hasContext(): bool
29
    {
30
        return !empty($this->context);
31
    }
32
33
    public function getContext(): array
34
    {
35
        return $this->context;
36
    }
37
38
    public static function createFromException(Throwable $exception, string $path = ''): self
39
    {
40
        $payload = new Payload($exception->getMessage(), static::uuid4());
41
        $trace = new Stacktrace($exception);
42
        $trace->setPath($path);
43
        $context = $trace->getFrames();
44
        $payload->setContext($context);
45
        return $payload;
46
    }
47
48
    public function setId(string $id): void
49
    {
50
        $this->id = $id;
51
    }
52
53
    public function getId(): string
54
    {
55
        return $this->id;
56
    }
57
58
    /**
59
     * Get payload data
60
     *
61
     * @return array
62
     */
63
    public function getData(): array
64
    {
65
        $extra = [
66
            'id' => $this->getId(),
67
        ];
68
69
        if ($this->hasTags()) {
70
            $extra['tags'] = $this->getTags();
71
        }
72
73
        if ($this->hasUser()) {
74
            $extra['user'] = $this->getUser();
75
        }
76
77
        if ($this->hasRelease()) {
78
            $extra['release'] = $this->getRelease();
79
        }
80
81
        $data = [
82
            'message' => $this->message,
83
            'extra' => $extra,
84
        ];
85
86
        if ($this->hasContext()) {
87
            $data['context'] = $this->getContext();
88
        }
89
90
        return $data;
91
    }
92
93
    /**
94
     * Get payload json encoded
95
     *
96
     * @return string
97
     */
98
    public function getEncodedData(): string
99
    {
100
        $data = $this->getData();
101
        $encoded = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
102
103
        if (JSON_ERROR_UTF8 === json_last_error()) {
104
            if (is_string($data)) {
0 ignored issues
show
introduced by
The condition is_string($data) is always false.
Loading history...
105
                $this->detectAndCleanUtf8($data);
106
            } elseif (is_array($data)) {
0 ignored issues
show
introduced by
The condition is_array($data) is always true.
Loading history...
107
                array_walk_recursive($data, array($this, 'detectAndCleanUtf8'));
108
            }
109
            $encoded = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
110
        }
111
112
        if (JSON_ERROR_NONE !== json_last_error()) {
113
            $error = json_last_error_msg();
114
            throw new \LogicException(sprintf('Failed to encode json data: %s.', $error));
115
        }
116
117
        return $encoded;
118
    }
119
120
    /**
121
     * Detect invalid UTF-8 string characters and convert to valid UTF-8.
122
     * @see https://github.com/Seldaek/monolog/blob/master/src/Monolog/Formatter/NormalizerFormatter.php
123
     */
124
    public function detectAndCleanUtf8(&$data)
125
    {
126
        if (is_string($data) && !preg_match('//u', $data)) {
127
            $data = preg_replace_callback(
128
                '/[\x80-\xFF]+/',
129
                function ($m) { return utf8_encode($m[0]); },
130
                $data
131
            );
132
            $data = str_replace(
133
                array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'),
134
                array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'),
135
                $data
136
            );
137
        }
138
    }
139
140
    /**
141
     * Get uuid v4
142
     *
143
     * @see http://www.php.net/manual/en/function.uniqid.php#94959
144
     * @return string
145
     */
146
    public static function uuid4(): string
147
    {
148
        mt_srand();
149
        return sprintf(
150
            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
151
            // 32 bits for "time_low"
152
            mt_rand(0, 0xffff),
153
            mt_rand(0, 0xffff),
154
            // 16 bits for "time_mid"
155
            mt_rand(0, 0xffff),
156
            // 16 bits for "time_hi_and_version",
157
            // four most significant bits holds version number 4
158
            mt_rand(0, 0x0fff) | 0x4000,
159
            // 16 bits, 8 bits for "clk_seq_hi_res",
160
            // 8 bits for "clk_seq_low",
161
            // two most significant bits holds zero and one for variant DCE1.1
162
            mt_rand(0, 0x3fff) | 0x8000,
163
            // 48 bits for "node"
164
            mt_rand(0, 0xffff),
165
            mt_rand(0, 0xffff),
166
            mt_rand(0, 0xffff)
167
        );
168
    }
169
}
170