Created
October 27, 2017 07:22
-
-
Save IzzySoft/4b1482b1a441393b447ce57874840bfc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
############################################################################ | |
# smtp mailer # | |
# Written by Itzchak Rehberg <[email protected]> # | |
# ------------------------------------------------ # | |
# This module should replace php´s mail() function. It is fully syntax # | |
# compatible. In addition, when an error occures, a detailed error info # | |
# is stored in the array $smtp->err # | |
# NOTE: Being intended to speak to your "Intranet MailServer", it´s kept # | |
# simple: no TLS etc., just pure "insecure" SMTP. # | |
# ------------------------------------------------------------------------ # | |
# It is recommended to define YOUR local settings. Please, do so only in # | |
# the "defaults" section - unless you are really sure what you are doing! # | |
############################################################################ | |
/** Extended SMTP module | |
* @package Api | |
* @class smtp | |
* @author Itzchak Rehberg ([email protected]) | |
* @copyright (c) 2001-2017 by Itzchak Rehberg | |
*/ | |
class smtp { | |
var $err = array("code"=>"000","msg"=>"init","desc"=>""); | |
var $to_res = array(); | |
// defaults | |
protected $default_domain = '.qumran.org'; | |
protected $fromuser = '[email protected]'; | |
protected $smtpserver = 'jona.qumran.org'; | |
/** Class initialization | |
* @constructor smtp | |
* @param optional string hostname hostname to identify with at the SMTP server | |
* @param optional string fromuser default sender (and "Return-Path") | |
* @param optional string server smtp server to use | |
* @param optional integer port port of this smtp server (default: 25) | |
* @param optional string charset charset for the message (default: iso-8859-15) | |
*/ | |
function __construct($hostname="",$fromuser="",$server="",$port=25,$charset="utf-8") { | |
( empty($hostname) ) ? $this->hostname = gethostname() : $this->hostname = $hostname; | |
if ( !strpos($this->hostname,".") ) $this->hostname .= $this->default_domain; | |
if ( !empty($fromuser) ) $this->fromuser = $fromuser; | |
if ( !preg_match('![ <]!',$this->fromuser) ) $this->fromuser = '<'.$this->fromuser.'>'; | |
if ( !empty($server) ) $this->smtpserver = $server; | |
$this->port = $port; | |
$this->mimeversion = "1.0"; | |
$this->charset = $charset; | |
// don't change anything below here - unless you know what you're doing! | |
$this->err["code"] = "000"; | |
$this->err["msg"] = "init"; | |
$this->err["desc"] = "Session is just initializing."; | |
} | |
// ==================================================[ some sub-functions ]=== | |
/** read response from socket */ | |
protected function socket2msg($socket) { | |
$followme = "-"; //$this->err["msg"] = ""; | |
do { | |
$rmsg = fgets($socket,255); | |
// echo "< $rmsg"; | |
if (substr($rmsg,0,1) != 2 && substr($rmsg,0,1) != 3) { // session end | |
$rc = fclose($socket); | |
if (substr($rmsg,0,1)==4 || substr($rmsg,0,1)==5) { // error reported | |
$this->err["code"] = substr($rmsg,0,3); | |
$this->err["msg"] = trim(substr($rmsg,4)); | |
$this->err["desc"] = ""; | |
} | |
return false; | |
} | |
$this->err["code"] = substr($rmsg,0,3); | |
$followme = substr($rmsg,3,1); | |
$this->err["msg"] = trim(substr($rmsg,4)); | |
$this->err["desc"] = ""; | |
if ($followme == " ") { break; } | |
} while ($followme == "-"); | |
return true; | |
} | |
/** Send a single line to the socket */ | |
protected function msg2socket($socket,$message) { | |
// echo "> $message"; | |
$rc = fputs($socket,"$message"); | |
if (!$rc) { | |
$this->err["code"] = "420"; | |
$this->err["msg"] = "lost connection"; | |
$this->err["desc"] = "Lost connection to smtp server."; | |
$rc = fclose($socket); | |
return false; | |
} | |
return true; | |
} | |
/** send a multi-line text to the socket via self::msg2socket() */ | |
protected function put2socket($socket,$message) { | |
$this->err["code"] = "000"; | |
$this->err["msg"] = "init"; | |
$this->err["desc"] = "The session is still to be initiated."; | |
$pos = strpos($message,"\n"); | |
if (!is_int($pos)) { // no new line found | |
$message .= "\n"; | |
$this->msg2socket($socket,$message); | |
} else { // multiple lines, we have to split it | |
do { | |
$msglen = $pos + 1; | |
$msg = substr($message,0,$msglen); | |
$message = substr($message,$msglen); | |
$pos = strpos($msg,"\n"); | |
if (!is_int($pos)) { // line not terminated | |
$msg .= "\n"; | |
} | |
$pos = strpos($msg,"."); // escape leading periods | |
if (is_int($pos) && !$pos): | |
$msg = "." . $msg; | |
endif; | |
if (!$this->msg2socket($socket,$msg)): return false; endif; | |
$pos = strpos($message,"\n"); | |
} while (strlen($message)>0); | |
} | |
return true; | |
} | |
/** Check the header passed to self::smail() for essential elements | |
* (whether it contains subject and recipient and is correctly terminated) | |
*/ | |
protected function check_header($to,$subject,$header) { | |
// first we check for the subject | |
if ( !(is_string($subject) && !$subject) ) { // subject specified? | |
$theader = strtolower($header); | |
$nl = strpos($theader,"\nsubject:"); // found after a new line | |
$beg = strpos($theader,"subject:"); // found at start | |
if ( !(is_int($nl)) || (is_int($beg) && !$beg) ) { | |
$subject = "Subject: " . stripslashes($subject); | |
$pos = substr($subject,"\n"); | |
if (!is_int($pos)) $subject .= "\n"; | |
$header .= $subject; | |
} | |
} | |
// now we check for the recipient | |
if ( !(is_string($to) && !$to) ) { // recipient specified? | |
$nl = strpos($theader,"\nto:"); // found after a new line | |
$beg = strpos($theader,"to:"); // found at start | |
if ( !(is_int($nl)) || (is_int($beg) && !$beg) ) { | |
$pos = substr($to,"\n"); | |
if (!is_int($pos)) $subject .= "\n"; | |
$to = "To: " .$to ."\n"; | |
$header .= $to; | |
} | |
} | |
// so what about the mime version... | |
$nl = strpos($theader,"\nmime-version:"); // found after a new line | |
$beg = strpos($theader,"mime-version:"); // found at start | |
if ( !(is_int($nl)) || (is_int($beg) && !$beg) ) { | |
$header .= "MIME-Version: " . $this->mimeversion . "\n"; | |
} | |
// and the content type? | |
$nl = strpos($theader,"\ncontent-type:"); // found after a new line | |
$beg = strpos($theader,"content-type:"); // found at start | |
if ( !(is_int($nl)) || (is_int($beg) && !$beg) ) { | |
$header .= "Content-type: text/plain; charset=" . $this->charset . "\n"; | |
} | |
// now we complete the header (make sure it's correct terminated) | |
$header = chop($header); | |
$header .= "\n"; | |
return $header; | |
} | |
/** Create a new mail header (called if none was passed to self::smail()) | |
*/ | |
protected function make_header($to,$subject) { | |
$now = getdate(); | |
$header = "Date: " . gmdate("D, d M Y H:i:s") . " +0000\n"; | |
$header .= "From: ".$this->fromuser."\n"; | |
$header .= "To: $to\n"; | |
$header .= "Subject: " . stripslashes($subject) . "\n"; | |
$header .= "MIME-Version: " . $this->mimeversion . "\n"; | |
$header .= "Content-type: text/plain; charset=" . $this->charset . "\n"; | |
$header .= "Message-Id: <". microtime(true) ."@" .$this->hostname.">\n"; | |
return $header; | |
} | |
// ==============================================[ main function: smail() ]=== | |
/** Send a mail via SMTP | |
* @class smtp | |
* @method smail | |
* @param string to target address | |
* @param string subject mail subject | |
* @param string message the message body | |
* @param optional string header mail header (will be generated automatically) | |
* @return boolean success | |
*/ | |
public function smail($to,$subject,$message,$header="") { | |
$errcode = ""; $errmsg = ""; // error code and message of failed connection | |
$timeout = 5; // timeout in secs | |
// now we try to open the socket and check, if any smtp server responds | |
$socket = fsockopen($this->smtpserver,$this->port,$errcode,$errmsg,$timeout); | |
if (!$socket) { | |
$this->err["code"] = "420"; | |
$this->err["msg"] = "$errcode:$errmsg"; | |
$this->err["desc"] = "Connection to ".$this->smtpserver.":".$this->port." failed - could not open socket."; | |
return false; | |
} else { | |
$rrc = $this->socket2msg($socket); | |
} | |
// now we can send our message. 1st we identify ourselves and the sender | |
$cmds = array ( | |
"\$src = \$this->msg2socket(\$socket,\"HELO \$this->hostname\n\");", | |
"\$rrc = \$this->socket2msg(\$socket);", | |
"\$src = \$this->msg2socket(\$socket,\"MAIL FROM:<\$this->fromuser>\n\");", | |
"\$rrc = \$this->socket2msg(\$socket);" | |
); | |
for ($src=true,$rrc=true,$i=0; $i<count($cmds);$i++) { | |
eval ($cmds[$i]); | |
if (!$src || !$rrc) return false; | |
} | |
// now we've got to evaluate the $to's | |
$toaddr = explode(",",$to); | |
$numaddr = count($toaddr); | |
for ($i=0; $i<$numaddr; $i++) { | |
$src = $this->msg2socket($socket,"RCPT TO:<$toaddr[$i]>\n"); | |
$rrc = $this->socket2msg($socket); | |
$this->to_res[$i]['addr'] = $toaddr[$i]; // for lateron validation | |
$this->to_res[$i]['code'] = $this->err["code"]; | |
$this->to_res[$i]['msg'] = $this->err["msg"]; | |
$this->to_res[$i]['desc'] = $this->err["desc"]; | |
} | |
//now we have to make sure that at least one $to-address was accepted | |
$stop = 1; | |
for ($i=0;$i<count($this->to_res);$i++) { | |
$rc = substr($this->to_res[$i]['code'],0,1); | |
if ($rc == 2) { // at least to this address we can deliver | |
$stop = 0; | |
} | |
} | |
if ($stop) return false; // no address found we can deliver to | |
// now we can go to deliver the message! | |
if (!$this->msg2socket($socket,"DATA\n")) return false; | |
if (!$this->socket2msg($socket)) return false; | |
if ($header != "") { | |
$header = $this->check_header($to,$subject,$header); | |
} else { | |
$header = $this->make_header($to,$subject); | |
} | |
if (!$this->put2socket($socket,$header)) return false; | |
if (!$this->put2socket($socket,"\n")) return false; | |
$message = chop($message); | |
$message .= "\n"; | |
if (!$this->put2socket($socket,$message)) return false; | |
if (!$this->msg2socket($socket,".\n")) return false; | |
if (!$this->socket2msg($socket)) return false; | |
if (!$this->msg2socket($socket,"QUIT\n")) return false; | |
Do { | |
$closing = $this->socket2msg($socket); | |
} while ($closing); | |
return true; | |
} | |
} // end of class | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment