Xataface Email Module  0.3.2
Email/Mailmerge Module for Xataface
 All Data Structures Files Functions Variables Pages
SMTP5.php
Go to the documentation of this file.
1 <?php
2 
3 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4  * *
5  * XPertMailer is a PHP Mail Class that can send and read messages in MIME format. *
6  * This file is part of the XPertMailer package (http://xpertmailer.sourceforge.net/) *
7  * Copyright (C) 2007 Tanase Laurentiu Iulian *
8  * *
9  * This library is free software; you can redistribute it and/or modify it under the *
10  * terms of the GNU Lesser General Public License as published by the Free Software *
11  * Foundation; either version 2.1 of the License, or (at your option) any later version. *
12  * *
13  * This library is distributed in the hope that it will be useful, but WITHOUT ANY *
14  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
15  * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU Lesser General Public License along with *
18  * this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, *
19  * Fifth Floor, Boston, MA 02110-1301, USA *
20  * *
21  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22 
23 if (!class_exists('MIME5')) require_once 'MIME5.php';
24 
25 $_RESULT = array();
26 
27 class SMTP5 {
28 
29  const CRLF = "\r\n";
30  const PORT = 25;
31  const TOUT = 30;
32  const COUT = 5;
33  const BLEN = 1024;
34 
35  static private function _cres($conn = null, &$resp, $code1 = null, $code2 = null, $debug = null) {
36  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
37  $err = array();
38  if (!is_resource($conn)) $err[] = 'invalid resource connection';
39  if (!(is_int($code1) && $code1 > 99 && $code1 < 1000)) $err[] = 'invalid 1 code value';
40  if ($code2 != null) {
41  if (!(is_int($code2) && $code2 > 99 && $code2 < 1000)) $err[] = 'invalid 2 code value';
42  }
43  if (count($err) > 0) return FUNC5::trace($debug, implode(', ', $err), 1);
44  else {
45  $ret = true;
46  do {
47  if ($result = fgets($conn, self::BLEN)) {
48  $resp[] = $result;
49  $rescode = substr($result, 0, 3);
50  if (!($rescode == $code1 || $rescode == $code2)) {
51  $ret = false;
52  break;
53  }
54  } else {
55  $resp[] = 'can not read';
56  $ret = false;
57  break;
58  }
59  } while ($result[3] == '-');
60  return $ret;
61  }
62  }
63 
64  static public function mxconnect($host = null, $port = null, $tout = null, $name = null, $context = null, $debug = null) {
65  global $_RESULT;
66  $_RESULT = array();
67  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
68  if (!is_string($host)) FUNC5::trace($debug, 'invalid host type');
69  else {
70  $host = strtolower(trim($host));
71  if (!($host != '' && FUNC5::is_hostname($host, true, $debug))) FUNC5::trace($debug, 'invalid host value');
72  }
73  $res = FUNC5::is_win() ? FUNC5::getmxrr_win($host, $arr, $debug) : getmxrr($host, $arr);
74  $con = false;
75  if ($res) {
76  foreach ($arr as $mx) {
77  if ($con = self::connect($mx, $port, null, null, null, $tout, $name, $context, null, $debug)) break;
78  }
79  }
80  if (!$con) $con = self::connect($host, $port, null, null, null, $tout, $name, $context, null, $debug);
81  return $con;
82  }
83 
84  static public function connect($host = null, $port = null, $user = null, $pass = null, $vssl = null, $tout = null, $name = null, $context = null, $login = null, $debug = null) {
85  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
86  global $_RESULT;
87  $_RESULT = $err = array();
88  if ($port == null) $port = self::PORT;
89  if ($tout == null) $tout = self::TOUT;
90  if (!is_string($host)) $err[] = 'invalid host type';
91  else {
92  $host = strtolower(trim($host));
93  if (!($host != '' && ($host == 'localhost' || FUNC5::is_ipv4($host) || FUNC5::is_hostname($host, true, $debug)))) $err[] = 'invalid host value';
94  }
95  if (!(is_int($port) && $port > 0)) $err[] = 'invalid port value';
96  if ($user != null) {
97  if (!is_string($user)) $err[] = 'invalid username type';
98  else if (($user = FUNC5::str_clear($user)) == '') $err[] = 'invalid username value';
99  }
100  if ($pass != null) {
101  if (!is_string($pass)) $err[] = 'invalid password type';
102  else if (($pass = FUNC5::str_clear($pass)) == '') $err[] = 'invalid password value';
103  }
104  if (($user != null && $pass == null) || ($user == null && $pass != null)) $err[] = 'invalid username/password combination';
105  if ($vssl != null) {
106  if (!is_string($vssl)) $err[] = 'invalid ssl version type';
107  else {
108  $vssl = strtolower($vssl);
109  if (!($vssl == 'tls' || $vssl == 'ssl' || $vssl == 'sslv2' || $vssl == 'sslv3')) $err[] = 'invalid ssl version value';
110  }
111  }
112  if (!(is_int($tout) && $tout > 0)) $err[] = 'invalid timeout value';
113  if ($name != null) {
114  if (!is_string($name)) $err[] = 'invalid name type';
115  else {
116  $name = strtolower(trim($name));
117  if (!($name != '' && ($name == 'localhost' || FUNC5::is_ipv4($name) || FUNC5::is_hostname($name, true, $debug)))) $err[] = 'invalid name value';
118  }
119  } else $name = '127.0.0.1';
120  if ($context != null && !is_resource($context)) $err[] = 'invalid context type';
121  if ($login != null) {
122  $login = strtolower(trim($login));
123  if (!($login == 'login' || $login == 'plain' || $login == 'cram-md5')) $err[] = 'invalid authentication type value';
124  }
125  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
126  else {
127  $ret = false;
128  $prt = ($vssl == null) ? 'tcp' : $vssl;
129  $conn = ($context == null) ? stream_socket_client($prt.'://'.$host.':'.$port, $errno, $errstr, $tout) : stream_socket_client($prt.'://'.$host.':'.$port, $errno, $errstr, $tout, STREAM_CLIENT_CONNECT, $context);
130  if (!$conn) $_RESULT[101] = $errstr;
131  else if (!stream_set_timeout($conn, self::COUT)) $_RESULT[102] = 'could not set stream timeout';
132  else if (!self::_cres($conn, $resp, 220, null, $debug)) $_RESULT[103] = $resp;
133  else {
134  $continue = true;
135  if (!self::ehlo($conn, $name, $debug)) $continue = self::helo($conn, $name, $debug);
136  if ($continue) {
137  if ($user == null) $ret = true;
138  else if ($login != null) $ret = self::auth($conn, $user, $pass, $login, $debug);
139  else {
140  list($code, $arr) = each($_RESULT);
141  $auth['default'] = $auth['login'] = $auth['plain'] = $auth['cram-md5'] = false;
142  foreach ($arr as $line) {
143  if (substr($line, 0, strlen('250-AUTH ')) == '250-AUTH ') {
144  foreach (explode(' ', substr($line, strlen('250-AUTH '))) as $type) {
145  $type = strtolower(trim($type));
146  if ($type == 'login' || $type == 'plain' || $type == 'cram-md5') $auth[$type] = true;
147  }
148  } else if (substr($line, 0, strlen('250 AUTH=')) == '250 AUTH=') {
149  $expl = explode(' ', strtolower(trim(substr($line, strlen('250 AUTH=')))), 2);
150  if ($expl[0] == 'login' || $expl[0] == 'plain' || $expl[0] == 'cram-md5') $auth['default'] = $expl[0];
151  }
152  }
153  if ($auth['default']) $ret = self::auth($conn, $user, $pass, $auth['default'], $debug);
154  if (!$ret && $auth['login'] && $auth['default'] != 'login') $ret = self::auth($conn, $user, $pass, 'login', $debug);
155  if (!$ret && $auth['plain'] && $auth['default'] != 'plain') $ret = self::auth($conn, $user, $pass, 'plain', $debug);
156  if (!$ret && $auth['cram-md5'] && $auth['default'] != 'cram-md5') $ret = self::auth($conn, $user, $pass, 'cram-md5', $debug);
157  if (!$ret && !$auth['login'] && $auth['default'] != 'login') $ret = self::auth($conn, $user, $pass, 'login', $debug);
158  if (!$ret && !$auth['plain'] && $auth['default'] != 'plain') $ret = self::auth($conn, $user, $pass, 'plain', $debug);
159  if (!$ret && !$auth['cram-md5'] && $auth['default'] != 'cram-md5') $ret = self::auth($conn, $user, $pass, 'cram-md5', $debug);
160  }
161  }
162  }
163  if (!$ret) {
164  if (is_resource($conn)) self::disconnect($conn, $debug);
165  $conn = false;
166  }
167  return $conn;
168  }
169  }
170 
171  static public function send($conn = null, $addrs = null, $mess = null, $from = null, $debug = null) {
172  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
173  global $_RESULT;
174  $_RESULT = $err = array();
175  if (!is_resource($conn)) $err[] = 'invalid resource connection';
176  if (!is_array($addrs)) $err[] = 'invalid to address type';
177  else {
178  $aver = true;
179  if (count($addrs) > 0) {
180  foreach ($addrs as $addr) {
181  if (!FUNC5::is_mail($addr)) {
182  $aver = false;
183  break;
184  }
185  }
186  } else $aver = false;
187  if (!$aver) $err[] = 'invalid to address value';
188  }
189  if (!is_string($mess)) $err[] = 'invalid message value';
190  if ($from == null) {
191  $from = @ini_get('sendmail_from');
192  if ($from == '' || !FUNC5::is_mail($from)) $from = (isset($_SERVER['SERVER_ADMIN']) && FUNC5::is_mail($_SERVER['SERVER_ADMIN'])) ? $_SERVER['SERVER_ADMIN'] : 'postmaster@localhost';
193  } else {
194  if (!is_string($from)) $err[] = 'invalid from address type';
195  else if (!($from != '' && FUNC5::is_mail($from))) $err[] = 'invalid from address value';
196  }
197  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
198  else {
199  $ret = false;
200  if (self::from($conn, $from, $debug)) {
201  $continue = true;
202  foreach ($addrs as $dest) {
203  if (!self::to($conn, $dest, $debug)) {
204  $continue = false;
205  break;
206  }
207  }
208  if ($continue) {
209  if (self::data($conn, $mess, $debug)) $ret = self::rset($conn, $debug);
210  }
211  }
212  return $ret;
213  }
214  }
215 
216  static public function disconnect($conn = null, $debug = null) {
217  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
218  global $_RESULT;
219  $_RESULT = array();
220  if (!is_resource($conn)) return FUNC5::trace($debug, 'invalid resource connection', 1);
221  else {
222  if (!fwrite($conn, 'QUIT'.self::CRLF)) $_RESULT[300] = 'can not write';
223  else $_RESULT[301] = 'Send QUIT';
224  return @fclose($conn);
225  }
226  }
227 
228  static public function quit($conn = null, $debug = null) {
229  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
230  global $_RESULT;
231  $_RESULT = array();
232  $ret = false;
233  if (!is_resource($conn)) FUNC5::trace($debug, 'invalid resource connection');
234  else if (!fwrite($conn, 'QUIT'.self::CRLF)) $_RESULT[302] = 'can not write';
235  else {
236  $_RESULT[303] = ($vget = @fgets($conn, self::BLEN)) ? $vget : 'can not read';
237  $ret = true;
238  }
239  return $ret;
240  }
241 
242  static public function helo($conn = null, $host = null, $debug = null) {
243  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
244  global $_RESULT;
245  $_RESULT = $err = array();
246  if (!is_resource($conn)) $err[] = 'invalid resource connection';
247  if (!is_string($host)) $err[] = 'invalid host type';
248  else {
249  $host = strtolower(trim($host));
250  if (!($host != '' && ($host == 'localhost' || FUNC5::is_ipv4($host) || FUNC5::is_hostname($host, true, $debug)))) $err[] = 'invalid host value';
251  }
252  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
253  else {
254  $ret = false;
255  if (!fwrite($conn, 'HELO '.$host.self::CRLF)) $_RESULT[304] = 'can not write';
256  else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[305] = $resp;
257  else {
258  $_RESULT[306] = $resp;
259  $ret = true;
260  }
261  return $ret;
262  }
263  }
264 
265  static public function ehlo($conn = null, $host = null, $debug = null) {
266  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
267  global $_RESULT;
268  $_RESULT = $err = array();
269  if (!is_resource($conn)) $err[] = 'invalid resource connection';
270  if (!is_string($host)) $err[] = 'invalid host type';
271  else {
272  $host = strtolower(trim($host));
273  if (!($host != '' && ($host == 'localhost' || FUNC5::is_ipv4($host) || FUNC5::is_hostname($host, true, $debug)))) $err[] = 'invalid host value';
274  }
275  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
276  else {
277  $ret = false;
278  if (!fwrite($conn, 'EHLO '.$host.self::CRLF)) $_RESULT[307] = 'can not write';
279  else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[308] = $resp;
280  else {
281  $_RESULT[309] = $resp;
282  $ret = true;
283  }
284  return $ret;
285  }
286  }
287 
288  static public function auth($conn = null, $user = null, $pass = null, $type = null, $debug = null) {
289  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
290  global $_RESULT;
291  $_RESULT = $err = array();
292  if (!is_resource($conn)) $err[] = 'invalid resource connection';
293  if (!is_string($user)) $err[] = 'invalid username type';
294  else if (($user = FUNC5::str_clear($user)) == '') $err[] = 'invalid username value';
295  if (!is_string($pass)) $err[] = 'invalid password type';
296  else if (($pass = FUNC5::str_clear($pass)) == '') $err[] = 'invalid password value';
297  if ($type == null) $type = 'login';
298  if (!is_string($type)) $err[] = 'invalid authentication type';
299  else {
300  $type = strtolower(trim($type));
301  if (!($type == 'login' || $type == 'plain' || $type == 'cram-md5')) $err[] = 'invalid authentication type value';
302  }
303  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
304  else {
305  $ret = false;
306  if ($type == 'login') {
307  if (!fwrite($conn, 'AUTH LOGIN'.self::CRLF)) $_RESULT[310] = 'can not write';
308  else if (!self::_cres($conn, $resp, 334, null, $debug)) $_RESULT[311] = $resp;
309  else if (!fwrite($conn, base64_encode($user).self::CRLF)) $_RESULT[312] = 'can not write';
310  else if (!self::_cres($conn, $resp, 334, null, $debug)) $_RESULT[313] = $resp;
311  else if (!fwrite($conn, base64_encode($pass).self::CRLF)) $_RESULT[314] = 'can not write';
312  else if (!self::_cres($conn, $resp, 235, null, $debug)) $_RESULT[315] = $resp;
313  else {
314  $_RESULT[316] = $resp;
315  $ret = true;
316  }
317  } else if ($type == 'plain') {
318  if (!fwrite($conn, 'AUTH PLAIN '.base64_encode($user.chr(0).$user.chr(0).$pass).self::CRLF)) $_RESULT[317] = 'can not write';
319  else if (!self::_cres($conn, $resp, 235, null, $debug)) $_RESULT[318] = $resp;
320  else {
321  $_RESULT[319] = $resp;
322  $ret = true;
323  }
324  } else if ($type == 'cram-md5') {
325  if (!fwrite($conn, 'AUTH CRAM-MD5'.self::CRLF)) $_RESULT[200] = 'can not write';
326  else if (!self::_cres($conn, $resp, 334, null, $debug)) $_RESULT[201] = $resp;
327  else {
328  if (strlen($pass) > 64) $pass = pack('H32', md5($pass));
329  if (strlen($pass) < 64) $pass = str_pad($pass, 64, chr(0));
330  $pad1 = substr($pass, 0, 64) ^ str_repeat(chr(0x36), 64);
331  $pad2 = substr($pass, 0, 64) ^ str_repeat(chr(0x5C), 64);
332  $chal = substr($resp[count($resp)-1], 4);
333  $innr = pack('H32', md5($pad1.base64_decode($chal)));
334  if (!fwrite($conn, base64_encode($user.' '.md5($pad2.$innr)).self::CRLF)) $_RESULT[202] = 'can not write';
335  else if (!self::_cres($conn, $resp, 235, null, $debug)) $_RESULT[203] = $resp;
336  else {
337  $_RESULT[204] = $resp;
338  $ret = true;
339  }
340  }
341  }
342  return $ret;
343  }
344  }
345 
346  static public function from($conn = null, $addr = null, $debug = null) {
347  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
348  global $_RESULT;
349  $_RESULT = $err = array();
350  if (!is_resource($conn)) $err[] = 'invalid resource connection';
351  if (!is_string($addr)) $err[] = 'invalid from address type';
352  else if (!($addr != '' && FUNC5::is_mail($addr))) $err[] = 'invalid from address value';
353  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
354  else {
355  $ret = false;
356  if (!fwrite($conn, 'MAIL FROM:<'.$addr.'>'.self::CRLF)) $_RESULT[320] = 'can not write';
357  else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[321] = $resp;
358  else {
359  $_RESULT[322] = $resp;
360  $ret = true;
361  }
362  return $ret;
363  }
364  }
365 
366  static public function to($conn = null, $addr = null, $debug = null) {
367  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
368  global $_RESULT;
369  $_RESULT = $err = array();
370  if (!is_resource($conn)) $err[] = 'invalid resource connection';
371  if (!is_string($addr)) $err[] = 'invalid to address type';
372  else if (!($addr != '' && FUNC5::is_mail($addr))) $err[] = 'invalid to address value';
373  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
374  else {
375  $ret = false;
376  if (!fwrite($conn, 'RCPT TO:<'.$addr.'>'.self::CRLF)) $_RESULT[323] = 'can not write';
377  else if (!self::_cres($conn, $resp, 250, 251, $debug)) $_RESULT[324] = $resp;
378  else {
379  $_RESULT[325] = $resp;
380  $ret = true;
381  }
382  return $ret;
383  }
384  }
385 
386  static public function data($conn = null, $mess = null, $debug = null) {
387  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
388  global $_RESULT;
389  $_RESULT = $err = array();
390  if (!is_resource($conn)) $err[] = 'invalid resource connection';
391  if (!(is_string($mess) && $mess != '')) $err[] = 'invalid message value';
392  if (count($err) > 0) FUNC5::trace($debug, implode(', ', $err));
393  else {
394  $ret = false;
395  if (!fwrite($conn, 'DATA'.self::CRLF)) $_RESULT[326] = 'can not write';
396  else if (!self::_cres($conn, $resp, 354, null, $debug)) $_RESULT[327] = $resp;
397  else {
398  $continue = true;
399  foreach (explode(self::CRLF, $mess) as $line) {
400  if ($line != '' && $line[0] == '.') $line = '.'.$line;
401  if (!fwrite($conn, $line.self::CRLF)) {
402  $_RESULT[328] = 'can not write';
403  $continue = false;
404  break;
405  }
406  }
407  if ($continue) {
408  if (!fwrite($conn, '.'.self::CRLF)) $_RESULT[329] = 'can not write';
409  else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[330] = $resp;
410  else {
411  $_RESULT[331] = $resp;
412  $ret = true;
413  }
414  }
415  }
416  return $ret;
417  }
418  }
419 
420  static public function rset($conn = null, $debug = null) {
421  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
422  global $_RESULT;
423  $_RESULT = array();
424  $ret = false;
425  if (!is_resource($conn)) FUNC5::trace($debug, 'invalid resource connection');
426  else if (!fwrite($conn, 'RSET'.self::CRLF)) $_RESULT[332] = 'can not write';
427  else if (!self::_cres($conn, $resp, 250, null, $debug)) $_RESULT[333] = $resp;
428  else {
429  $_RESULT[334] = $resp;
430  $ret = true;
431  }
432  return $ret;
433  }
434 
435  static public function recv($conn = null, $code1 = null, $code2 = null, $debug = null) {
436  if (!FUNC5::is_debug($debug)) $debug = debug_backtrace();
437  global $_RESULT;
438  $_RESULT = array();
439  $ret = false;
440  if (!self::_cres($conn, $resp, $code1, $code2, $debug)) $_RESULT[335] = $resp;
441  else {
442  $_RESULT[336] = $resp;
443  $ret = true;
444  }
445  return $ret;
446  }
447 
448 }
449 
450 ?>