GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

ImapHelper::searchSubjectAndPlainText()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 18
rs 9.6666
cc 3
nc 3
nop 2
1
<?php
2
namespace Checkdomain\Comodo;
3
4
use Zend\Mail\Exception\ExceptionInterface;
5
use Zend\Mail\Storage\Message;
6
use Zend\Mail\Storage\Part;
7
8
/**
9
 * Class ImapHelper
10
 */
11
class ImapHelper
12
{
13
    const PROCESSED_FLAG = 'checkdomain_comodo_processed';
14
15
    public static $subjects = [
16
        'order_received'       => 'Your order has been received',
17
        'confirmation'         => 'CONFIRMATION',
18
        'information_required' => 'Information Required',
19
        '1_expiry'             => 'Customer certificate expiry warning (1 days)',
20
        '30_expiry'            => 'Customer certificate expiry warning (30 days)',
21
        '60_expiry'            => 'Customer certificate expiry warning (60 days)',
22
    ];
23
24
    public static $bodies = [
25
        'issued' => '/Your [a-zA-Z ]* Certificate for [\*a-zA-Z0-9\_\-öäü\.]* is attached!/',
26
    ];
27
28
    /**
29
     *  Fetches the mail recursively, through the folders.
30
     *
31
     * @param ImapAdapter $imap             imap helper class
32
     * @param string      $search           imap-searchterm
33
     * @param bool        $markProcessed    Sets the flag as processed
34
     * @param bool        $assume           Assumes domainName / order-Number in the mail
35
     * @param \Closure    $callbackFunction callback
36
     *
37
     * @return array
38
     */
39
    public function fetchMails(ImapAdapter $imap, $search, $markProcessed = true, $assume = false, \Closure $callbackFunction = null)
40
    {
41
        $folder = 'INBOX';
42
43
        $imap->selectFolder($folder);
44
        $result = $imap->search(array($search));
45
46
        $messages = [];
47
48
        foreach ($result as $id) {
49
            $message = null;
50
51
            try {
52
                $message = $imap->getMessage($id);
53
54
                $messages[$id]['id']     = $id;
55
                $messages[$id]['folder'] = $folder;
56
57
                // Zend-mail sometimes got problems, with incorrect e-mails
58
                try {
59
                    $messages[$id]['subject'] = utf8_decode($message->getHeader('subject', 'string'));
60
                } catch (\Exception $e) {
61
                    $messages[$id]['subject'] = '-No subject-';
62
                }
63
64
                try {
65
                    $messages[$id]['received'] = strtotime($message->getHeader('date', 'string'));
66
                } catch (\Exception $e) {
67
                    $messages[$id]['received'] = '-No date-';
68
                }
69
70
                $messages[$id]['plainText']   = $this->getPlainText($message);
71
                $messages[$id]['attachments'] = $this->getAttachments($message);
72
                $messages[$id]['type']        = $this->getTypeOfMail($messages[$id]);
73
74
                if ($assume) {
75
                    $messages[$id]['orderNumber'] = $this->assumeOrderNumber($messages[$id]);
76
                    $messages[$id]['domainName']  = $this->assumeDomainName($messages[$id]);
77
                }
78
79
                $success = true;
80
                if (is_callable($callbackFunction)) {
81
                    $success = $callbackFunction($id, $messages[$id]);
82
                }
83
            } catch (ExceptionInterface $e) {
84
                // General decoding error -> removeMessage
85
                unset($messages[$id]);
86
87
                // Always mark as processed
88
                $success = true;
89
            }
90
91
            if ($markProcessed && $success) {
92
                $this->markProcessed($imap, $id, $message);
93
            }
94
        }
95
96
        return $messages;
97
    }
98
99
    /**
100
     * Marks the mail with the processed flag
101
     *
102
     * @param ImapAdapter $imap
103
     * @param integer     $id
104
     * @param Message     $message
105
     */
106
    protected function markProcessed(ImapAdapter $imap, $id, Message $message = null)
107
    {
108
        $flags   = $message ? $message->getFlags() : [];
109
        $flags[] = self::PROCESSED_FLAG;
110
111
        try {
112
            $imap->setFlags($id, $flags);
113
        } catch (ExceptionInterface $e) {
114
            // Nothing to do
115
        }
116
    }
117
118
    /**
119
     * Tries to find out, what Comodo wanna tell us...
120
     *
121
     * @param array $mail
122
     *
123
     * @return null|string
124
     */
125
    protected function getTypeOfMail(array $mail)
126
    {
127
        foreach (self::$subjects as $key => $subject) {
128
            if (stristr($mail['subject'], $subject) !== false) {
129
                return $key;
130
            }
131
        }
132
133
        foreach (self::$bodies as $key => $body) {
134
            if (preg_match($body, $mail['plainText'])) {
135
                return $key;
136
            }
137
        }
138
139
        return null;
140
    }
141
142
    /**
143
     * @param Part $part
144
     *
145
     * @return string|null
146
     */
147
    public function getPlainText(Part $part)
148
    {
149
        $text = null;
150
151
        if ($part->isMultipart()) {
152
            $partCount = $part->countParts();
153
154
            // Parse all parts
155
            for ($i = 0; $i < $partCount; $i++) {
156
                $subPart = $part->getPart($i + 1);
157
158
                // Check for headers, to avoid exceptions
159
                if ($subPart->getHeaders() !== null) {
160
                    if ($subPart->isMultipart()) {
161
                        // Part is multipart as well
162
                        $tmp = $this->getPlainText($subPart);
163
                        $text = ($tmp !== null) ? $tmp : $text;
164
                    } else {
165
                        // Try to get plain/text of this content
166
                        $tmp = $this->getPlainTextOfPart($subPart);
167
                        $text = ($tmp !== null) ? $tmp : $text;
168
                    }
169
                }
170
            }
171
        } else {
172
            // Its not multipart, so try to get its content
173
            $text = $this->getPlainTextOfPart($part);
174
        }
175
176
        return $text;
177
    }
178
179
    /**
180
     * @param Part $part
181
     *
182
     * @return null|string
183
     */
184
    private function getPlainTextOfPart(Part $part)
185
    {
186
        try {
187
            if ($part->getHeaderField('Content-Disposition') == 'attachment') {
188
                return null;
189
            }
190
        } catch (\Exception $e) {
191
            // Zend throws an Exception, if headerField does not exist
192
        }
193
194
        try {
195
            // If content-type is text/plain, return its content
196
            if ($part->getHeaderField('Content-Type') == 'text/plain') {
197
                return $this->getStringFromPart($part);
198
            }
199
        } catch (\Exception $e) {
200
            // If content-type is not available (exception thrown), return its content
201
            return $this->getStringFromPart($part);
202
        }
203
204
        return null;
205
    }
206
207
    /**
208
     * @param $part
209
     *
210
     * @return null|string
211
     */
212
    public function getStringFromPart($part)
213
    {
214
        if ($part === null) {
215
            return null;
216
        }
217
218
        if ($part instanceof Part) {
219
            $text = $part->getContent();
220
        } else {
221
            $text = $part;
222
        }
223
224
        return strip_tags($text);
225
    }
226
227
    /**
228
     * @param Message $message
229
     *
230
     * @return array|null
231
     */
232
    public function getAttachments(Message $message)
233
    {
234
        $attachments = null;
235
236
        // Only multi-part will have attachments
237
        if ($message->isMultipart()) {
238
            if ($message->countParts() > 1) {
239
240
                $partCount = $message->countParts();
241
                for ($i = 0; $i < $partCount; $i++) {
242
                    $part = $message->getPart($i + 1);
243
244
                    // Check for headers, to avoid exceptions
245
                    if ($part->getHeaders() !== null) {
246
                        // Getting disposition
247
                        $disposition = null;
248
                        try {
249
                            $disposition = $part->getHeaderField('Content-Disposition');
250
                        } catch (\Exception $e) {
251
                            // Zend throws an Exception, if headerField does not exist
252
                        }
253
254
                        if ($disposition == 'attachment') {
255
                            $content = quoted_printable_decode($part->getContent());
256
257
                            // Encoding?
258
                            try {
259
                                $transferEncoding = $part->getHeaderField('Content-Transfer-Encoding');
260
261
                                if ($transferEncoding == 'base64') {
262
                                    $content = base64_decode($content);
263
                                }
264
                            } catch (\Exception $e) {
265
                                // Zend throws an Exception, if headerField does not exist
266
                            }
267
268
                            $attachments[] = array(
269
                                'mime'     => $part->getHeaderField('Content-Type'),
270
                                'filename' => $part->getHeaderField('Content-Disposition', 'filename'),
271
                                'content'  => $content
272
                            );
273
                        }
274
                    }
275
                }
276
            }
277
        }
278
279
        return $attachments;
280
    }
281
282
    /**
283
     * @param string $message
284
     *
285
     * @return integer|null
286
     */
287
    protected function assumeOrderNumber($message)
288
    {
289
        $pattern = '/[order|\#][^0-9]+([0-9]{7,8})/i';
290
291
        return $this->searchSubjectAndPlainText($pattern, $message);
292
    }
293
294
    /**
295
     * @param string $message
296
     *
297
     * @return string|null
298
     */
299
    protected function assumeDomainName($message)
300
    {
301
        $pattern = '/(?:certificate for|domain|domain name){1}[\s\t\n\r\:\-]*((?:[\*a-z0-9äöüß-]+\.)+[a-z0-9äöüß-]+)/i';
302
303
        return $this->searchSubjectAndPlainText($pattern, $message);
304
    }
305
306
    /**
307
     * @param $pattern
308
     * @param $message
309
     *
310
     * @return null
311
     */
312
    protected function searchSubjectAndPlainText($pattern, $message)
313
    {
314
        $matchesText = array();
315
        preg_match($pattern, $message['subject'], $matchesText);
316
317
        if (!empty($matchesText[1])) {
318
            return $matchesText[1];
319
        }
320
321
        $matchesSubject = array();
322
        preg_match($pattern, $message['plainText'], $matchesSubject);
323
324
        if (!empty($matchesSubject[1])) {
325
            return $matchesSubject[1];
326
        }
327
328
        return null;
329
    }
330
}
331