[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * PHPMailer RFC821 SMTP email transport class. 4 * PHP Version 5 5 * @package PHPMailer 6 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project 7 * @author Marcus Bointon (Synchro/coolbru) <[email protected]> 8 * @author Jim Jagielski (jimjag) <[email protected]> 9 * @author Andy Prevost (codeworxtech) <[email protected]> 10 * @author Brent R. Matzelle (original founder) 11 * @copyright 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 RFC821 SMTP email transport class. 22 * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server. 23 * @package PHPMailer 24 * @author Chris Ryan <[email protected]> 25 * @author Marcus Bointon <[email protected]> 26 */ 27 class SMTP 28 { 29 /** 30 * The PHPMailer SMTP version number. 31 * @type string 32 */ 33 const VERSION = '5.2.9'; 34 35 /** 36 * SMTP line break constant. 37 * @type string 38 */ 39 const CRLF = "\r\n"; 40 41 /** 42 * The SMTP port to use if one is not specified. 43 * @type integer 44 */ 45 const DEFAULT_SMTP_PORT = 25; 46 47 /** 48 * The maximum line length allowed by RFC 2822 section 2.1.1 49 * @type integer 50 */ 51 const MAX_LINE_LENGTH = 998; 52 53 /** 54 * Debug level for no output 55 */ 56 const DEBUG_OFF = 0; 57 58 /** 59 * Debug level to show client -> server messages 60 */ 61 const DEBUG_CLIENT = 1; 62 63 /** 64 * Debug level to show client -> server and server -> client messages 65 */ 66 const DEBUG_SERVER = 2; 67 68 /** 69 * Debug level to show connection status, client -> server and server -> client messages 70 */ 71 const DEBUG_CONNECTION = 3; 72 73 /** 74 * Debug level to show all messages 75 */ 76 const DEBUG_LOWLEVEL = 4; 77 78 /** 79 * The PHPMailer SMTP Version number. 80 * @type string 81 * @deprecated Use the `VERSION` constant instead 82 * @see SMTP::VERSION 83 */ 84 public $Version = '5.2.9'; 85 86 /** 87 * SMTP server port number. 88 * @type integer 89 * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead 90 * @see SMTP::DEFAULT_SMTP_PORT 91 */ 92 public $SMTP_PORT = 25; 93 94 /** 95 * SMTP reply line ending. 96 * @type string 97 * @deprecated Use the `CRLF` constant instead 98 * @see SMTP::CRLF 99 */ 100 public $CRLF = "\r\n"; 101 102 /** 103 * Debug output level. 104 * Options: 105 * * self::DEBUG_OFF (`0`) No debug output, default 106 * * self::DEBUG_CLIENT (`1`) Client commands 107 * * self::DEBUG_SERVER (`2`) Client commands and server responses 108 * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status 109 * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages 110 * @type integer 111 */ 112 public $do_debug = self::DEBUG_OFF; 113 114 /** 115 * How to handle debug output. 116 * Options: 117 * * `echo` Output plain-text as-is, appropriate for CLI 118 * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output 119 * * `error_log` Output to error log as configured in php.ini 120 * 121 * Alternatively, you can provide a callable expecting two params: a message string and the debug level: 122 * <code> 123 * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";}; 124 * </code> 125 * @type string|callable 126 */ 127 public $Debugoutput = 'echo'; 128 129 /** 130 * Whether to use VERP. 131 * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path 132 * @link http://www.postfix.org/VERP_README.html Info on VERP 133 * @type boolean 134 */ 135 public $do_verp = false; 136 137 /** 138 * The timeout value for connection, in seconds. 139 * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2 140 * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure. 141 * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2 142 * @type integer 143 */ 144 public $Timeout = 300; 145 146 /** 147 * The SMTP timelimit value for reads, in seconds. 148 * @type integer 149 */ 150 public $Timelimit = 30; 151 152 /** 153 * The socket for the server connection. 154 * @type resource 155 */ 156 protected $smtp_conn; 157 158 /** 159 * Error message, if any, for the last call. 160 * @type array 161 */ 162 protected $error = array(); 163 164 /** 165 * The reply the server sent to us for HELO. 166 * If null, no HELO string has yet been received. 167 * @type string|null 168 */ 169 protected $helo_rply = null; 170 171 /** 172 * The most recent reply received from the server. 173 * @type string 174 */ 175 protected $last_reply = ''; 176 177 /** 178 * Output debugging info via a user-selected method. 179 * @see SMTP::$Debugoutput 180 * @see SMTP::$do_debug 181 * @param string $str Debug string to output 182 * @param integer $level The debug level of this message; see DEBUG_* constants 183 * @return void 184 */ 185 protected function edebug($str, $level = 0) 186 { 187 if ($level > $this->do_debug) { 188 return; 189 } 190 if (is_callable($this->Debugoutput)) { 191 call_user_func($this->Debugoutput, $str, $this->do_debug); 192 return; 193 } 194 switch ($this->Debugoutput) { 195 case 'error_log': 196 //Don't output, just log 197 error_log($str); 198 break; 199 case 'html': 200 //Cleans up output a bit for a better looking, HTML-safe output 201 echo htmlentities( 202 preg_replace('/[\r\n]+/', '', $str), 203 ENT_QUOTES, 204 'UTF-8' 205 ) 206 . "<br>\n"; 207 break; 208 case 'echo': 209 default: 210 //Normalize line breaks 211 $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str); 212 echo gmdate('Y-m-d H:i:s') . "\t" . str_replace( 213 "\n", 214 "\n \t ", 215 trim($str) 216 )."\n"; 217 } 218 } 219 220 /** 221 * Connect to an SMTP server. 222 * @param string $host SMTP server IP or host name 223 * @param integer $port The port number to connect to 224 * @param integer $timeout How long to wait for the connection to open 225 * @param array $options An array of options for stream_context_create() 226 * @access public 227 * @return boolean 228 */ 229 public function connect($host, $port = null, $timeout = 30, $options = array()) 230 { 231 static $streamok; 232 //This is enabled by default since 5.0.0 but some providers disable it 233 //Check this once and cache the result 234 if (is_null($streamok)) { 235 $streamok = function_exists('stream_socket_client'); 236 } 237 // Clear errors to avoid confusion 238 $this->error = array(); 239 // Make sure we are __not__ connected 240 if ($this->connected()) { 241 // Already connected, generate error 242 $this->error = array('error' => 'Already connected to a server'); 243 return false; 244 } 245 if (empty($port)) { 246 $port = self::DEFAULT_SMTP_PORT; 247 } 248 // Connect to the SMTP server 249 $this->edebug( 250 "Connection: opening to $host:$port, t=$timeout, opt=".var_export($options, true), 251 self::DEBUG_CONNECTION 252 ); 253 $errno = 0; 254 $errstr = ''; 255 if ($streamok) { 256 $socket_context = stream_context_create($options); 257 //Suppress errors; connection failures are handled at a higher level 258 $this->smtp_conn = @stream_socket_client( 259 $host . ":" . $port, 260 $errno, 261 $errstr, 262 $timeout, 263 STREAM_CLIENT_CONNECT, 264 $socket_context 265 ); 266 } else { 267 //Fall back to fsockopen which should work in more places, but is missing some features 268 $this->edebug( 269 "Connection: stream_socket_client not available, falling back to fsockopen", 270 self::DEBUG_CONNECTION 271 ); 272 $this->smtp_conn = fsockopen( 273 $host, 274 $port, 275 $errno, 276 $errstr, 277 $timeout 278 ); 279 } 280 // Verify we connected properly 281 if (!is_resource($this->smtp_conn)) { 282 $this->error = array( 283 'error' => 'Failed to connect to server', 284 'errno' => $errno, 285 'errstr' => $errstr 286 ); 287 $this->edebug( 288 'SMTP ERROR: ' . $this->error['error'] 289 . ": $errstr ($errno)", 290 self::DEBUG_CLIENT 291 ); 292 return false; 293 } 294 $this->edebug('Connection: opened', self::DEBUG_CONNECTION); 295 // SMTP server can take longer to respond, give longer timeout for first read 296 // Windows does not have support for this timeout function 297 if (substr(PHP_OS, 0, 3) != 'WIN') { 298 $max = ini_get('max_execution_time'); 299 if ($max != 0 && $timeout > $max) { // Don't bother if unlimited 300 @set_time_limit($timeout); 301 } 302 stream_set_timeout($this->smtp_conn, $timeout, 0); 303 } 304 // Get any announcement 305 $announce = $this->get_lines(); 306 $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER); 307 return true; 308 } 309 310 /** 311 * Initiate a TLS (encrypted) session. 312 * @access public 313 * @return boolean 314 */ 315 public function startTLS() 316 { 317 if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) { 318 return false; 319 } 320 // Begin encrypted connection 321 if (!stream_socket_enable_crypto( 322 $this->smtp_conn, 323 true, 324 STREAM_CRYPTO_METHOD_TLS_CLIENT 325 )) { 326 return false; 327 } 328 return true; 329 } 330 331 /** 332 * Perform SMTP authentication. 333 * Must be run after hello(). 334 * @see hello() 335 * @param string $username The user name 336 * @param string $password The password 337 * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5) 338 * @param string $realm The auth realm for NTLM 339 * @param string $workstation The auth workstation for NTLM 340 * @access public 341 * @return boolean True if successfully authenticated. 342 */ 343 public function authenticate( 344 $username, 345 $password, 346 $authtype = 'LOGIN', 347 $realm = '', 348 $workstation = '' 349 ) { 350 if (empty($authtype)) { 351 $authtype = 'LOGIN'; 352 } 353 switch ($authtype) { 354 case 'PLAIN': 355 // Start authentication 356 if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) { 357 return false; 358 } 359 // Send encoded username and password 360 if (!$this->sendCommand( 361 'User & Password', 362 base64_encode("\0" . $username . "\0" . $password), 363 235 364 ) 365 ) { 366 return false; 367 } 368 break; 369 case 'LOGIN': 370 // Start authentication 371 if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) { 372 return false; 373 } 374 if (!$this->sendCommand("Username", base64_encode($username), 334)) { 375 return false; 376 } 377 if (!$this->sendCommand("Password", base64_encode($password), 235)) { 378 return false; 379 } 380 break; 381 case 'NTLM': 382 /* 383 * ntlm_sasl_client.php 384 * Bundled with Permission 385 * 386 * How to telnet in windows: 387 * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx 388 * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication 389 */ 390 require_once 'extras/ntlm_sasl_client.php'; 391 $temp = new stdClass(); 392 $ntlm_client = new ntlm_sasl_client_class; 393 //Check that functions are available 394 if (!$ntlm_client->Initialize($temp)) { 395 $this->error = array('error' => $temp->error); 396 $this->edebug( 397 'You need to enable some modules in your php.ini file: ' 398 . $this->error['error'], 399 self::DEBUG_CLIENT 400 ); 401 return false; 402 } 403 //msg1 404 $msg1 = $ntlm_client->TypeMsg1($realm, $workstation); //msg1 405 406 if (!$this->sendCommand( 407 'AUTH NTLM', 408 'AUTH NTLM ' . base64_encode($msg1), 409 334 410 ) 411 ) { 412 return false; 413 } 414 //Though 0 based, there is a white space after the 3 digit number 415 //msg2 416 $challenge = substr($this->last_reply, 3); 417 $challenge = base64_decode($challenge); 418 $ntlm_res = $ntlm_client->NTLMResponse( 419 substr($challenge, 24, 8), 420 $password 421 ); 422 //msg3 423 $msg3 = $ntlm_client->TypeMsg3( 424 $ntlm_res, 425 $username, 426 $realm, 427 $workstation 428 ); 429 // send encoded username 430 return $this->sendCommand('Username', base64_encode($msg3), 235); 431 case 'CRAM-MD5': 432 // Start authentication 433 if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) { 434 return false; 435 } 436 // Get the challenge 437 $challenge = base64_decode(substr($this->last_reply, 4)); 438 439 // Build the response 440 $response = $username . ' ' . $this->hmac($challenge, $password); 441 442 // send encoded credentials 443 return $this->sendCommand('Username', base64_encode($response), 235); 444 } 445 return true; 446 } 447 448 /** 449 * Calculate an MD5 HMAC hash. 450 * Works like hash_hmac('md5', $data, $key) 451 * in case that function is not available 452 * @param string $data The data to hash 453 * @param string $key The key to hash with 454 * @access protected 455 * @return string 456 */ 457 protected function hmac($data, $key) 458 { 459 if (function_exists('hash_hmac')) { 460 return hash_hmac('md5', $data, $key); 461 } 462 463 // The following borrowed from 464 // http://php.net/manual/en/function.mhash.php#27225 465 466 // RFC 2104 HMAC implementation for php. 467 // Creates an md5 HMAC. 468 // Eliminates the need to install mhash to compute a HMAC 469 // by Lance Rushing 470 471 $bytelen = 64; // byte length for md5 472 if (strlen($key) > $bytelen) { 473 $key = pack('H*', md5($key)); 474 } 475 $key = str_pad($key, $bytelen, chr(0x00)); 476 $ipad = str_pad('', $bytelen, chr(0x36)); 477 $opad = str_pad('', $bytelen, chr(0x5c)); 478 $k_ipad = $key ^ $ipad; 479 $k_opad = $key ^ $opad; 480 481 return md5($k_opad . pack('H*', md5($k_ipad . $data))); 482 } 483 484 /** 485 * Check connection state. 486 * @access public 487 * @return boolean True if connected. 488 */ 489 public function connected() 490 { 491 if (is_resource($this->smtp_conn)) { 492 $sock_status = stream_get_meta_data($this->smtp_conn); 493 if ($sock_status['eof']) { 494 // The socket is valid but we are not connected 495 $this->edebug( 496 'SMTP NOTICE: EOF caught while checking if connected', 497 self::DEBUG_CLIENT 498 ); 499 $this->close(); 500 return false; 501 } 502 return true; // everything looks good 503 } 504 return false; 505 } 506 507 /** 508 * Close the socket and clean up the state of the class. 509 * Don't use this function without first trying to use QUIT. 510 * @see quit() 511 * @access public 512 * @return void 513 */ 514 public function close() 515 { 516 $this->error = array(); 517 $this->helo_rply = null; 518 if (is_resource($this->smtp_conn)) { 519 // close the connection and cleanup 520 fclose($this->smtp_conn); 521 $this->smtp_conn = null; //Makes for cleaner serialization 522 $this->edebug('Connection: closed', self::DEBUG_CONNECTION); 523 } 524 } 525 526 /** 527 * Send an SMTP DATA command. 528 * Issues a data command and sends the msg_data to the server, 529 * finializing the mail transaction. $msg_data is the message 530 * that is to be send with the headers. Each header needs to be 531 * on a single line followed by a <CRLF> with the message headers 532 * and the message body being separated by and additional <CRLF>. 533 * Implements rfc 821: DATA <CRLF> 534 * @param string $msg_data Message data to send 535 * @access public 536 * @return boolean 537 */ 538 public function data($msg_data) 539 { 540 if (!$this->sendCommand('DATA', 'DATA', 354)) { 541 return false; 542 } 543 /* The server is ready to accept data! 544 * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF) 545 * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into 546 * smaller lines to fit within the limit. 547 * We will also look for lines that start with a '.' and prepend an additional '.'. 548 * NOTE: this does not count towards line-length limit. 549 */ 550 551 // Normalize line breaks before exploding 552 $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data)); 553 554 /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field 555 * of the first line (':' separated) does not contain a space then it _should_ be a header and we will 556 * process all lines before a blank line as headers. 557 */ 558 559 $field = substr($lines[0], 0, strpos($lines[0], ':')); 560 $in_headers = false; 561 if (!empty($field) && strpos($field, ' ') === false) { 562 $in_headers = true; 563 } 564 565 foreach ($lines as $line) { 566 $lines_out = array(); 567 if ($in_headers and $line == '') { 568 $in_headers = false; 569 } 570 // ok we need to break this line up into several smaller lines 571 //This is a small micro-optimisation: isset($str[$len]) is equivalent to (strlen($str) > $len) 572 while (isset($line[self::MAX_LINE_LENGTH])) { 573 //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on 574 //so as to avoid breaking in the middle of a word 575 $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' '); 576 if (!$pos) { //Deliberately matches both false and 0 577 //No nice break found, add a hard break 578 $pos = self::MAX_LINE_LENGTH - 1; 579 $lines_out[] = substr($line, 0, $pos); 580 $line = substr($line, $pos); 581 } else { 582 //Break at the found point 583 $lines_out[] = substr($line, 0, $pos); 584 //Move along by the amount we dealt with 585 $line = substr($line, $pos + 1); 586 } 587 /* If processing headers add a LWSP-char to the front of new line 588 * RFC822 section 3.1.1 589 */ 590 if ($in_headers) { 591 $line = "\t" . $line; 592 } 593 } 594 $lines_out[] = $line; 595 596 // Send the lines to the server 597 foreach ($lines_out as $line_out) { 598 //RFC2821 section 4.5.2 599 if (!empty($line_out) and $line_out[0] == '.') { 600 $line_out = '.' . $line_out; 601 } 602 $this->client_send($line_out . self::CRLF); 603 } 604 } 605 606 // Message data has been sent, complete the command 607 return $this->sendCommand('DATA END', '.', 250); 608 } 609 610 /** 611 * Send an SMTP HELO or EHLO command. 612 * Used to identify the sending server to the receiving server. 613 * This makes sure that client and server are in a known state. 614 * Implements RFC 821: HELO <SP> <domain> <CRLF> 615 * and RFC 2821 EHLO. 616 * @param string $host The host name or IP to connect to 617 * @access public 618 * @return boolean 619 */ 620 public function hello($host = '') 621 { 622 // Try extended hello first (RFC 2821) 623 return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host)); 624 } 625 626 /** 627 * Send an SMTP HELO or EHLO command. 628 * Low-level implementation used by hello() 629 * @see hello() 630 * @param string $hello The HELO string 631 * @param string $host The hostname to say we are 632 * @access protected 633 * @return boolean 634 */ 635 protected function sendHello($hello, $host) 636 { 637 $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250); 638 $this->helo_rply = $this->last_reply; 639 return $noerror; 640 } 641 642 /** 643 * Send an SMTP MAIL command. 644 * Starts a mail transaction from the email address specified in 645 * $from. Returns true if successful or false otherwise. If True 646 * the mail transaction is started and then one or more recipient 647 * commands may be called followed by a data command. 648 * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF> 649 * @param string $from Source address of this message 650 * @access public 651 * @return boolean 652 */ 653 public function mail($from) 654 { 655 $useVerp = ($this->do_verp ? ' XVERP' : ''); 656 return $this->sendCommand( 657 'MAIL FROM', 658 'MAIL FROM:<' . $from . '>' . $useVerp, 659 250 660 ); 661 } 662 663 /** 664 * Send an SMTP QUIT command. 665 * Closes the socket if there is no error or the $close_on_error argument is true. 666 * Implements from rfc 821: QUIT <CRLF> 667 * @param boolean $close_on_error Should the connection close if an error occurs? 668 * @access public 669 * @return boolean 670 */ 671 public function quit($close_on_error = true) 672 { 673 $noerror = $this->sendCommand('QUIT', 'QUIT', 221); 674 $err = $this->error; //Save any error 675 if ($noerror or $close_on_error) { 676 $this->close(); 677 $this->error = $err; //Restore any error from the quit command 678 } 679 return $noerror; 680 } 681 682 /** 683 * Send an SMTP RCPT command. 684 * Sets the TO argument to $toaddr. 685 * Returns true if the recipient was accepted false if it was rejected. 686 * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF> 687 * @param string $toaddr The address the message is being sent to 688 * @access public 689 * @return boolean 690 */ 691 public function recipient($toaddr) 692 { 693 return $this->sendCommand( 694 'RCPT TO', 695 'RCPT TO:<' . $toaddr . '>', 696 array(250, 251) 697 ); 698 } 699 700 /** 701 * Send an SMTP RSET command. 702 * Abort any transaction that is currently in progress. 703 * Implements rfc 821: RSET <CRLF> 704 * @access public 705 * @return boolean True on success. 706 */ 707 public function reset() 708 { 709 return $this->sendCommand('RSET', 'RSET', 250); 710 } 711 712 /** 713 * Send a command to an SMTP server and check its return code. 714 * @param string $command The command name - not sent to the server 715 * @param string $commandstring The actual command to send 716 * @param integer|array $expect One or more expected integer success codes 717 * @access protected 718 * @return boolean True on success. 719 */ 720 protected function sendCommand($command, $commandstring, $expect) 721 { 722 if (!$this->connected()) { 723 $this->error = array( 724 'error' => "Called $command without being connected" 725 ); 726 return false; 727 } 728 $this->client_send($commandstring . self::CRLF); 729 730 $this->last_reply = $this->get_lines(); 731 $code = substr($this->last_reply, 0, 3); 732 733 $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER); 734 735 if (!in_array($code, (array)$expect)) { 736 $this->error = array( 737 'error' => "$command command failed", 738 'smtp_code' => $code, 739 'detail' => substr($this->last_reply, 4) 740 ); 741 $this->edebug( 742 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply, 743 self::DEBUG_CLIENT 744 ); 745 return false; 746 } 747 748 $this->error = array(); 749 return true; 750 } 751 752 /** 753 * Send an SMTP SAML command. 754 * Starts a mail transaction from the email address specified in $from. 755 * Returns true if successful or false otherwise. If True 756 * the mail transaction is started and then one or more recipient 757 * commands may be called followed by a data command. This command 758 * will send the message to the users terminal if they are logged 759 * in and send them an email. 760 * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF> 761 * @param string $from The address the message is from 762 * @access public 763 * @return boolean 764 */ 765 public function sendAndMail($from) 766 { 767 return $this->sendCommand('SAML', "SAML FROM:$from", 250); 768 } 769 770 /** 771 * Send an SMTP VRFY command. 772 * @param string $name The name to verify 773 * @access public 774 * @return boolean 775 */ 776 public function verify($name) 777 { 778 return $this->sendCommand('VRFY', "VRFY $name", array(250, 251)); 779 } 780 781 /** 782 * Send an SMTP NOOP command. 783 * Used to keep keep-alives alive, doesn't actually do anything 784 * @access public 785 * @return boolean 786 */ 787 public function noop() 788 { 789 return $this->sendCommand('NOOP', 'NOOP', 250); 790 } 791 792 /** 793 * Send an SMTP TURN command. 794 * This is an optional command for SMTP that this class does not support. 795 * This method is here to make the RFC821 Definition complete for this class 796 * and _may_ be implemented in future 797 * Implements from rfc 821: TURN <CRLF> 798 * @access public 799 * @return boolean 800 */ 801 public function turn() 802 { 803 $this->error = array( 804 'error' => 'The SMTP TURN command is not implemented' 805 ); 806 $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT); 807 return false; 808 } 809 810 /** 811 * Send raw data to the server. 812 * @param string $data The data to send 813 * @access public 814 * @return integer|boolean The number of bytes sent to the server or false on error 815 */ 816 public function client_send($data) 817 { 818 $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT); 819 return fwrite($this->smtp_conn, $data); 820 } 821 822 /** 823 * Get the latest error. 824 * @access public 825 * @return array 826 */ 827 public function getError() 828 { 829 return $this->error; 830 } 831 832 /** 833 * Get the last reply from the server. 834 * @access public 835 * @return string 836 */ 837 public function getLastReply() 838 { 839 return $this->last_reply; 840 } 841 842 /** 843 * Read the SMTP server's response. 844 * Either before eof or socket timeout occurs on the operation. 845 * With SMTP we can tell if we have more lines to read if the 846 * 4th character is '-' symbol. If it is a space then we don't 847 * need to read anything else. 848 * @access protected 849 * @return string 850 */ 851 protected function get_lines() 852 { 853 // If the connection is bad, give up straight away 854 if (!is_resource($this->smtp_conn)) { 855 return ''; 856 } 857 $data = ''; 858 $endtime = 0; 859 stream_set_timeout($this->smtp_conn, $this->Timeout); 860 if ($this->Timelimit > 0) { 861 $endtime = time() + $this->Timelimit; 862 } 863 while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) { 864 $str = @fgets($this->smtp_conn, 515); 865 $this->edebug("SMTP -> get_lines(): \$data was \"$data\"", self::DEBUG_LOWLEVEL); 866 $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL); 867 $data .= $str; 868 $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL); 869 // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen 870 if ((isset($str[3]) and $str[3] == ' ')) { 871 break; 872 } 873 // Timed-out? Log and break 874 $info = stream_get_meta_data($this->smtp_conn); 875 if ($info['timed_out']) { 876 $this->edebug( 877 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)', 878 self::DEBUG_LOWLEVEL 879 ); 880 break; 881 } 882 // Now check if reads took too long 883 if ($endtime and time() > $endtime) { 884 $this->edebug( 885 'SMTP -> get_lines(): timelimit reached ('. 886 $this->Timelimit . ' sec)', 887 self::DEBUG_LOWLEVEL 888 ); 889 break; 890 } 891 } 892 return $data; 893 } 894 895 /** 896 * Enable or disable VERP address generation. 897 * @param boolean $enabled 898 */ 899 public function setVerp($enabled = false) 900 { 901 $this->do_verp = $enabled; 902 } 903 904 /** 905 * Get VERP address generation mode. 906 * @return boolean 907 */ 908 public function getVerp() 909 { 910 return $this->do_verp; 911 } 912 913 /** 914 * Set debug output method. 915 * @param string $method The function/method to use for debugging output. 916 */ 917 public function setDebugOutput($method = 'echo') 918 { 919 $this->Debugoutput = $method; 920 } 921 922 /** 923 * Get debug output method. 924 * @return string 925 */ 926 public function getDebugOutput() 927 { 928 return $this->Debugoutput; 929 } 930 931 /** 932 * Set debug output level. 933 * @param integer $level 934 */ 935 public function setDebugLevel($level = 0) 936 { 937 $this->do_debug = $level; 938 } 939 940 /** 941 * Get debug output level. 942 * @return integer 943 */ 944 public function getDebugLevel() 945 { 946 return $this->do_debug; 947 } 948 949 /** 950 * Set SMTP timeout. 951 * @param integer $timeout 952 */ 953 public function setTimeout($timeout = 0) 954 { 955 $this->Timeout = $timeout; 956 } 957 958 /** 959 * Get SMTP timeout. 960 * @return integer 961 */ 962 public function getTimeout() 963 { 964 return $this->Timeout; 965 } 966 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |