Просмотр файла mc-2.7.0/libraries/email.php

Размер файла: 21.47Kb
  1. <?php
  2.  
  3. /**
  4. * Универсальный класс для отправки email сообщений
  5. * @author Leo West <lwest@free.fr>
  6. * @author webi.ru <adm@webi.ru>
  7. * @link http://webi.ru/webi_files/php_libmail.html
  8. */
  9. class Mail {
  10. /* определение переменных идет через VAR, для обеспечения работы в php старых версий
  11. массивы адресов кому отправить
  12. @var array
  13. */
  14.  
  15. var $sendto = array();
  16. /*
  17. @var array
  18. */
  19. var $acc = array();
  20. /*
  21. @var array
  22. */
  23. var $abcc = array();
  24. /*
  25. прикрепляемые файлы
  26. @var array
  27. */
  28. var $aattach = array();
  29. /*
  30. массив заголовков
  31. @var array
  32. */
  33. var $xheaders = array();
  34. /*
  35. приоритеты
  36. @var array
  37. */
  38. var $priorities = array('1 (Highest)', '2 (High)', '3 (Normal)', '4 (Low)', '5 (Lowest)');
  39. /*
  40. кодировка по умолчанию
  41. @var string
  42. */
  43. var $charset = "windows-1251";
  44. var $ctencoding = "8bit";
  45. var $receipt = 0;
  46. var $text_html = "text/plain"; // формат письма. по умолчанию текстовый
  47. var $smtp_on = false; // отправка через smtp. по умолчанию выключена
  48.  
  49. /*
  50. конструктор тоже по старому объявлен для совместимости со старыми версиями php
  51. пошел конструктор.
  52. входящий параметр кодировка письма
  53. внесено изменение webi.ru
  54. */
  55.  
  56. function Mail($charset = "") {
  57. $this->autoCheck(true);
  58. $this->boundary = "--" . md5(uniqid("myboundary"));
  59.  
  60.  
  61. if ($charset != "") {
  62. $this->charset = strtolower($charset);
  63. if ($this->charset == "us-ascii") {
  64. $this->ctencoding = "7bit";
  65. }
  66. }
  67. }
  68.  
  69. /*
  70.  
  71. включение выключение проверки валидности email
  72. пример: autoCheck( true ) проверка влючена
  73. по умолчанию проверка включена
  74.  
  75.  
  76. */
  77.  
  78. /**
  79. * @param boolean $bool
  80. */
  81. function autoCheck($bool) {
  82. if ($bool) {
  83. $this->checkAddress = true;
  84. } else {
  85. $this->checkAddress = false;
  86. }
  87. }
  88.  
  89. /*
  90.  
  91. Тема письма
  92. внесено изменения кодирования не латинских символов
  93.  
  94. */
  95.  
  96. /**
  97. * @param string $subject
  98. */
  99. function Subject($subject) {
  100.  
  101. $this->xheaders['Subject'] = "=?" . $this->charset . "?Q?" . str_replace("+", "_", str_replace("%", "=", urlencode(strtr($subject, "\r\n", " ")))) . "?=";
  102. }
  103.  
  104. /*
  105.  
  106. от кого
  107. */
  108.  
  109. function From($from) {
  110.  
  111. if (!is_string($from)) {
  112. echo "ошибка, From должен быть строкой";
  113. exit;
  114. }
  115. $this->xheaders['From'] = $from;
  116. }
  117.  
  118. /*
  119. на какой адрес отвечать
  120.  
  121. */
  122.  
  123. function ReplyTo($address) {
  124.  
  125. if (!is_string($address)) {
  126. return false;
  127. }
  128.  
  129. $this->xheaders["Reply-To"] = $address;
  130. }
  131.  
  132. /*
  133. Добавление заголовка для получения уведомления о прочтении. обратный адрес берется из "From" (или из "ReplyTo" если указан)
  134.  
  135. */
  136.  
  137. function Receipt() {
  138. $this->receipt = 1;
  139. }
  140.  
  141. /*
  142. set the mail recipient
  143. @param string $to email address, accept both a single address or an array of addresses
  144. */
  145.  
  146. function To($to) {
  147.  
  148. // если это массив
  149. if (is_array($to)) {
  150. $this->sendto = $to;
  151. foreach ($to as $key => $value) { // перебираем массив и добавляем в массив для отправки через smtp
  152. $this->smtpsendto[$value] = $value; // ключи и значения одинаковые, чтобы исключить дубли адресов
  153. }
  154. } else {
  155. $this->sendto[] = $to;
  156. $this->smtpsendto[$to] = $to; // ключи и значения одинаковые, чтобы исключить дубли адресов
  157. }
  158.  
  159. if ($this->checkAddress == true)
  160. $this->CheckAdresses($this->sendto);
  161. }
  162.  
  163. /* Cc()
  164. * установка заголдовка CC ( открытая копия, все получатели будут видеть куда ушла копия )
  165. * $cc : email address(es), accept both array and string
  166. */
  167.  
  168. function Cc($cc) {
  169. if (is_array($cc)) {
  170. $this->acc = $cc;
  171.  
  172. foreach ($cc as $key => $value) { // перебираем массив и добавляем в массив для отправки через smtp
  173. $this->smtpsendto[$value] = $value; // ключи и значения одинаковые, чтобы исключить дубли адресов
  174. }
  175. } else {
  176. $this->acc[] = $cc;
  177. $this->smtpsendto[$cc] = $cc; // ключи и значения одинаковые, чтобы исключить дубли адресов
  178. }
  179.  
  180. if ($this->checkAddress == true)
  181. $this->CheckAdresses($this->acc);
  182. }
  183.  
  184. /* Bcc()
  185. * скрытая копия. не будет помещать заголовок кому ушло письмо
  186. * $bcc : email address(es), accept both array and string
  187. */
  188.  
  189. function Bcc($bcc) {
  190. if (is_array($bcc)) {
  191. $this->abcc = $bcc;
  192. foreach ($bcc as $key => $value) {
  193. // перебираем массив и добавляем в массив для отправки через smtp
  194. {
  195. $this->smtpsendto[$value] = $value;
  196. }
  197. // ключи и значения одинаковые, чтобы исключить дубли адресов
  198. }
  199. } else {
  200. $this->abcc[] = $bcc;
  201. $this->smtpsendto[$bcc] = $bcc; // ключи и значения одинаковые, чтобы исключить дубли адресов
  202. }
  203.  
  204. if ($this->checkAddress == true) {
  205. $this->CheckAdresses($this->abcc);
  206. }
  207. }
  208.  
  209. /* Body( text [ text_html ] )
  210. * $text_html в каком формате будет письмо, в тексте или html. по умолчанию стоит текст
  211. */
  212.  
  213. /**
  214. * @param string $body
  215. */
  216. function Body($body, $text_html = "") {
  217. $this->body = $body;
  218.  
  219. if ($text_html == "html") {
  220. $this->text_html = "text/html";
  221. }
  222. }
  223.  
  224. /* Organization( $org )
  225. * set the Organization header
  226. */
  227.  
  228. function Organization($org) {
  229. if (trim($org != "")) {
  230. $this->xheaders['Organization'] = $org;
  231. }
  232. }
  233.  
  234. /* Priority( $priority )
  235. * set the mail priority
  236. * $priority : integer taken between 1 (highest) and 5 ( lowest )
  237. * ex: $mail->Priority(1) ; => Highest
  238. */
  239.  
  240. function Priority($priority) {
  241. if (!intval($priority)) {
  242. return false;
  243. }
  244.  
  245. if (!isset($this->priorities[$priority - 1])) {
  246. return false;
  247. }
  248.  
  249. $this->xheaders["X-Priority"] = $this->priorities[$priority - 1];
  250.  
  251. return true;
  252. }
  253.  
  254. /*
  255. прикрепленные файлы
  256.  
  257. @param string $filename : путь к файлу, который надо отправить
  258. @param string $webi_filename : реальное имя файла. если вдруг вставляется файл временный, то его имя будет хрен пойми каким..
  259. @param string $filetype : MIME-тип файла. по умолчанию 'application/x-unknown-content-type'
  260. @param string $disposition : инструкция почтовому клиенту как отображать прикрепленный файл ("inline") как часть письма или ("attachment") как прикрепленный файл
  261. */
  262.  
  263. function Attach($filename, $webi_filename = "", $filetype = "", $disposition = "inline") {
  264. // TODO : если типа файла не указан, ставим неизвестный тип
  265. if ($filetype == "") {
  266. $filetype = "application/x-unknown-content-type";
  267. }
  268.  
  269. $this->aattach[] = $filename;
  270. $this->webi_filename[] = $webi_filename;
  271. $this->actype[] = $filetype;
  272. $this->adispo[] = $disposition;
  273. }
  274.  
  275. /*
  276.  
  277. Собераем письмо
  278.  
  279.  
  280. */
  281.  
  282. function BuildMail() {
  283. $this->headers = "";
  284. $this->xheaders['To'] = implode(", ", $this->sendto); // этот заголовок будет не нужен при отправке через mail()
  285. if (count($this->acc) > 0) {
  286. $this->xheaders['CC'] = implode(", ", $this->acc);
  287. }
  288.  
  289. if (count($this->abcc) > 0) {
  290. $this->xheaders['BCC'] = implode(", ", $this->abcc);
  291. } // этот заголовок будет не нужен при отправке через smtp
  292. if ($this->receipt) {
  293. if (isset($this->xheaders["Reply-To"]))
  294. $this->xheaders["Disposition-Notification-To"] = $this->xheaders["Reply-To"];
  295. else
  296. $this->xheaders["Disposition-Notification-To"] = $this->xheaders['From'];
  297. }
  298.  
  299. if ($this->charset != "") {
  300. $this->xheaders["Mime-Version"] = "1.0";
  301. $this->xheaders["Content-Type"] = $this->text_html . "; charset=$this->charset";
  302. $this->xheaders["Content-Transfer-Encoding"] = $this->ctencoding;
  303. }
  304.  
  305. //$this->xheaders["X-Mailer"] = "Php_libMail_v_1.5(webi.ru)";
  306. // вставаляем файлы
  307. if (count($this->aattach) > 0) {
  308. $this->_build_attachement();
  309. } else {
  310. $this->fullBody = $this->body;
  311. }
  312. // создание заголовков если отправка идет через smtp
  313. if ($this->smtp_on) {
  314. // разбиваем (FROM - от кого) на юзера и домен. домен понадобится в заголовке
  315. $user_domen = explode('@', $this->xheaders['From']);
  316. $this->headers = "Date: " . date("D, j M Y G:i:s") . " +0700\r\n";
  317. $this->headers .= "Message-ID: <" . rand() . "." . date("YmjHis") . "@" . $user_domen[1] . ">\r\n";
  318. reset($this->xheaders);
  319. while (list($hdr, $value) = each($this->xheaders)) {
  320. if ($hdr != "BCC") {
  321. $this->headers .= $hdr . ": " . $value . "\r\n";
  322. } // пропускаем заголовок для отправки скрытой копии
  323. }
  324. } else {
  325. reset($this->xheaders);
  326. while (list($hdr, $value) = each($this->xheaders)) {
  327. if ($hdr != "Subject" and $hdr != "To") {
  328. $this->headers .= "$hdr: $value\n";
  329. } // пропускаем заголовки кому и тему... они вставятся сами
  330. }
  331. }
  332. }
  333.  
  334. // включение отправки через smtp используя сокеты
  335. // после запуска этой функции отправка через smtp включена
  336. // для отправки через защищенное соединение сервер нужно указывать с добавлением "ssl://" например так "ssl://smtp.gmail.com"
  337. function smtp_on($smtp_serv, $login, $pass, $port = 25, $timeout = 5) {
  338. $this->smtp_on = true; // включаем отправку через smtp
  339.  
  340. $this->smtp_serv = $smtp_serv;
  341. $this->smtp_login = $login;
  342. $this->smtp_pass = $pass;
  343. $this->smtp_port = $port;
  344. $this->smtp_timeout = $timeout;
  345. }
  346.  
  347. function get_data($smtp_conn) {
  348. $data = "";
  349. while ($str = fgets($smtp_conn, 515)) {
  350. $data .= $str;
  351. if (substr($str, 3, 1) == " ") {
  352. break;
  353. }
  354. }
  355. return $data;
  356. }
  357.  
  358. /*
  359. отправка письма
  360.  
  361. */
  362.  
  363. function Send() {
  364. $this->BuildMail();
  365. $this->strTo = implode(", ", $this->sendto);
  366.  
  367. // если отправка без использования smtp
  368. if (!$this->smtp_on) {
  369. $res = @mail($this->strTo, $this->xheaders['Subject'], $this->fullBody, $this->headers);
  370. } else { // если через smtp
  371. if (!$this->smtp_serv OR ! $this->smtp_login OR ! $this->smtp_pass OR ! $this->smtp_port)
  372. return false; // если нет хотя бы одного из основных данных для коннекта, выходим с ошибкой
  373.  
  374.  
  375.  
  376.  
  377.  
  378. // разбиваем (FROM - от кого) на юзера и домен. юзер понадобится в приветсвии с сервом
  379. $user_domen = explode('@', $this->xheaders['From']);
  380.  
  381.  
  382. $this->smtp_log = '';
  383. $smtp_conn = fsockopen($this->smtp_serv, $this->smtp_port, $errno, $errstr, $this->smtp_timeout);
  384. if (!$smtp_conn) {
  385. $this->smtp_log .= "соединение с сервером не прошло\n\n";
  386. fclose($smtp_conn);
  387. return;
  388. }
  389.  
  390. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  391.  
  392. fputs($smtp_conn, "EHLO " . $user_domen[0] . "\r\n");
  393. $this->smtp_log .= "Я: EHLO " . $user_domen[0] . "\n";
  394. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  395. $code = substr($data, 0, 3); // получаем код ответа
  396.  
  397. if ($code != 250) {
  398. $this->smtp_log .= "ошибка приветсвия EHLO \n";
  399. fclose($smtp_conn);
  400. return;
  401. }
  402.  
  403. fputs($smtp_conn, "AUTH LOGIN\r\n");
  404. $this->smtp_log .= "Я: AUTH LOGIN\n";
  405. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  406. $code = substr($data, 0, 3);
  407.  
  408. if ($code != 334) {
  409. $this->smtp_log .= "сервер не разрешил начать авторизацию \n";
  410. fclose($smtp_conn);
  411. return;
  412. }
  413.  
  414. fputs($smtp_conn, base64_encode($this->smtp_login) . "\r\n");
  415. $this->smtp_log .= "Я: " . base64_encode($this->smtp_login) . "\n";
  416. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  417.  
  418. $code = substr($data, 0, 3);
  419. if ($code != 334) {
  420. $this->smtp_log .= "ошибка доступа к такому юзеру\n";
  421. fclose($smtp_conn);
  422. return;
  423. }
  424.  
  425.  
  426. fputs($smtp_conn, base64_encode($this->smtp_pass) . "\r\n");
  427. $this->smtp_log .= "Я: " . base64_encode($this->smtp_pass) . "\n";
  428. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  429.  
  430. $code = substr($data, 0, 3);
  431. if ($code != 235) {
  432. $this->smtp_log .= "не правильный пароль\n";
  433. fclose($smtp_conn);
  434. return;
  435. }
  436.  
  437. fputs($smtp_conn, "MAIL FROM:<" . $this->xheaders['From'] . "> SIZE=" . strlen($this->headers . "\r\n" . $this->fullBody) . "\r\n");
  438. $this->smtp_log .= "Я: MAIL FROM:<" . $this->xheaders['From'] . "> SIZE=" . strlen($this->headers . "\r\n" . $this->fullBody) . "\n";
  439. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  440.  
  441. $code = substr($data, 0, 3);
  442. if ($code != 250) {
  443. $this->smtp_log .= "сервер отказал в команде MAIL FROM\n";
  444. fclose($smtp_conn);
  445. return;
  446. }
  447.  
  448.  
  449.  
  450. foreach ($this->smtpsendto as $keywebi => $valuewebi) {
  451. fputs($smtp_conn, "RCPT TO:<" . $valuewebi . ">\r\n");
  452. $this->smtp_log .= "Я: RCPT TO:<" . $valuewebi . ">\n";
  453. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  454. $code = substr($data, 0, 3);
  455. if ($code != 250 AND $code != 251) {
  456. $this->smtp_log .= "Сервер не принял команду RCPT TO\n";
  457. fclose($smtp_conn);
  458. return;
  459. }
  460. }
  461. fputs($smtp_conn, "DATA\r\n");
  462. $this->smtp_log .= "Я: DATA\n";
  463. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  464.  
  465. $code = substr($data, 0, 3);
  466. if ($code != 354) {
  467. $this->smtp_log .= "сервер не принял DATA\n";
  468. fclose($smtp_conn);
  469. return;
  470. }
  471.  
  472. fputs($smtp_conn, $this->headers . "\r\n" . $this->fullBody . "\r\n.\r\n");
  473. $this->smtp_log .= "Я: " . $this->headers . "\r\n" . $this->fullBody . "\r\n.\r\n";
  474.  
  475. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  476.  
  477. $code = substr($data, 0, 3);
  478. if ($code != 250) {
  479. $this->smtp_log .= "ошибка отправки письма\n";
  480. fclose($smtp_conn);
  481. return;
  482. }
  483.  
  484. fputs($smtp_conn, "QUIT\r\n");
  485. $this->smtp_log .= "QUIT\r\n";
  486. $this->smtp_log .= $data = $this->get_data($smtp_conn) . "\n";
  487. fclose($smtp_conn);
  488. }
  489. }
  490.  
  491. /*
  492. * показывает что было отправлено
  493. *
  494. */
  495.  
  496. function Get() {
  497. if (isset($this->smtp_log)) {
  498. if ($this->smtp_log) {
  499. return $this->smtp_log; // если есть лог отправки smtp выведем его
  500. }
  501. }
  502.  
  503. $this->BuildMail();
  504. $mail = $this->headers . "\n\n";
  505. $mail .= $this->fullBody;
  506. return $mail;
  507. }
  508.  
  509. /*
  510. проверка мыла
  511. возвращает true или false
  512. */
  513.  
  514. function ValidEmail($address) {
  515.  
  516. // если существует современная функция фильтрации данных, то проверять будем этой функцией. появилась в php 5.2
  517. if (function_exists('filter_list')) {
  518. $valid_email = filter_var($address, FILTER_VALIDATE_EMAIL);
  519. if ($valid_email !== false)
  520. return true;
  521. else
  522. return false;
  523. } else { // а если php еще старой версии, то проверка валидности пойдет старым способом
  524. if (ereg(".*<(.+)>", $address, $regs)) {
  525. $address = $regs[1];
  526. }
  527. if (ereg("^[^@ ]+@([a-zA-Z0-9\-]+\.)+([a-zA-Z0-9\-]{2}|net|com|gov|mil|org|edu|int)\$", $address))
  528. return true;
  529. else
  530. return false;
  531. }
  532. }
  533.  
  534. /*
  535.  
  536. проверка массива адресов
  537.  
  538.  
  539. */
  540.  
  541. function CheckAdresses($aad) {
  542. for ($i = 0; $i < count($aad); $i++) {
  543. if (!$this->ValidEmail($aad[$i])) {
  544. echo "ошибка : не верный email " . $aad[$i];
  545. exit;
  546. }
  547. }
  548. }
  549.  
  550. /*
  551. сборка файлов для отправки
  552. */
  553.  
  554. function _build_attachement() {
  555.  
  556. $this->xheaders["Content-Type"] = "multipart/mixed;\n boundary=\"$this->boundary\"";
  557.  
  558. $this->fullBody = "This is a multi-part message in MIME format.\n--$this->boundary\n";
  559. $this->fullBody .= "Content-Type: " . $this->text_html . "; charset=$this->charset\nContent-Transfer-Encoding: $this->ctencoding\n\n" . $this->body . "\n";
  560.  
  561. $sep = chr(13) . chr(10);
  562.  
  563. $ata = array();
  564. $k = 0;
  565.  
  566. // перебираем файлы
  567. for ($i = 0; $i < count($this->aattach); $i++) {
  568.  
  569. $filename = $this->aattach[$i];
  570.  
  571. $webi_filename = $this->webi_filename[$i]; // имя файла, которое может приходить в класс, и имеет другое имя файла
  572. if (strlen($webi_filename))
  573. $basename = basename($webi_filename); // если есть другое имя файла, то оно будет таким
  574. else
  575. $basename = basename($filename); // а если нет другого имени файла, то имя будет выдернуто из самого загружаемого файла
  576.  
  577. $ctype = $this->actype[$i]; // content-type
  578. $disposition = $this->adispo[$i];
  579.  
  580. if (!file_exists($filename)) {
  581. echo "ошибка прикрепления файла : файл $filename не существует";
  582. exit;
  583. }
  584. $subhdr = "--$this->boundary\nContent-type: $ctype;\n name=\"$basename\"\nContent-Transfer-Encoding: base64\nContent-Disposition: $disposition;\n filename=\"$basename\"\n";
  585. $ata[$k++] = $subhdr;
  586. // non encoded line length
  587. $linesz = filesize($filename) + 1;
  588. $fp = fopen($filename, 'r');
  589. $ata[$k++] = chunk_split(base64_encode(fread($fp, $linesz)));
  590. fclose($fp);
  591. }
  592. $this->fullBody .= implode($sep, $ata);
  593. }
  594.  
  595. }