<?php1/**2* PHPMailer POP-Before-SMTP Authentication Class.3* PHP Version 5.5.4*5* @see https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project6*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 - 2020 Marcus Bointon12* @copyright 2010 - 2012 Jim Jagielski13* @copyright 2004 - 2009 Andy Prevost14* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License15* @note This program is distributed in the hope that it will be useful - WITHOUT16* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or17* FITNESS FOR A PARTICULAR PURPOSE.18*/1920namespace PHPMailer\PHPMailer;2122/**23* PHPMailer POP-Before-SMTP Authentication Class.24* Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.25* 1) This class does not support APOP authentication.26* 2) Opening and closing lots of POP3 connections can be quite slow. If you need27* to send a batch of emails then just perform the authentication once at the start,28* and then loop through your mail sending script. Providing this process doesn't29* take longer than the verification period lasts on your POP3 server, you should be fine.30* 3) This is really ancient technology; you should only need to use it to talk to very old systems.31* 4) This POP3 class is deliberately lightweight and incomplete, implementing just32* enough to do authentication.33* If you want a more complete class there are other POP3 classes for PHP available.34*35* @author Richard Davey (original author) <[email protected]>36* @author Marcus Bointon (Synchro/coolbru) <[email protected]>37* @author Jim Jagielski (jimjag) <[email protected]>38* @author Andy Prevost (codeworxtech) <[email protected]>39*/40class POP341{42/**43* The POP3 PHPMailer Version number.44*45* @var string46*/47const VERSION = '6.1.7';4849/**50* Default POP3 port number.51*52* @var int53*/54const DEFAULT_PORT = 110;5556/**57* Default timeout in seconds.58*59* @var int60*/61const DEFAULT_TIMEOUT = 30;6263/**64* Debug display level.65* Options: 0 = no, 1+ = yes.66*67* @var int68*/69public $do_debug = 0;7071/**72* POP3 mail server hostname.73*74* @var string75*/76public $host;7778/**79* POP3 port number.80*81* @var int82*/83public $port;8485/**86* POP3 Timeout Value in seconds.87*88* @var int89*/90public $tval;9192/**93* POP3 username.94*95* @var string96*/97public $username;9899/**100* POP3 password.101*102* @var string103*/104public $password;105106/**107* Resource handle for the POP3 connection socket.108*109* @var resource110*/111protected $pop_conn;112113/**114* Are we connected?115*116* @var bool117*/118protected $connected = false;119120/**121* Error container.122*123* @var array124*/125protected $errors = [];126127/**128* Line break constant.129*/130const LE = "\r\n";131132/**133* Simple static wrapper for all-in-one POP before SMTP.134*135* @param string $host The hostname to connect to136* @param int|bool $port The port number to connect to137* @param int|bool $timeout The timeout value138* @param string $username139* @param string $password140* @param int $debug_level141*142* @return bool143*/144public static function popBeforeSmtp(145$host,146$port = false,147$timeout = false,148$username = '',149$password = '',150$debug_level = 0151) {152$pop = new self();153154return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level);155}156157/**158* Authenticate with a POP3 server.159* A connect, login, disconnect sequence160* appropriate for POP-before SMTP authorisation.161*162* @param string $host The hostname to connect to163* @param int|bool $port The port number to connect to164* @param int|bool $timeout The timeout value165* @param string $username166* @param string $password167* @param int $debug_level168*169* @return bool170*/171public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0)172{173$this->host = $host;174// If no port value provided, use default175if (false === $port) {176$this->port = static::DEFAULT_PORT;177} else {178$this->port = (int) $port;179}180// If no timeout value provided, use default181if (false === $timeout) {182$this->tval = static::DEFAULT_TIMEOUT;183} else {184$this->tval = (int) $timeout;185}186$this->do_debug = $debug_level;187$this->username = $username;188$this->password = $password;189// Reset the error log190$this->errors = [];191// connect192$result = $this->connect($this->host, $this->port, $this->tval);193if ($result) {194$login_result = $this->login($this->username, $this->password);195if ($login_result) {196$this->disconnect();197198return true;199}200}201// We need to disconnect regardless of whether the login succeeded202$this->disconnect();203204return false;205}206207/**208* Connect to a POP3 server.209*210* @param string $host211* @param int|bool $port212* @param int $tval213*214* @return bool215*/216public function connect($host, $port = false, $tval = 30)217{218// Are we already connected?219if ($this->connected) {220return true;221}222223//On Windows this will raise a PHP Warning error if the hostname doesn't exist.224//Rather than suppress it with @fsockopen, capture it cleanly instead225set_error_handler([$this, 'catchWarning']);226227if (false === $port) {228$port = static::DEFAULT_PORT;229}230231// connect to the POP3 server232$errno = 0;233$errstr = '';234$this->pop_conn = fsockopen(235$host, // POP3 Host236$port, // Port #237$errno, // Error Number238$errstr, // Error Message239$tval240); // Timeout (seconds)241// Restore the error handler242restore_error_handler();243244// Did we connect?245if (false === $this->pop_conn) {246// It would appear not...247$this->setError(248"Failed to connect to server $host on port $port. errno: $errno; errstr: $errstr"249);250251return false;252}253254// Increase the stream time-out255stream_set_timeout($this->pop_conn, $tval, 0);256257// Get the POP3 server response258$pop3_response = $this->getResponse();259// Check for the +OK260if ($this->checkResponse($pop3_response)) {261// The connection is established and the POP3 server is talking262$this->connected = true;263264return true;265}266267return false;268}269270/**271* Log in to the POP3 server.272* Does not support APOP (RFC 2828, 4949).273*274* @param string $username275* @param string $password276*277* @return bool278*/279public function login($username = '', $password = '')280{281if (!$this->connected) {282$this->setError('Not connected to POP3 server');283}284if (empty($username)) {285$username = $this->username;286}287if (empty($password)) {288$password = $this->password;289}290291// Send the Username292$this->sendString("USER $username" . static::LE);293$pop3_response = $this->getResponse();294if ($this->checkResponse($pop3_response)) {295// Send the Password296$this->sendString("PASS $password" . static::LE);297$pop3_response = $this->getResponse();298if ($this->checkResponse($pop3_response)) {299return true;300}301}302303return false;304}305306/**307* Disconnect from the POP3 server.308*/309public function disconnect()310{311$this->sendString('QUIT');312//The QUIT command may cause the daemon to exit, which will kill our connection313//So ignore errors here314try {315@fclose($this->pop_conn);316} catch (Exception $e) {317//Do nothing318}319}320321/**322* Get a response from the POP3 server.323*324* @param int $size The maximum number of bytes to retrieve325*326* @return string327*/328protected function getResponse($size = 128)329{330$response = fgets($this->pop_conn, $size);331if ($this->do_debug >= 1) {332echo 'Server -> Client: ', $response;333}334335return $response;336}337338/**339* Send raw data to the POP3 server.340*341* @param string $string342*343* @return int344*/345protected function sendString($string)346{347if ($this->pop_conn) {348if ($this->do_debug >= 2) { //Show client messages when debug >= 2349echo 'Client -> Server: ', $string;350}351352return fwrite($this->pop_conn, $string, strlen($string));353}354355return 0;356}357358/**359* Checks the POP3 server response.360* Looks for for +OK or -ERR.361*362* @param string $string363*364* @return bool365*/366protected function checkResponse($string)367{368if (strpos($string, '+OK') !== 0) {369$this->setError("Server reported an error: $string");370371return false;372}373374return true;375}376377/**378* Add an error to the internal error store.379* Also display debug output if it's enabled.380*381* @param string $error382*/383protected function setError($error)384{385$this->errors[] = $error;386if ($this->do_debug >= 1) {387echo '<pre>';388foreach ($this->errors as $e) {389print_r($e);390}391echo '</pre>';392}393}394395/**396* Get an array of error messages, if any.397*398* @return array399*/400public function getErrors()401{402return $this->errors;403}404405/**406* POP3 connection error handler.407*408* @param int $errno409* @param string $errstr410* @param string $errfile411* @param int $errline412*/413protected function catchWarning($errno, $errstr, $errfile, $errline)414{415$this->setError(416'Connecting to the POP3 server raised a PHP warning:' .417"errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline"418);419}420}421422423