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