|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 /*~ class.smtp.php 00003 .---------------------------------------------------------------------------. 00004 | Software: PHPMailer - PHP email class | 00005 | Version: 5.1 | 00006 | Contact: via sourceforge.net support pages (also www.codeworxtech.com) | 00007 | Info: http://phpmailer.sourceforge.net | 00008 | Support: http://sourceforge.net/projects/phpmailer/ | 00009 | ------------------------------------------------------------------------- | 00010 | Admin: Andy Prevost (project admininistrator) | 00011 | Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net | 00012 | : Marcus Bointon (coolbru) coolbru@users.sourceforge.net | 00013 | Founder: Brent R. Matzelle (original founder) | 00014 | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. | 00015 | Copyright (c) 2001-2003, Brent R. Matzelle | 00016 | ------------------------------------------------------------------------- | 00017 | License: Distributed under the Lesser General Public License (LGPL) | 00018 | http://www.gnu.org/copyleft/lesser.html | 00019 | This program is distributed in the hope that it will be useful - WITHOUT | 00020 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 00021 | FITNESS FOR A PARTICULAR PURPOSE. | 00022 | ------------------------------------------------------------------------- | 00023 | We offer a number of paid services (www.codeworxtech.com): | 00024 | - Web Hosting on highly optimized fast and secure servers | 00025 | - Technology Consulting | 00026 | - Oursourcing (highly qualified programmers and graphic designers) | 00027 '---------------------------------------------------------------------------' 00028 */ 00029 00049 class SMTP { 00054 public $SMTP_PORT = 25; 00055 00060 public $CRLF = "\r\n"; 00061 00066 public $do_debug; // the level of debug to perform 00067 00072 public $do_verp = false; 00073 00075 // PROPERTIES, PRIVATE AND PROTECTED 00077 00078 private $smtp_conn; // the socket to the server 00079 private $error; // error if any on the last call 00080 private $helo_rply; // the reply the server sent to us for HELO 00081 00087 public function __construct() { 00088 $this->smtp_conn = 0; 00089 $this->error = null; 00090 $this->helo_rply = null; 00091 00092 $this->do_debug = 0; 00093 } 00094 00096 // CONNECTION FUNCTIONS 00098 00112 public function Connect($host, $port = 0, $tval = 30) { 00113 // set the error val to null so there is no confusion 00114 $this->error = null; 00115 00116 // make sure we are __not__ connected 00117 if($this->connected()) { 00118 // already connected, generate error 00119 $this->error = array("error" => "Already connected to a server"); 00120 return false; 00121 } 00122 00123 if(empty($port)) { 00124 $port = $this->SMTP_PORT; 00125 } 00126 00127 // connect to the smtp server 00128 $this->smtp_conn = @fsockopen($host, // the host of the server 00129 $port, // the port to use 00130 $errno, // error number if any 00131 $errstr, // error message if any 00132 $tval); // give up after ? secs 00133 // verify we connected properly 00134 if(empty($this->smtp_conn)) { 00135 $this->error = array("error" => "Failed to connect to server", 00136 "errno" => $errno, 00137 "errstr" => $errstr); 00138 if($this->do_debug >= 1) { 00139 echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />'; 00140 } 00141 return false; 00142 } 00143 00144 // SMTP server can take longer to respond, give longer timeout for first read 00145 // Windows does not have support for this timeout function 00146 if(substr(PHP_OS, 0, 3) != "WIN") 00147 socket_set_timeout($this->smtp_conn, $tval, 0); 00148 00149 // get any announcement 00150 $announce = $this->get_lines(); 00151 00152 if($this->do_debug >= 2) { 00153 echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />'; 00154 } 00155 00156 return true; 00157 } 00158 00168 public function StartTLS() { 00169 $this->error = null; # to avoid confusion 00170 00171 if(!$this->connected()) { 00172 $this->error = array("error" => "Called StartTLS() without being connected"); 00173 return false; 00174 } 00175 00176 fputs($this->smtp_conn,"STARTTLS" . $this->CRLF); 00177 00178 $rply = $this->get_lines(); 00179 $code = substr($rply,0,3); 00180 00181 if($this->do_debug >= 2) { 00182 echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />'; 00183 } 00184 00185 if($code != 220) { 00186 $this->error = 00187 array("error" => "STARTTLS not accepted from server", 00188 "smtp_code" => $code, 00189 "smtp_msg" => substr($rply,4)); 00190 if($this->do_debug >= 1) { 00191 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00192 } 00193 return false; 00194 } 00195 00196 // Begin encrypted connection 00197 if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { 00198 return false; 00199 } 00200 00201 return true; 00202 } 00203 00210 public function Authenticate($username, $password) { 00211 // Start authentication 00212 fputs($this->smtp_conn,"AUTH LOGIN" . $this->CRLF); 00213 00214 $rply = $this->get_lines(); 00215 $code = substr($rply,0,3); 00216 00217 if($code != 334) { 00218 $this->error = 00219 array("error" => "AUTH not accepted from server", 00220 "smtp_code" => $code, 00221 "smtp_msg" => substr($rply,4)); 00222 if($this->do_debug >= 1) { 00223 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00224 } 00225 return false; 00226 } 00227 00228 // Send encoded username 00229 fputs($this->smtp_conn, base64_encode($username) . $this->CRLF); 00230 00231 $rply = $this->get_lines(); 00232 $code = substr($rply,0,3); 00233 00234 if($code != 334) { 00235 $this->error = 00236 array("error" => "Username not accepted from server", 00237 "smtp_code" => $code, 00238 "smtp_msg" => substr($rply,4)); 00239 if($this->do_debug >= 1) { 00240 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00241 } 00242 return false; 00243 } 00244 00245 // Send encoded password 00246 fputs($this->smtp_conn, base64_encode($password) . $this->CRLF); 00247 00248 $rply = $this->get_lines(); 00249 $code = substr($rply,0,3); 00250 00251 if($code != 235) { 00252 $this->error = 00253 array("error" => "Password not accepted from server", 00254 "smtp_code" => $code, 00255 "smtp_msg" => substr($rply,4)); 00256 if($this->do_debug >= 1) { 00257 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00258 } 00259 return false; 00260 } 00261 00262 return true; 00263 } 00264 00270 public function Connected() { 00271 if(!empty($this->smtp_conn)) { 00272 $sock_status = socket_get_status($this->smtp_conn); 00273 if($sock_status["eof"]) { 00274 // the socket is valid but we are not connected 00275 if($this->do_debug >= 1) { 00276 echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected"; 00277 } 00278 $this->Close(); 00279 return false; 00280 } 00281 return true; // everything looks good 00282 } 00283 return false; 00284 } 00285 00293 public function Close() { 00294 $this->error = null; // so there is no confusion 00295 $this->helo_rply = null; 00296 if(!empty($this->smtp_conn)) { 00297 // close the connection and cleanup 00298 fclose($this->smtp_conn); 00299 $this->smtp_conn = 0; 00300 } 00301 } 00302 00304 // SMTP COMMANDS 00306 00326 public function Data($msg_data) { 00327 $this->error = null; // so no confusion is caused 00328 00329 if(!$this->connected()) { 00330 $this->error = array( 00331 "error" => "Called Data() without being connected"); 00332 return false; 00333 } 00334 00335 fputs($this->smtp_conn,"DATA" . $this->CRLF); 00336 00337 $rply = $this->get_lines(); 00338 $code = substr($rply,0,3); 00339 00340 if($this->do_debug >= 2) { 00341 echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />'; 00342 } 00343 00344 if($code != 354) { 00345 $this->error = 00346 array("error" => "DATA command not accepted from server", 00347 "smtp_code" => $code, 00348 "smtp_msg" => substr($rply,4)); 00349 if($this->do_debug >= 1) { 00350 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00351 } 00352 return false; 00353 } 00354 00355 /* the server is ready to accept data! 00356 * according to rfc 821 we should not send more than 1000 00357 * including the CRLF 00358 * characters on a single line so we will break the data up 00359 * into lines by \r and/or \n then if needed we will break 00360 * each of those into smaller lines to fit within the limit. 00361 * in addition we will be looking for lines that start with 00362 * a period '.' and append and additional period '.' to that 00363 * line. NOTE: this does not count towards limit. 00364 */ 00365 00366 // normalize the line breaks so we know the explode works 00367 $msg_data = str_replace("\r\n","\n",$msg_data); 00368 $msg_data = str_replace("\r","\n",$msg_data); 00369 $lines = explode("\n",$msg_data); 00370 00371 /* we need to find a good way to determine is headers are 00372 * in the msg_data or if it is a straight msg body 00373 * currently I am assuming rfc 822 definitions of msg headers 00374 * and if the first field of the first line (':' sperated) 00375 * does not contain a space then it _should_ be a header 00376 * and we can process all lines before a blank "" line as 00377 * headers. 00378 */ 00379 00380 $field = substr($lines[0],0,strpos($lines[0],":")); 00381 $in_headers = false; 00382 if(!empty($field) && !strstr($field," ")) { 00383 $in_headers = true; 00384 } 00385 00386 $max_line_length = 998; // used below; set here for ease in change 00387 00388 while(list(,$line) = @each($lines)) { 00389 $lines_out = null; 00390 if($line == "" && $in_headers) { 00391 $in_headers = false; 00392 } 00393 // ok we need to break this line up into several smaller lines 00394 while(strlen($line) > $max_line_length) { 00395 $pos = strrpos(substr($line,0,$max_line_length)," "); 00396 00397 // Patch to fix DOS attack 00398 if(!$pos) { 00399 $pos = $max_line_length - 1; 00400 $lines_out[] = substr($line,0,$pos); 00401 $line = substr($line,$pos); 00402 } else { 00403 $lines_out[] = substr($line,0,$pos); 00404 $line = substr($line,$pos + 1); 00405 } 00406 00407 /* if processing headers add a LWSP-char to the front of new line 00408 * rfc 822 on long msg headers 00409 */ 00410 if($in_headers) { 00411 $line = "\t" . $line; 00412 } 00413 } 00414 $lines_out[] = $line; 00415 00416 // send the lines to the server 00417 while(list(,$line_out) = @each($lines_out)) { 00418 if(strlen($line_out) > 0) 00419 { 00420 if(substr($line_out, 0, 1) == ".") { 00421 $line_out = "." . $line_out; 00422 } 00423 } 00424 fputs($this->smtp_conn,$line_out . $this->CRLF); 00425 } 00426 } 00427 00428 // message data has been sent 00429 fputs($this->smtp_conn, $this->CRLF . "." . $this->CRLF); 00430 00431 $rply = $this->get_lines(); 00432 $code = substr($rply,0,3); 00433 00434 if($this->do_debug >= 2) { 00435 echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />'; 00436 } 00437 00438 if($code != 250) { 00439 $this->error = 00440 array("error" => "DATA not accepted from server", 00441 "smtp_code" => $code, 00442 "smtp_msg" => substr($rply,4)); 00443 if($this->do_debug >= 1) { 00444 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00445 } 00446 return false; 00447 } 00448 return true; 00449 } 00450 00463 public function Hello($host = '') { 00464 $this->error = null; // so no confusion is caused 00465 00466 if(!$this->connected()) { 00467 $this->error = array( 00468 "error" => "Called Hello() without being connected"); 00469 return false; 00470 } 00471 00472 // if hostname for HELO was not specified send default 00473 if(empty($host)) { 00474 // determine appropriate default to send to server 00475 $host = "localhost"; 00476 } 00477 00478 // Send extended hello first (RFC 2821) 00479 if(!$this->SendHello("EHLO", $host)) { 00480 if(!$this->SendHello("HELO", $host)) { 00481 return false; 00482 } 00483 } 00484 00485 return true; 00486 } 00487 00493 private function SendHello($hello, $host) { 00494 fputs($this->smtp_conn, $hello . " " . $host . $this->CRLF); 00495 00496 $rply = $this->get_lines(); 00497 $code = substr($rply,0,3); 00498 00499 if($this->do_debug >= 2) { 00500 echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />'; 00501 } 00502 00503 if($code != 250) { 00504 $this->error = 00505 array("error" => $hello . " not accepted from server", 00506 "smtp_code" => $code, 00507 "smtp_msg" => substr($rply,4)); 00508 if($this->do_debug >= 1) { 00509 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00510 } 00511 return false; 00512 } 00513 00514 $this->helo_rply = $rply; 00515 00516 return true; 00517 } 00518 00533 public function Mail($from) { 00534 $this->error = null; // so no confusion is caused 00535 00536 if(!$this->connected()) { 00537 $this->error = array( 00538 "error" => "Called Mail() without being connected"); 00539 return false; 00540 } 00541 00542 $useVerp = ($this->do_verp ? "XVERP" : ""); 00543 fputs($this->smtp_conn,"MAIL FROM:<" . $from . ">" . $useVerp . $this->CRLF); 00544 00545 $rply = $this->get_lines(); 00546 $code = substr($rply,0,3); 00547 00548 if($this->do_debug >= 2) { 00549 echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />'; 00550 } 00551 00552 if($code != 250) { 00553 $this->error = 00554 array("error" => "MAIL not accepted from server", 00555 "smtp_code" => $code, 00556 "smtp_msg" => substr($rply,4)); 00557 if($this->do_debug >= 1) { 00558 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00559 } 00560 return false; 00561 } 00562 return true; 00563 } 00564 00576 public function Quit($close_on_error = true) { 00577 $this->error = null; // so there is no confusion 00578 00579 if(!$this->connected()) { 00580 $this->error = array( 00581 "error" => "Called Quit() without being connected"); 00582 return false; 00583 } 00584 00585 // send the quit command to the server 00586 fputs($this->smtp_conn,"quit" . $this->CRLF); 00587 00588 // get any good-bye messages 00589 $byemsg = $this->get_lines(); 00590 00591 if($this->do_debug >= 2) { 00592 echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />'; 00593 } 00594 00595 $rval = true; 00596 $e = null; 00597 00598 $code = substr($byemsg,0,3); 00599 if($code != 221) { 00600 // use e as a tmp var cause Close will overwrite $this->error 00601 $e = array("error" => "SMTP server rejected quit command", 00602 "smtp_code" => $code, 00603 "smtp_rply" => substr($byemsg,4)); 00604 $rval = false; 00605 if($this->do_debug >= 1) { 00606 echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />'; 00607 } 00608 } 00609 00610 if(empty($e) || $close_on_error) { 00611 $this->Close(); 00612 } 00613 00614 return $rval; 00615 } 00616 00629 public function Recipient($to) { 00630 $this->error = null; // so no confusion is caused 00631 00632 if(!$this->connected()) { 00633 $this->error = array( 00634 "error" => "Called Recipient() without being connected"); 00635 return false; 00636 } 00637 00638 fputs($this->smtp_conn,"RCPT TO:<" . $to . ">" . $this->CRLF); 00639 00640 $rply = $this->get_lines(); 00641 $code = substr($rply,0,3); 00642 00643 if($this->do_debug >= 2) { 00644 echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />'; 00645 } 00646 00647 if($code != 250 && $code != 251) { 00648 $this->error = 00649 array("error" => "RCPT not accepted from server", 00650 "smtp_code" => $code, 00651 "smtp_msg" => substr($rply,4)); 00652 if($this->do_debug >= 1) { 00653 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00654 } 00655 return false; 00656 } 00657 return true; 00658 } 00659 00672 public function Reset() { 00673 $this->error = null; // so no confusion is caused 00674 00675 if(!$this->connected()) { 00676 $this->error = array( 00677 "error" => "Called Reset() without being connected"); 00678 return false; 00679 } 00680 00681 fputs($this->smtp_conn,"RSET" . $this->CRLF); 00682 00683 $rply = $this->get_lines(); 00684 $code = substr($rply,0,3); 00685 00686 if($this->do_debug >= 2) { 00687 echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />'; 00688 } 00689 00690 if($code != 250) { 00691 $this->error = 00692 array("error" => "RSET failed", 00693 "smtp_code" => $code, 00694 "smtp_msg" => substr($rply,4)); 00695 if($this->do_debug >= 1) { 00696 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00697 } 00698 return false; 00699 } 00700 00701 return true; 00702 } 00703 00720 public function SendAndMail($from) { 00721 $this->error = null; // so no confusion is caused 00722 00723 if(!$this->connected()) { 00724 $this->error = array( 00725 "error" => "Called SendAndMail() without being connected"); 00726 return false; 00727 } 00728 00729 fputs($this->smtp_conn,"SAML FROM:" . $from . $this->CRLF); 00730 00731 $rply = $this->get_lines(); 00732 $code = substr($rply,0,3); 00733 00734 if($this->do_debug >= 2) { 00735 echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />'; 00736 } 00737 00738 if($code != 250) { 00739 $this->error = 00740 array("error" => "SAML not accepted from server", 00741 "smtp_code" => $code, 00742 "smtp_msg" => substr($rply,4)); 00743 if($this->do_debug >= 1) { 00744 echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />'; 00745 } 00746 return false; 00747 } 00748 return true; 00749 } 00750 00764 public function Turn() { 00765 $this->error = array("error" => "This method, TURN, of the SMTP ". 00766 "is not implemented"); 00767 if($this->do_debug >= 1) { 00768 echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />'; 00769 } 00770 return false; 00771 } 00772 00778 public function getError() { 00779 return $this->error; 00780 } 00781 00783 // INTERNAL FUNCTIONS 00785 00795 private function get_lines() { 00796 $data = ""; 00797 while($str = @fgets($this->smtp_conn,515)) { 00798 if($this->do_debug >= 4) { 00799 echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />'; 00800 echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />'; 00801 } 00802 $data .= $str; 00803 if($this->do_debug >= 4) { 00804 echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />'; 00805 } 00806 // if 4th character is a space, we are done reading, break the loop 00807 if(substr($str,3,1) == " ") { break; } 00808 } 00809 return $data; 00810 } 00811 00812 } 00813 00814 ?>