PageRenderTime 25ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/system/library/mail.php

https://gitlab.com/shapcy/opencart
PHP | 427 lines | 322 code | 104 blank | 1 comment | 113 complexity | 0e2a32be8421f82b65c60b46865a4f3b MD5 | raw file
  1. <?php
  2. class Mail {
  3. protected $to;
  4. protected $from;
  5. protected $sender;
  6. protected $reply_to;
  7. protected $subject;
  8. protected $text;
  9. protected $html;
  10. protected $attachments = array();
  11. public $protocol = 'mail';
  12. public $smtp_hostname;
  13. public $smtp_username;
  14. public $smtp_password;
  15. public $smtp_port = 25;
  16. public $smtp_timeout = 5;
  17. public $verp = false;
  18. public $parameter = '';
  19. public function __construct($config = array()) {
  20. foreach ($config as $key => $value) {
  21. $this->$key = $value;
  22. }
  23. }
  24. public function setTo($to) {
  25. $this->to = $to;
  26. }
  27. public function setFrom($from) {
  28. $this->from = $from;
  29. }
  30. public function setSender($sender) {
  31. $this->sender = $sender;
  32. }
  33. public function setReplyTo($reply_to) {
  34. $this->reply_to = $reply_to;
  35. }
  36. public function setSubject($subject) {
  37. $this->subject = $subject;
  38. }
  39. public function setText($text) {
  40. $this->text = $text;
  41. }
  42. public function setHtml($html) {
  43. $this->html = $html;
  44. }
  45. public function addAttachment($filename) {
  46. $this->attachments[] = $filename;
  47. }
  48. public function send() {
  49. if (!$this->to) {
  50. throw new \Exception('Error: E-Mail to required!');
  51. }
  52. if (!$this->from) {
  53. throw new \Exception('Error: E-Mail from required!');
  54. }
  55. if (!$this->sender) {
  56. throw new \Exception('Error: E-Mail sender required!');
  57. }
  58. if (!$this->subject) {
  59. throw new \Exception('Error: E-Mail subject required!');
  60. }
  61. if ((!$this->text) && (!$this->html)) {
  62. throw new \Exception('Error: E-Mail message required!');
  63. }
  64. if (is_array($this->to)) {
  65. $to = implode(',', $this->to);
  66. } else {
  67. $to = $this->to;
  68. }
  69. $boundary = '----=_NextPart_' . md5(time());
  70. $header = 'MIME-Version: 1.0' . PHP_EOL;
  71. if ($this->protocol != 'mail') {
  72. $header .= 'To: <' . $to . '>' . PHP_EOL;
  73. $header .= 'Subject: =?UTF-8?B?' . base64_encode($this->subject) . '?=' . PHP_EOL;
  74. }
  75. $header .= 'Date: ' . date('D, d M Y H:i:s O') . PHP_EOL;
  76. $header .= 'From: =?UTF-8?B?' . base64_encode($this->sender) . '?= <' . $this->from . '>' . PHP_EOL;
  77. if (!$this->reply_to) {
  78. $header .= 'Reply-To: =?UTF-8?B?' . base64_encode($this->sender) . '?= <' . $this->from . '>' . PHP_EOL;
  79. } else {
  80. $header .= 'Reply-To: =?UTF-8?B?' . base64_encode($this->reply_to) . '?= <' . $this->reply_to . '>' . PHP_EOL;
  81. }
  82. $header .= 'Return-Path: ' . $this->from . PHP_EOL;
  83. $header .= 'X-Mailer: PHP/' . phpversion() . PHP_EOL;
  84. $header .= 'Content-Type: multipart/related; boundary="' . $boundary . '"' . PHP_EOL . PHP_EOL;
  85. if (!$this->html) {
  86. $message = '--' . $boundary . PHP_EOL;
  87. $message .= 'Content-Type: text/plain; charset="utf-8"' . PHP_EOL;
  88. $message .= 'Content-Transfer-Encoding: 8bit' . PHP_EOL . PHP_EOL;
  89. $message .= $this->text . PHP_EOL;
  90. } else {
  91. $message = '--' . $boundary . PHP_EOL;
  92. $message .= 'Content-Type: multipart/alternative; boundary="' . $boundary . '_alt"' . PHP_EOL . PHP_EOL;
  93. $message .= '--' . $boundary . '_alt' . PHP_EOL;
  94. $message .= 'Content-Type: text/plain; charset="utf-8"' . PHP_EOL;
  95. $message .= 'Content-Transfer-Encoding: 8bit' . PHP_EOL . PHP_EOL;
  96. if ($this->text) {
  97. $message .= $this->text . PHP_EOL;
  98. } else {
  99. $message .= 'This is a HTML email and your email client software does not support HTML email!' . PHP_EOL;
  100. }
  101. $message .= '--' . $boundary . '_alt' . PHP_EOL;
  102. $message .= 'Content-Type: text/html; charset="utf-8"' . PHP_EOL;
  103. $message .= 'Content-Transfer-Encoding: 8bit' . PHP_EOL . PHP_EOL;
  104. $message .= $this->html . PHP_EOL;
  105. $message .= '--' . $boundary . '_alt--' . PHP_EOL;
  106. }
  107. foreach ($this->attachments as $attachment) {
  108. if (file_exists($attachment)) {
  109. $handle = fopen($attachment, 'r');
  110. $content = fread($handle, filesize($attachment));
  111. fclose($handle);
  112. $message .= '--' . $boundary . PHP_EOL;
  113. $message .= 'Content-Type: application/octet-stream; name="' . basename($attachment) . '"' . PHP_EOL;
  114. $message .= 'Content-Transfer-Encoding: base64' . PHP_EOL;
  115. $message .= 'Content-Disposition: attachment; filename="' . basename($attachment) . '"' . PHP_EOL;
  116. $message .= 'Content-ID: <' . basename(urlencode($attachment)) . '>' . PHP_EOL;
  117. $message .= 'X-Attachment-Id: ' . basename(urlencode($attachment)) . PHP_EOL . PHP_EOL;
  118. $message .= chunk_split(base64_encode($content));
  119. }
  120. }
  121. $message .= '--' . $boundary . '--' . PHP_EOL;
  122. if ($this->protocol == 'mail') {
  123. ini_set('sendmail_from', $this->from);
  124. if ($this->parameter) {
  125. mail($to, '=?UTF-8?B?' . base64_encode($this->subject) . '?=', $message, $header, $this->parameter);
  126. } else {
  127. mail($to, '=?UTF-8?B?' . base64_encode($this->subject) . '?=', $message, $header);
  128. }
  129. } elseif ($this->protocol == 'smtp') {
  130. if (substr($this->smtp_hostname, 0, 3) == 'tls') {
  131. $hostname = substr($this->smtp_hostname, 6);
  132. } else {
  133. $hostname = $this->smtp_hostname;
  134. }
  135. $handle = fsockopen($hostname, $this->smtp_port, $errno, $errstr, $this->smtp_timeout);
  136. if (!$handle) {
  137. throw new \Exception('Error: ' . $errstr . ' (' . $errno . ')');
  138. } else {
  139. if (substr(PHP_OS, 0, 3) != 'WIN') {
  140. socket_set_timeout($handle, $this->smtp_timeout, 0);
  141. }
  142. while ($line = fgets($handle, 515)) {
  143. if (substr($line, 3, 1) == ' ') {
  144. break;
  145. }
  146. }
  147. fputs($handle, 'EHLO ' . getenv('SERVER_NAME') . "\r\n");
  148. $reply = '';
  149. while ($line = fgets($handle, 515)) {
  150. $reply .= $line;
  151. if (substr($line, 3, 1) == ' ') {
  152. break;
  153. }
  154. }
  155. if (substr($reply, 0, 3) != 250) {
  156. throw new \Exception('Error: EHLO not accepted from server!');
  157. }
  158. if (substr($this->smtp_hostname, 0, 3) == 'tls') {
  159. fputs($handle, 'STARTTLS' . "\r\n");
  160. $reply = '';
  161. while ($line = fgets($handle, 515)) {
  162. $reply .= $line;
  163. if (substr($line, 3, 1) == ' ') {
  164. break;
  165. }
  166. }
  167. if (substr($reply, 0, 3) != 220) {
  168. throw new \Exception('Error: STARTTLS not accepted from server!');
  169. }
  170. stream_socket_enable_crypto($handle, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
  171. }
  172. if (!empty($this->smtp_username) && !empty($this->smtp_password)) {
  173. fputs($handle, 'EHLO ' . getenv('SERVER_NAME') . "\r\n");
  174. $reply = '';
  175. while ($line = fgets($handle, 515)) {
  176. $reply .= $line;
  177. if (substr($line, 3, 1) == ' ') {
  178. break;
  179. }
  180. }
  181. if (substr($reply, 0, 3) != 250) {
  182. throw new \Exception('Error: EHLO not accepted from server!');
  183. }
  184. fputs($handle, 'AUTH LOGIN' . "\r\n");
  185. $reply = '';
  186. while ($line = fgets($handle, 515)) {
  187. $reply .= $line;
  188. if (substr($line, 3, 1) == ' ') {
  189. break;
  190. }
  191. }
  192. if (substr($reply, 0, 3) != 334) {
  193. throw new \Exception('Error: AUTH LOGIN not accepted from server!');
  194. }
  195. fputs($handle, base64_encode($this->smtp_username) . "\r\n");
  196. $reply = '';
  197. while ($line = fgets($handle, 515)) {
  198. $reply .= $line;
  199. if (substr($line, 3, 1) == ' ') {
  200. break;
  201. }
  202. }
  203. if (substr($reply, 0, 3) != 334) {
  204. throw new \Exception('Error: Username not accepted from server!');
  205. }
  206. fputs($handle, base64_encode($this->smtp_password) . "\r\n");
  207. $reply = '';
  208. while ($line = fgets($handle, 515)) {
  209. $reply .= $line;
  210. if (substr($line, 3, 1) == ' ') {
  211. break;
  212. }
  213. }
  214. if (substr($reply, 0, 3) != 235) {
  215. throw new \Exception('Error: Password not accepted from server!');
  216. }
  217. } else {
  218. fputs($handle, 'HELO ' . getenv('SERVER_NAME') . "\r\n");
  219. $reply = '';
  220. while ($line = fgets($handle, 515)) {
  221. $reply .= $line;
  222. if (substr($line, 3, 1) == ' ') {
  223. break;
  224. }
  225. }
  226. if (substr($reply, 0, 3) != 250) {
  227. throw new \Exception('Error: HELO not accepted from server!');
  228. }
  229. }
  230. if ($this->verp) {
  231. fputs($handle, 'MAIL FROM: <' . $this->from . '>XVERP' . "\r\n");
  232. } else {
  233. fputs($handle, 'MAIL FROM: <' . $this->from . '>' . "\r\n");
  234. }
  235. $reply = '';
  236. while ($line = fgets($handle, 515)) {
  237. $reply .= $line;
  238. if (substr($line, 3, 1) == ' ') {
  239. break;
  240. }
  241. }
  242. if (substr($reply, 0, 3) != 250) {
  243. throw new \Exception('Error: MAIL FROM not accepted from server!');
  244. }
  245. if (!is_array($this->to)) {
  246. fputs($handle, 'RCPT TO: <' . $this->to . '>' . "\r\n");
  247. $reply = '';
  248. while ($line = fgets($handle, 515)) {
  249. $reply .= $line;
  250. if (substr($line, 3, 1) == ' ') {
  251. break;
  252. }
  253. }
  254. if ((substr($reply, 0, 3) != 250) && (substr($reply, 0, 3) != 251)) {
  255. throw new \Exception('Error: RCPT TO not accepted from server!');
  256. }
  257. } else {
  258. foreach ($this->to as $recipient) {
  259. fputs($handle, 'RCPT TO: <' . $recipient . '>' . "\r\n");
  260. $reply = '';
  261. while ($line = fgets($handle, 515)) {
  262. $reply .= $line;
  263. if (substr($line, 3, 1) == ' ') {
  264. break;
  265. }
  266. }
  267. if ((substr($reply, 0, 3) != 250) && (substr($reply, 0, 3) != 251)) {
  268. throw new \Exception('Error: RCPT TO not accepted from server!');
  269. }
  270. }
  271. }
  272. fputs($handle, 'DATA' . "\r\n");
  273. $reply = '';
  274. while ($line = fgets($handle, 515)) {
  275. $reply .= $line;
  276. if (substr($line, 3, 1) == ' ') {
  277. break;
  278. }
  279. }
  280. if (substr($reply, 0, 3) != 354) {
  281. throw new \Exception('Error: DATA not accepted from server!');
  282. }
  283. // According to rfc 821 we should not send more than 1000 including the CRLF
  284. $message = str_replace("\r\n", "\n", $header . $message);
  285. $message = str_replace("\r", "\n", $message);
  286. $lines = explode("\n", $message);
  287. foreach ($lines as $line) {
  288. $results = str_split($line, 998);
  289. foreach ($results as $result) {
  290. if (substr(PHP_OS, 0, 3) != 'WIN') {
  291. fputs($handle, $result . "\r\n");
  292. } else {
  293. fputs($handle, str_replace("\n", "\r\n", $result) . "\r\n");
  294. }
  295. }
  296. }
  297. fputs($handle, '.' . "\r\n");
  298. $reply = '';
  299. while ($line = fgets($handle, 515)) {
  300. $reply .= $line;
  301. if (substr($line, 3, 1) == ' ') {
  302. break;
  303. }
  304. }
  305. if (substr($reply, 0, 3) != 250) {
  306. throw new \Exception('Error: DATA not accepted from server!');
  307. }
  308. fputs($handle, 'QUIT' . "\r\n");
  309. $reply = '';
  310. while ($line = fgets($handle, 515)) {
  311. $reply .= $line;
  312. if (substr($line, 3, 1) == ' ') {
  313. break;
  314. }
  315. }
  316. if (substr($reply, 0, 3) != 221) {
  317. throw new \Exception('Error: QUIT not accepted from server!');
  318. }
  319. fclose($handle);
  320. }
  321. }
  322. }
  323. }