Passed
Push — master ( b29af0...6d200b )
by Malte
03:13
created

Folder::parseAttributes()   A

Complexity

Conditions 6
Paths 32

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 5
nc 32
nop 1
dl 0
loc 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
/*
3
* File:     Folder.php
4
* Category: -
5
* Author:   M. Goldenbaum
6
* Created:  19.01.17 22:21
7
* Updated:  -
8
*
9
* Description:
10
*  -
11
*/
12
13
namespace Webklex\IMAP;
14
15
use Webklex\IMAP\Exceptions\GetMessagesFailedException;
16
use Webklex\IMAP\Exceptions\MessageSearchValidationException;
17
use Webklex\IMAP\Query\WhereQuery;
18
use Webklex\IMAP\Support\FolderCollection;
19
use Webklex\IMAP\Support\MessageCollection;
20
21
/**
22
 * Class Folder
23
 *
24
 * @package Webklex\IMAP
25
 */
26
class Folder {
27
28
    /**
29
     * Client instance
30
     *
31
     * @var \Webklex\IMAP\Client
32
     */
33
    protected $client;
34
35
    /**
36
     * Folder full path
37
     *
38
     * @var string
39
     */
40
    public $path;
41
42
    /**
43
     * Folder name
44
     *
45
     * @var string
46
     */
47
    public $name;
48
49
    /**
50
     * Folder fullname
51
     *
52
     * @var string
53
     */
54
    public $fullName;
55
56
    /**
57
     * Children folders
58
     *
59
     * @var FolderCollection|array
60
     */
61
    public $children = [];
62
63
    /**
64
     * Delimiter for folder
65
     *
66
     * @var string
67
     */
68
    public $delimiter;
69
70
    /**
71
     * Indicates if folder can't containg any "children".
72
     * CreateFolder won't work on this folder.
73
     *
74
     * @var boolean
75
     */
76
    public $no_inferiors;
77
78
    /**
79
     * Indicates if folder is only container, not a mailbox - you can't open it.
80
     *
81
     * @var boolean
82
     */
83
    public $no_select;
84
85
    /**
86
     * Indicates if folder is marked. This means that it may contain new messages since the last time it was checked.
87
     * Not provided by all IMAP servers.
88
     *
89
     * @var boolean
90
     */
91
    public $marked;
92
93
    /**
94
     * Indicates if folder containg any "children".
95
     * Not provided by all IMAP servers.
96
     *
97
     * @var boolean
98
     */
99
    public $has_children;
100
101
    /**
102
     * Indicates if folder refers to other.
103
     * Not provided by all IMAP servers.
104
     *
105
     * @var boolean
106
     */
107
    public $referal;
108
109
    /**
110
     * Folder constructor.
111
     *
112
     * @param \Webklex\IMAP\Client $client
113
     *
114
     * @param object $structure
115
     */
116
    public function __construct(Client $client, $structure) {
117
        $this->client = $client;
118
119
        $this->setDelimiter($structure->delimiter);
120
        $this->path      = $structure->name;
121
        $this->fullName  = $this->decodeName($structure->name);
122
        $this->name      = $this->getSimpleName($this->delimiter, $this->fullName);
123
124
        $this->parseAttributes($structure->attributes);
125
    }
126
127
    /**
128
     * Get a new search query instance
129
     * @param string $charset
130
     *
131
     * @return WhereQuery
132
     * @throws Exceptions\ConnectionFailedException
133
     */
134
    public function query($charset = 'UTF-8'){
135
        $this->getClient()->checkConnection();
136
        $this->getClient()->openFolder($this);
137
138
        return new WhereQuery($this->getClient(), $charset);
139
    }
140
141
    /**
142
     * @inheritdoc self::query($charset = 'UTF-8')
143
     * @throws Exceptions\ConnectionFailedException
144
     */
145
    public function search($charset = 'UTF-8'){
146
        return $this->query($charset);
147
    }
148
149
    /**
150
     * @inheritdoc self::query($charset = 'UTF-8')
151
     * @throws Exceptions\ConnectionFailedException
152
     */
153
    public function messages($charset = 'UTF-8'){
154
        return $this->query($charset);
155
    }
156
157
    /**
158
     * Determine if folder has children.
159
     *
160
     * @return bool
161
     */
162
    public function hasChildren() {
163
        return $this->has_children;
164
    }
165
166
    /**
167
     * Set children.
168
     *
169
     * @param FolderCollection|array $children
170
     *
171
     * @return self
172
     */
173
    public function setChildren($children = []) {
174
        $this->children = $children;
175
176
        return $this;
177
    }
178
179
    /**
180
     * Get a specific message by UID
181
     *
182
     * @param integer      $uid     Please note that the uid is not unique and can change
183
     * @param integer|null $msglist
184
     * @param integer|null $fetch_options
185
     * @param boolean      $fetch_body
186
     * @param boolean      $fetch_attachment
187
     * @param boolean      $fetch_flags
188
     *
189
     * @return Message|null
190
     *
191
     * @throws Exceptions\ConnectionFailedException
192
     * @throws Exceptions\InvalidWhereQueryCriteriaException
193
     * @throws GetMessagesFailedException
194
     * @throws MessageSearchValidationException
195
     */
196
    public function getMessage($uid, $msglist = null, $fetch_options = null, $fetch_body = false, $fetch_attachment = false, $fetch_flags = true) {
197
        if (imap_msgno($this->getClient()->getConnection(), $uid) > 0) {
0 ignored issues
show
Bug introduced by
It seems like $this->getClient()->getConnection() can also be of type true; however, parameter $imap_stream of imap_msgno() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

197
        if (imap_msgno(/** @scrutinizer ignore-type */ $this->getClient()->getConnection(), $uid) > 0) {
Loading history...
198
            return new Message($uid, $msglist, $this->getClient(), $fetch_options, $fetch_body, $fetch_attachment, $fetch_flags);
199
        }
200
201
        return null;
202
    }
203
204
    /**
205
     * Get all messages
206
     *
207
     * @param string    $criteria
208
     * @param int|null  $fetch_options
209
     * @param boolean   $fetch_body
210
     * @param boolean   $fetch_attachment
211
     * @param boolean   $fetch_flags
212
     * @param int|null  $limit
213
     * @param int       $page
214
     * @param string    $charset
215
     *
216
     * @return MessageCollection
217
     * @throws Exceptions\ConnectionFailedException
218
     * @throws Exceptions\InvalidWhereQueryCriteriaException
219
     * @throws GetMessagesFailedException
220
     */
221
    public function getMessages($criteria = 'ALL', $fetch_options = null, $fetch_body = true, $fetch_attachment = true, $fetch_flags = true, $limit = null, $page = 1, $charset = "UTF-8") {
222
223
        return $this->query($charset)->where($criteria)->setFetchOptions($fetch_options)->setFetchBody($fetch_body)
0 ignored issues
show
Bug introduced by
It seems like $fetch_options can also be of type integer; however, parameter $fetch_options of Webklex\IMAP\Query\Query::setFetchOptions() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

223
        return $this->query($charset)->where($criteria)->setFetchOptions(/** @scrutinizer ignore-type */ $fetch_options)->setFetchBody($fetch_body)
Loading history...
224
            ->setFetchAttachment($fetch_attachment)->setFetchFlags($fetch_flags)
0 ignored issues
show
Bug introduced by
$fetch_flags of type boolean is incompatible with the type integer expected by parameter $fetch_flags of Webklex\IMAP\Query\Query::setFetchFlags(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

224
            ->setFetchAttachment($fetch_attachment)->setFetchFlags(/** @scrutinizer ignore-type */ $fetch_flags)
Loading history...
225
            ->limit($limit, $page)->get();
226
    }
227
228
    /**
229
     * Get all unseen messages
230
     *
231
     * @param string    $criteria
232
     * @param int|null  $fetch_options
233
     * @param boolean   $fetch_body
234
     * @param boolean   $fetch_attachment
235
     * @param boolean   $fetch_flags
236
     * @param int|null  $limit
237
     * @param int       $page
238
     * @param string    $charset
239
     *
240
     * @return MessageCollection
241
     * @throws Exceptions\ConnectionFailedException
242
     * @throws Exceptions\InvalidWhereQueryCriteriaException
243
     * @throws GetMessagesFailedException
244
     * @throws MessageSearchValidationException
245
     *
246
     * @deprecated 1.0.5:2.0.0 No longer needed. Use Folder::getMessages('UNSEEN') instead
247
     * @see Folder::getMessages()
248
     */
249
    public function getUnseenMessages($criteria = 'UNSEEN', $fetch_options = null, $fetch_body = true, $fetch_attachment = true, $fetch_flags = true, $limit = null, $page = 1, $charset = "UTF-8") {
250
        return $this->getMessages($criteria, $fetch_options, $fetch_body, $fetch_attachment, $fetch_flags, $limit, $page, $charset);
251
    }
252
253
    /**
254
     * Search messages by a given search criteria
255
     *
256
     * @param array   $where  Is a two dimensional array where each array represents a criteria set:
257
     *                        ---------------------------------------------------------------------------------------
258
     *                        The following sample would search for all messages received from [email protected] or
259
     *                        contain the text "Hello world!":
260
     *                        [['FROM' => '[email protected]'],[' TEXT' => 'Hello world!']]
261
     *                        ---------------------------------------------------------------------------------------
262
     *                        The following sample would search for all messages received since march 15 2018:
263
     *                        [['SINCE' => Carbon::parse('15.03.2018')]]
264
     *                        ---------------------------------------------------------------------------------------
265
     *                        The following sample would search for all flagged messages:
266
     *                        [['FLAGGED']]
267
     *                        ---------------------------------------------------------------------------------------
268
     * @param int|null  $fetch_options
269
     * @param boolean   $fetch_body
270
     * @param boolean   $fetch_attachment
271
     * @param boolean   $fetch_flags
272
     * @param int|null  $limit
273
     * @param int       $page
274
     * @param string    $charset
275
     *
276
     * @return MessageCollection
277
     *
278
     * @throws Exceptions\ConnectionFailedException
279
     * @throws Exceptions\InvalidWhereQueryCriteriaException
280
     * @throws GetMessagesFailedException
281
     *
282
     * @doc http://php.net/manual/en/function.imap-search.php
283
     *      imap_search() only supports IMAP2 search criterias, because the function mail_criteria() (from c-client lib)
284
     *      is used in ext/imap/php_imap.c for parsing the search string.
285
     *      IMAP2 search criteria is defined in RFC 1176, section "tag SEARCH search_criteria".
286
     *
287
     *      https://tools.ietf.org/html/rfc1176 - INTERACTIVE MAIL ACCESS PROTOCOL - VERSION 2
288
     *      https://tools.ietf.org/html/rfc1064 - INTERACTIVE MAIL ACCESS PROTOCOL - VERSION 2
289
     *      https://tools.ietf.org/html/rfc822  - STANDARD FOR THE FORMAT OF ARPA INTERNET TEXT MESSAGES
290
     *      Date and time example from RFC822:
291
     *      date-time   =  [ day "," ] date time        ; dd mm yy
292
     *                                                  ;  hh:mm:ss zzz
293
     *
294
     *      day         =  "Mon"  / "Tue" /  "Wed"  / "Thu" /  "Fri"  / "Sat" /  "Sun"
295
     *
296
     *      date        =  1*2DIGIT month 2DIGIT        ; day month year
297
     *                                                  ;  e.g. 20 Jun 82
298
     *
299
     *      month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr" /  "May"  /  "Jun" /  "Jul"  /  "Aug" /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"
300
     *
301
     *      time        =  hour zone                    ; ANSI and Military
302
     *
303
     *      hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
304
     *
305
     *      zone        =  "UT"  / "GMT"         ; Universal Time
306
     *                                           ; North American : UT
307
     *                  =  "EST" / "EDT"         ;  Eastern:  - 5/ - 4
308
     *                  =  "CST" / "CDT"         ;  Central:  - 6/ - 5
309
     *                  =  "MST" / "MDT"         ;  Mountain: - 7/ - 6
310
     *                  =  "PST" / "PDT"         ;  Pacific:  - 8/ - 7
311
     *                  =  1ALPHA                ; Military: Z = UT;
312
     *                                           ;  A:-1; (J not used)
313
     *                                           ;  M:-12; N:+1; Y:+12
314
     *                  / ( ("+" / "-") 4DIGIT ) ; Local differential
315
     *                                           ;  hours+min. (HHMM)
316
     *
317
     * @deprecated 1.2.1:2.0.0 No longer needed. Use Folder::query() instead
318
     * @see Folder::query()
319
     */
320
    public function searchMessages(array $where, $fetch_options = null, $fetch_body = true,  $fetch_attachment = true, $fetch_flags = true, $limit = null, $page = 1, $charset = "UTF-8") {
321
        $this->getClient()->checkConnection();
322
323
        return $this->query($charset)->where($where)->setFetchOptions($fetch_options)->setFetchBody($fetch_body)
0 ignored issues
show
Bug introduced by
It seems like $fetch_options can also be of type integer; however, parameter $fetch_options of Webklex\IMAP\Query\Query::setFetchOptions() does only seem to accept boolean, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

323
        return $this->query($charset)->where($where)->setFetchOptions(/** @scrutinizer ignore-type */ $fetch_options)->setFetchBody($fetch_body)
Loading history...
324
            ->setFetchAttachment($fetch_attachment)->setFetchFlags($fetch_flags)
0 ignored issues
show
Bug introduced by
$fetch_flags of type boolean is incompatible with the type integer expected by parameter $fetch_flags of Webklex\IMAP\Query\Query::setFetchFlags(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

324
            ->setFetchAttachment($fetch_attachment)->setFetchFlags(/** @scrutinizer ignore-type */ $fetch_flags)
Loading history...
325
            ->limit($limit, $page)->get();
326
327
    }
328
329
    /**
330
     * Decode name.
331
     * It converts UTF7-IMAP encoding to UTF-8.
332
     *
333
     * @param $name
334
     *
335
     * @return mixed|string
336
     */
337
    protected function decodeName($name) {
338
        preg_match('#\{(.*)\}(.*)#', $name, $preg);
339
        return mb_convert_encoding($preg[2], "UTF-8", "UTF7-IMAP");
340
    }
341
342
    /**
343
     * Get simple name (without parent folders).
344
     *
345
     * @param $delimiter
346
     * @param $fullName
347
     *
348
     * @return mixed
349
     */
350
    protected function getSimpleName($delimiter, $fullName) {
351
        $arr = explode($delimiter, $fullName);
352
353
        return end($arr);
354
    }
355
356
    /**
357
     * Parse attributes and set it to object properties.
358
     *
359
     * @param $attributes
360
     */
361
    protected function parseAttributes($attributes) {
362
        $this->no_inferiors = ($attributes & LATT_NOINFERIORS) ? true : false;
363
        $this->no_select    = ($attributes & LATT_NOSELECT) ? true : false;
364
        $this->marked       = ($attributes & LATT_MARKED) ? true : false;
365
        $this->referal      = ($attributes & LATT_REFERRAL) ? true : false;
366
        $this->has_children = ($attributes & LATT_HASCHILDREN) ? true : false;
367
    }
368
369
    /**
370
     * Delete the current Mailbox
371
     * @param boolean $expunge
372
     *
373
     * @return bool
374
     *
375
     * @throws Exceptions\ConnectionFailedException
376
     */
377
    public function delete($expunge = true) {
378
        $status = imap_deletemailbox($this->client->getConnection(), $this->path);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; however, parameter $imap_stream of imap_deletemailbox() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

378
        $status = imap_deletemailbox(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->path);
Loading history...
379
        if($expunge) $this->client->expunge();
380
381
        return $status;
382
    }
383
384
    /**
385
     * Move or Rename the current Mailbox
386
     *
387
     * @param string $target_mailbox
388
     * @param boolean $expunge
389
     *
390
     * @return bool
391
     *
392
     * @throws Exceptions\ConnectionFailedException
393
     */
394
    public function move($target_mailbox, $expunge = true) {
395
        $status = imap_renamemailbox($this->client->getConnection(), $this->path, $target_mailbox);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; however, parameter $imap_stream of imap_renamemailbox() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

395
        $status = imap_renamemailbox(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->path, $target_mailbox);
Loading history...
396
        if($expunge) $this->client->expunge();
397
398
        return $status;
399
    }
400
401
    /**
402
     * Returns status information on a mailbox
403
     *
404
     * @param integer   $options
405
     *                  SA_MESSAGES     - set $status->messages to the number of messages in the mailbox
406
     *                  SA_RECENT       - set $status->recent to the number of recent messages in the mailbox
407
     *                  SA_UNSEEN       - set $status->unseen to the number of unseen (new) messages in the mailbox
408
     *                  SA_UIDNEXT      - set $status->uidnext to the next uid to be used in the mailbox
409
     *                  SA_UIDVALIDITY  - set $status->uidvalidity to a constant that changes when uids for the mailbox may no longer be valid
410
     *                  SA_ALL          - set all of the above
411
     *
412
     * @return object
413
     * @throws Exceptions\ConnectionFailedException
414
     */
415
    public function getStatus($options) {
416
        return imap_status($this->client->getConnection(), $this->path, $options);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; however, parameter $imap_stream of imap_status() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

416
        return imap_status(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->path, $options);
Loading history...
417
    }
418
419
    /**
420
     * Append a string message to the current mailbox
421
     *
422
     * @param string $message
423
     * @param string $options
424
     * @param string $internal_date
425
     *
426
     * @return bool
427
     * @throws Exceptions\ConnectionFailedException
428
     */
429
    public function appendMessage($message, $options = null, $internal_date = null) {
430
        return imap_append($this->client->getConnection(), $this->path, $message, $options, $internal_date);
0 ignored issues
show
Bug introduced by
It seems like $this->client->getConnection() can also be of type true; however, parameter $imap_stream of imap_append() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

430
        return imap_append(/** @scrutinizer ignore-type */ $this->client->getConnection(), $this->path, $message, $options, $internal_date);
Loading history...
431
    }
432
433
    /**
434
     * Get the current Client instance
435
     *
436
     * @return Client
437
     */
438
    public function getClient() {
439
        return $this->client;
440
    }
441
442
    /**
443
     * @param $delimiter
444
     */
445
    public function setDelimiter($delimiter){
446
        if(in_array($delimiter, [null, '', ' ', false]) === true) {
447
            $delimiter = config('imap.options.delimiter', '/');
448
        }
449
450
        $this->delimiter = $delimiter;
451
    }
452
}
453