class.pop3.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417
  1. <?php
  2. /**
  3. * PHPMailer POP-Before-SMTP Authentication Class.
  4. * PHP Version 5
  5. * @package PHPMailer
  6. * @link https://github.com/PHPMailer/PHPMailer/
  7. * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
  8. * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
  9. * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  10. * @author Brent R. Matzelle (original founder)
  11. * @copyright 2012 - 2014 Marcus Bointon
  12. * @copyright 2010 - 2012 Jim Jagielski
  13. * @copyright 2004 - 2009 Andy Prevost
  14. * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  15. * @note This program is distributed in the hope that it will be useful - WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  17. * FITNESS FOR A PARTICULAR PURPOSE.
  18. */
  19. /**
  20. * PHPMailer POP-Before-SMTP Authentication Class.
  21. * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.
  22. * Does not support APOP.
  23. * @package PHPMailer
  24. * @author Richard Davey (original author) <rich@corephp.co.uk>
  25. * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
  26. * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
  27. * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
  28. */
  29. class POP3
  30. {
  31. /**
  32. * The POP3 PHPMailer Version number.
  33. * @type string
  34. * @access public
  35. */
  36. public $Version = '5.2.7';
  37. /**
  38. * Default POP3 port number.
  39. * @type int
  40. * @access public
  41. */
  42. public $POP3_PORT = 110;
  43. /**
  44. * Default timeout in seconds.
  45. * @type int
  46. * @access public
  47. */
  48. public $POP3_TIMEOUT = 30;
  49. /**
  50. * POP3 Carriage Return + Line Feed.
  51. * @type string
  52. * @access public
  53. * @deprecated Use the constant instead
  54. */
  55. public $CRLF = "\r\n";
  56. /**
  57. * Debug display level.
  58. * Options: 0 = no, 1+ = yes
  59. * @type int
  60. * @access public
  61. */
  62. public $do_debug = 0;
  63. /**
  64. * POP3 mail server hostname.
  65. * @type string
  66. * @access public
  67. */
  68. public $host;
  69. /**
  70. * POP3 port number.
  71. * @type int
  72. * @access public
  73. */
  74. public $port;
  75. /**
  76. * POP3 Timeout Value in seconds.
  77. * @type int
  78. * @access public
  79. */
  80. public $tval;
  81. /**
  82. * POP3 username
  83. * @type string
  84. * @access public
  85. */
  86. public $username;
  87. /**
  88. * POP3 password.
  89. * @type string
  90. * @access public
  91. */
  92. public $password;
  93. /**
  94. * Resource handle for the POP3 connection socket.
  95. * @type resource
  96. * @access private
  97. */
  98. private $pop_conn;
  99. /**
  100. * Are we connected?
  101. * @type bool
  102. * @access private
  103. */
  104. private $connected;
  105. /**
  106. * Error container.
  107. * @type array
  108. * @access private
  109. */
  110. private $error;
  111. /**
  112. * Line break constant
  113. */
  114. const CRLF = "\r\n";
  115. /**
  116. * Constructor.
  117. * @access public
  118. */
  119. public function __construct()
  120. {
  121. $this->pop_conn = 0;
  122. $this->connected = false;
  123. $this->error = null;
  124. }
  125. /**
  126. * Simple static wrapper for all-in-one POP before SMTP
  127. * @param $host
  128. * @param bool $port
  129. * @param bool $tval
  130. * @param string $username
  131. * @param string $password
  132. * @param int $debug_level
  133. * @return bool
  134. */
  135. public static function popBeforeSmtp(
  136. $host,
  137. $port = false,
  138. $tval = false,
  139. $username = '',
  140. $password = '',
  141. $debug_level = 0
  142. ) {
  143. $pop = new POP3;
  144. return $pop->authorise($host, $port, $tval, $username, $password, $debug_level);
  145. }
  146. /**
  147. * Authenticate with a POP3 server.
  148. * A connect, login, disconnect sequence
  149. * appropriate for POP-before SMTP authorisation.
  150. * @access public
  151. * @param string $host
  152. * @param bool|int $port
  153. * @param bool|int $tval
  154. * @param string $username
  155. * @param string $password
  156. * @param int $debug_level
  157. * @return bool
  158. */
  159. public function authorise($host, $port = false, $tval = false, $username = '', $password = '', $debug_level = 0)
  160. {
  161. $this->host = $host;
  162. // If no port value provided, use default
  163. if ($port === false) {
  164. $this->port = $this->POP3_PORT;
  165. } else {
  166. $this->port = $port;
  167. }
  168. // If no timeout value provided, use default
  169. if ($tval === false) {
  170. $this->tval = $this->POP3_TIMEOUT;
  171. } else {
  172. $this->tval = $tval;
  173. }
  174. $this->do_debug = $debug_level;
  175. $this->username = $username;
  176. $this->password = $password;
  177. // Refresh the error log
  178. $this->error = null;
  179. // connect
  180. $result = $this->connect($this->host, $this->port, $this->tval);
  181. if ($result) {
  182. $login_result = $this->login($this->username, $this->password);
  183. if ($login_result) {
  184. $this->disconnect();
  185. return true;
  186. }
  187. }
  188. // We need to disconnect regardless of whether the login succeeded
  189. $this->disconnect();
  190. return false;
  191. }
  192. /**
  193. * Connect to a POP3 server.
  194. * @access public
  195. * @param string $host
  196. * @param bool|int $port
  197. * @param integer $tval
  198. * @return boolean
  199. */
  200. public function connect($host, $port = false, $tval = 30)
  201. {
  202. // Are we already connected?
  203. if ($this->connected) {
  204. return true;
  205. }
  206. //On Windows this will raise a PHP Warning error if the hostname doesn't exist.
  207. //Rather than suppress it with @fsockopen, capture it cleanly instead
  208. set_error_handler(array($this, 'catchWarning'));
  209. // connect to the POP3 server
  210. $this->pop_conn = fsockopen(
  211. $host, // POP3 Host
  212. $port, // Port #
  213. $errno, // Error Number
  214. $errstr, // Error Message
  215. $tval
  216. ); // Timeout (seconds)
  217. // Restore the error handler
  218. restore_error_handler();
  219. // Does the Error Log now contain anything?
  220. if ($this->error && $this->do_debug >= 1) {
  221. $this->displayErrors();
  222. }
  223. // Did we connect?
  224. if ($this->pop_conn == false) {
  225. // It would appear not...
  226. $this->error = array(
  227. 'error' => "Failed to connect to server $host on port $port",
  228. 'errno' => $errno,
  229. 'errstr' => $errstr
  230. );
  231. if ($this->do_debug >= 1) {
  232. $this->displayErrors();
  233. }
  234. return false;
  235. }
  236. // Increase the stream time-out
  237. // Check for PHP 4.3.0 or later
  238. if (version_compare(phpversion(), '5.0.0', 'ge')) {
  239. stream_set_timeout($this->pop_conn, $tval, 0);
  240. } else {
  241. // Does not work on Windows
  242. if (substr(PHP_OS, 0, 3) !== 'WIN') {
  243. socket_set_timeout($this->pop_conn, $tval, 0);
  244. }
  245. }
  246. // Get the POP3 server response
  247. $pop3_response = $this->getResponse();
  248. // Check for the +OK
  249. if ($this->checkResponse($pop3_response)) {
  250. // The connection is established and the POP3 server is talking
  251. $this->connected = true;
  252. return true;
  253. }
  254. return false;
  255. }
  256. /**
  257. * Log in to the POP3 server.
  258. * Does not support APOP (RFC 2828, 4949).
  259. * @access public
  260. * @param string $username
  261. * @param string $password
  262. * @return boolean
  263. */
  264. public function login($username = '', $password = '')
  265. {
  266. if ($this->connected == false) {
  267. $this->error = 'Not connected to POP3 server';
  268. if ($this->do_debug >= 1) {
  269. $this->displayErrors();
  270. }
  271. }
  272. if (empty($username)) {
  273. $username = $this->username;
  274. }
  275. if (empty($password)) {
  276. $password = $this->password;
  277. }
  278. // Send the Username
  279. $this->sendString("USER $username" . self::CRLF);
  280. $pop3_response = $this->getResponse();
  281. if ($this->checkResponse($pop3_response)) {
  282. // Send the Password
  283. $this->sendString("PASS $password" . self::CRLF);
  284. $pop3_response = $this->getResponse();
  285. if ($this->checkResponse($pop3_response)) {
  286. return true;
  287. }
  288. }
  289. return false;
  290. }
  291. /**
  292. * Disconnect from the POP3 server.
  293. * @access public
  294. */
  295. public function disconnect()
  296. {
  297. $this->sendString('QUIT');
  298. //The QUIT command may cause the daemon to exit, which will kill our connection
  299. //So ignore errors here
  300. @fclose($this->pop_conn);
  301. }
  302. /**
  303. * Get a response from the POP3 server.
  304. * $size is the maximum number of bytes to retrieve
  305. * @param integer $size
  306. * @return string
  307. * @access private
  308. */
  309. private function getResponse($size = 128)
  310. {
  311. $response = fgets($this->pop_conn, $size);
  312. if ($this->do_debug >= 1) {
  313. echo "Server -> Client: $response";
  314. }
  315. return $response;
  316. }
  317. /**
  318. * Send raw data to the POP3 server.
  319. * @param string $string
  320. * @return integer
  321. * @access private
  322. */
  323. private function sendString($string)
  324. {
  325. if ($this->pop_conn) {
  326. if ($this->do_debug >= 2) { //Show client messages when debug >= 2
  327. echo "Client -> Server: $string";
  328. }
  329. return fwrite($this->pop_conn, $string, strlen($string));
  330. }
  331. return 0;
  332. }
  333. /**
  334. * Checks the POP3 server response.
  335. * Looks for for +OK or -ERR.
  336. * @param string $string
  337. * @return boolean
  338. * @access private
  339. */
  340. private function checkResponse($string)
  341. {
  342. if (substr($string, 0, 3) !== '+OK') {
  343. $this->error = array(
  344. 'error' => "Server reported an error: $string",
  345. 'errno' => 0,
  346. 'errstr' => ''
  347. );
  348. if ($this->do_debug >= 1) {
  349. $this->displayErrors();
  350. }
  351. return false;
  352. } else {
  353. return true;
  354. }
  355. }
  356. /**
  357. * Display errors if debug is enabled.
  358. * @access private
  359. */
  360. private function displayErrors()
  361. {
  362. echo '<pre>';
  363. foreach ($this->error as $single_error) {
  364. print_r($single_error);
  365. }
  366. echo '</pre>';
  367. }
  368. /**
  369. * POP3 connection error handler.
  370. * @param integer $errno
  371. * @param string $errstr
  372. * @param string $errfile
  373. * @param integer $errline
  374. * @access private
  375. */
  376. private function catchWarning($errno, $errstr, $errfile, $errline)
  377. {
  378. $this->error[] = array(
  379. 'error' => "Connecting to the POP3 server raised a PHP warning: ",
  380. 'errno' => $errno,
  381. 'errstr' => $errstr,
  382. 'errfile' => $errfile,
  383. 'errline' => $errline
  384. );
  385. }
  386. }