XOOPS 2.5.6  Final
 All Classes Namespaces Files Functions Variables Pages
class.smtp.php
Go to the documentation of this file.
1 <?php
2 /*~ class.smtp.php
3 .---------------------------------------------------------------------------.
4 | Software: PHPMailer - PHP email class |
5 | Version: 5.2.1 |
6 | Site: https://code.google.com/a/apache-extras.org/p/phpmailer/ |
7 | ------------------------------------------------------------------------- |
8 | Admin: Jim Jagielski (project admininistrator) |
9 | Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
10 | : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
11 | : Jim Jagielski (jimjag) jimjag@gmail.com |
12 | Founder: Brent R. Matzelle (original founder) |
13 | Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
14 | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
15 | Copyright (c) 2001-2003, Brent R. Matzelle |
16 | ------------------------------------------------------------------------- |
17 | License: Distributed under the Lesser General Public License (LGPL) |
18 | http://www.gnu.org/copyleft/lesser.html |
19 | This program is distributed in the hope that it will be useful - WITHOUT |
20 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
21 | FITNESS FOR A PARTICULAR PURPOSE. |
22 '---------------------------------------------------------------------------'
23 */
24 
46 class SMTP {
51  public $SMTP_PORT = 25;
52 
57  public $CRLF = "\r\n";
58 
63  public $do_debug; // the level of debug to perform
64 
69  public $do_verp = false;
70 
75  public $Version = '5.2.1';
76 
78  // PROPERTIES, PRIVATE AND PROTECTED
80 
81  private $smtp_conn; // the socket to the server
82  private $error; // error if any on the last call
83  private $helo_rply; // the reply the server sent to us for HELO
84 
90  public function __construct() {
91  $this->smtp_conn = 0;
92  $this->error = null;
93  $this->helo_rply = null;
94 
95  $this->do_debug = 0;
96  }
97 
99  // CONNECTION FUNCTIONS
101 
115  public function Connect($host, $port = 0, $tval = 30) {
116  // set the error val to null so there is no confusion
117  $this->error = null;
118 
119  // make sure we are __not__ connected
120  if($this->connected()) {
121  // already connected, generate error
122  $this->error = array("error" => "Already connected to a server");
123  return false;
124  }
125 
126  if(empty($port)) {
127  $port = $this->SMTP_PORT;
128  }
129 
130  // connect to the smtp server
131  $this->smtp_conn = @fsockopen($host, // the host of the server
132  $port, // the port to use
133  $errno, // error number if any
134  $errstr, // error message if any
135  $tval); // give up after ? secs
136  // verify we connected properly
137  if(empty($this->smtp_conn)) {
138  $this->error = array("error" => "Failed to connect to server",
139  "errno" => $errno,
140  "errstr" => $errstr);
141  if($this->do_debug >= 1) {
142  echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
143  }
144  return false;
145  }
146 
147  // SMTP server can take longer to respond, give longer timeout for first read
148  // Windows does not have support for this timeout function
149  if(substr(PHP_OS, 0, 3) != "WIN")
150  socket_set_timeout($this->smtp_conn, $tval, 0);
151 
152  // get any announcement
153  $announce = $this->get_lines();
154 
155  if($this->do_debug >= 2) {
156  echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
157  }
158 
159  return true;
160  }
161 
171  public function StartTLS() {
172  $this->error = null; # to avoid confusion
173 
174  if(!$this->connected()) {
175  $this->error = array("error" => "Called StartTLS() without being connected");
176  return false;
177  }
178 
179  fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
180 
181  $rply = $this->get_lines();
182  $code = substr($rply,0,3);
183 
184  if($this->do_debug >= 2) {
185  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
186  }
187 
188  if($code != 220) {
189  $this->error =
190  array("error" => "STARTTLS not accepted from server",
191  "smtp_code" => $code,
192  "smtp_msg" => substr($rply,4));
193  if($this->do_debug >= 1) {
194  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
195  }
196  return false;
197  }
198 
199  // Begin encrypted connection
200  if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
201  return false;
202  }
203 
204  return true;
205  }
206 
213  public function Authenticate($username, $password) {
214  // Start authentication
215  fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
216 
217  $rply = $this->get_lines();
218  $code = substr($rply,0,3);
219 
220  if($code != 334) {
221  $this->error =
222  array("error" => "AUTH not accepted from server",
223  "smtp_code" => $code,
224  "smtp_msg" => substr($rply,4));
225  if($this->do_debug >= 1) {
226  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
227  }
228  return false;
229  }
230 
231  // Send encoded username
232  fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
233 
234  $rply = $this->get_lines();
235  $code = substr($rply,0,3);
236 
237  if($code != 334) {
238  $this->error =
239  array("error" => "Username not accepted from server",
240  "smtp_code" => $code,
241  "smtp_msg" => substr($rply,4));
242  if($this->do_debug >= 1) {
243  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
244  }
245  return false;
246  }
247 
248  // Send encoded password
249  fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
250 
251  $rply = $this->get_lines();
252  $code = substr($rply,0,3);
253 
254  if($code != 235) {
255  $this->error =
256  array("error" => "Password not accepted from server",
257  "smtp_code" => $code,
258  "smtp_msg" => substr($rply,4));
259  if($this->do_debug >= 1) {
260  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
261  }
262  return false;
263  }
264 
265  return true;
266  }
267 
273  public function Connected() {
274  if(!empty($this->smtp_conn)) {
275  $sock_status = socket_get_status($this->smtp_conn);
276  if($sock_status["eof"]) {
277  // the socket is valid but we are not connected
278  if($this->do_debug >= 1) {
279  echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
280  }
281  $this->Close();
282  return false;
283  }
284  return true; // everything looks good
285  }
286  return false;
287  }
288 
296  public function Close() {
297  $this->error = null; // so there is no confusion
298  $this->helo_rply = null;
299  if(!empty($this->smtp_conn)) {
300  // close the connection and cleanup
301  fclose($this->smtp_conn);
302  $this->smtp_conn = 0;
303  }
304  }
305 
307  // SMTP COMMANDS
309 
329  public function Data($msg_data) {
330  $this->error = null; // so no confusion is caused
331 
332  if(!$this->connected()) {
333  $this->error = array(
334  "error" => "Called Data() without being connected");
335  return false;
336  }
337 
338  fputs($this->smtp_conn,"DATA" . $this->CRLF);
339 
340  $rply = $this->get_lines();
341  $code = substr($rply,0,3);
342 
343  if($this->do_debug >= 2) {
344  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
345  }
346 
347  if($code != 354) {
348  $this->error =
349  array("error" => "DATA command not accepted from server",
350  "smtp_code" => $code,
351  "smtp_msg" => substr($rply,4));
352  if($this->do_debug >= 1) {
353  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
354  }
355  return false;
356  }
357 
358  /* the server is ready to accept data!
359  * according to rfc 821 we should not send more than 1000
360  * including the CRLF
361  * characters on a single line so we will break the data up
362  * into lines by \r and/or \n then if needed we will break
363  * each of those into smaller lines to fit within the limit.
364  * in addition we will be looking for lines that start with
365  * a period '.' and append and additional period '.' to that
366  * line. NOTE: this does not count towards limit.
367  */
368 
369  // normalize the line breaks so we know the explode works
370  $msg_data = str_replace("\r\n","\n",$msg_data);
371  $msg_data = str_replace("\r","\n",$msg_data);
372  $lines = explode("\n",$msg_data);
373 
374  /* we need to find a good way to determine is headers are
375  * in the msg_data or if it is a straight msg body
376  * currently I am assuming rfc 822 definitions of msg headers
377  * and if the first field of the first line (':' sperated)
378  * does not contain a space then it _should_ be a header
379  * and we can process all lines before a blank "" line as
380  * headers.
381  */
382 
383  $field = substr($lines[0],0,strpos($lines[0],":"));
384  $in_headers = false;
385  if(!empty($field) && !strstr($field," ")) {
386  $in_headers = true;
387  }
388 
389  $max_line_length = 998; // used below; set here for ease in change
390 
391  while(list(,$line) = @each($lines)) {
392  $lines_out = null;
393  if($line == "" && $in_headers) {
394  $in_headers = false;
395  }
396  // ok we need to break this line up into several smaller lines
397  while(strlen($line) > $max_line_length) {
398  $pos = strrpos(substr($line,0,$max_line_length)," ");
399 
400  // Patch to fix DOS attack
401  if(!$pos) {
402  $pos = $max_line_length - 1;
403  $lines_out[] = substr($line,0,$pos);
404  $line = substr($line,$pos);
405  } else {
406  $lines_out[] = substr($line,0,$pos);
407  $line = substr($line,$pos + 1);
408  }
409 
410  /* if processing headers add a LWSP-char to the front of new line
411  * rfc 822 on long msg headers
412  */
413  if($in_headers) {
414  $line = "\t" . $line;
415  }
416  }
417  $lines_out[] = $line;
418 
419  // send the lines to the server
420  while(list(,$line_out) = @each($lines_out)) {
421  if(strlen($line_out) > 0)
422  {
423  if(substr($line_out, 0, 1) == ".") {
424  $line_out = "." . $line_out;
425  }
426  }
427  fputs($this->smtp_conn,$line_out . $this->CRLF);
428  }
429  }
430 
431  // message data has been sent
432  fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
433 
434  $rply = $this->get_lines();
435  $code = substr($rply,0,3);
436 
437  if($this->do_debug >= 2) {
438  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
439  }
440 
441  if($code != 250) {
442  $this->error =
443  array("error" => "DATA not accepted from server",
444  "smtp_code" => $code,
445  "smtp_msg" => substr($rply,4));
446  if($this->do_debug >= 1) {
447  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
448  }
449  return false;
450  }
451  return true;
452  }
453 
466  public function Hello($host = '') {
467  $this->error = null; // so no confusion is caused
468 
469  if(!$this->connected()) {
470  $this->error = array(
471  "error" => "Called Hello() without being connected");
472  return false;
473  }
474 
475  // if hostname for HELO was not specified send default
476  if(empty($host)) {
477  // determine appropriate default to send to server
478  $host = "localhost";
479  }
480 
481  // Send extended hello first (RFC 2821)
482  if(!$this->SendHello("EHLO", $host)) {
483  if(!$this->SendHello("HELO", $host)) {
484  return false;
485  }
486  }
487 
488  return true;
489  }
490 
496  private function SendHello($hello, $host) {
497  fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
498 
499  $rply = $this->get_lines();
500  $code = substr($rply,0,3);
501 
502  if($this->do_debug >= 2) {
503  echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
504  }
505 
506  if($code != 250) {
507  $this->error =
508  array("error" => $hello . " not accepted from server",
509  "smtp_code" => $code,
510  "smtp_msg" => substr($rply,4));
511  if($this->do_debug >= 1) {
512  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
513  }
514  return false;
515  }
516 
517  $this->helo_rply = $rply;
518 
519  return true;
520  }
521 
536  public function Mail($from) {
537  $this->error = null; // so no confusion is caused
538 
539  if(!$this->connected()) {
540  $this->error = array(
541  "error" => "Called Mail() without being connected");
542  return false;
543  }
544 
545  $useVerp = ($this->do_verp ? "XVERP" : "");
546  fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
547 
548  $rply = $this->get_lines();
549  $code = substr($rply,0,3);
550 
551  if($this->do_debug >= 2) {
552  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
553  }
554 
555  if($code != 250) {
556  $this->error =
557  array("error" => "MAIL not accepted from server",
558  "smtp_code" => $code,
559  "smtp_msg" => substr($rply,4));
560  if($this->do_debug >= 1) {
561  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
562  }
563  return false;
564  }
565  return true;
566  }
567 
579  public function Quit($close_on_error = true) {
580  $this->error = null; // so there is no confusion
581 
582  if(!$this->connected()) {
583  $this->error = array(
584  "error" => "Called Quit() without being connected");
585  return false;
586  }
587 
588  // send the quit command to the server
589  fputs($this->smtp_conn,"quit" . $this->CRLF);
590 
591  // get any good-bye messages
592  $byemsg = $this->get_lines();
593 
594  if($this->do_debug >= 2) {
595  echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
596  }
597 
598  $rval = true;
599  $e = null;
600 
601  $code = substr($byemsg,0,3);
602  if($code != 221) {
603  // use e as a tmp var cause Close will overwrite $this->error
604  $e = array("error" => "SMTP server rejected quit command",
605  "smtp_code" => $code,
606  "smtp_rply" => substr($byemsg,4));
607  $rval = false;
608  if($this->do_debug >= 1) {
609  echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
610  }
611  }
612 
613  if(empty($e) || $close_on_error) {
614  $this->Close();
615  }
616 
617  return $rval;
618  }
619 
632  public function Recipient($to) {
633  $this->error = null; // so no confusion is caused
634 
635  if(!$this->connected()) {
636  $this->error = array(
637  "error" => "Called Recipient() without being connected");
638  return false;
639  }
640 
641  fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
642 
643  $rply = $this->get_lines();
644  $code = substr($rply,0,3);
645 
646  if($this->do_debug >= 2) {
647  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
648  }
649 
650  if($code != 250 && $code != 251) {
651  $this->error =
652  array("error" => "RCPT not accepted from server",
653  "smtp_code" => $code,
654  "smtp_msg" => substr($rply,4));
655  if($this->do_debug >= 1) {
656  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
657  }
658  return false;
659  }
660  return true;
661  }
662 
675  public function Reset() {
676  $this->error = null; // so no confusion is caused
677 
678  if(!$this->connected()) {
679  $this->error = array(
680  "error" => "Called Reset() without being connected");
681  return false;
682  }
683 
684  fputs($this->smtp_conn,"RSET" . $this->CRLF);
685 
686  $rply = $this->get_lines();
687  $code = substr($rply,0,3);
688 
689  if($this->do_debug >= 2) {
690  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
691  }
692 
693  if($code != 250) {
694  $this->error =
695  array("error" => "RSET failed",
696  "smtp_code" => $code,
697  "smtp_msg" => substr($rply,4));
698  if($this->do_debug >= 1) {
699  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
700  }
701  return false;
702  }
703 
704  return true;
705  }
706 
723  public function SendAndMail($from) {
724  $this->error = null; // so no confusion is caused
725 
726  if(!$this->connected()) {
727  $this->error = array(
728  "error" => "Called SendAndMail() without being connected");
729  return false;
730  }
731 
732  fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
733 
734  $rply = $this->get_lines();
735  $code = substr($rply,0,3);
736 
737  if($this->do_debug >= 2) {
738  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
739  }
740 
741  if($code != 250) {
742  $this->error =
743  array("error" => "SAML not accepted from server",
744  "smtp_code" => $code,
745  "smtp_msg" => substr($rply,4));
746  if($this->do_debug >= 1) {
747  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
748  }
749  return false;
750  }
751  return true;
752  }
753 
767  public function Turn() {
768  $this->error = array("error" => "This method, TURN, of the SMTP ".
769  "is not implemented");
770  if($this->do_debug >= 1) {
771  echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
772  }
773  return false;
774  }
775 
781  public function getError() {
782  return $this->error;
783  }
784 
786  // INTERNAL FUNCTIONS
788 
798  private function get_lines() {
799  $data = "";
800  while(!feof($this->smtp_conn)) {
801  $str = @fgets($this->smtp_conn,515);
802  if($this->do_debug >= 4) {
803  echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
804  echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
805  }
806  $data .= $str;
807  if($this->do_debug >= 4) {
808  echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
809  }
810  // if 4th character is a space, we are done reading, break the loop
811  if(substr($str,3,1) == " ") { break; }
812  }
813  return $data;
814  }
815 
816 }
817 
818 ?>