POP3.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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 http://www.gnu.org/copyleft/lesser.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.4.0';
  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. }
  278. if (empty($username)) {
  279. $username = $this->username;
  280. }
  281. if (empty($password)) {
  282. $password = $this->password;
  283. }
  284. //Send the Username
  285. $this->sendString("USER $username" . static::LE);
  286. $pop3_response = $this->getResponse();
  287. if ($this->checkResponse($pop3_response)) {
  288. //Send the Password
  289. $this->sendString("PASS $password" . static::LE);
  290. $pop3_response = $this->getResponse();
  291. if ($this->checkResponse($pop3_response)) {
  292. return true;
  293. }
  294. }
  295. return false;
  296. }
  297. /**
  298. * Disconnect from the POP3 server.
  299. */
  300. public function disconnect()
  301. {
  302. $this->sendString('QUIT');
  303. //The QUIT command may cause the daemon to exit, which will kill our connection
  304. //So ignore errors here
  305. try {
  306. @fclose($this->pop_conn);
  307. } catch (Exception $e) {
  308. //Do nothing
  309. }
  310. }
  311. /**
  312. * Get a response from the POP3 server.
  313. *
  314. * @param int $size The maximum number of bytes to retrieve
  315. *
  316. * @return string
  317. */
  318. protected function getResponse($size = 128)
  319. {
  320. $response = fgets($this->pop_conn, $size);
  321. if ($this->do_debug >= self::DEBUG_SERVER) {
  322. echo 'Server -> Client: ', $response;
  323. }
  324. return $response;
  325. }
  326. /**
  327. * Send raw data to the POP3 server.
  328. *
  329. * @param string $string
  330. *
  331. * @return int
  332. */
  333. protected function sendString($string)
  334. {
  335. if ($this->pop_conn) {
  336. if ($this->do_debug >= self::DEBUG_CLIENT) { //Show client messages when debug >= 2
  337. echo 'Client -> Server: ', $string;
  338. }
  339. return fwrite($this->pop_conn, $string, strlen($string));
  340. }
  341. return 0;
  342. }
  343. /**
  344. * Checks the POP3 server response.
  345. * Looks for for +OK or -ERR.
  346. *
  347. * @param string $string
  348. *
  349. * @return bool
  350. */
  351. protected function checkResponse($string)
  352. {
  353. if (strpos($string, '+OK') !== 0) {
  354. $this->setError("Server reported an error: $string");
  355. return false;
  356. }
  357. return true;
  358. }
  359. /**
  360. * Add an error to the internal error store.
  361. * Also display debug output if it's enabled.
  362. *
  363. * @param string $error
  364. */
  365. protected function setError($error)
  366. {
  367. $this->errors[] = $error;
  368. if ($this->do_debug >= self::DEBUG_SERVER) {
  369. echo '<pre>';
  370. foreach ($this->errors as $e) {
  371. print_r($e);
  372. }
  373. echo '</pre>';
  374. }
  375. }
  376. /**
  377. * Get an array of error messages, if any.
  378. *
  379. * @return array
  380. */
  381. public function getErrors()
  382. {
  383. return $this->errors;
  384. }
  385. /**
  386. * POP3 connection error handler.
  387. *
  388. * @param int $errno
  389. * @param string $errstr
  390. * @param string $errfile
  391. * @param int $errline
  392. */
  393. protected function catchWarning($errno, $errstr, $errfile, $errline)
  394. {
  395. $this->setError(
  396. 'Connecting to the POP3 server raised a PHP warning:' .
  397. "errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline"
  398. );
  399. }
  400. }