POP3.php 12 KB

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