Sentry::sendReport()   B
last analyzed

Complexity

Conditions 7
Paths 7

Size

Total Lines 59
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 7
eloc 37
c 2
b 0
f 0
nc 7
nop 1
dl 0
loc 59
ccs 0
cts 46
cp 0
crap 56
rs 8.3946

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace App\Forwarding;
4
5
use App\Report;
6
use Cake\Core\Configure;
7
use Cake\Log\Log;
8
use Exception;
9
10
use function curl_errno;
11
use function curl_exec;
12
use function curl_init;
13
use function curl_setopt;
14
use function curl_strerror;
15
use function date_default_timezone_set;
16
use function http_build_query;
17
use function is_array;
18
use function is_string;
19
use function json_decode;
20
use function json_encode;
21
use function time;
22
23
use const CURLOPT_HTTPHEADER;
24
use const CURLOPT_POST;
25
use const CURLOPT_POSTFIELDS;
26
use const CURLOPT_RETURNTRANSFER;
27
use const CURLOPT_USERPWD;
28
29
class Sentry
30
{
31
    public static function getSentryTimestamp(): int
32
    {
33
        date_default_timezone_set('UTC');
34
35
        return time();
36
    }
37
38
    /**
39
     * Send report and get ID
40
     *
41
     * @param array<string,mixed> $report The report as an array
42
     * @return string The event ID
43
     *
44
     * @see https://develop.sentry.dev/sdk/store/
45
     */
46
    public static function sendReport(array $report): string
47
    {
48
        $sentryConfig = Configure::read('Forwarding.Sentry');
49
        if ($sentryConfig === null) {
50
            throw new Exception('Missing Sentry config');
51
        }
52
53
        $data = json_encode($report);
54
        $ch = curl_init($sentryConfig['base_url'] . '/api/' . $sentryConfig['project_id'] . '/store/');
55
        if ($ch === false) {
56
            throw new Exception('Could not init cURL');
57
        }
58
59
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
60
        curl_setopt($ch, CURLOPT_USERPWD, $sentryConfig['key'] . ':');
61
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
62
            'Content-type: application/json',
63
            'X-Sentry-Auth: Sentry sentry_version=7, sentry_timestamp=' . self::getSentryTimestamp()
64
            . ', sentry_key=' . $sentryConfig['key'] . ', sentry_client=phpmyadmin-proxy/0.1'
65
            . ', sentry_secret=' . $sentryConfig['secret'],
66
        ]);
67
        curl_setopt($ch, CURLOPT_POST, 1);
68
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
69
70
        $output = curl_exec($ch);
71
72
        $errNo = curl_errno($ch);
73
74
        if ($errNo !== 0) {
75
            $errorMessage = curl_strerror($errNo);
76
            $error = 'Creating the report failed, cURL error (' . $errNo . '): ' . $errorMessage;
77
            Log::error($error);
78
79
            throw new Exception($error);
80
        }
81
82
        if (! is_string($output)) {
83
            $error = 'Creating the report failed: ' . json_encode($output);
84
            Log::error($error);
85
86
            throw new Exception($error);
87
        }
88
89
        $response = json_decode((string) $output, true);
90
        if (! is_array($response)) {
91
            $error = 'Invalid JSON response: ' . json_encode($output);
92
            Log::error($error);
93
94
            throw new Exception($error);
95
        }
96
97
        if (! isset($response['id'])) {
98
            $error = 'Invalid response Id: ' . json_encode($response);
99
            Log::error($error);
100
101
            throw new Exception($error);
102
        }
103
104
        return (string) $response['id'];
105
    }
106
107
    /**
108
     * Set user feedback to Sentry API
109
     *
110
     * @param string $eventId  The event ID
111
     * @param string $comments The comment sent by the user
112
     * @param string $userId   The unique user id
113
     * @return void nothing
114
     */
115
    public static function sendFeedback(string $eventId, string $comments, string $userId): void
116
    {
117
        $sentryConfig = Configure::read('Forwarding.Sentry');
118
        if ($sentryConfig === null) {
119
            throw new Exception('Missing Sentry config');
120
        }
121
122
        $data = [
123
            'comments' => $comments,
124
            'email' => 'u+' . $userId . '@r.local',// 75 chars max (fake hostname to pass email validation rule)
125
            'name' => 'phpMyAdmin User',
126
        ];
127
        $ch = curl_init(
128
            $sentryConfig['base_url'] . '/api/embed/error-page/?eventId=' . $eventId . '&dsn=' . $sentryConfig['dsn_url']
129
        );
130
        if ($ch === false) {
131
            throw new Exception('Could not init cURL');
132
        }
133
134
        curl_setopt($ch, CURLOPT_USERPWD, $sentryConfig['key'] . ':');
135
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
136
        curl_setopt($ch, CURLOPT_POST, 1);
137
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
138
139
        $output = curl_exec($ch);
140
        if (! is_string($output)) {
141
            $error = 'Creating the report feedback failed: ' . json_encode($output);
142
            Log::error($error);
143
144
            return;
145
        }
146
147
        $response = json_decode((string) $output, true);
148
        if (! is_array($response)) {
149
            $error = 'Invalid JSON response: ' . json_encode($output);
150
            Log::error($error);
151
152
            return;
153
        }
154
155
        if (isset($response['errors'])) {
156
            $error = 'Response has errors: ' . json_encode($response['errors']);
157
            Log::error($error);
158
159
            return;
160
        }
161
    }
162
163
    public static function process(Report $report): void
164
    {
165
        foreach ($report->getReports() as $reportData) {
166
            $eventId = self::sendReport($reportData);
167
            if (! $report->hasUserFeedback()) {
168
                continue;
169
            }
170
171
            self::sendFeedback($eventId, $report->getUserFeedback(), $report->getUserId());
172
        }
173
    }
174
}
175