Issues (3)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/MailReader/MailReader.php (3 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace JM\MailReader;
4
5
class MailReader
6
{
7
8
    /**
9
     * @var array
10
     */
11
    private $settings = ['server' => '', 'username' => '', 'password' => ''];
12
13
    /**
14
     * @var array
15
     */
16
    private $messages = [];
17
18
    /**
19
     * @var string
20
     */
21
    private $mailbox = 'INBOX';
22
23
    /**
24
     * @var resource
25
     */
26
    private $conn;
27
28
29
    /**
30
     * When this class is destructed we
31
     * might want to close the connection.
32
     */
33
    public function __destruct()
34
    {
35
        $this->close();
36
    }
37
38
39
    /**
40
     * Open a connection to a mail server.
41
     *
42
     * @param array $credentials
43
     *
44
     * @return bool
45
     * @throws \Exception
46
     */
47
    public function connect($credentials = [])
48
    {
49
        if ($diff = array_diff(array_keys($this->settings), array_keys($credentials))) {
50
            throw new \Exception("Missing credentials, the following fields are missing ".implode('/', $diff));
51
        }
52
53
        $this->settings = array_merge($this->settings, $credentials);
54
55
        if (isset($this->settings['port']) === false) {
56
            $this->settings['port'] = 143;
57
        }
58
59
        $this->conn = @imap_open('{'.$this->settings['server'].':'.$this->settings['port'].'/notls}',
60
            $this->settings['username'], $this->settings['password']);
61
62
        if ($this->conn == false) {
63
            throw new \Exception("Could not connect or authorize to ".$this->settings['server'].':'.$this->settings['port']);
64
        }
65
66
        return ($this->conn != null);
67
    }
68
69
70
    /**
71
     * Close the connection to the mail server.
72
     */
73
    private function close()
74
    {
75
        if ($this->conn) {
76
            imap_close($this->conn);
77
        }
78
    }
79
80
81
    /**
82
     * @param string $mailbox
83
     *
84
     * @return bool
85
     */
86
    public function setMailbox($mailbox = 'INBOX')
87
    {
88
89
        if ($mailbox == 'INBOX') {
90
            $mailbox = "{".$this->settings['server']."}INBOX";
91
        } else {
92
            $mailbox = "{".$this->settings['server']."}INBOX.".imap_utf7_encode($mailbox);
93
        }
94
95
        $result = false;
96
97
        if ($this->conn) {
98
            $result = imap_reopen($this->conn, $mailbox);
99
            $this->mailbox = $mailbox;
100
        }
101
102
        return $result;
103
    }
104
105
106
    /**
107
     * Return the name of the current mailbox.
108
     *
109
     * @return string
110
     */
111
    public function getMailbox()
112
    {
113
        $mailbox = str_replace("{".$this->settings['server']."}", '', $this->mailbox);
114
        $mailbox = (substr($mailbox, 0, 6) == 'INBOX.') ? substr($mailbox, -6) : $mailbox;
115
116
        return $mailbox;
117
    }
118
119
120
    /**
121
     * Mark a given message as read.
122
     *
123
     * @param string $index
124
     *
125
     * @return bool
126
     */
127
    public function markMessageAsRead($index = '')
128
    {
129
        return imap_setflag_full($this->conn, $index, "\\Seen");
130
    }
131
132
133
    /**
134
     * Filter unread message sent to $to
135
     *
136
     * @param string $to
137
     *
138
     * @return array
139
     */
140
    public function filterUnReadMessagesTo($to = '')
141
    {
142
        $filteredResult = $this->filterTo($to);
143
        $filteredMessages = [];
144
145
        if (is_array($filteredResult) && count($filteredResult) > 0) {
146
            foreach ($filteredResult as $message) {
147
                if (isset($message['header'])) {
148
                    $header = $message['header'];
149
                    if ($header->Unseen == 'U') {
150
                        $filteredMessages[] = $message;
151
                    }
152
                }
153
            }
154
        }
155
156
        return $filteredMessages;
157
    }
158
159
160
    /**
161
     * Filter message sent to $to
162
     *
163
     * @param string $to
164
     *
165
     * @return array
166
     */
167
    public function filterTo($to = '')
168
    {
169
        $msg_cnt = imap_num_msg($this->conn);
170
        if ($msg_cnt > 0 && count($this->messages) == 0) {
171
            $this->readMailbox();
172
        }
173
174
        $filteredResult = imap_search($this->conn, 'TO "'.$to.'"');
175
        $filteredMessages = [];
176
177
        if (is_array($filteredResult) && count($filteredResult) > 0) {
178
            foreach ($filteredResult as $index) {
179
                $filteredMessages[] = $this->getMessageInformation($index);
180
            }
181
        }
182
183
        return $filteredMessages;
184
    }
185
186
187
    /**
188
     * Create a mailbox (folder)
189
     *
190
     * @param string $name
191
     *
192
     * @return bool
193
     */
194
    public function createMailbox($name = '')
195
    {
196
        if (empty($name)) {
197
            return false;
198
        }
199
200
        $name = imap_utf7_encode($name);
201
202
        return imap_createmailbox($this->conn, "{".$this->settings['server']."}INBOX.".$name);
203
    }
204
205
206
    /**
207
     * Subscribe to a mailbox.
208
     *
209
     * @param string $name
210
     *
211
     * @return bool
212
     */
213
    public function subscribeMailbox($name = '') {
214
        if (empty($name)) {
215
            return false;
216
        }
217
218
        $name = imap_utf7_encode($name);
219
        return imap_subscribe ( $this->conn, "{".$this->settings['server']."}INBOX.".$name );
220
    }
221
222
    /**
223
     * This function will be deleted in version 1.3
224
     * This function is deprecated because of the naming
225
     * inconsistency.
226
     *
227
     * @param string $name
228
     *
229
     * @deprecated
230
     * @return bool
231
     */
232
    public function removeMailbox($name = '')
233
    {
234
        return $this->deleteMailbox($name);
235
    }
236
237
238
    /**
239
     * Delete a mailbox (folder)
240
     *
241
     * @param string $name
242
     *
243
     * @return bool
244
     */
245
    public function deleteMailbox($name = '')
246
    {
247
        if (empty($name)) {
248
            return false;
249
        }
250
251
        $name = imap_utf7_encode($name);
252
253
        return imap_deletemailbox($this->conn, "{".$this->settings['server']."}INBOX.".$name);
254
    }
255
256
257
258
259
    /**
260
     * Check to see if a given mailbox (folder) exists on the server.
261
     *
262
     * @param string $name
263
     *
264
     * @return bool
265
     */
266
    public function mailboxExists($name = '')
267
    {
268
        if (empty($name)) {
269
            return false;
270
        }
271
272
        $name = imap_utf7_encode($name);
273
        $prefixedName = "{".$this->settings['server']."}INBOX.".$name;
274
        $mailboxes = imap_list($this->conn, "{".$this->settings['server']."}", "*");
275
276
        return in_array($prefixedName, $mailboxes);
277
    }
278
279
280
    /**
281
     * Return all mailboxes (folders) on the server.
282
     *
283
     * @return array
284
     */
285
    public function getMailboxes()
286
    {
287
        return imap_list($this->conn, "{".$this->settings['server']."}", "*");
288
    }
289
290
291
    /**
292
     * Return all mailboxes (folders) on the server. This function removes the
293
     * mailbox prefixes like {server}INBOX.<name here>
294
     *
295
     * @return array
296
     */
297
    public function getPrettyMailboxes()
298
    {
299
        $mailboxes = $this->getMailboxes();
300
        $result = [];
301
        if (is_array($mailboxes) && count($mailboxes) > 0) {
302
            $prefixedMailbox = "INBOX.";
303
            foreach ($mailboxes as $mailbox) {
304
                // Remove the server prefix
305
                $mailbox = str_replace('{'.$this->settings['server'].'}', '', $mailbox);
306
307
                // Remove the INBOX. prefix (if present)
308
                $mailbox = str_replace($prefixedMailbox, '', $mailbox);
309
310
                $result[] = $mailbox;
311
            }
312
        }
313
314
        return $result;
315
    }
316
317
318
    /**
319
     * Rename a mailbox (folder)
320
     *
321
     * @param string $from
322
     * @param string $to
323
     *
324
     * @return bool
325
     */
326
    public function renameMailbox($from = '', $to = '')
327
    {
328
        if (empty($from) || empty($to)) {
329
            return false;
330
        }
331
332
        $from = imap_utf7_encode($from);
333
        $to = imap_utf7_encode($to);
334
335
        return imap_renamemailbox($this->conn, "{".$this->settings['server']."}INBOX.".$from,
336
            "{".$this->settings['server']."}INBOX.".$to);
337
    }
338
339
340
    /**
341
     * Move a given message at $index to a given mailbox (folder).
342
     *
343
     * @param int    $index
344
     * @param string $to
345
     *
346
     * @return bool
347
     */
348
    public function moveMessage($index = -1, $to = '')
349
    {
350
        if (empty($to)) {
351
            return false;
352
        }
353
354
        $msgId = 0;
355
356
        if (is_array($this->messages) == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
357
            foreach($this ->messages as $msg) {
358
                if ($msg['index'] == $index) {
359
                    $msgId = $msg['index'];
360
                    break;
361
                }
362
            }
363
        }
364
365
366
        if ($msgId >= 0) {
367
            $to = imap_utf7_encode($to);
368
369
            imap_mail_move($this->conn, $msgId, "INBOX.".$to);
370
            imap_expunge($this->conn);
371
        }
372
373
        return false;
374
    }
375
376
377
378
    /**
379
     * Delete a given email message. The param $index
380
     * is bases of the [index] field on an email array.
381
     *
382
     * @param int $index
383
     *
384
     * @return bool
385
     */
386
    public function deleteMessage($index = -1)
387
    {
388
        if ($index == -1) {
389
            return false;
390
        }
391
392
        $result = imap_delete($this->conn, $index);
393
        if ($result) {
394
            // Real delete emails marked as deleted
395
            imap_expunge($this->conn);
396
        }
397
        return $result;
398
    }
399
400
401
    /**
402
     * Return message information without reading it from the server
403
     *
404
     * @param string $id
405
     *
406
     * @return mixed
407
     */
408
    public function getMessageInformation($id = '')
409
    {
410
        $message = [];
411
        if (is_array($this->messages) == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
412
            foreach($this ->messages as $msg) {
413
                if ($msg['index'] == $id) {
414
                    return $msg;
415
                }
416
            }
417
        }
418
        return $message;
419
    }
420
421
    /**
422
     * Return a message based on its index in the mailbox.
423
     *
424
     * @param string $id
425
     *
426
     * @return mixed
427
     */
428
    public function getMessage($id = '')
429
    {
430
        $message = [];
431
        if (is_array($this->messages) == true) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
432
            foreach($this ->messages as $msg) {
433
                if ($msg['index'] == $id) {
434
                    $message = $msg;
435
                    break;
436
                }
437
            }
438
        }
439
440
        if (is_array($message) === true) {
441
            // Get the message body but do not mark as read
442
            $message['body'] = quoted_printable_decode(imap_fetchbody($this->conn, $message['index'], FT_PEEK));
443
        }
444
445
        return $message;
446
    }
447
448
449
    /**
450
     * Retrieve a list of message in the mailbox.
451
     *
452
     * @return array
453
     */
454
    public function readMailbox()
455
    {
456
        $msg_cnt = imap_num_msg($this->conn);
457
458
        $messages = [];
459
        for ($i = 1; $i <= $msg_cnt; $i++) {
460
            $header = imap_headerinfo($this->conn, $i);
461
            $messages[] = [
462
                'index'     => trim($header->Msgno),
463
                'header'    => $header,
464
                'structure' => imap_fetchstructure($this->conn, $i)
465
            ];
466
        }
467
        $this->messages = $messages;
468
        return $this->messages;
469
    }
470
}