GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Issues (3647)

symphony/lib/toolkit/class.smtp.php (32 issues)

1
<?php
2
/**
3
 * @package toolkit
4
 */
5
6
/**
7
 * Exceptions to be thrown by the SMTP Client class
8
 */
9
class SMTPException extends Exception
10
{
11
}
12
13
/**
14
 * A SMTP client class, for sending text/plain emails.
15
 * This class only supports the very basic SMTP functions.
16
 * Inspired by the SMTP class in the Zend library
17
 *
18
 * @author Huib Keemink <[email protected]>
19
 * @version 0.1 - 20 okt 2010
20
 */
21
class SMTP
22
{
23
    const TIMEOUT = 30;
24
25
    protected $_host;
26
    protected $_port;
27
    protected $_user = null;
28
    protected $_pass = null;
29
    protected $_transport = 'tcp';
30
    protected $_secure = false;
31
32
    protected $_header_fields = array();
33
34
    protected $_from = null;
35
36
    protected $_helo_host = null;
37
    protected $_connection = false;
38
39
    protected $_helo = false;
40
    protected $_mail = false;
41
    protected $_data = false;
42
    protected $_rcpt = false;
43
    protected $_auth = false;
44
45
    /**
46
     * Constructor.
47
     *
48
     * @param string $host
49
     *  Host to connect to. Defaults to localhost (127.0.0.1)
50
     * @param integer $port
51
     *  When ssl is used, defaults to 465
52
     *  When no ssl is used, and ini_get returns no value, defaults to 25.
53
     * @param array $options
54
     *  Currently supports 3 values:
55
     *    $options['secure'] can be ssl, tls or null.
56
     *    $options['username'] the username used to login to the server. Leave empty for no authentication.
57
     *    $options['password'] the password used to login to the server. Leave empty for no authentication.
58
     *    $options['helo_hostname'] the hostname address used in the EHLO/HELO commands. Ideally an FQDN.
59
     *    $options['local_ip'] the ip address used in the EHLO/HELO commands if no helo_hostname is given.
60
     * @throws SMTPException
61
     */
62
    public function __construct($host = '127.0.0.1', $port = null, $options = array())
0 ignored issues
show
Incorrect spacing between argument "$host" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$host"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$port" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$port"; expected 0 but found 1
Loading history...
Incorrect spacing between argument "$options" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$options"; expected 0 but found 1
Loading history...
63
    {
64
        if ($options['secure'] !== null) {
65
            switch (strtolower($options['secure'])) {
66
                case 'tls':
67
                    $this->_secure = 'tls';
68
                    break;
69
                case 'ssl':
70
                    $this->_transport = 'ssl';
71
                    $this->_secure = 'ssl';
72
                    if ($port === null) {
73
                        $port = 465;
74
                    }
75
                    break;
76
                case 'no':
77
                    break;
78
                default:
79
                    throw new SMTPException(__('Unsupported SSL type'));
80
            }
81
        }
82
83
        if (!empty($options['helo_hostname'])) {
84
            $this->_helo_host = $options['helo_hostname'];
85
        } elseif (!empty($options['local_ip'])) {
86
            $this->_helo_host = '[' . $options['local_ip'] . ']';
87
        } else {
88
            $this->_helo_host = '[' . gethostbyname(php_uname('n')) . ']';
89
        }
90
91
        if ($port === null) {
92
            $port = 25;
93
        }
94
95
        if (($options['username'] !== null) && ($options['password'] !== null)) {
96
            $this->_user = $options['username'];
97
            $this->_pass = $options['password'];
98
        }
99
100
        $this->_host = $host;
101
        $this->_port = $port;
102
    }
103
104
    /**
105
     * Checks to see if `$this->_connection` is a valid resource. Throws an
106
     * exception if there is no connection, otherwise returns true.
107
     *
108
     * @throws SMTPException
109
     * @return boolean
110
     */
111
    public function checkConnection()
112
    {
113
        if (!is_resource($this->_connection)) {
0 ignored issues
show
The condition is_resource($this->_connection) is always false.
Loading history...
114
            throw new SMTPException(__('No connection has been established to %s', array($this->_host)));
115
        }
116
117
        return true;
118
    }
119
120
    /**
121
     * The actual email sending.
122
     * The connection to the server (connecting, EHLO, AUTH, etc) is done here,
123
     * right before the actual email is sent. This is to make sure the connection does not time out.
124
     *
125
     * @param string $from
126
     *  The from string. Should have the following format: [email protected]
127
     * @param string $to
128
     *  The email address to send the email to.
129
     * @param string $subject
130
     *  The subject to send the email to.
131
     * @param string $message
132
     * @throws SMTPException
133
     * @throws Exception
134
     * @return boolean
135
     */
136
    public function sendMail($from, $to, $message)
137
    {
138
        $this->_connect($this->_host, $this->_port);
139
        $this->mail($from);
140
141
        if (!is_array($to)) {
0 ignored issues
show
The condition is_array($to) is always false.
Loading history...
142
            $to = array($to);
143
        }
144
145
        foreach ($to as $recipient) {
146
            $this->rcpt($recipient);
147
        }
0 ignored issues
show
No blank line found after control structure
Loading history...
148
        $this->data($message);
149
        $this->rset();
150
    }
151
152
    /**
153
     * Sets a header to be sent in the email.
154
     *
155
     * @throws SMTPException
156
     * @param string $header
157
     * @param string $value
158
     * @return void
159
     */
160
    public function setHeader($header, $value)
161
    {
162
        if (is_array($value)) {
0 ignored issues
show
The condition is_array($value) is always false.
Loading history...
163
            throw new SMTPException(__('Header fields can only contain strings'));
164
        }
165
166
        $this->_header_fields[$header] = $value;
167
    }
168
169
170
    /**
171
     * Initiates the ehlo/helo requests.
172
     *
173
     * @throws SMTPException
174
     * @throws Exception
175
     * @return void
176
     */
177
    public function helo()
178
    {
179
        if ($this->_mail !== false) {
180
            throw new SMTPException(__('Can not call HELO on existing session'));
181
        }
182
183
        //wait for the server to be ready
184
        $this->_expect(220, 300);
185
186
        //send ehlo or ehlo request.
187
        try {
188
            $this->_ehlo();
189
        } catch (SMTPException $e) {
190
            $this->_helo();
191
        } catch (Exception $e) {
192
            throw $e;
193
        }
194
195
        $this->_helo = true;
196
    }
197
198
    /**
199
     * Calls the MAIL command on the server.
200
     *
201
     * @throws SMTPException
202
     * @param string $from
203
     *  The email address to send the email from.
204
     * @return void
205
     */
206
    public function mail($from)
207
    {
208
        if ($this->_helo == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
209
            throw new SMTPException(__('Must call EHLO (or HELO) before calling MAIL'));
210
        } elseif ($this->_mail !== false) {
211
            throw new SMTPException(__('Only one call to MAIL may be made at a time.'));
212
        }
213
214
        $this->_send('MAIL FROM:<' . $from . '>');
215
        $this->_expect(250, 300);
216
217
        $this->_from = $from;
218
        $this->_mail = true;
219
        $this->_rcpt = false;
220
        $this->_data = false;
221
    }
222
223
    /**
224
     * Calls the RCPT command on the server. May be called multiple times for more than one recipient.
225
     *
226
     * @throws SMTPException
227
     * @param string $to
228
     *  The address to send the email to.
229
     * @return void
230
     */
231
    public function rcpt($to)
232
    {
233
        if ($this->_mail == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
234
            throw new SMTPException(__('Must call MAIL before calling RCPT'));
235
        }
236
237
        $this->_send('RCPT TO:<' . $to . '>');
238
        $this->_expect(array(250, 251), 300);
239
240
        $this->_rcpt = true;
241
    }
242
243
    /**
244
     * Calls the data command on the server.
245
     * Also includes header fields in the command.
246
     *
247
     * @throws SMTPException
248
     * @param string $data
249
     * @return void
250
     */
251
    public function data($data)
252
    {
253
        if ($this->_rcpt == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
254
            throw new SMTPException(__('Must call RCPT before calling DATA'));
255
        }
256
257
        $this->_send('DATA');
258
        $this->_expect(354, 120);
259
260
        foreach ($this->_header_fields as $name => $body) {
261
            // Every header can contain an array. Will insert multiple header fields of that type with the contents of array.
262
            // Useful for multiple recipients, for instance.
263
            if (!is_array($body)) {
264
                $body = array($body);
265
            }
266
267
            foreach ($body as $val) {
268
                $this->_send($name . ': ' . $val);
269
            }
270
        }
0 ignored issues
show
No blank line found after control structure
Loading history...
271
        // Send an empty newline. Solves bugs with Apple Mail
272
        $this->_send('');
273
274
        // Because the message can contain \n as a newline, replace all \r\n with \n and explode on \n.
275
        // The send() function will use the proper line ending (\r\n).
276
        $data = str_replace("\r\n", "\n", $data);
277
        $data_arr = explode("\n", $data);
278
279
        foreach ($data_arr as $line) {
280
            // Escape line if first character is a period (dot). http://tools.ietf.org/html/rfc2821#section-4.5.2
281
            if (strpos($line, '.') === 0) {
282
                $line = '.' . $line;
283
            }
0 ignored issues
show
No blank line found after control structure
Loading history...
284
            $this->_send($line);
285
        }
286
287
        $this->_send('.');
288
        $this->_expect(250, 600);
289
        $this->_data = true;
290
    }
291
292
    /**
293
     * Resets the current session. This 'undoes' all rcpt, mail, etc calls.
294
     *
295
     * @throws SMTPException
296
     * @return void
297
     */
298
    public function rset()
299
    {
300
        $this->_send('RSET');
301
        // MS ESMTP doesn't follow RFC, see [ZF-1377]
302
        $this->_expect(array(250, 220));
303
304
        $this->_mail = false;
305
        $this->_rcpt = false;
306
        $this->_data = false;
307
    }
308
309
    /**
310
     * Disconnects to the server.
311
     *
312
     * @throws SMTPException
313
     * @return void
314
     */
315
    public function quit()
316
    {
317
        $this->_send('QUIT');
318
        $this->_expect(221, 300);
319
        $this->_connection = null;
320
    }
321
322
    /**
323
     * Authenticates to the server.
324
     * Currently supports the AUTH LOGIN command.
325
     * May be extended if more methods are needed.
326
     *
327
     * @throws SMTPException
328
     * @return void
329
     */
330
    protected function _auth()
331
    {
332
        if ($this->_helo == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
333
            throw new SMTPException(__('Must call EHLO (or HELO) before calling AUTH'));
334
        } elseif ($this->_auth !== false) {
335
            throw new SMTPException(__('Can not call AUTH again.'));
336
        }
337
338
        $this->_send('AUTH LOGIN');
339
        $this->_expect(334);
340
        $this->_send(base64_encode($this->_user));
341
        $this->_expect(334);
342
        $this->_send(base64_encode($this->_pass));
343
        $this->_expect(235);
344
        $this->_auth = true;
345
    }
346
347
    /**
348
     * Calls the EHLO function.
349
     * This is the HELO function for more modern servers.
350
     *
351
     * @throws SMTPException
352
     * @return void
353
     */
354
    protected function _ehlo()
355
    {
356
        $this->_send('EHLO ' . $this->_helo_host);
357
        $this->_expect(array(250, 220), 300);
358
    }
359
360
    /**
361
     * Initiates the connection by calling the HELO function.
362
     * This function should only be used if the server does not support the HELO function.
363
     *
364
     * @throws SMTPException
365
     * @return void
366
     */
367
    protected function _helo()
368
    {
369
        $this->_send('HELO ' . $this->_helo_host);
370
        $this->_expect(array(250, 220), 300);
371
    }
372
373
    /**
374
     * Encrypts the current session with TLS.
375
     *
376
     * @throws SMTPException
377
     * @return void
378
     */
379
    protected function _tls()
380
    {
381
        if ($this->_secure == 'tls') {
382
            $this->_send('STARTTLS');
383
            $this->_expect(220, 180);
384
            if (!stream_socket_enable_crypto($this->_connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
0 ignored issues
show
$this->_connection of type boolean is incompatible with the type resource expected by parameter $stream of stream_socket_enable_crypto(). ( Ignorable by Annotation )

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

384
            if (!stream_socket_enable_crypto(/** @scrutinizer ignore-type */ $this->_connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
Loading history...
385
                throw new SMTPException(__('Unable to connect via TLS'));
386
            }
0 ignored issues
show
No blank line found after control structure
Loading history...
387
            $this->_ehlo();
388
        }
389
    }
390
391
    /**
392
     * Send a request to the host, appends the request with a line break.
393
     *
394
     * @param string $request
395
     * @throws SMTPException
396
     * @return boolean|integer number of characters written.
397
     */
398
    protected function _send($request)
399
    {
400
        $this->checkConnection();
401
402
        $result = fwrite($this->_connection, $request . "\r\n");
0 ignored issues
show
$this->_connection of type boolean is incompatible with the type resource expected by parameter $handle of fwrite(). ( Ignorable by Annotation )

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

402
        $result = fwrite(/** @scrutinizer ignore-type */ $this->_connection, $request . "\r\n");
Loading history...
403
404
        if ($result === false) {
405
            throw new SMTPException(__('Could not send request: %s', array($request)));
406
        }
0 ignored issues
show
No blank line found after control structure
Loading history...
407
        return $result;
408
    }
409
410
    /**
411
     * Get a line from the stream.
412
     *
413
     * @param integer $timeout
414
     *  Per-request timeout value if applicable. Defaults to null which
415
     *  will not set a timeout.
416
     * @throws SMTPException
417
     * @return string
418
     */
419
    protected function _receive($timeout = null)
0 ignored issues
show
Incorrect spacing between argument "$timeout" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$timeout"; expected 0 but found 1
Loading history...
420
    {
421
        $this->checkConnection();
422
423
        if ($timeout !== null) {
424
            stream_set_timeout($this->_connection, $timeout);
0 ignored issues
show
$this->_connection of type boolean is incompatible with the type resource expected by parameter $stream of stream_set_timeout(). ( Ignorable by Annotation )

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

424
            stream_set_timeout(/** @scrutinizer ignore-type */ $this->_connection, $timeout);
Loading history...
425
        }
426
427
        $response = fgets($this->_connection, 1024);
0 ignored issues
show
$this->_connection of type boolean is incompatible with the type resource expected by parameter $handle of fgets(). ( Ignorable by Annotation )

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

427
        $response = fgets(/** @scrutinizer ignore-type */ $this->_connection, 1024);
Loading history...
428
        $info = stream_get_meta_data($this->_connection);
0 ignored issues
show
$this->_connection of type boolean is incompatible with the type resource expected by parameter $stream of stream_get_meta_data(). ( Ignorable by Annotation )

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

428
        $info = stream_get_meta_data(/** @scrutinizer ignore-type */ $this->_connection);
Loading history...
429
430
        if (!empty($info['timed_out'])) {
431
            throw new SMTPException(__('%s has timed out', array($this->_host)));
432
        } elseif ($response === false) {
433
            throw new SMTPException(__('Could not read from %s', array($this->_host)));
434
        }
435
436
        return $response;
437
    }
438
439
    /**
440
     * Parse server response for successful codes
441
     *
442
     * Read the response from the stream and check for expected return code.
443
     *
444
     * @throws SMTPException
445
     * @param  string|array $code
446
     *  One or more codes that indicate a successful response
447
     * @param integer $timeout
448
     *  Per-request timeout value if applicable. Defaults to null which
449
     *  will not set a timeout.
450
     * @return string
451
     *  Last line of response string
452
     */
453
    protected function _expect($code, $timeout = null)
0 ignored issues
show
Incorrect spacing between argument "$timeout" and equals sign; expected 0 but found 1
Loading history...
Incorrect spacing between default value and equals sign for argument "$timeout"; expected 0 but found 1
Loading history...
454
    {
455
        $this->_response = array();
0 ignored issues
show
Bug Best Practice introduced by
The property _response does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
456
        $cmd  = '';
0 ignored issues
show
The assignment to $cmd is dead and can be removed.
Loading history...
457
        $more = '';
0 ignored issues
show
The assignment to $more is dead and can be removed.
Loading history...
458
        $msg  = '';
0 ignored issues
show
The assignment to $msg is dead and can be removed.
Loading history...
459
        $errMsg = '';
460
461
        if (!is_array($code)) {
462
            $code = array($code);
463
        }
464
465
        // Borrowed from the Zend Email Library
466
        do {
467
            $result = $this->_receive($timeout);
468
            list($cmd, $more, $msg) = preg_split('/([\s-]+)/', $result, 2, PREG_SPLIT_DELIM_CAPTURE);
469
470
            if ($errMsg !== '') {
471
                $errMsg .= ' ' . $msg;
472
            } elseif ($cmd === null || !in_array($cmd, $code)) {
473
                $errMsg = $msg;
474
            }
475
        } while (strpos($more, '-') === 0); // The '-' message prefix indicates an information string instead of a response string.
476
477
        if ($errMsg !== '') {
478
            $this->rset();
479
            throw new SMTPException($errMsg);
480
        }
481
482
        return $msg;
483
    }
484
485
    /**
486
     * Connect to the host, and perform basic functions like helo and auth.
487
     *
488
     *
489
     * @param string $host
490
     * @param integer $port
491
     * @throws SMTPException
492
     * @throws Exception
493
     * @return void
494
     */
495
    protected function _connect($host, $port)
496
    {
497
        $errorNum = 0;
498
        $errorStr = '';
499
500
        $remoteAddr = $this->_transport . '://' . $host . ':' . $port;
501
502
        if (!is_resource($this->_connection)) {
0 ignored issues
show
The condition is_resource($this->_connection) is always false.
Loading history...
503
            $this->_connection = @stream_socket_client($remoteAddr, $errorNum, $errorStr, self::TIMEOUT);
504
505
            if ($this->_connection === false) {
506
                if ($errorNum == 0) {
507
                    throw new SMTPException(__('Unable to open socket. Unknown error'));
508
                } else {
509
                    throw new SMTPException(__('Unable to open socket. %s', array($errorStr)));
510
                }
511
            }
512
513
            if (@stream_set_timeout($this->_connection, self::TIMEOUT) === false) {
514
                throw new SMTPException(__('Unable to set timeout.'));
515
            }
516
517
            $this->helo();
518
519
            if ($this->_secure == 'tls') {
520
                $this->_tls();
521
            }
522
523
            if (($this->_user !== null) && ($this->_pass !== null)) {
524
                $this->_auth();
525
            }
526
        }
527
    }
528
}
529