class.pop3.php 11 KB

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