*/}}

POP3.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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.1';
  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([$this, 'catchWarning']);
  229. if (false === $port) {
  230. $port = static::DEFAULT_PORT;
  231. }
  232. //Connect to the POP3 server
  233. $errno = 0;
  234. $errstr = '';
  235. $this->pop_conn = fsockopen(
  236. $host, //POP3 Host
  237. $port, //Port #
  238. $errno, //Error Number
  239. $errstr, //Error Message
  240. $tval
  241. ); //Timeout (seconds)
  242. //Restore the error handler
  243. restore_error_handler();
  244. //Did we connect?
  245. if (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. );
  250. return false;
  251. }
  252. //Increase the stream time-out
  253. stream_set_timeout($this->pop_conn, $tval, 0);
  254. //Get the POP3 server response
  255. $pop3_response = $this->getResponse();
  256. //Check for the +OK
  257. if ($this->checkResponse($pop3_response)) {
  258. //The connection is established and the POP3 server is talking
  259. $this->connected = true;
  260. return true;
  261. }
  262. return false;
  263. }
  264. /**
  265. * Log in to the POP3 server.
  266. * Does not support APOP (RFC 2828, 4949).
  267. *
  268. * @param string $username
  269. * @param string $password
  270. *
  271. * @return bool
  272. */
  273. public function login($username = '', $password = '')
  274. {
  275. if (!$this->connected) {
  276. $this->setError('Not connected to POP3 server');
  277. return false;
  278. }
  279. if (empty($username)) {
  280. $username = $this->username;
  281. }
  282. if (empty($password)) {
  283. $password = $this->password;
  284. }
  285. //Send the Username
  286. $this->sendString("USER $username" . static::LE);
  287. $pop3_response = $this->getResponse();
  288. if ($this->checkResponse($pop3_response)) {
  289. //Send the Password
  290. $this->sendString("PASS $password" . static::LE);
  291. $pop3_response = $this->getResponse();
  292. if ($this->checkResponse($pop3_response)) {
  293. return true;
  294. }
  295. }
  296. return false;
  297. }
  298. /**
  299. * Disconnect from the POP3 server.
  300. */
  301. public function disconnect()
  302. {
  303. // If could not connect at all, no need to disconnect
  304. if ($this->pop_conn === false) {
  305. return;
  306. }
  307. $this->sendString('QUIT' . static::LE);
  308. // RFC 1939 shows POP3 server sending a +OK response to the QUIT command.
  309. // Try to get it. Ignore any failures here.
  310. try {
  311. $this->getResponse();
  312. } catch (Exception $e) {
  313. //Do nothing
  314. }
  315. //The QUIT command may cause the daemon to exit, which will kill our connection
  316. //So ignore errors here
  317. try {
  318. @fclose($this->pop_conn);
  319. } catch (Exception $e) {
  320. //Do nothing
  321. }
  322. // Clean up attributes.
  323. $this->connected = false;
  324. $this->pop_conn = false;
  325. }
  326. /**
  327. * Get a response from the POP3 server.
  328. *
  329. * @param int $size The maximum number of bytes to retrieve
  330. *
  331. * @return string
  332. */
  333. protected function getResponse($size = 128)
  334. {
  335. $response = fgets($this->pop_conn, $size);
  336. if ($this->do_debug >= self::DEBUG_SERVER) {
  337. echo 'Server -> Client: ', $response;
  338. }
  339. return $response;
  340. }
  341. /**
  342. * Send raw data to the POP3 server.
  343. *
  344. * @param string $string
  345. *
  346. * @return int
  347. */
  348. protected function sendString($string)
  349. {
  350. if ($this->pop_conn) {
  351. if ($this->do_debug >= self::DEBUG_CLIENT) { //Show client messages when debug >= 2
  352. echo 'Client -> Server: ', $string;
  353. }
  354. return fwrite($this->pop_conn, $string, strlen($string));
  355. }
  356. return 0;
  357. }
  358. /**
  359. * Checks the POP3 server response.
  360. * Looks for for +OK or -ERR.
  361. *
  362. * @param string $string
  363. *
  364. * @return bool
  365. */
  366. protected function checkResponse($string)
  367. {
  368. if (strpos($string, '+OK') !== 0) {
  369. $this->setError("Server reported an error: $string");
  370. return false;
  371. }
  372. return true;
  373. }
  374. /**
  375. * Add an error to the internal error store.
  376. * Also display debug output if it's enabled.
  377. *
  378. * @param string $error
  379. */
  380. protected function setError($error)
  381. {
  382. $this->errors[] = $error;
  383. if ($this->do_debug >= self::DEBUG_SERVER) {
  384. echo '<pre>';
  385. foreach ($this->errors as $e) {
  386. print_r($e);
  387. }
  388. echo '</pre>';
  389. }
  390. }
  391. /**
  392. * Get an array of error messages, if any.
  393. *
  394. * @return array
  395. */
  396. public function getErrors()
  397. {
  398. return $this->errors;
  399. }
  400. /**
  401. * POP3 connection error handler.
  402. *
  403. * @param int $errno
  404. * @param string $errstr
  405. * @param string $errfile
  406. * @param int $errline
  407. */
  408. protected function catchWarning($errno, $errstr, $errfile, $errline)
  409. {
  410. $this->setError(
  411. 'Connecting to the POP3 server raised a PHP warning:' .
  412. "errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline"
  413. );
  414. }
  415. }