EliteConf
 All Data Structures 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.1 |
6 | Contact: via sourceforge.net support pages (also www.codeworxtech.com) |
7 | Info: http://phpmailer.sourceforge.net |
8 | Support: http://sourceforge.net/projects/phpmailer/ |
9 | ------------------------------------------------------------------------- |
10 | Admin: Andy Prevost (project admininistrator) |
11 | Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
12 | : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
13 | Founder: Brent R. Matzelle (original founder) |
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 | We offer a number of paid services (www.codeworxtech.com): |
24 | - Web Hosting on highly optimized fast and secure servers |
25 | - Technology Consulting |
26 | - Oursourcing (highly qualified programmers and graphic designers) |
27 '---------------------------------------------------------------------------'
28 */
29 
49 class SMTP {
54  public $SMTP_PORT = 25;
55 
60  public $CRLF = "\r\n";
61 
66  public $do_debug; // the level of debug to perform
67 
72  public $do_verp = false;
73 
75  // PROPERTIES, PRIVATE AND PROTECTED
77 
78  private $smtp_conn; // the socket to the server
79  private $error; // error if any on the last call
80  private $helo_rply; // the reply the server sent to us for HELO
81 
87  public function __construct() {
88  $this->smtp_conn = 0;
89  $this->error = null;
90  $this->helo_rply = null;
91 
92  $this->do_debug = 0;
93  }
94 
96  // CONNECTION FUNCTIONS
98 
112  public function Connect($host, $port = 0, $tval = 30) {
113  // set the error val to null so there is no confusion
114  $this->error = null;
115 
116  // make sure we are __not__ connected
117  if($this->connected()) {
118  // already connected, generate error
119  $this->error = array("error" => "Already connected to a server");
120  return false;
121  }
122 
123  if(empty($port)) {
124  $port = $this->SMTP_PORT;
125  }
126 
127  // connect to the smtp server
128  $this->smtp_conn = @fsockopen($host, // the host of the server
129  $port, // the port to use
130  $errno, // error number if any
131  $errstr, // error message if any
132  $tval); // give up after ? secs
133  // verify we connected properly
134  if(empty($this->smtp_conn)) {
135  $this->error = array("error" => "Failed to connect to server",
136  "errno" => $errno,
137  "errstr" => $errstr);
138  if($this->do_debug >= 1) {
139  echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
140  }
141  return false;
142  }
143 
144  // SMTP server can take longer to respond, give longer timeout for first read
145  // Windows does not have support for this timeout function
146  if(substr(PHP_OS, 0, 3) != "WIN")
147  socket_set_timeout($this->smtp_conn, $tval, 0);
148 
149  // get any announcement
150  $announce = $this->get_lines();
151 
152  if($this->do_debug >= 2) {
153  echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
154  }
155 
156  return true;
157  }
158 
168  public function StartTLS() {
169  $this->error = null; # to avoid confusion
170 
171  if(!$this->connected()) {
172  $this->error = array("error" => "Called StartTLS() without being connected");
173  return false;
174  }
175 
176  fputs($this->smtp_conn,"STARTTLS" . $this->CRLF);
177 
178  $rply = $this->get_lines();
179  $code = substr($rply,0,3);
180 
181  if($this->do_debug >= 2) {
182  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
183  }
184 
185  if($code != 220) {
186  $this->error =
187  array("error" => "STARTTLS not accepted from server",
188  "smtp_code" => $code,
189  "smtp_msg" => substr($rply,4));
190  if($this->do_debug >= 1) {
191  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
192  }
193  return false;
194  }
195 
196  // Begin encrypted connection
197  if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
198  return false;
199  }
200 
201  return true;
202  }
203 
210  public function Authenticate($username, $password) {
211  // Start authentication
212  fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF);
213 
214  $rply = $this->get_lines();
215  $code = substr($rply,0,3);
216 
217  if($code != 334) {
218  $this->error =
219  array("error" => "AUTH not accepted from server",
220  "smtp_code" => $code,
221  "smtp_msg" => substr($rply,4));
222  if($this->do_debug >= 1) {
223  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
224  }
225  return false;
226  }
227 
228  // Send encoded username
229  fputs($this->smtp_conn, base64_encode($username) . $this->CRLF);
230 
231  $rply = $this->get_lines();
232  $code = substr($rply,0,3);
233 
234  if($code != 334) {
235  $this->error =
236  array("error" => "Username not accepted from server",
237  "smtp_code" => $code,
238  "smtp_msg" => substr($rply,4));
239  if($this->do_debug >= 1) {
240  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
241  }
242  return false;
243  }
244 
245  // Send encoded password
246  fputs($this->smtp_conn, base64_encode($password) . $this->CRLF);
247 
248  $rply = $this->get_lines();
249  $code = substr($rply,0,3);
250 
251  if($code != 235) {
252  $this->error =
253  array("error" => "Password not accepted from server",
254  "smtp_code" => $code,
255  "smtp_msg" => substr($rply,4));
256  if($this->do_debug >= 1) {
257  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
258  }
259  return false;
260  }
261 
262  return true;
263  }
264 
270  public function Connected() {
271  if(!empty($this->smtp_conn)) {
272  $sock_status = socket_get_status($this->smtp_conn);
273  if($sock_status["eof"]) {
274  // the socket is valid but we are not connected
275  if($this->do_debug >= 1) {
276  echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
277  }
278  $this->Close();
279  return false;
280  }
281  return true; // everything looks good
282  }
283  return false;
284  }
285 
293  public function Close() {
294  $this->error = null; // so there is no confusion
295  $this->helo_rply = null;
296  if(!empty($this->smtp_conn)) {
297  // close the connection and cleanup
298  fclose($this->smtp_conn);
299  $this->smtp_conn = 0;
300  }
301  }
302 
304  // SMTP COMMANDS
306 
326  public function Data($msg_data) {
327  $this->error = null; // so no confusion is caused
328 
329  if(!$this->connected()) {
330  $this->error = array(
331  "error" => "Called Data() without being connected");
332  return false;
333  }
334 
335  fputs($this->smtp_conn,"DATA" . $this->CRLF);
336 
337  $rply = $this->get_lines();
338  $code = substr($rply,0,3);
339 
340  if($this->do_debug >= 2) {
341  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
342  }
343 
344  if($code != 354) {
345  $this->error =
346  array("error" => "DATA command not accepted from server",
347  "smtp_code" => $code,
348  "smtp_msg" => substr($rply,4));
349  if($this->do_debug >= 1) {
350  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
351  }
352  return false;
353  }
354 
355  /* the server is ready to accept data!
356  * according to rfc 821 we should not send more than 1000
357  * including the CRLF
358  * characters on a single line so we will break the data up
359  * into lines by \r and/or \n then if needed we will break
360  * each of those into smaller lines to fit within the limit.
361  * in addition we will be looking for lines that start with
362  * a period '.' and append and additional period '.' to that
363  * line. NOTE: this does not count towards limit.
364  */
365 
366  // normalize the line breaks so we know the explode works
367  $msg_data = str_replace("\r\n","\n",$msg_data);
368  $msg_data = str_replace("\r","\n",$msg_data);
369  $lines = explode("\n",$msg_data);
370 
371  /* we need to find a good way to determine is headers are
372  * in the msg_data or if it is a straight msg body
373  * currently I am assuming rfc 822 definitions of msg headers
374  * and if the first field of the first line (':' sperated)
375  * does not contain a space then it _should_ be a header
376  * and we can process all lines before a blank "" line as
377  * headers.
378  */
379 
380  $field = substr($lines[0],0,strpos($lines[0],":"));
381  $in_headers = false;
382  if(!empty($field) && !strstr($field," ")) {
383  $in_headers = true;
384  }
385 
386  $max_line_length = 998; // used below; set here for ease in change
387 
388  while(list(,$line) = @each($lines)) {
389  $lines_out = null;
390  if($line == "" && $in_headers) {
391  $in_headers = false;
392  }
393  // ok we need to break this line up into several smaller lines
394  while(strlen($line) > $max_line_length) {
395  $pos = strrpos(substr($line,0,$max_line_length)," ");
396 
397  // Patch to fix DOS attack
398  if(!$pos) {
399  $pos = $max_line_length - 1;
400  $lines_out[] = substr($line,0,$pos);
401  $line = substr($line,$pos);
402  } else {
403  $lines_out[] = substr($line,0,$pos);
404  $line = substr($line,$pos + 1);
405  }
406 
407  /* if processing headers add a LWSP-char to the front of new line
408  * rfc 822 on long msg headers
409  */
410  if($in_headers) {
411  $line = "\t" . $line;
412  }
413  }
414  $lines_out[] = $line;
415 
416  // send the lines to the server
417  while(list(,$line_out) = @each($lines_out)) {
418  if(strlen($line_out) > 0)
419  {
420  if(substr($line_out, 0, 1) == ".") {
421  $line_out = "." . $line_out;
422  }
423  }
424  fputs($this->smtp_conn,$line_out . $this->CRLF);
425  }
426  }
427 
428  // message data has been sent
429  fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF);
430 
431  $rply = $this->get_lines();
432  $code = substr($rply,0,3);
433 
434  if($this->do_debug >= 2) {
435  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
436  }
437 
438  if($code != 250) {
439  $this->error =
440  array("error" => "DATA not accepted from server",
441  "smtp_code" => $code,
442  "smtp_msg" => substr($rply,4));
443  if($this->do_debug >= 1) {
444  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
445  }
446  return false;
447  }
448  return true;
449  }
450 
463  public function Hello($host = '') {
464  $this->error = null; // so no confusion is caused
465 
466  if(!$this->connected()) {
467  $this->error = array(
468  "error" => "Called Hello() without being connected");
469  return false;
470  }
471 
472  // if hostname for HELO was not specified send default
473  if(empty($host)) {
474  // determine appropriate default to send to server
475  $host = "localhost";
476  }
477 
478  // Send extended hello first (RFC 2821)
479  if(!$this->SendHello("EHLO", $host)) {
480  if(!$this->SendHello("HELO", $host)) {
481  return false;
482  }
483  }
484 
485  return true;
486  }
487 
493  private function SendHello($hello, $host) {
494  fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF);
495 
496  $rply = $this->get_lines();
497  $code = substr($rply,0,3);
498 
499  if($this->do_debug >= 2) {
500  echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
501  }
502 
503  if($code != 250) {
504  $this->error =
505  array("error" => $hello . " not accepted from server",
506  "smtp_code" => $code,
507  "smtp_msg" => substr($rply,4));
508  if($this->do_debug >= 1) {
509  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
510  }
511  return false;
512  }
513 
514  $this->helo_rply = $rply;
515 
516  return true;
517  }
518 
533  public function Mail($from) {
534  $this->error = null; // so no confusion is caused
535 
536  if(!$this->connected()) {
537  $this->error = array(
538  "error" => "Called Mail() without being connected");
539  return false;
540  }
541 
542  $useVerp = ($this->do_verp ? "XVERP" : "");
543  fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF);
544 
545  $rply = $this->get_lines();
546  $code = substr($rply,0,3);
547 
548  if($this->do_debug >= 2) {
549  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
550  }
551 
552  if($code != 250) {
553  $this->error =
554  array("error" => "MAIL not accepted from server",
555  "smtp_code" => $code,
556  "smtp_msg" => substr($rply,4));
557  if($this->do_debug >= 1) {
558  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
559  }
560  return false;
561  }
562  return true;
563  }
564 
576  public function Quit($close_on_error = true) {
577  $this->error = null; // so there is no confusion
578 
579  if(!$this->connected()) {
580  $this->error = array(
581  "error" => "Called Quit() without being connected");
582  return false;
583  }
584 
585  // send the quit command to the server
586  fputs($this->smtp_conn,"quit" . $this->CRLF);
587 
588  // get any good-bye messages
589  $byemsg = $this->get_lines();
590 
591  if($this->do_debug >= 2) {
592  echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
593  }
594 
595  $rval = true;
596  $e = null;
597 
598  $code = substr($byemsg,0,3);
599  if($code != 221) {
600  // use e as a tmp var cause Close will overwrite $this->error
601  $e = array("error" => "SMTP server rejected quit command",
602  "smtp_code" => $code,
603  "smtp_rply" => substr($byemsg,4));
604  $rval = false;
605  if($this->do_debug >= 1) {
606  echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
607  }
608  }
609 
610  if(empty($e) || $close_on_error) {
611  $this->Close();
612  }
613 
614  return $rval;
615  }
616 
629  public function Recipient($to) {
630  $this->error = null; // so no confusion is caused
631 
632  if(!$this->connected()) {
633  $this->error = array(
634  "error" => "Called Recipient() without being connected");
635  return false;
636  }
637 
638  fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF);
639 
640  $rply = $this->get_lines();
641  $code = substr($rply,0,3);
642 
643  if($this->do_debug >= 2) {
644  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
645  }
646 
647  if($code != 250 && $code != 251) {
648  $this->error =
649  array("error" => "RCPT not accepted from server",
650  "smtp_code" => $code,
651  "smtp_msg" => substr($rply,4));
652  if($this->do_debug >= 1) {
653  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
654  }
655  return false;
656  }
657  return true;
658  }
659 
672  public function Reset() {
673  $this->error = null; // so no confusion is caused
674 
675  if(!$this->connected()) {
676  $this->error = array(
677  "error" => "Called Reset() without being connected");
678  return false;
679  }
680 
681  fputs($this->smtp_conn,"RSET" . $this->CRLF);
682 
683  $rply = $this->get_lines();
684  $code = substr($rply,0,3);
685 
686  if($this->do_debug >= 2) {
687  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
688  }
689 
690  if($code != 250) {
691  $this->error =
692  array("error" => "RSET failed",
693  "smtp_code" => $code,
694  "smtp_msg" => substr($rply,4));
695  if($this->do_debug >= 1) {
696  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
697  }
698  return false;
699  }
700 
701  return true;
702  }
703 
720  public function SendAndMail($from) {
721  $this->error = null; // so no confusion is caused
722 
723  if(!$this->connected()) {
724  $this->error = array(
725  "error" => "Called SendAndMail() without being connected");
726  return false;
727  }
728 
729  fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF);
730 
731  $rply = $this->get_lines();
732  $code = substr($rply,0,3);
733 
734  if($this->do_debug >= 2) {
735  echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
736  }
737 
738  if($code != 250) {
739  $this->error =
740  array("error" => "SAML not accepted from server",
741  "smtp_code" => $code,
742  "smtp_msg" => substr($rply,4));
743  if($this->do_debug >= 1) {
744  echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
745  }
746  return false;
747  }
748  return true;
749  }
750 
764  public function Turn() {
765  $this->error = array("error" => "This method, TURN, of the SMTP ".
766  "is not implemented");
767  if($this->do_debug >= 1) {
768  echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
769  }
770  return false;
771  }
772 
778  public function getError() {
779  return $this->error;
780  }
781 
783  // INTERNAL FUNCTIONS
785 
795  private function get_lines() {
796  $data = "";
797  while($str = @fgets($this->smtp_conn,515)) {
798  if($this->do_debug >= 4) {
799  echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
800  echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
801  }
802  $data .= $str;
803  if($this->do_debug >= 4) {
804  echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
805  }
806  // if 4th character is a space, we are done reading, break the loop
807  if(substr($str,3,1) == " ") { break; }
808  }
809  return $data;
810  }
811 
812 }
813 
814 ?>