Passed
Push — master ( 1c274f...deee47 )
by Daniel
02:49 queued 01:06
created

Mail::getDecodedBody()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Dacastro4\LaravelGmail\Services\Message;
4
5
use Carbon\Carbon;
6
use Dacastro4\LaravelGmail\GmailConnection;
7
use Dacastro4\LaravelGmail\Traits\HasDecodableBody;
8
use Dacastro4\LaravelGmail\Traits\Modifiable;
9
use Dacastro4\LaravelGmail\Traits\Replyable;
10
use Google_Service_Gmail;
11
use Illuminate\Support\Collection;
12
13
/**
14
 * Class SingleMessage
15
 * @package Dacastro4\LaravelGmail\services
16
 */
17
class Mail extends GmailConnection
18
{
19
	use HasDecodableBody,
0 ignored issues
show
Bug introduced by
The trait Dacastro4\LaravelGmail\Traits\Modifiable requires the property $users_messages which is not provided by Dacastro4\LaravelGmail\Services\Message\Mail.
Loading history...
Bug introduced by
The trait Dacastro4\LaravelGmail\Traits\Replyable requires the property $users_messages which is not provided by Dacastro4\LaravelGmail\Services\Message\Mail.
Loading history...
20
	Modifiable,
21
	Replyable {
22
		Replyable::__construct as private __rConstruct;
23
		Modifiable::__construct as private __mConstruct;
24
	}
25
26
	/**
27
	 * @var
28
	 */
29
	public $id;
30
31
	/**
32
	 * @var
33
	 */
34
	public $internalDate;
35
36
	/**
37
	 * @var
38
	 */
39
	public $labels;
40
41
	/**
42
	 * @var
43
	 */
44
	public $size;
45
46
	/**
47
	 * @var
48
	 */
49
	public $threatId;
50
51
	/**
52
	 * @var \Google_Service_Gmail_MessagePart
53
	 */
54
	public $payload;
55
56
	/**
57
	 * @var Google_Service_Gmail
58
	 */
59
	public $service;
60
61
	/**
62
	 * SingleMessage constructor.
63
	 *
64
	 * @param \Google_Service_Gmail_Message $message
65
	 * @param bool $preload
66
	 *
67
	 */
68
	public function __construct( \Google_Service_Gmail_Message $message = null, $preload = false )
69
	{
70
71
		$this->service = new Google_Service_Gmail( $this );
72
73
		$this->__rConstruct();
74
		$this->__mConstruct();
75
		parent::__construct( config() );
0 ignored issues
show
Unused Code introduced by
The call to Dacastro4\LaravelGmail\T...difiable::__construct() has too many arguments starting with config(). ( Ignorable by Annotation )

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

75
		parent::/** @scrutinizer ignore-call */ 
76
          __construct( config() );

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
76
77
		if ( ! is_null( $message ) ) {
78
			if ( $preload ) {
79
				$message = $this->service->users_messages->get( 'me', $message->getId() );
80
			}
81
82
			$this->id = $message->getId();
83
			$this->internalDate = $message->getInternalDate();
84
			$this->labels = $message->getLabelIds();
85
			$this->size = $message->getSizeEstimate();
86
			$this->threatId = $message->getThreadId();
87
			$this->payload = $message->getPayload();
88
			
89
		}
90
	}
91
92
	/**
93
	 * Returns ID of the email
94
	 *
95
	 * @return string
96
	 */
97
	public function getId()
98
	{
99
		return $this->id;
100
	}
101
102
	/**
103
	 * Return a UNIX version of the date
104
	 *
105
	 * @return int UNIX date
106
	 */
107
	public function getInternalDate()
108
	{
109
		return $this->internalDate;
110
	}
111
112
	/**
113
	 * Returns the labels of the email
114
	 * Example: INBOX, STARRED, UNREAD
115
	 *
116
	 * @return array
117
	 */
118
	public function getLabels()
119
	{
120
		return $this->labels;
121
	}
122
123
	/**
124
	 * Returns approximate size of the email
125
	 *
126
	 * @return mixed
127
	 */
128
	public function getSize()
129
	{
130
		return $this->size;
131
	}
132
133
	/**
134
	 * Returns threat ID of the email
135
	 *
136
	 * @return string
137
	 */
138
	public function getThreatId()
139
	{
140
		return $this->threatId;
141
	}
142
143
	/**
144
	 * Returns all the headers of the email
145
	 *
146
	 * @return Collection
147
	 */
148
	public function getHeaders()
149
	{
150
		return $this->buildHeaders( $this->payload->getHeaders() );
151
	}
152
153
	/**
154
	 * Returns the subject of the email
155
	 *
156
	 * @return string
157
	 */
158
	public function getSubject()
159
	{
160
		return $this->getHeader( 'Subject' );
161
	}
162
163
	/**
164
	 * Returns array of name and email of each recipient
165
	 *
166
	 * @return array
167
	 */
168
	public function getFrom()
169
	{
170
		$from = $this->getHeader( 'From' );
171
172
		preg_match( '/<(.*)>/', $from, $matches );
173
174
		$name = preg_replace( '/ <(.*)>/', '', $from );
175
176
		return [
177
			'name'  => $name,
178
			'email' => isset( $matches[ 1 ] ) ? $matches[ 1 ] : null,
179
		];
180
	}
181
182
	/**
183
	 * Returns email of sender
184
	 *
185
	 * @return string|null
186
	 */
187
	public function getFromEmail()
188
	{
189
		$from = $this->getHeader( 'From' );
190
191
		preg_match( '/<(.*)>/', $from, $matches );
192
193
		return isset( $matches[ 1 ] ) ? $matches[ 1 ] : null;
194
	}
195
196
	/**
197
	 * Returns name of the sender
198
	 *
199
	 * @return string|null
200
	 */
201
	public function getFromName()
202
	{
203
		$from = $this->getHeader( 'From' );
204
205
		$name = preg_replace( '/ <(.*)>/', '', $from );
206
207
		return $name;
208
	}
209
210
	/**
211
	 * Returns array list of recipients
212
	 *
213
	 * @return array
214
	 */
215
	public function getTo()
216
	{
217
		$allTo = $this->getHeader( 'To' );
218
219
		return $this->formatEmailList( $allTo );
220
	}
221
222
	/**
223
	 * Returns the original date that the email was sent
224
	 *
225
	 * @return Carbon
226
	 */
227
	public function getDate()
228
	{
229
		return Carbon::parse( $this->getHeader( 'Date' ) );
230
	}
231
232
	/**
233
	 * Returns email of the original recipient
234
	 *
235
	 * @return string
236
	 */
237
	public function getDeliveredTo()
238
	{
239
		return $this->getHeader( 'Delivered-To' );
240
	}
241
242
	/**
243
	 * @param bool $raw
244
	 *
245
	 * @return string
246
	 */
247
	public function getPlainTextBody( $raw = false )
248
	{
249
		$content = $this->getBody();
250
251
		return $raw ? $content : $this->getDecodedBody( $content );
252
	}
253
254
	/**
255
	 * @return string base64 version of the body
256
	 */
257
	public function getRawPlainTextBody()
258
	{
259
		return $this->getPlainTextBody( true );
260
	}
261
262
	/**
263
	 * @param bool $raw
264
	 *
265
	 * @return string
266
	 */
267
	public function getHtmlBody( $raw = false )
268
	{
269
		$content = $this->getBody( 'text/html' );
270
271
		return $raw ? $content : $this->getDecodedBody( $content );
272
	}
273
274
	/**
275
	 * @return string base64 version of the body
276
	 */
277
	public function getRawHtmlBody()
278
	{
279
		return $this->getHtmlBody( true );
280
	}
281
282
	/**
283
	 * Returns a collection of attachments
284
	 *
285
	 * @param bool $preload Preload the attachment's data
286
	 *
287
	 * @return Collection
288
	 * @throws \Exception
289
	 */
290
	public function getAttachments( $preload = false )
291
	{
292
		$attachments = new Collection( [] );
293
		$parts = $this->payload->getParts();
294
295
		/** @var \Google_Service_Gmail_MessagePart $part */
296
		foreach ( $parts as $part ) {
297
298
			$body = $part->getBody();
299
300
			if ( $body->getAttachmentId() ) {
301
				$attachment = ( new Attachment( $this->getId(), $part ) );
302
				if ( $preload ) {
303
					$attachment = $attachment->getData();
304
				}
305
				$attachments->push(
306
					$attachment
307
				);
308
			}
309
310
		}
311
312
		return $attachments;
313
314
	}
315
316
	/**
317
	 * @return Collection
318
	 * @throws \Exception
319
	 */
320
	public function getAttachmentsWithData()
321
	{
322
		return $this->getAttachments( true );
323
	}
324
325
	/**
326
	 * @return boolean
327
	 */
328
	public function hasAttachments()
329
	{
330
		$attachments = 0;
331
		$parts = $this->payload->getParts();
332
333
		/**  @var \Google_Service_Gmail_MessagePart $part */
334
		foreach ( $parts as $part ) {
335
			$body = $part->getBody();
336
			if ( $body->getAttachmentId() ) {
337
				$attachments ++;
338
				break;
339
			}
340
		}
341
342
		return ! ! $attachments;
343
	}
344
345
	/**
346
	 * @param string $type
347
	 *
348
	 * @return \Google_Service_Gmail_MessagePart|null
349
	 */
350
	private function getBodyPart( $type = 'text/plain' )
351
	{
352
		$body = $this->payload->getParts();
353
354
355
		if ( $this->hasAttachments() ) {
356
			//Get the first attachment that is the main body
357
			$body = isset( $body[ 0 ] ) ? $body[ 0 ] : [];
358
			$parts = $body->getParts();
359
		} else {
360
			$parts = $body;
361
		}
362
363
		/** @var \Google_Service_Gmail_MessagePart $part */
364
		foreach ( $parts as $part ) {
365
			if ( $part->getMimeType() === $type ) {
366
				break;
367
			}
368
		}
369
370
		return isset($part) ? $part : null;
371
372
	}
373
374
	public function getBody( $type = 'text/plain' )
375
	{
376
		$part = $this->getBodyPart( $type );
377
		$body = $part->getBody();
378
379
		return $body->getData();
380
	}
381
382
	/**
383
	 * Get's the gmail information from the Mail
384
	 *
385
	 * @return Mail
386
	 */
387
	public function load()
388
	{
389
		$message = $this->service->users_messages->get( 'me', $this->getId() );
390
391
		return new self( $message );
392
	}
393
394
	private function buildHeaders( $emailHeaders )
395
	{
396
		$headers = [];
397
398
		foreach ( $emailHeaders as $header ) {
399
			/** @var \Google_Service_Gmail_MessagePartHeader $header */
400
401
			$head = new \stdClass();
402
403
			$head->key = $header->getName();
404
			$head->value = $header->getValue();
405
406
			$headers[] = $head;
407
		}
408
409
		return collect( $headers );
410
411
	}
412
413
	/**
414
	 * Returns an array of emails from an string in RFC 822 format
415
	 *
416
	 * @param string $emails email list in RFC 822 format
417
	 *
418
	 * @return array
419
	 */
420
	public function formatEmailList( $emails )
421
	{
422
		$all = [];
423
		$explodedEmails = explode( ',', $emails );
424
425
		foreach ( $explodedEmails as $email ) {
426
427
			$item = [];
428
429
			preg_match( '/<(.*)>/', $email, $matches );
430
431
			$item[ 'email' ] = str_replace( ' ', '', isset( $matches[ 1 ] ) ? $matches[ 1 ] : $email );
432
433
			$name = preg_replace( '/ <(.*)>/', '', $email );
434
435
			if ( starts_with( $name, ' ' ) ) {
436
				$name = substr( $name, 1 );
437
			}
438
439
			$item[ 'name' ] = str_replace( "\"", '', $name ?: null );
440
441
			$all[] = $item;
442
443
		}
444
445
		return $all;
446
	}
447
448
	/**
449
	 * Sets the access token in case we wanna use a different token
450
	 *
451
	 * @param string $token
452
	 *
453
	 * @return Mail
454
	 */
455
	public function using( $token )
456
	{
457
		$this->setToken($token);
458
459
		return $this;
460
	}
461
462
463
464
	/* added by buckfuddey */
465
466
	public function hasNoParts(){
467
		if (empty($this->payload->getParts())) {
468
			return true;
469
		} else {
470
			return false;
471
		}
472
	}
473
474
475
	public function extractFromBody(){
476
477
		if ($this->hasNoParts()) {
478
			$type = $this->payload->getMimeType();
479
			$body = $this->payload->getBody();
480
			if ($type == 'text/html' || $type == 'text/plain') {
481
				$this->bodyArr[$type] = $this->getDecodedBody($body->getData());
0 ignored issues
show
Bug Best Practice introduced by
The property bodyArr does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
482
			}
483
			if ($body->getAttachmentId()) {
484
				$this->attachmentData[] = array(
0 ignored issues
show
Bug Best Practice introduced by
The property attachmentData does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
485
					'id' => $body->getAttachmentId(),
486
					'fileName' => $part->getFilename(),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $part does not exist. Did you maybe mean $parts?
Loading history...
487
					'mimeType' => $type
488
				);
489
			}
490
		} else {
491
			$parts = $this->payload->getParts();
492
			foreach ($parts as $part) {
493
				if (empty($part->getParts())) {
494
					$type = $part->getMimeType();
495
					$body = $part->getBody();
496
					if ($type == 'text/html' || $type == 'text/plain') {
497
						if (isset($this->messageBodyArr[$type])) {
498
							$this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
499
						} else {
500
							$this->messageBodyArr[$type] = $this->getDecodedBody($body->getData());
0 ignored issues
show
Bug Best Practice introduced by
The property messageBodyArr does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
501
						}
502
					}
503
504
					if ($body->getAttachmentId()) {
505
						$this->attachmentData[] = array(
506
							'id' => $body->getAttachmentId(),
507
							'fileName'  => $part->getFilename(),
508
							'mimeType' => $type
509
						);						
510
					}				
511
				} else {
512
					$subParts = $part->getParts();
513
					$this->traverseData($subParts);
514
				}
515
			}
516
		}		
517
	}
518
519
	public function traverseData($parts){
520
		foreach ($parts as $part) {			
521
			if (empty($part->getParts())) {
522
				$type = $part->getMimeType();
523
				$body = $part->getBody();
524
				if ($type == 'text/html' || $type == 'text/plain') {
525
					if (isset($this->messageBodyArr[$type])) {
526
						$this->messageBodyArr[$type] .= $this->getDecodedBody($body->getData());
527
					} else {
528
						$this->messageBodyArr[$type] = $this->getDecodedBody($body->getData());
0 ignored issues
show
Bug Best Practice introduced by
The property messageBodyArr does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
529
					}						
530
				}
531
532
				if ($body->getAttachmentId()) {
533
					$this->attachmentData[] = array(
0 ignored issues
show
Bug Best Practice introduced by
The property attachmentData does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
534
						'id' => $body->getAttachmentId(),
535
						'fileName'  => $part->getFilename(),
536
						'mimeType' => $type
537
					);
538
539
				}
540
			} else {
541
				$subParts = $part->getParts();
542
				$this->traverseData($subParts);
543
			}
544
		}
545
	}
546
547
	public function getDecodedBody( $content ) {
548
		$content = str_replace( '_', '/', str_replace( '-', '+', $content ) );
549
		return base64_decode( $content );
550
	}
551
552
}
553