Completed
Push — master ( 8f74cc...e4e1da )
by Rudie
01:29
created

IMAPMessage::decodedContent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace rdx\imap;
4
5
class IMAPMessage extends IMAPMessageContent implements IMAPMessagePartInterface {
6
7
	/** @var IMAPMailbox */
8
	protected $mailbox;
9
10
	/** @var int */
11
	protected $msgNumber = 1; // starts at 1, not 0
12
13
	/** @var bool */
14
	protected $unseen = true;
15
16
	/** @var string[]  */
17
	protected $headers = [];
18
19
	/** @var string */
20
	protected $subject = '';
21
22
	/** @var string */
23
	protected $subtype = '';
24
25
	public function __construct( IMAPMailbox $mailbox, $msgNumber, $unseen = null ) {
26
		$this->mailbox = $mailbox;
27
		$this->msgNumber = $msgNumber;
28
		$this->unseen = $unseen;
29
30
		if ( $unseen === null ) {
31
			$this->unseen = (bool) trim($this->header('unseen'));
32
		}
33
	}
34
35
	/** @return bool|bool[] */
36
	protected function flags( $flags, $clear ) {
37
		$cb = [$this->mailbox()->imap(), $clear ? 'unflag' : 'flag'];
38
39
		$feedback = [];
40
		foreach ( (array) $flags AS $flag ) {
41
			$flag = '\\' . ucfirst($flag);
42
			$feedback[] = call_user_func($cb, $this->msgNumber, $flag);
43
		}
44
45
		return is_array($flags) ? $feedback : $feedback[0];
46
	}
47
48
	/** @return bool|bool[] */
49
	public function flag( $flags ) {
50
		return $this->flags($flags, false);
51
	}
52
53
	/** @return bool|bool[] */
54
	public function unflag( $flags ) {
55
		return $this->flags($flags, true);
56
	}
57
58
	/** @return int */
59
	public function utc() {
60
		return strtotime($this->header('date'));
61
	}
62
63
	/** @return string */
64
	public function subject() {
65
		if ( empty($this->subject) ) {
66
			$subject = $this->mailbox()->imap()->utf8($this->header('subject'));
67
			$this->subject = trim($subject);
68
		}
69
70
		return $this->subject;
71
	}
72
73
	/** @return string[] */
74
	public function headers() {
75
		if ( empty($this->headers) ) {
76
			$this->headers = $this->mailbox()->imap()->headerinfo($this->msgNumber);
77
		}
78
79
		return $this->headers;
80
	}
81
82
	/** @return string */
83
	public function header( $name ) {
84
		$headers = $this->headers();
85
		return @$headers[ strtolower($name) ];
86
	}
87
88
	/** @return IMAPMessagePart */
89
	public function createMessagePart( $structure, $section ) {
90
		return new IMAPMessagePart($this, $structure, $section);
91
	}
92
93
	/** @return IMAPMessagePart[] */
94
	public function parts() {
95
		if ( empty($this->parts) ) {
96
			$structure = $this->structure();
97
98
			// Possibilities:
99
			// - PLAIN
100
			// - ALTERNATIVE
101
			// - MIXED
102
			// - DELIVERY-STATUS
103
			// - RFC822
104
			// - REPORT
105
			// - HTML
106
			// - CALENDAR
107
			// - JPEG
108
109
			if ( empty($structure->parts) ) {
110
				$this->parts[] = $this->createMessagePart(
111
					$structure,
112
					[1]
113
				);
114
			}
115
			else {
116
				foreach ( $structure->parts as $n => $part ) {
117
					$this->parts[] = $this->createMessagePart(
118
						$part,
119
						[$n + 1]
120
					);
121
				}
122
			}
123
		}
124
125
		return $this->parts;
126
	}
127
128
	/** @return object */
129
	public function structure() {
130
		if ( empty($this->structure) ) {
131
			$this->structure = $this->mailbox()->imap()->fetchstructure($this->msgNumber);
132
		}
133
134
		return $this->structure;
135
	}
136
137
	/** @return string */
138
	public function subtype() {
139
		if ( empty($this->subtype) ) {
140
			$structure = $this->structure();
141
			$this->subtype = @$structure->subtype ?: '';
142
		}
143
144
		return $this->subtype;
145
	}
146
147
	/** @return int[] */
148
	public function section() {
149
		return [];
150
	}
151
152
	/** @return string */
153
	public function content() {
154
		if ( count($this->parts()) == 1 ) {
155
			return $this->part(0)->content();
156
		}
157
158
		return '';
159
	}
160
161
	/** @return string */
162
	public function decodedContent() {
163
		if ( count($this->parts()) == 1 ) {
164
			return $this->part(0)->decodedContent();
165
		}
166
167
		return '';
168
	}
169
170
	/** @return bool */
171
	public function delete() {
172
		return $this->mailbox()->imap()->delete($this->msgNumber);
173
	}
174
175
	/** @return string[] */
176
	public function simpleStructure() {
177
		$parts = [];
178
		foreach ( $this->allParts() as $part ) {
179
			$name = '';
180
181
			$name .= implode('.', $part->section()) . '. ';
182
			if ( $part->parts() ) {
183
				$name .= '*';
184
			}
185
			$name .= $part->subtype();
186
			if ( $part->parameter('disposition') ) {
187
				if ( $filename = $part->filename() ) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface rdx\imap\IMAPMessagePartInterface as the method filename() does only exist in the following implementations of said interface: rdx\imap\IMAPMessagePart.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
188
					$name .= ' (' . $filename . ')';
189
				}
190
			}
191
			if ( $bytes = $part->parameter('bytes') ) {
192
				$name .= ' (' . number_format($bytes/1024, 1) . 'kb)';
193
			}
194
195
			$parts[] = $name;
196
		}
197
198
		return $parts;
199
	}
200
201
	/** @return int */
202
	public function msgNumber() {
203
		return $this->msgNumber;
204
	}
205
206
	/** @return IMAPMailbox */
207
	public function mailbox() {
208
		return $this->mailbox;
209
	}
210
211
}
212