fixheader($key); return isset($this->headers[$key]); } /** * Bind value to e-mail header * @return string * @param $key string * @param $val string **/ function set($key,$val) { $key=$this->fixheader($key); return $this->headers[$key]=$val; } /** * Return value of e-mail header * @return string|NULL * @param $key string **/ function get($key) { $key=$this->fixheader($key); return isset($this->headers[$key])?$this->headers[$key]:NULL; } /** * Remove header * @return NULL * @param $key string **/ function clear($key) { $key=$this->fixheader($key); unset($this->headers[$key]); } /** * Return client-server conversation history * @return string **/ function log() { return str_replace("\n",PHP_EOL,$this->log); } /** * Send SMTP command and record server response * @return string * @param $cmd string * @param $log bool **/ protected function dialog($cmd=NULL,$log=TRUE) { $socket=&$this->socket; if (!is_null($cmd)) fputs($socket,$cmd."\r\n"); $reply=''; while (!feof($socket) && ($info=stream_get_meta_data($socket)) && !$info['timed_out'] && $str=fgets($socket,4096)) { $reply.=$str; if (preg_match('/(?:^|\n)\d{3} .+?\r\n/s',$reply)) break; } if ($log) { $this->log.=$cmd."\n"; $this->log.=str_replace("\r",'',$reply); } return $reply; } /** * Add e-mail attachment * @return NULL * @param $file **/ function attach($file) { if (!is_file($file)) user_error(sprintf(self::E_Attach,$file)); $this->attachments[]=$file; } /** * Transmit message * @return bool * @param $message string * @param $log bool **/ function send($message,$log=TRUE) { if ($this->scheme=='ssl' && !extension_loaded('openssl')) return FALSE; // Message should not be blank if (!$message) user_error(self::E_Blank); $fw=Base::instance(); // Retrieve headers $headers=$this->headers; // Connect to the server $socket=&$this->socket; $socket=@fsockopen($this->host,$this->port); if (!$socket) return FALSE; stream_set_blocking($socket,TRUE); // Get server's initial response $this->dialog(NULL,FALSE); // Announce presence $reply=$this->dialog('EHLO '.$fw->get('HOST'),$log); if (strtolower($this->scheme)=='tls') { $this->dialog('STARTTLS',$log); stream_socket_enable_crypto( $socket,TRUE,STREAM_CRYPTO_METHOD_TLS_CLIENT); $reply=$this->dialog('EHLO '.$fw->get('HOST'),$log); if (preg_match('/8BITMIME/',$reply)) $headers['Content-Transfer-Encoding']='8bit'; else { $headers['Content-Transfer-Encoding']='quoted-printable'; $message=quoted_printable_encode($message); } } if ($this->user && $this->pw && preg_match('/AUTH/',$reply)) { // Authenticate $this->dialog('AUTH LOGIN',$log); $this->dialog(base64_encode($this->user),$log); $this->dialog(base64_encode($this->pw),$log); } // Required headers $reqd=array('From','To','Subject'); foreach ($reqd as $id) if (empty($headers[$id])) user_error(sprintf(self::E_Header,$id)); $eol="\r\n"; $str=''; // Stringify headers foreach ($headers as $key=>$val) if (!in_array($key,$reqd)) $str.=$key.': '.$val.$eol; // Start message dialog $this->dialog('MAIL FROM: '.strstr($headers['From'],'<'),$log); foreach ($fw->split($headers['To']. (isset($headers['Cc'])?(';'.$headers['Cc']):''). (isset($headers['Bcc'])?(';'.$headers['Bcc']):'')) as $dst) $this->dialog('RCPT TO: '.strstr($dst,'<'),$log); $this->dialog('DATA',$log); if ($this->attachments) { // Replace Content-Type $hash=uniqid(NULL,TRUE); $type=$headers['Content-Type']; $headers['Content-Type']='multipart/mixed; '. 'boundary="'.$hash.'"'; // Send mail headers $out=''; foreach ($headers as $key=>$val) if ($key!='Bcc') $out.=$key.': '.$val.$eol; $out.=$eol; $out.='This is a multi-part message in MIME format'.$eol; $out.=$eol; $out.='--'.$hash.$eol; $out.='Content-Type: '.$type.$eol; $out.=$eol; $out.=$message.$eol; foreach ($this->attachments as $attachment) { $out.='--'.$hash.$eol; $out.='Content-Type: application/octet-stream'.$eol; $out.='Content-Transfer-Encoding: base64'.$eol; $out.='Content-Disposition: attachment; '. 'filename="'.basename($attachment).'"'.$eol; $out.=$eol; $out.=chunk_split( base64_encode(file_get_contents($attachment))).$eol; } $out.=$eol; $out.='--'.$hash.'--'.$eol; $out.='.'; $this->dialog($out,FALSE); } else { // Send mail headers $out=''; foreach ($headers as $key=>$val) if ($key!='Bcc') $out.=$key.': '.$val.$eol; $out.=$eol; $out.=$message.$eol; $out.='.'; // Send message $this->dialog($out); } $this->dialog('QUIT',$log); if ($socket) fclose($socket); return TRUE; } /** * Instantiate class * @param $host string * @param $port int * @param $scheme string * @param $user string * @param $pw string **/ function __construct($host,$port,$scheme,$user,$pw) { $this->headers=array( 'MIME-Version'=>'1.0', 'Content-Type'=>'text/plain; '. 'charset='.Base::instance()->get('ENCODING') ); $this->host=$host; if (strtolower($this->scheme=strtolower($scheme))=='ssl') $this->host='ssl://'.$host; $this->port=$port; $this->user=$user; $this->pw=$pw; } }