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