class.pop3.php 11 KB

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