1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* PHPMailer POP-Before-SMTP Authentication Class. |
4
|
|
|
* PHP Version 5 |
5
|
|
|
* @package PHPMailer |
6
|
|
|
* @link https://github.com/PHPMailer/PHPMailer/ |
7
|
|
|
* @author Marcus Bointon (Synchro/coolbru) <[email protected]> |
8
|
|
|
* @author Jim Jagielski (jimjag) <[email protected]> |
9
|
|
|
* @author Andy Prevost (codeworxtech) <[email protected]> |
10
|
|
|
* @author Brent R. Matzelle (original founder) |
11
|
|
|
* @copyright 2012 - 2014 Marcus Bointon |
12
|
|
|
* @copyright 2010 - 2012 Jim Jagielski |
13
|
|
|
* @copyright 2004 - 2009 Andy Prevost |
14
|
|
|
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License |
15
|
|
|
* @note This program is distributed in the hope that it will be useful - WITHOUT |
16
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
17
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. |
18
|
|
|
*/ |
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* PHPMailer POP-Before-SMTP Authentication Class. |
22
|
|
|
* Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication. |
23
|
|
|
* Does not support APOP. |
24
|
|
|
* @package PHPMailer |
25
|
|
|
* @author Richard Davey (original author) <[email protected]> |
26
|
|
|
* @author Marcus Bointon (Synchro/coolbru) <[email protected]> |
27
|
|
|
* @author Jim Jagielski (jimjag) <[email protected]> |
28
|
|
|
* @author Andy Prevost (codeworxtech) <[email protected]> |
29
|
|
|
*/ |
30
|
|
|
class POP3 |
31
|
|
|
{ |
32
|
|
|
/** |
33
|
|
|
* The POP3 PHPMailer Version number. |
34
|
|
|
* @var string |
35
|
|
|
* @access public |
36
|
|
|
*/ |
37
|
|
|
public $Version = '5.2.27'; |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Default POP3 port number. |
41
|
|
|
* @var integer |
42
|
|
|
* @access public |
43
|
|
|
*/ |
44
|
|
|
public $POP3_PORT = 110; |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Default timeout in seconds. |
48
|
|
|
* @var integer |
49
|
|
|
* @access public |
50
|
|
|
*/ |
51
|
|
|
public $POP3_TIMEOUT = 30; |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* POP3 Carriage Return + Line Feed. |
55
|
|
|
* @var string |
56
|
|
|
* @access public |
57
|
|
|
* @deprecated Use the constant instead |
58
|
|
|
*/ |
59
|
|
|
public $CRLF = "\r\n"; |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* Debug display level. |
63
|
|
|
* Options: 0 = no, 1+ = yes |
64
|
|
|
* @var integer |
65
|
|
|
* @access public |
66
|
|
|
*/ |
67
|
|
|
public $do_debug = 0; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* POP3 mail server hostname. |
71
|
|
|
* @var string |
72
|
|
|
* @access public |
73
|
|
|
*/ |
74
|
|
|
public $host; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* POP3 port number. |
78
|
|
|
* @var integer |
79
|
|
|
* @access public |
80
|
|
|
*/ |
81
|
|
|
public $port; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* POP3 Timeout Value in seconds. |
85
|
|
|
* @var integer |
86
|
|
|
* @access public |
87
|
|
|
*/ |
88
|
|
|
public $tval; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* POP3 username |
92
|
|
|
* @var string |
93
|
|
|
* @access public |
94
|
|
|
*/ |
95
|
|
|
public $username; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* POP3 password. |
99
|
|
|
* @var string |
100
|
|
|
* @access public |
101
|
|
|
*/ |
102
|
|
|
public $password; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Resource handle for the POP3 connection socket. |
106
|
|
|
* @var resource |
107
|
|
|
* @access protected |
108
|
|
|
*/ |
109
|
|
|
protected $pop_conn; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Are we connected? |
113
|
|
|
* @var boolean |
114
|
|
|
* @access protected |
115
|
|
|
*/ |
116
|
|
|
protected $connected = false; |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* Error container. |
120
|
|
|
* @var array |
121
|
|
|
* @access protected |
122
|
|
|
*/ |
123
|
|
|
protected $errors = array(); |
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Line break constant |
127
|
|
|
*/ |
128
|
|
|
const CRLF = "\r\n"; |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Simple static wrapper for all-in-one POP before SMTP |
132
|
|
|
* @param $host |
133
|
|
|
* @param integer|boolean $port The port number to connect to |
134
|
|
|
* @param integer|boolean $timeout The timeout value |
135
|
|
|
* @param string $username |
136
|
|
|
* @param string $password |
137
|
|
|
* @param integer $debug_level |
138
|
|
|
* @return boolean |
139
|
|
|
*/ |
140
|
|
|
public static function popBeforeSmtp( |
141
|
|
|
$host, |
142
|
|
|
$port = false, |
143
|
|
|
$timeout = false, |
144
|
|
|
$username = '', |
145
|
|
|
$password = '', |
146
|
|
|
$debug_level = 0 |
147
|
|
|
) { |
148
|
|
|
$pop = new POP3; |
149
|
|
|
return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Authenticate with a POP3 server. |
154
|
|
|
* A connect, login, disconnect sequence |
155
|
|
|
* appropriate for POP-before SMTP authorisation. |
156
|
|
|
* @access public |
157
|
|
|
* @param string $host The hostname to connect to |
158
|
|
|
* @param integer|boolean $port The port number to connect to |
159
|
|
|
* @param integer|boolean $timeout The timeout value |
160
|
|
|
* @param string $username |
161
|
|
|
* @param string $password |
162
|
|
|
* @param integer $debug_level |
163
|
|
|
* @return boolean |
164
|
|
|
*/ |
165
|
|
|
public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0) |
166
|
|
|
{ |
167
|
|
|
$this->host = $host; |
168
|
|
|
// If no port value provided, use default |
169
|
|
|
if (false === $port) { |
170
|
|
|
$this->port = $this->POP3_PORT; |
171
|
|
|
} else { |
172
|
|
|
$this->port = (integer)$port; |
173
|
|
|
} |
174
|
|
|
// If no timeout value provided, use default |
175
|
|
|
if (false === $timeout) { |
176
|
|
|
$this->tval = $this->POP3_TIMEOUT; |
177
|
|
|
} else { |
178
|
|
|
$this->tval = (integer)$timeout; |
179
|
|
|
} |
180
|
|
|
$this->do_debug = $debug_level; |
181
|
|
|
$this->username = $username; |
182
|
|
|
$this->password = $password; |
183
|
|
|
// Reset the error log |
184
|
|
|
$this->errors = array(); |
185
|
|
|
// connect |
186
|
|
|
$result = $this->connect($this->host, $this->port, $this->tval); |
187
|
|
|
if ($result) { |
188
|
|
|
$login_result = $this->login($this->username, $this->password); |
189
|
|
|
if ($login_result) { |
190
|
|
|
$this->disconnect(); |
191
|
|
|
return true; |
192
|
|
|
} |
193
|
|
|
} |
194
|
|
|
// We need to disconnect regardless of whether the login succeeded |
195
|
|
|
$this->disconnect(); |
196
|
|
|
return false; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Connect to a POP3 server. |
201
|
|
|
* @access public |
202
|
|
|
* @param string $host |
203
|
|
|
* @param integer|boolean $port |
204
|
|
|
* @param integer $tval |
205
|
|
|
* @return boolean |
206
|
|
|
*/ |
207
|
|
|
public function connect($host, $port = false, $tval = 30) |
208
|
|
|
{ |
209
|
|
|
// Are we already connected? |
210
|
|
|
if ($this->connected) { |
211
|
|
|
return true; |
212
|
|
|
} |
213
|
|
|
|
214
|
|
|
//On Windows this will raise a PHP Warning error if the hostname doesn't exist. |
215
|
|
|
//Rather than suppress it with @fsockopen, capture it cleanly instead |
216
|
|
|
set_error_handler(array($this, 'catchWarning')); |
217
|
|
|
|
218
|
|
|
if (false === $port) { |
219
|
|
|
$port = $this->POP3_PORT; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
// connect to the POP3 server |
223
|
|
|
$this->pop_conn = fsockopen( |
|
|
|
|
224
|
|
|
$host, // POP3 Host |
225
|
|
|
$port, // Port # |
|
|
|
|
226
|
|
|
$errno, // Error Number |
227
|
|
|
$errstr, // Error Message |
228
|
|
|
$tval |
229
|
|
|
); // Timeout (seconds) |
230
|
|
|
// Restore the error handler |
231
|
|
|
restore_error_handler(); |
232
|
|
|
|
233
|
|
|
// Did we connect? |
234
|
|
|
if (false === $this->pop_conn) { |
235
|
|
|
// It would appear not... |
236
|
|
|
$this->setError(array( |
237
|
|
|
'error' => "Failed to connect to server $host on port $port", |
238
|
|
|
'errno' => $errno, |
239
|
|
|
'errstr' => $errstr |
240
|
|
|
)); |
241
|
|
|
return false; |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
// Increase the stream time-out |
245
|
|
|
stream_set_timeout($this->pop_conn, $tval, 0); |
246
|
|
|
|
247
|
|
|
// Get the POP3 server response |
248
|
|
|
$pop3_response = $this->getResponse(); |
249
|
|
|
// Check for the +OK |
250
|
|
|
if ($this->checkResponse($pop3_response)) { |
251
|
|
|
// The connection is established and the POP3 server is talking |
252
|
|
|
$this->connected = true; |
253
|
|
|
return true; |
254
|
|
|
} |
255
|
|
|
return false; |
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
/** |
259
|
|
|
* Log in to the POP3 server. |
260
|
|
|
* Does not support APOP (RFC 2828, 4949). |
261
|
|
|
* @access public |
262
|
|
|
* @param string $username |
263
|
|
|
* @param string $password |
264
|
|
|
* @return boolean |
265
|
|
|
*/ |
266
|
|
|
public function login($username = '', $password = '') |
267
|
|
|
{ |
268
|
|
|
if (!$this->connected) { |
269
|
|
|
$this->setError('Not connected to POP3 server'); |
270
|
|
|
} |
271
|
|
|
if (empty($username)) { |
272
|
|
|
$username = $this->username; |
273
|
|
|
} |
274
|
|
|
if (empty($password)) { |
275
|
|
|
$password = $this->password; |
276
|
|
|
} |
277
|
|
|
|
278
|
|
|
// Send the Username |
279
|
|
|
$this->sendString("USER $username" . self::CRLF); |
280
|
|
|
$pop3_response = $this->getResponse(); |
281
|
|
|
if ($this->checkResponse($pop3_response)) { |
282
|
|
|
// Send the Password |
283
|
|
|
$this->sendString("PASS $password" . self::CRLF); |
284
|
|
|
$pop3_response = $this->getResponse(); |
285
|
|
|
if ($this->checkResponse($pop3_response)) { |
286
|
|
|
return true; |
287
|
|
|
} |
288
|
|
|
} |
289
|
|
|
return false; |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
/** |
293
|
|
|
* Disconnect from the POP3 server. |
294
|
|
|
* @access public |
295
|
|
|
*/ |
296
|
|
|
public function disconnect() |
297
|
|
|
{ |
298
|
|
|
$this->sendString('QUIT'); |
299
|
|
|
//The QUIT command may cause the daemon to exit, which will kill our connection |
300
|
|
|
//So ignore errors here |
301
|
|
|
try { |
302
|
|
|
@fclose($this->pop_conn); |
|
|
|
|
303
|
|
|
} catch (Exception $e) { |
304
|
|
|
//Do nothing |
305
|
|
|
}; |
306
|
|
|
} |
307
|
|
|
|
308
|
|
|
/** |
309
|
|
|
* Get a response from the POP3 server. |
310
|
|
|
* $size is the maximum number of bytes to retrieve |
311
|
|
|
* @param integer $size |
312
|
|
|
* @return string |
313
|
|
|
* @access protected |
314
|
|
|
*/ |
315
|
|
|
protected function getResponse($size = 128) |
316
|
|
|
{ |
317
|
|
|
$response = fgets($this->pop_conn, $size); |
318
|
|
|
if ($this->do_debug >= 1) { |
319
|
|
|
echo "Server -> Client: $response"; |
320
|
|
|
} |
321
|
|
|
return $response; |
322
|
|
|
} |
323
|
|
|
|
324
|
|
|
/** |
325
|
|
|
* Send raw data to the POP3 server. |
326
|
|
|
* @param string $string |
327
|
|
|
* @return integer |
328
|
|
|
* @access protected |
329
|
|
|
*/ |
330
|
|
|
protected function sendString($string) |
331
|
|
|
{ |
332
|
|
|
if ($this->pop_conn) { |
333
|
|
|
if ($this->do_debug >= 2) { //Show client messages when debug >= 2 |
334
|
|
|
echo "Client -> Server: $string"; |
335
|
|
|
} |
336
|
|
|
return fwrite($this->pop_conn, $string, strlen($string)); |
337
|
|
|
} |
338
|
|
|
return 0; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Checks the POP3 server response. |
343
|
|
|
* Looks for for +OK or -ERR. |
344
|
|
|
* @param string $string |
345
|
|
|
* @return boolean |
346
|
|
|
* @access protected |
347
|
|
|
*/ |
348
|
|
|
protected function checkResponse($string) |
349
|
|
|
{ |
350
|
|
|
if (substr($string, 0, 3) !== '+OK') { |
351
|
|
|
$this->setError(array( |
352
|
|
|
'error' => "Server reported an error: $string", |
353
|
|
|
'errno' => 0, |
354
|
|
|
'errstr' => '' |
355
|
|
|
)); |
356
|
|
|
return false; |
357
|
|
|
} else { |
358
|
|
|
return true; |
359
|
|
|
} |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
/** |
363
|
|
|
* Add an error to the internal error store. |
364
|
|
|
* Also display debug output if it's enabled. |
365
|
|
|
* @param $error |
366
|
|
|
* @access protected |
367
|
|
|
*/ |
368
|
|
|
protected function setError($error) |
369
|
|
|
{ |
370
|
|
|
$this->errors[] = $error; |
371
|
|
|
if ($this->do_debug >= 1) { |
372
|
|
|
echo '<pre>'; |
373
|
|
|
foreach ($this->errors as $error) { |
|
|
|
|
374
|
|
|
print_r($error); |
375
|
|
|
} |
376
|
|
|
echo '</pre>'; |
377
|
|
|
} |
378
|
|
|
} |
379
|
|
|
|
380
|
|
|
/** |
381
|
|
|
* Get an array of error messages, if any. |
382
|
|
|
* @return array |
383
|
|
|
*/ |
384
|
|
|
public function getErrors() |
385
|
|
|
{ |
386
|
|
|
return $this->errors; |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
/** |
390
|
|
|
* POP3 connection error handler. |
391
|
|
|
* @param integer $errno |
392
|
|
|
* @param string $errstr |
393
|
|
|
* @param string $errfile |
394
|
|
|
* @param integer $errline |
395
|
|
|
* @access protected |
396
|
|
|
*/ |
397
|
|
|
protected function catchWarning($errno, $errstr, $errfile, $errline) |
398
|
|
|
{ |
399
|
|
|
$this->setError(array( |
400
|
|
|
'error' => "Connecting to the POP3 server raised a PHP warning: ", |
401
|
|
|
'errno' => $errno, |
402
|
|
|
'errstr' => $errstr, |
403
|
|
|
'errfile' => $errfile, |
404
|
|
|
'errline' => $errline |
405
|
|
|
)); |
406
|
|
|
} |
407
|
|
|
} |
408
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.