Passed
Push — master ( bbacda...9d4008 )
by Marcus
43:43
created

src/POP3.php (3 issues)

Severity

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
 * PHPMailer POP-Before-SMTP Authentication Class.
4
 * PHP Version 5.5
5
 *
6
 * @package   PHPMailer
7
 * @see       https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
8
 * @author    Marcus Bointon (Synchro/coolbru) <[email protected]>
9
 * @author    Jim Jagielski (jimjag) <[email protected]>
10
 * @author    Andy Prevost (codeworxtech) <[email protected]>
11
 * @author    Brent R. Matzelle (original founder)
12
 * @copyright 2012 - 2016 Marcus Bointon
13
 * @copyright 2010 - 2012 Jim Jagielski
14
 * @copyright 2004 - 2009 Andy Prevost
15
 * @license   http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
16
 * @note      This program is distributed in the hope that it will be useful - WITHOUT
17
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
 * FITNESS FOR A PARTICULAR PURPOSE.
19
 */
20
21
namespace PHPMailer\PHPMailer;
22
23
/**
24
 * PHPMailer POP-Before-SMTP Authentication Class.
25
 * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.
26
 * 1) This class does not support APOP authentication.
27
 * 2) Opening and closing lots of POP3 connections can be quite slow. If you need
28
 *   to send a batch of emails then just perform the authentication once at the start,
29
 *   and then loop through your mail sending script. Providing this process doesn't
30
 *   take longer than the verification period lasts on your POP3 server, you should be fine.
31
 * 3) This is really ancient technology; you should only need to use it to talk to very old systems.
32
 * 4) This POP3 class is deliberately lightweight and incomplete, and implements just
33
 *   enough to do authentication.
34
 *   If you want a more complete class there are other POP3 classes for PHP available.
35
 *
36
 * @package PHPMailer
37
 * @author  Richard Davey (original author) <[email protected]>
38
 * @author  Marcus Bointon (Synchro/coolbru) <[email protected]>
39
 * @author  Jim Jagielski (jimjag) <[email protected]>
40
 * @author  Andy Prevost (codeworxtech) <[email protected]>
41
 */
42
class POP3
43
{
44
    /**
45
     * The POP3 PHPMailer Version number.
46
     *
47
     * @var string
48
     */
49
    const VERSION = '6.0.0';
50
51
    /**
52
     * Default POP3 port number.
53
     *
54
     * @var integer
55
     */
56
    const DEFAULT_PORT = 110;
57
58
    /**
59
     * Default timeout in seconds.
60
     *
61
     * @var integer
62
     */
63
    const DEFAULT_TIMEOUT = 30;
64
65
    /**
66
     * Debug display level.
67
     * Options: 0 = no, 1+ = yes
68
     *
69
     * @var integer
70
     */
71
    public $do_debug = 0;
72
73
    /**
74
     * POP3 mail server hostname.
75
     *
76
     * @var string
77
     */
78
    public $host;
79
80
    /**
81
     * POP3 port number.
82
     *
83
     * @var integer
84
     */
85
    public $port;
86
87
    /**
88
     * POP3 Timeout Value in seconds.
89
     *
90
     * @var integer
91
     */
92
    public $tval;
93
94
    /**
95
     * POP3 username
96
     *
97
     * @var string
98
     */
99
    public $username;
100
101
    /**
102
     * POP3 password.
103
     *
104
     * @var string
105
     */
106
    public $password;
107
108
    /**
109
     * Resource handle for the POP3 connection socket.
110
     *
111
     * @var resource
112
     */
113
    protected $pop_conn;
114
115
    /**
116
     * Are we connected?
117
     *
118
     * @var boolean
119
     */
120
    protected $connected = false;
121
122
    /**
123
     * Error container.
124
     *
125
     * @var array
126
     */
127
    protected $errors = [];
128
129
    /**
130
     * Line break constant
131
     */
132
    const LE = "\r\n";
133
134
    /**
135
     * Simple static wrapper for all-in-one POP before SMTP
136
     *
137
     * @param string $host
138
     * @param integer|boolean $port The port number to connect to
139
     * @param integer|boolean $timeout The timeout value
140
     * @param string $username
141
     * @param string $password
142
     * @param integer $debug_level
143
     *
144
     * @return boolean
145
     */
146
    public static function popBeforeSmtp(
147
        $host,
148
        $port = false,
149
        $timeout = false,
150
        $username = '',
151
        $password = '',
152
        $debug_level = 0
153
    ) {
154
        $pop = new POP3;
155
        return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level);
156
    }
157
158
    /**
159
     * Authenticate with a POP3 server.
160
     * A connect, login, disconnect sequence
161
     * appropriate for POP-before SMTP authorisation.
162
     *
163
     * @param string $host The hostname to connect to
164
     * @param integer|boolean $port The port number to connect to
165
     * @param integer|boolean $timeout The timeout value
166
     * @param string $username
167
     * @param string $password
168
     * @param integer $debug_level
169
     *
170
     * @return boolean
171
     */
172
    public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0)
173
    {
174
        $this->host = $host;
175
        // If no port value provided, use default
176
        if (false === $port) {
177
            $this->port = static::DEFAULT_PORT;
178
        } else {
179
            $this->port = (integer)$port;
180
        }
181
        // If no timeout value provided, use default
182
        if (false === $timeout) {
183
            $this->tval = static::DEFAULT_TIMEOUT;
184
        } else {
185
            $this->tval = (integer)$timeout;
186
        }
187
        $this->do_debug = $debug_level;
188
        $this->username = $username;
189
        $this->password = $password;
190
        //  Reset the error log
191
        $this->errors = [];
192
        //  connect
193
        $result = $this->connect($this->host, $this->port, $this->tval);
194
        if ($result) {
195
            $login_result = $this->login($this->username, $this->password);
196
            if ($login_result) {
197
                $this->disconnect();
198
                return true;
199
            }
200
        }
201
        // We need to disconnect regardless of whether the login succeeded
202
        $this->disconnect();
203
        return false;
204
    }
205
206
    /**
207
     * Connect to a POP3 server.
208
     *
209
     * @param string $host
210
     * @param integer|boolean $port
211
     * @param integer $tval
212
     *
213
     * @return boolean
214
     */
215
    public function connect($host, $port = false, $tval = 30)
216
    {
217
        //  Are we already connected?
218
        if ($this->connected) {
219
            return true;
220
        }
221
222
        //On Windows this will raise a PHP Warning error if the hostname doesn't exist.
223
        //Rather than suppress it with @fsockopen, capture it cleanly instead
224
        set_error_handler([$this, 'catchWarning']);
225
226
        if (false === $port) {
227
            $port = static::DEFAULT_PORT;
228
        }
229
230
        //  connect to the POP3 server
231
        $this->pop_conn = fsockopen(
232
            $host, //  POP3 Host
233
            $port, //  Port #
234
            $errno, //  Error Number
235
            $errstr, //  Error Message
236
            $tval
237
        ); //  Timeout (seconds)
238
        //  Restore the error handler
239
        restore_error_handler();
240
241
        //  Did we connect?
242
        if (false === $this->pop_conn) {
243
            //  It would appear not...
244
            $this->setError(
245
                [
0 ignored issues
show
array('error' => "Failed...o, 'errstr' => $errstr) is of type array<string,integer|nul...errstr":"string|null"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
246
                'error' => "Failed to connect to server $host on port $port",
247
                'errno' => $errno,
248
                'errstr' => $errstr
249
                ]
250
            );
251
            return false;
252
        }
253
254
        //  Increase the stream time-out
255
        stream_set_timeout($this->pop_conn, $tval, 0);
256
257
        //  Get the POP3 server response
258
        $pop3_response = $this->getResponse();
259
        //  Check for the +OK
260
        if ($this->checkResponse($pop3_response)) {
261
            //  The connection is established and the POP3 server is talking
262
            $this->connected = true;
263
            return true;
264
        }
265
        return false;
266
    }
267
268
    /**
269
     * Log in to the POP3 server.
270
     * Does not support APOP (RFC 2828, 4949).
271
     *
272
     * @param string $username
273
     * @param string $password
274
     *
275
     * @return boolean
276
     */
277
    public function login($username = '', $password = '')
278
    {
279
        if (!$this->connected) {
280
            $this->setError('Not connected to POP3 server');
281
        }
282
        if (empty($username)) {
283
            $username = $this->username;
284
        }
285
        if (empty($password)) {
286
            $password = $this->password;
287
        }
288
289
        // Send the Username
290
        $this->sendString("USER $username" . static::LE);
291
        $pop3_response = $this->getResponse();
292
        if ($this->checkResponse($pop3_response)) {
293
            // Send the Password
294
            $this->sendString("PASS $password" . static::LE);
295
            $pop3_response = $this->getResponse();
296
            if ($this->checkResponse($pop3_response)) {
297
                return true;
298
            }
299
        }
300
        return false;
301
    }
302
303
    /**
304
     * Disconnect from the POP3 server.
305
     */
306
    public function disconnect()
307
    {
308
        $this->sendString('QUIT');
309
        //The QUIT command may cause the daemon to exit, which will kill our connection
310
        //So ignore errors here
311
        try {
312
            @fclose($this->pop_conn);
313
        } catch (Exception $e) {
314
            //Do nothing
315
        };
316
    }
317
318
    /**
319
     * Get a response from the POP3 server.
320
     * $size is the maximum number of bytes to retrieve
321
     *
322
     * @param integer $size
323
     *
324
     * @return string
325
     */
326
    protected function getResponse($size = 128)
327
    {
328
        $response = fgets($this->pop_conn, $size);
329
        if ($this->do_debug >= 1) {
330
            echo 'Server -> Client: ', $response;
331
        }
332
        return $response;
333
    }
334
335
    /**
336
     * Send raw data to the POP3 server.
337
     *
338
     * @param string $string
339
     *
340
     * @return integer
341
     */
342
    protected function sendString($string)
343
    {
344
        if ($this->pop_conn) {
345
            if ($this->do_debug >= 2) { //Show client messages when debug >= 2
346
                echo 'Client -> Server: ', $string;
347
            }
348
            return fwrite($this->pop_conn, $string, strlen($string));
349
        }
350
        return 0;
351
    }
352
353
    /**
354
     * Checks the POP3 server response.
355
     * Looks for for +OK or -ERR.
356
     *
357
     * @param string $string
358
     *
359
     * @return boolean
360
     */
361
    protected function checkResponse($string)
362
    {
363
        if (substr($string, 0, 3) !== '+OK') {
364
            $this->setError(
365
                [
0 ignored issues
show
array('error' => "Server...' => 0, 'errstr' => '') is of type array<string,integer|str...er","errstr":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
366
                'error' => "Server reported an error: $string",
367
                'errno' => 0,
368
                'errstr' => ''
369
                ]
370
            );
371
            return false;
372
        } else {
373
            return true;
374
        }
375
    }
376
377
    /**
378
     * Add an error to the internal error store.
379
     * Also display debug output if it's enabled.
380
     *
381
     * @param string $error
382
     */
383
    protected function setError($error)
384
    {
385
        $this->errors[] = $error;
386
        if ($this->do_debug >= 1) {
387
            echo '<pre>';
388
            foreach ($this->errors as $error) {
389
                print_r($error);
390
            }
391
            echo '</pre>';
392
        }
393
    }
394
395
    /**
396
     * Get an array of error messages, if any.
397
     *
398
     * @return array
399
     */
400
    public function getErrors()
401
    {
402
        return $this->errors;
403
    }
404
405
    /**
406
     * POP3 connection error handler.
407
     *
408
     * @param integer $errno
409
     * @param string $errstr
410
     * @param string $errfile
411
     * @param integer $errline
412
     */
413
    protected function catchWarning($errno, $errstr, $errfile, $errline)
414
    {
415
        $this->setError(
416
            [
0 ignored issues
show
array('error' => 'Connec... 'errline' => $errline) is of type array<string,string|inte...","errline":"integer"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
417
            'error' => 'Connecting to the POP3 server raised a PHP warning: ',
418
            'errno' => $errno,
419
            'errstr' => $errstr,
420
            'errfile' => $errfile,
421
            'errline' => $errline
422
            ]
423
        );
424
    }
425
}
426