Source for file smtp.php

Documentation is available at smtp.php

  1. <?php
  2. /*~ class.smtp.php
  3. .---------------------------------------------------------------------------.
  4. |  Software: PHPMailer - PHP email class                                    |
  5. |   Version: 5.2.6                                                          |
  6. |      Site: https://github.com/PHPMailer/PHPMailer/                        |
  7. | ------------------------------------------------------------------------- |
  8. |    Admins: Marcus Bointon                                                 |
  9. |    Admins: Jim Jagielski                                                  |
  10. |   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
  11. |          : Marcus Bointon (coolbru) phpmailer@synchromedia.co.uk          |
  12. |          : Jim Jagielski (jimjag) jimjag@gmail.com                        |
  13. |   Founder: Brent R. Matzelle (original founder)                           |
  14. | Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved.              |
  15. | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
  16. | Copyright (c) 2001-2003, Brent R. Matzelle                                |
  17. | ------------------------------------------------------------------------- |
  18. |   License: Distributed under the Lesser General Public License (LGPL)     |
  19. |            http://www.gnu.org/copyleft/lesser.html                        |
  20. | This program is distributed in the hope that it will be useful - WITHOUT  |
  21. | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
  22. | FITNESS FOR A PARTICULAR PURPOSE.                                         |
  23. '---------------------------------------------------------------------------'
  24. */
  25.  
  26. /**
  27.  * PHPMailer - PHP SMTP email transport class
  28.  * NOTE: Designed for use with PHP version 5 and up
  29.  * @package PHPMailer
  30.  * @author Andy Prevost
  31.  * @author Marcus Bointon
  32.  * @copyright 2004 - 2008 Andy Prevost
  33.  * @author Jim Jagielski
  34.  * @copyright 2010 - 2012 Jim Jagielski
  35.  * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
  36.  */
  37.  
  38. /**
  39.  * PHP RFC821 SMTP client
  40.  *
  41.  * Implements all the RFC 821 SMTP commands except TURN which will always return a not implemented error.
  42.  * SMTP also provides some utility methods for sending mail to an SMTP server.
  43.  * @author Chris Ryan
  44.  * @package PHPMailer
  45.  */
  46.  
  47. class SMTP {
  48.   /**
  49.    *  SMTP server port
  50.    *  @var int 
  51.    */
  52.   public $SMTP_PORT = 25;
  53.  
  54.   /**
  55.    *  SMTP reply line ending (don't change)
  56.    *  @var string 
  57.    */
  58.   public $CRLF = "\r\n";
  59.  
  60.   /**
  61.    *  Debug output level; 0 for no output
  62.    *  @var int 
  63.    */
  64.   public $do_debug = 0;
  65.  
  66.   /**
  67.    * Sets the function/method to use for debugging output.
  68.    * Right now we only honor 'echo', 'html' or 'error_log'
  69.    * @var string 
  70.    */
  71.   public $Debugoutput     = 'echo';
  72.  
  73.   /**
  74.    *  Sets VERP use on/off (default is off)
  75.    *  @var bool 
  76.    */
  77.   public $do_verp = false;
  78.  
  79.   /**
  80.    * Sets the SMTP timeout value for reads, in seconds
  81.    * @var int 
  82.    */
  83.   public $Timeout         = 15;
  84.  
  85.   /**
  86.    * Sets the SMTP timelimit value for reads, in seconds
  87.    * @var int 
  88.    */
  89.   public $Timelimit       = 30;
  90.  
  91.   /**
  92.    * Sets the SMTP PHPMailer Version number
  93.    * @var string 
  94.    */
  95.   public $Version         = '5.2.6';
  96.  
  97.   /////////////////////////////////////////////////
  98.   // PROPERTIES, PRIVATE AND PROTECTED
  99.   /////////////////////////////////////////////////
  100.  
  101.   /**
  102.    * @var resource The socket to the server
  103.    */
  104.   protected $smtp_conn;
  105.   /**
  106.    * @var string Error message, if any, for the last call
  107.    */
  108.   protected $error;
  109.   /**
  110.    * @var string The reply the server sent to us for HELO
  111.    */
  112.   protected $helo_rply;
  113.  
  114.   /**
  115.    * Outputs debugging info via user-defined method
  116.    * @param string $str 
  117.    */
  118.   protected function edebug($str{
  119.     switch ($this->Debugoutput{
  120.       case 'error_log':
  121.         error_log($str);
  122.         break;
  123.       case 'html':
  124.         //Cleans up output a bit for a better looking display that's HTML-safe
  125.         echo htmlentities(preg_replace('/[\r\n]+/'''$str)ENT_QUOTES'UTF-8')."<br>\n";
  126.         break;
  127.       case 'echo':
  128.       default:
  129.         //Just echoes exactly what was received
  130.         echo $str;
  131.     }
  132.   }
  133.  
  134.   /**
  135.    * Initialize the class so that the data is in a known state.
  136.    * @access public
  137.    * @return SMTP 
  138.    */
  139.   public function __construct({
  140.     $this->smtp_conn = 0;
  141.     $this->error = null;
  142.     $this->helo_rply = null;
  143.  
  144.     $this->do_debug = 0;
  145.   }
  146.  
  147.   /////////////////////////////////////////////////
  148.   // CONNECTION FUNCTIONS
  149.   /////////////////////////////////////////////////
  150.  
  151.   /**
  152.    * Connect to an SMTP server
  153.    *
  154.    * SMTP CODE SUCCESS: 220
  155.    * SMTP CODE FAILURE: 421
  156.    * @access public
  157.    * @param string $host SMTP server IP or host name
  158.    * @param int $port The port number to connect to, or use the default port if not specified
  159.    * @param int $timeout How long to wait for the connection to open
  160.    * @param array $options An array of options compatible with stream_context_create()
  161.    * @return bool 
  162.    */
  163.   public function Connect($host$port 0$timeout 30$options array()) {
  164.     // Clear errors to avoid confusion
  165.     $this->error = null;
  166.  
  167.     // Make sure we are __not__ connected
  168.     if($this->connected()) {
  169.       // Already connected, generate error
  170.       $this->error = array('error' => 'Already connected to a server');
  171.       return false;
  172.     }
  173.  
  174.     if(empty($port)) {
  175.       $port $this->SMTP_PORT;
  176.     }
  177.  
  178.     // Connect to the SMTP server
  179.     $errno 0;
  180.     $errstr '';
  181.     $socket_context stream_context_create($options);
  182.     //Need to suppress errors here as connection failures can be handled at a higher level
  183.     $this->smtp_conn = @stream_socket_client($host.":".$port$errno$errstr$timeoutSTREAM_CLIENT_CONNECT$socket_context);
  184.  
  185.     // Verify we connected properly
  186.     if(empty($this->smtp_conn)) {
  187.       $this->error = array('error' => 'Failed to connect to server',
  188.                            'errno' => $errno,
  189.                            'errstr' => $errstr);
  190.       if($this->do_debug >= 1{
  191.         $this->edebug('SMTP -> ERROR: ' $this->error['error'"$errstr ($errno)");
  192.       }
  193.       return false;
  194.     }
  195.  
  196.     // SMTP server can take longer to respond, give longer timeout for first read
  197.     // Windows does not have support for this timeout function
  198.     if(substr(PHP_OS03!= 'WIN'{
  199.       $max ini_get('max_execution_time');
  200.       if ($max != && $timeout $max// Don't bother if unlimited
  201.         @set_time_limit($timeout);
  202.       }
  203.       stream_set_timeout($this->smtp_conn$timeout0);
  204.     }
  205.  
  206.     // get any announcement
  207.     $announce $this->get_lines();
  208.  
  209.     if($this->do_debug >= 2{
  210.       $this->edebug('SMTP -> FROM SERVER:' $announce);
  211.     }
  212.  
  213.     return true;
  214.   }
  215.  
  216.   /**
  217.    * Initiate a TLS communication with the server.
  218.    *
  219.    * SMTP CODE 220 Ready to start TLS
  220.    * SMTP CODE 501 Syntax error (no parameters allowed)
  221.    * SMTP CODE 454 TLS not available due to temporary reason
  222.    * @access public
  223.    * @return bool success
  224.    */
  225.   public function StartTLS({
  226.     $this->error = null# to avoid confusion
  227.  
  228.     if(!$this->connected()) {
  229.       $this->error = array('error' => 'Called StartTLS() without being connected');
  230.       return false;
  231.     }
  232.  
  233.     $this->client_send('STARTTLS' $this->CRLF);
  234.  
  235.     $rply $this->get_lines();
  236.     $code substr($rply03);
  237.  
  238.     if($this->do_debug >= 2{
  239.       $this->edebug('SMTP -> FROM SERVER:' $rply);
  240.     }
  241.  
  242.     if($code != 220{
  243.       $this->error =
  244.          array('error'     => 'STARTTLS not accepted from server',
  245.                'smtp_code' => $code,
  246.                'smtp_msg'  => substr($rply4));
  247.       if($this->do_debug >= 1{
  248.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  249.       }
  250.       return false;
  251.     }
  252.  
  253.     // Begin encrypted connection
  254.     if(!stream_socket_enable_crypto($this->smtp_conntrueSTREAM_CRYPTO_METHOD_TLS_CLIENT)) {
  255.       return false;
  256.     }
  257.  
  258.     return true;
  259.   }
  260.  
  261.   /**
  262.    * Performs SMTP authentication.  Must be run after running the
  263.    * Hello() method.  Returns true if successfully authenticated.
  264.    * @access public
  265.    * @param string $username 
  266.    * @param string $password 
  267.    * @param string $authtype 
  268.    * @param string $realm 
  269.    * @param string $workstation 
  270.    * @return bool 
  271.    */
  272.   public function Authenticate($username$password$authtype='LOGIN'$realm=''$workstation=''{
  273.     if (empty($authtype)) {
  274.       $authtype 'LOGIN';
  275.     }
  276.  
  277.     switch ($authtype{
  278.       case 'PLAIN':
  279.         // Start authentication
  280.         $this->client_send('AUTH PLAIN' $this->CRLF);
  281.  
  282.         $rply $this->get_lines();
  283.         $code substr($rply03);
  284.  
  285.         if($code != 334{
  286.           $this->error =
  287.             array('error' => 'AUTH not accepted from server',
  288.                   'smtp_code' => $code,
  289.                   'smtp_msg' => substr($rply4));
  290.           if($this->do_debug >= 1{
  291.             $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  292.           }
  293.           return false;
  294.         }
  295.         // Send encoded username and password
  296.           $this->client_send(base64_encode("\0".$username."\0".$password$this->CRLF);
  297.  
  298.         $rply $this->get_lines();
  299.         $code substr($rply03);
  300.  
  301.         if($code != 235{
  302.           $this->error =
  303.             array('error' => 'Authentication not accepted from server',
  304.                   'smtp_code' => $code,
  305.                   'smtp_msg' => substr($rply4));
  306.           if($this->do_debug >= 1{
  307.             $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  308.           }
  309.           return false;
  310.         }
  311.         break;
  312.       case 'LOGIN':
  313.         // Start authentication
  314.         $this->client_send('AUTH LOGIN' $this->CRLF);
  315.  
  316.         $rply $this->get_lines();
  317.         $code substr($rply03);
  318.  
  319.         if($code != 334{
  320.           $this->error =
  321.             array('error' => 'AUTH not accepted from server',
  322.                   'smtp_code' => $code,
  323.                   'smtp_msg' => substr($rply4));
  324.           if($this->do_debug >= 1{
  325.             $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  326.           }
  327.           return false;
  328.         }
  329.  
  330.         // Send encoded username
  331.         $this->client_send(base64_encode($username$this->CRLF);
  332.  
  333.         $rply $this->get_lines();
  334.         $code substr($rply03);
  335.  
  336.         if($code != 334{
  337.           $this->error =
  338.             array('error' => 'Username not accepted from server',
  339.                   'smtp_code' => $code,
  340.                   'smtp_msg' => substr($rply4));
  341.           if($this->do_debug >= 1{
  342.             $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  343.           }
  344.           return false;
  345.         }
  346.  
  347.         // Send encoded password
  348.         $this->client_send(base64_encode($password$this->CRLF);
  349.  
  350.         $rply $this->get_lines();
  351.         $code substr($rply03);
  352.  
  353.         if($code != 235{
  354.           $this->error =
  355.             array('error' => 'Password not accepted from server',
  356.                   'smtp_code' => $code,
  357.                   'smtp_msg' => substr($rply4));
  358.           if($this->do_debug >= 1{
  359.             $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  360.           }
  361.           return false;
  362.         }
  363.         break;
  364.       case 'NTLM':
  365.         /*
  366.          * ntlm_sasl_client.php
  367.          ** Bundled with Permission
  368.          **
  369.          ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
  370.          ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
  371.          */
  372.         if (file_exists('extras/ntlm_sasl_client.php')) {
  373.          require_once 'extras/ntlm_sasl_client.php';
  374.         }
  375.         $temp new stdClass();
  376.         $ntlm_client new ntlm_sasl_client_class;
  377.         if($ntlm_client->Initialize($temp)){//let's test if every function its available
  378.             $this->error = array('error' => $temp->error);
  379.             if($this->do_debug >= 1{
  380.                 $this->edebug('You need to enable some modules in your php.ini file: ' $this->error['error']);
  381.             }
  382.             return false;
  383.         }
  384.         $msg1 $ntlm_client->TypeMsg1($realm$workstation);//msg1
  385.  
  386.         $this->client_send('AUTH NTLM ' base64_encode($msg1$this->CRLF);
  387.  
  388.         $rply $this->get_lines();
  389.         $code substr($rply03);
  390.  
  391.         if($code != 334{
  392.             $this->error =
  393.                 array('error' => 'AUTH not accepted from server',
  394.                       'smtp_code' => $code,
  395.                       'smtp_msg' => substr($rply4));
  396.             if($this->do_debug >= 1{
  397.                 $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  398.             }
  399.             return false;
  400.         }
  401.  
  402.         $challenge substr($rply3);//though 0 based, there is a white space after the 3 digit number....//msg2
  403.         $challenge base64_decode($challenge);
  404.         $ntlm_res $ntlm_client->NTLMResponse(substr($challenge248)$password);
  405.         $msg3 $ntlm_client->TypeMsg3($ntlm_res$username$realm$workstation);//msg3
  406.         // Send encoded username
  407.         $this->client_send(base64_encode($msg3$this->CRLF);
  408.  
  409.         $rply $this->get_lines();
  410.         $code substr($rply03);
  411.  
  412.         if($code != 235{
  413.             $this->error =
  414.                 array('error' => 'Could not authenticate',
  415.                       'smtp_code' => $code,
  416.                       'smtp_msg' => substr($rply4));
  417.             if($this->do_debug >= 1{
  418.                 $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  419.             }
  420.             return false;
  421.         }
  422.         break;
  423.       case 'CRAM-MD5':
  424.         // Start authentication
  425.         $this->client_send('AUTH CRAM-MD5' $this->CRLF);
  426.  
  427.         $rply $this->get_lines();
  428.         $code substr($rply03);
  429.  
  430.         if($code != 334{
  431.           $this->error =
  432.             array('error' => 'AUTH not accepted from server',
  433.                   'smtp_code' => $code,
  434.                   'smtp_msg' => substr($rply4));
  435.           if($this->do_debug >= 1{
  436.             $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  437.           }
  438.           return false;
  439.         }
  440.  
  441.         // Get the challenge
  442.         $challenge base64_decode(substr($rply4));
  443.  
  444.         // Build the response
  445.         $response $username ' ' $this->hmac($challenge$password);
  446.  
  447.         // Send encoded credentials
  448.         $this->client_send(base64_encode($response$this->CRLF);
  449.  
  450.         $rply $this->get_lines();
  451.         $code substr($rply03);
  452.  
  453.         if($code != 235{
  454.           $this->error =
  455.             array('error' => 'Credentials not accepted from server',
  456.                   'smtp_code' => $code,
  457.                   'smtp_msg' => substr($rply4));
  458.           if($this->do_debug >= 1{
  459.             $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  460.           }
  461.           return false;
  462.         }
  463.         break;
  464.     }
  465.     return true;
  466.   }
  467.  
  468.   /**
  469.    * Works like hash_hmac('md5', $data, $key) in case that function is not available
  470.    * @access protected
  471.    * @param string $data 
  472.    * @param string $key 
  473.    * @return string 
  474.    */
  475.   protected function hmac($data$key{
  476.       if (function_exists('hash_hmac')) {
  477.           return hash_hmac('md5'$data$key);
  478.       }
  479.  
  480.       // The following borrowed from http://php.net/manual/en/function.mhash.php#27225
  481.  
  482.       // RFC 2104 HMAC implementation for php.
  483.       // Creates an md5 HMAC.
  484.       // Eliminates the need to install mhash to compute a HMAC
  485.       // Hacked by Lance Rushing
  486.  
  487.       $b 64// byte length for md5
  488.       if (strlen($key$b{
  489.           $key pack('H*'md5($key));
  490.       }
  491.       $key  str_pad($key$bchr(0x00));
  492.       $ipad str_pad(''$bchr(0x36));
  493.       $opad str_pad(''$bchr(0x5c));
  494.       $k_ipad $key $ipad ;
  495.       $k_opad $key $opad;
  496.  
  497.       return md5($k_opad  pack('H*'md5($k_ipad $data)));
  498.   }
  499.  
  500.   /**
  501.    * Returns true if connected to a server otherwise false
  502.    * @access public
  503.    * @return bool 
  504.    */
  505.   public function Connected({
  506.     if(!empty($this->smtp_conn)) {
  507.       $sock_status stream_get_meta_data($this->smtp_conn);
  508.       if($sock_status['eof']{
  509.         // the socket is valid but we are not connected
  510.         if($this->do_debug >= 1{
  511.             $this->edebug('SMTP -> NOTICE: EOF caught while checking if connected');
  512.         }
  513.         $this->Close();
  514.         return false;
  515.       }
  516.       return true// everything looks good
  517.     }
  518.     return false;
  519.   }
  520.  
  521.   /**
  522.    * Closes the socket and cleans up the state of the class.
  523.    * It is not considered good to use this function without
  524.    * first trying to use QUIT.
  525.    * @access public
  526.    * @return void 
  527.    */
  528.   public function Close({
  529.     $this->error = null// so there is no confusion
  530.     $this->helo_rply = null;
  531.     if(!empty($this->smtp_conn)) {
  532.       // close the connection and cleanup
  533.       fclose($this->smtp_conn);
  534.       $this->smtp_conn = 0;
  535.     }
  536.   }
  537.  
  538.   /////////////////////////////////////////////////
  539.   // SMTP COMMANDS
  540.   /////////////////////////////////////////////////
  541.  
  542.   /**
  543.    * Issues a data command and sends the msg_data to the server
  544.    * finializing the mail transaction. $msg_data is the message
  545.    * that is to be send with the headers. Each header needs to be
  546.    * on a single line followed by a <CRLF> with the message headers
  547.    * and the message body being separated by and additional <CRLF>.
  548.    *
  549.    * Implements rfc 821: DATA <CRLF>
  550.    *
  551.    * SMTP CODE INTERMEDIATE: 354
  552.    *     [data]
  553.    *     <CRLF>.<CRLF>
  554.    *     SMTP CODE SUCCESS: 250
  555.    *     SMTP CODE FAILURE: 552, 554, 451, 452
  556.    * SMTP CODE FAILURE: 451, 554
  557.    * SMTP CODE ERROR  : 500, 501, 503, 421
  558.    * @access public
  559.    * @param string $msg_data 
  560.    * @return bool 
  561.    */
  562.   public function Data($msg_data{
  563.     $this->error = null// so no confusion is caused
  564.  
  565.     if(!$this->connected()) {
  566.       $this->error = array(
  567.               'error' => 'Called Data() without being connected');
  568.       return false;
  569.     }
  570.  
  571.     $this->client_send('DATA' $this->CRLF);
  572.  
  573.     $rply $this->get_lines();
  574.     $code substr($rply03);
  575.  
  576.     if($this->do_debug >= 2{
  577.       $this->edebug('SMTP -> FROM SERVER:' $rply);
  578.     }
  579.  
  580.     if($code != 354{
  581.       $this->error =
  582.         array('error' => 'DATA command not accepted from server',
  583.               'smtp_code' => $code,
  584.               'smtp_msg' => substr($rply4));
  585.       if($this->do_debug >= 1{
  586.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  587.       }
  588.       return false;
  589.     }
  590.  
  591.     /* the server is ready to accept data!
  592.      * according to rfc 821 we should not send more than 1000
  593.      * including the CRLF
  594.      * characters on a single line so we will break the data up
  595.      * into lines by \r and/or \n then if needed we will break
  596.      * each of those into smaller lines to fit within the limit.
  597.      * in addition we will be looking for lines that start with
  598.      * a period '.' and append and additional period '.' to that
  599.      * line. NOTE: this does not count towards limit.
  600.      */
  601.  
  602.     // normalize the line breaks so we know the explode works
  603.     $msg_data str_replace("\r\n""\n"$msg_data);
  604.     $msg_data str_replace("\r""\n"$msg_data);
  605.     $lines explode("\n"$msg_data);
  606.  
  607.     /* we need to find a good way to determine is headers are
  608.      * in the msg_data or if it is a straight msg body
  609.      * currently I am assuming rfc 822 definitions of msg headers
  610.      * and if the first field of the first line (':' sperated)
  611.      * does not contain a space then it _should_ be a header
  612.      * and we can process all lines before a blank "" line as
  613.      * headers.
  614.      */
  615.  
  616.     $field substr($lines[0]0strpos($lines[0]':'));
  617.     $in_headers false;
  618.     if(!empty($field&& !strstr($field' ')) {
  619.       $in_headers true;
  620.     }
  621.  
  622.     $max_line_length 998// used below; set here for ease in change
  623.  
  624.     while(list($line@each($lines)) {
  625.       $lines_out null;
  626.       if($line == '' && $in_headers{
  627.         $in_headers false;
  628.       }
  629.       // ok we need to break this line up into several smaller lines
  630.       while(strlen($line$max_line_length{
  631.         $pos strrpos(substr($line0$max_line_length)' ');
  632.  
  633.         // Patch to fix DOS attack
  634.         if(!$pos{
  635.           $pos $max_line_length 1;
  636.           $lines_out[substr($line0$pos);
  637.           $line substr($line$pos);
  638.         else {
  639.           $lines_out[substr($line0$pos);
  640.           $line substr($line$pos 1);
  641.         }
  642.  
  643.         /* if processing headers add a LWSP-char to the front of new line
  644.          * rfc 822 on long msg headers
  645.          */
  646.         if($in_headers{
  647.           $line "\t" $line;
  648.         }
  649.       }
  650.       $lines_out[$line;
  651.  
  652.       // send the lines to the server
  653.       while(list($line_out@each($lines_out)) {
  654.         if(strlen($line_out0)
  655.         {
  656.           if(substr($line_out01== '.'{
  657.             $line_out '.' $line_out;
  658.           }
  659.         }
  660.         $this->client_send($line_out $this->CRLF);
  661.       }
  662.     }
  663.  
  664.     // message data has been sent
  665.     $this->client_send($this->CRLF . '.' $this->CRLF);
  666.  
  667.     $rply $this->get_lines();
  668.     $code substr($rply03);
  669.  
  670.     if($this->do_debug >= 2{
  671.       $this->edebug('SMTP -> FROM SERVER:' $rply);
  672.     }
  673.  
  674.     if($code != 250{
  675.       $this->error =
  676.         array('error' => 'DATA not accepted from server',
  677.               'smtp_code' => $code,
  678.               'smtp_msg' => substr($rply4));
  679.       if($this->do_debug >= 1{
  680.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  681.       }
  682.       return false;
  683.     }
  684.     return true;
  685.   }
  686.  
  687.   /**
  688.    * Sends the HELO command to the smtp server.
  689.    * This makes sure that we and the server are in
  690.    * the same known state.
  691.    *
  692.    * Implements from rfc 821: HELO <SP> <domain> <CRLF>
  693.    *
  694.    * SMTP CODE SUCCESS: 250
  695.    * SMTP CODE ERROR  : 500, 501, 504, 421
  696.    * @access public
  697.    * @param string $host 
  698.    * @return bool 
  699.    */
  700.   public function Hello($host ''{
  701.     $this->error = null// so no confusion is caused
  702.  
  703.     if(!$this->connected()) {
  704.       $this->error = array(
  705.             'error' => 'Called Hello() without being connected');
  706.       return false;
  707.     }
  708.  
  709.     // if hostname for HELO was not specified send default
  710.     if(empty($host)) {
  711.       // determine appropriate default to send to server
  712.       $host 'localhost';
  713.     }
  714.  
  715.     // Send extended hello first (RFC 2821)
  716.     if(!$this->SendHello('EHLO'$host)) {
  717.       if(!$this->SendHello('HELO'$host)) {
  718.         return false;
  719.       }
  720.     }
  721.  
  722.     return true;
  723.   }
  724.  
  725.   /**
  726.    * Sends a HELO/EHLO command.
  727.    * @access protected
  728.    * @param string $hello 
  729.    * @param string $host 
  730.    * @return bool 
  731.    */
  732.   protected function SendHello($hello$host{
  733.     $this->client_send($hello ' ' $host $this->CRLF);
  734.  
  735.     $rply $this->get_lines();
  736.     $code substr($rply03);
  737.  
  738.     if($this->do_debug >= 2{
  739.       $this->edebug('SMTP -> FROM SERVER: ' $rply);
  740.     }
  741.  
  742.     if($code != 250{
  743.       $this->error =
  744.         array('error' => $hello ' not accepted from server',
  745.               'smtp_code' => $code,
  746.               'smtp_msg' => substr($rply4));
  747.       if($this->do_debug >= 1{
  748.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  749.       }
  750.       return false;
  751.     }
  752.  
  753.     $this->helo_rply = $rply;
  754.  
  755.     return true;
  756.   }
  757.  
  758.   /**
  759.    * Starts a mail transaction from the email address specified in
  760.    * $from. Returns true if successful or false otherwise. If True
  761.    * the mail transaction is started and then one or more Recipient
  762.    * commands may be called followed by a Data command.
  763.    *
  764.    * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  765.    *
  766.    * SMTP CODE SUCCESS: 250
  767.    * SMTP CODE SUCCESS: 552, 451, 452
  768.    * SMTP CODE SUCCESS: 500, 501, 421
  769.    * @access public
  770.    * @param string $from 
  771.    * @return bool 
  772.    */
  773.   public function Mail($from{
  774.     $this->error = null// so no confusion is caused
  775.  
  776.     if(!$this->connected()) {
  777.       $this->error = array(
  778.               'error' => 'Called Mail() without being connected');
  779.       return false;
  780.     }
  781.  
  782.     $useVerp ($this->do_verp ? ' XVERP' '');
  783.     $this->client_send('MAIL FROM:<' $from '>' $useVerp $this->CRLF);
  784.  
  785.     $rply $this->get_lines();
  786.     $code substr($rply03);
  787.  
  788.     if($this->do_debug >= 2{
  789.       $this->edebug('SMTP -> FROM SERVER:' $rply);
  790.     }
  791.  
  792.     if($code != 250{
  793.       $this->error =
  794.         array('error' => 'MAIL not accepted from server',
  795.               'smtp_code' => $code,
  796.               'smtp_msg' => substr($rply4));
  797.       if($this->do_debug >= 1{
  798.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  799.       }
  800.       return false;
  801.     }
  802.     return true;
  803.   }
  804.  
  805.   /**
  806.    * Sends the quit command to the server and then closes the socket
  807.    * if there is no error or the $close_on_error argument is true.
  808.    *
  809.    * Implements from rfc 821: QUIT <CRLF>
  810.    *
  811.    * SMTP CODE SUCCESS: 221
  812.    * SMTP CODE ERROR  : 500
  813.    * @access public
  814.    * @param bool $close_on_error 
  815.    * @return bool 
  816.    */
  817.   public function Quit($close_on_error true{
  818.     $this->error = null// so there is no confusion
  819.  
  820.     if(!$this->connected()) {
  821.       $this->error = array(
  822.               'error' => 'Called Quit() without being connected');
  823.       return false;
  824.     }
  825.  
  826.     // send the quit command to the server
  827.     $this->client_send('quit' $this->CRLF);
  828.  
  829.     // get any good-bye messages
  830.     $byemsg $this->get_lines();
  831.  
  832.     if($this->do_debug >= 2{
  833.       $this->edebug('SMTP -> FROM SERVER:' $byemsg);
  834.     }
  835.  
  836.     $rval true;
  837.     $e null;
  838.  
  839.     $code substr($byemsg03);
  840.     if($code != 221{
  841.       // use e as a tmp var cause Close will overwrite $this->error
  842.       $e array('error' => 'SMTP server rejected quit command',
  843.                  'smtp_code' => $code,
  844.                  'smtp_rply' => substr($byemsg4));
  845.       $rval false;
  846.       if($this->do_debug >= 1{
  847.         $this->edebug('SMTP -> ERROR: ' $e['error'': ' $byemsg);
  848.       }
  849.     }
  850.  
  851.     if(empty($e|| $close_on_error{
  852.       $this->Close();
  853.     }
  854.  
  855.     return $rval;
  856.   }
  857.  
  858.   /**
  859.    * Sends the command RCPT to the SMTP server with the TO: argument of $to.
  860.    * Returns true if the recipient was accepted false if it was rejected.
  861.    *
  862.    * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  863.    *
  864.    * SMTP CODE SUCCESS: 250, 251
  865.    * SMTP CODE FAILURE: 550, 551, 552, 553, 450, 451, 452
  866.    * SMTP CODE ERROR  : 500, 501, 503, 421
  867.    * @access public
  868.    * @param string $to 
  869.    * @return bool 
  870.    */
  871.   public function Recipient($to{
  872.     $this->error = null// so no confusion is caused
  873.  
  874.     if(!$this->connected()) {
  875.       $this->error = array(
  876.               'error' => 'Called Recipient() without being connected');
  877.       return false;
  878.     }
  879.  
  880.     $this->client_send('RCPT TO:<' $to '>' $this->CRLF);
  881.  
  882.     $rply $this->get_lines();
  883.     $code substr($rply03);
  884.  
  885.     if($this->do_debug >= 2{
  886.       $this->edebug('SMTP -> FROM SERVER:' $rply);
  887.     }
  888.  
  889.     if($code != 250 && $code != 251{
  890.       $this->error =
  891.         array('error' => 'RCPT not accepted from server',
  892.               'smtp_code' => $code,
  893.               'smtp_msg' => substr($rply4));
  894.       if($this->do_debug >= 1{
  895.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  896.       }
  897.       return false;
  898.     }
  899.     return true;
  900.   }
  901.  
  902.   /**
  903.    * Sends the RSET command to abort and transaction that is
  904.    * currently in progress. Returns true if successful false
  905.    * otherwise.
  906.    *
  907.    * Implements rfc 821: RSET <CRLF>
  908.    *
  909.    * SMTP CODE SUCCESS: 250
  910.    * SMTP CODE ERROR  : 500, 501, 504, 421
  911.    * @access public
  912.    * @return bool 
  913.    */
  914.   public function Reset({
  915.     $this->error = null// so no confusion is caused
  916.  
  917.     if(!$this->connected()) {
  918.       $this->error = array('error' => 'Called Reset() without being connected');
  919.       return false;
  920.     }
  921.  
  922.     $this->client_send('RSET' $this->CRLF);
  923.  
  924.     $rply $this->get_lines();
  925.     $code substr($rply03);
  926.  
  927.     if($this->do_debug >= 2{
  928.       $this->edebug('SMTP -> FROM SERVER:' $rply);
  929.     }
  930.  
  931.     if($code != 250{
  932.       $this->error =
  933.         array('error' => 'RSET failed',
  934.               'smtp_code' => $code,
  935.               'smtp_msg' => substr($rply4));
  936.       if($this->do_debug >= 1{
  937.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  938.       }
  939.       return false;
  940.     }
  941.  
  942.     return true;
  943.   }
  944.  
  945.   /**
  946.    * Starts a mail transaction from the email address specified in
  947.    * $from. Returns true if successful or false otherwise. If True
  948.    * the mail transaction is started and then one or more Recipient
  949.    * commands may be called followed by a Data command. This command
  950.    * will send the message to the users terminal if they are logged
  951.    * in and send them an email.
  952.    *
  953.    * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  954.    *
  955.    * SMTP CODE SUCCESS: 250
  956.    * SMTP CODE SUCCESS: 552, 451, 452
  957.    * SMTP CODE SUCCESS: 500, 501, 502, 421
  958.    * @access public
  959.    * @param string $from 
  960.    * @return bool 
  961.    */
  962.   public function SendAndMail($from{
  963.     $this->error = null// so no confusion is caused
  964.  
  965.     if(!$this->connected()) {
  966.       $this->error = array(
  967.           'error' => 'Called SendAndMail() without being connected');
  968.       return false;
  969.     }
  970.  
  971.     $this->client_send('SAML FROM:' $from $this->CRLF);
  972.  
  973.     $rply $this->get_lines();
  974.     $code substr($rply03);
  975.  
  976.     if($this->do_debug >= 2{
  977.       $this->edebug('SMTP -> FROM SERVER:' $rply);
  978.     }
  979.  
  980.     if($code != 250{
  981.       $this->error =
  982.         array('error' => 'SAML not accepted from server',
  983.               'smtp_code' => $code,
  984.               'smtp_msg' => substr($rply4));
  985.       if($this->do_debug >= 1{
  986.         $this->edebug('SMTP -> ERROR: ' $this->error['error'': ' $rply);
  987.       }
  988.       return false;
  989.     }
  990.     return true;
  991.   }
  992.  
  993.   /**
  994.    * This is an optional command for SMTP that this class does not
  995.    * support. This method is here to make the RFC821 Definition
  996.    * complete for this class and __may__ be implimented in the future
  997.    *
  998.    * Implements from rfc 821: TURN <CRLF>
  999.    *
  1000.    * SMTP CODE SUCCESS: 250
  1001.    * SMTP CODE FAILURE: 502
  1002.    * SMTP CODE ERROR  : 500, 503
  1003.    * @access public
  1004.    * @return bool 
  1005.    */
  1006.   public function Turn({
  1007.     $this->error = array('error' => 'This method, TURN, of the SMTP '.
  1008.                                     'is not implemented');
  1009.     if($this->do_debug >= 1{
  1010.       $this->edebug('SMTP -> NOTICE: ' $this->error['error']);
  1011.     }
  1012.     return false;
  1013.   }
  1014.  
  1015.   /**
  1016.   * Sends data to the server
  1017.   * @param string $data 
  1018.   * @access public
  1019.   * @return Integer number of bytes sent to the server or FALSE on error
  1020.   */
  1021.   public function client_send($data{
  1022.       if ($this->do_debug >= 1{
  1023.           $this->edebug("CLIENT -> SMTP: $data");
  1024.       }
  1025.       return fwrite($this->smtp_conn$data);
  1026.   }
  1027.  
  1028.   /**
  1029.   * Get the current error
  1030.   * @access public
  1031.   * @return array 
  1032.   */
  1033.   public function getError({
  1034.     return $this->error;
  1035.   }
  1036.  
  1037.   /////////////////////////////////////////////////
  1038.   // INTERNAL FUNCTIONS
  1039.   /////////////////////////////////////////////////
  1040.  
  1041.   /**
  1042.    * Read in as many lines as possible
  1043.    * either before eof or socket timeout occurs on the operation.
  1044.    * With SMTP we can tell if we have more lines to read if the
  1045.    * 4th character is '-' symbol. If it is a space then we don't
  1046.    * need to read anything else.
  1047.    * @access protected
  1048.    * @return string 
  1049.    */
  1050.   protected function get_lines({
  1051.     $data '';
  1052.     $endtime 0;
  1053.     /* If for some reason the fp is bad, don't inf loop */
  1054.     if (!is_resource($this->smtp_conn)) {
  1055.       return $data;
  1056.     }
  1057.     stream_set_timeout($this->smtp_conn$this->Timeout);
  1058.     if ($this->Timelimit > 0{
  1059.       $endtime time($this->Timelimit;
  1060.     }
  1061.     while(is_resource($this->smtp_conn&& !feof($this->smtp_conn)) {
  1062.       $str @fgets($this->smtp_conn515);
  1063.       if($this->do_debug >= 4{
  1064.         $this->edebug("SMTP -> get_lines(): \$data was \"$data\"");
  1065.         $this->edebug("SMTP -> get_lines(): \$str is \"$str\"");
  1066.       }
  1067.       $data .= $str;
  1068.       if($this->do_debug >= 4{
  1069.         $this->edebug("SMTP -> get_lines(): \$data is \"$data\"");
  1070.       }
  1071.       // if 4th character is a space, we are done reading, break the loop
  1072.       if(substr($str31== ' 'break}
  1073.       // Timed-out? Log and break
  1074.       $info stream_get_meta_data($this->smtp_conn);
  1075.       if ($info['timed_out']{
  1076.         if($this->do_debug >= 4{
  1077.           $this->edebug('SMTP -> get_lines(): timed-out (' $this->Timeout . ' seconds)');
  1078.         }
  1079.         break;
  1080.       }
  1081.       // Now check if reads took too long
  1082.       if ($endtime{
  1083.         if (time($endtime{
  1084.           if($this->do_debug >= 4{
  1085.             $this->edebug('SMTP -> get_lines(): timelimit reached (' $this->Timelimit . ' seconds)');
  1086.           }
  1087.           break;
  1088.         }
  1089.       }
  1090.     }
  1091.     return $data;
  1092.   }
  1093.  
  1094. }

Documentation generated on Tue, 19 Nov 2013 15:13:59 +0100 by phpDocumentor 1.4.3