· 8 years ago · Mar 05, 2018, 04:10 PM
1<?php
2
3//my PHP tester thing
4//Uses PHPMailer by Andy Prevost and Marcus Bointon
5
6$current_dir = dirname(__FILE__);
7$prefix = "phptest-";
8$now = date("Y-m-d.H:i:s");
9touch($current_dir . DIRECTORY_SEPARATOR . $prefix . $now);
10
11
12ini_set('track_errors', 1);
13date_default_timezone_set('America/Phoenix');
14
15/*~ class.phpmailer.php
16.---------------------------------------------------------------------------.
17| Software: PHPMailer - PHP email class |
18| Version: 5.1 |
19| Contact: via sourceforge.net support pages (also www.worxware.com) |
20| Info: http://phpmailer.sourceforge.net |
21| Support: http://sourceforge.net/projects/phpmailer/ |
22| ------------------------------------------------------------------------- |
23| Admin: Andy Prevost (project admininistrator) |
24| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
25| : Marcus Bointon (coolbru) coolbru@users.sourceforge.net |
26| Founder: Brent R. Matzelle (original founder) |
27| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
28| Copyright (c) 2001-2003, Brent R. Matzelle |
29| ------------------------------------------------------------------------- |
30| License: Distributed under the Lesser General Public License (LGPL) |
31| http://www.gnu.org/copyleft/lesser.html |
32| This program is distributed in the hope that it will be useful - WITHOUT |
33| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
34| FITNESS FOR A PARTICULAR PURPOSE. |
35' ------------------------------------------------------------------------- '
36*/
37
38/**
39 * PHPMailer - PHP email transport class
40 * NOTE: Requires PHP version 5 or later
41 * @package PHPMailer
42 * @author Andy Prevost
43 * @author Marcus Bointon
44 * @copyright 2004 - 2009 Andy Prevost
45 * @version $Id: class.phpmailer.php 447 2009-05-25 01:36:38Z codeworxtech $
46 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
47 */
48
49if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
50
51class PHPMailer {
52
53 /////////////////////////////////////////////////
54 // PROPERTIES, PUBLIC
55 /////////////////////////////////////////////////
56
57 /**
58 * Email priority (1 = High, 3 = Normal, 5 = low).
59 * @var int
60 */
61 public $Priority = 3;
62
63 /**
64 * Sets the CharSet of the message.
65 * @var string
66 */
67 public $CharSet = 'iso-8859-1';
68
69 /**
70 * Sets the Content-type of the message.
71 * @var string
72 */
73 public $ContentType = 'text/plain';
74
75 /**
76 * Sets the Encoding of the message. Options for this are
77 * "8bit", "7bit", "binary", "base64", and "quoted-printable".
78 * @var string
79 */
80 public $Encoding = '8bit';
81
82 /**
83 * Holds the most recent mailer error message.
84 * @var string
85 */
86 public $ErrorInfo = '';
87
88 /**
89 * Sets the From email address for the message.
90 * @var string
91 */
92 public $From = 'root@localhost';
93
94 /**
95 * Sets the From name of the message.
96 * @var string
97 */
98 public $FromName = 'Root User';
99
100 /**
101 * Sets the Sender email (Return-Path) of the message. If not empty,
102 * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
103 * @var string
104 */
105 public $Sender = '';
106
107 /**
108 * Sets the Subject of the message.
109 * @var string
110 */
111 public $Subject = '';
112
113 /**
114 * Sets the Body of the message. This can be either an HTML or text body.
115 * If HTML then run IsHTML(true).
116 * @var string
117 */
118 public $Body = '';
119
120 /**
121 * Sets the text-only body of the message. This automatically sets the
122 * email to multipart/alternative. This body can be read by mail
123 * clients that do not have HTML email capability such as mutt. Clients
124 * that can read HTML will view the normal Body.
125 * @var string
126 */
127 public $AltBody = '';
128
129 /**
130 * Sets word wrapping on the body of the message to a given number of
131 * characters.
132 * @var int
133 */
134 public $WordWrap = 0;
135
136 /**
137 * Method to send mail: ("mail", "sendmail", or "smtp").
138 * @var string
139 */
140 public $Mailer = 'mail';
141
142 /**
143 * Sets the path of the sendmail program.
144 * @var string
145 */
146 public $Sendmail = '/usr/sbin/sendmail';
147
148 /**
149 * Path to PHPMailer plugins. Useful if the SMTP class
150 * is in a different directory than the PHP include path.
151 * @var string
152 */
153 public $PluginDir = '';
154
155 /**
156 * Sets the email address that a reading confirmation will be sent.
157 * @var string
158 */
159 public $ConfirmReadingTo = '';
160
161 /**
162 * Sets the hostname to use in Message-Id and Received headers
163 * and as default HELO string. If empty, the value returned
164 * by SERVER_NAME is used or 'localhost.localdomain'.
165 * @var string
166 */
167 public $Hostname = '';
168
169 /**
170 * Sets the message ID to be used in the Message-Id header.
171 * If empty, a unique id will be generated.
172 * @var string
173 */
174 public $MessageID = '';
175
176 /////////////////////////////////////////////////
177 // PROPERTIES FOR SMTP
178 /////////////////////////////////////////////////
179
180 /**
181 * Sets the SMTP hosts. All hosts must be separated by a
182 * semicolon. You can also specify a different port
183 * for each host by using this format: [hostname:port]
184 * (e.g. "smtp1.example.com:25;smtp2.example.com").
185 * Hosts will be tried in order.
186 * @var string
187 */
188 public $Host = 'localhost';
189
190 /**
191 * Sets the default SMTP server port.
192 * @var int
193 */
194 public $Port = 25;
195
196 /**
197 * Sets the SMTP HELO of the message (Default is $Hostname).
198 * @var string
199 */
200 public $Helo = '';
201
202 /**
203 * Sets connection prefix.
204 * Options are "", "ssl" or "tls"
205 * @var string
206 */
207 public $SMTPSecure = '';
208
209 /**
210 * Sets SMTP authentication. Utilizes the Username and Password variables.
211 * @var bool
212 */
213 public $SMTPAuth = false;
214
215 /**
216 * Sets SMTP username.
217 * @var string
218 */
219 public $Username = '';
220
221 /**
222 * Sets SMTP password.
223 * @var string
224 */
225 public $Password = '';
226
227 /**
228 * Sets the SMTP server timeout in seconds.
229 * This function will not work with the win32 version.
230 * @var int
231 */
232 public $Timeout = 10;
233
234 /**
235 * Sets SMTP class debugging on or off.
236 * @var bool
237 */
238 public $SMTPDebug = false;
239
240 /**
241 * Prevents the SMTP connection from being closed after each mail
242 * sending. If this is set to true then to close the connection
243 * requires an explicit call to SmtpClose().
244 * @var bool
245 */
246 public $SMTPKeepAlive = false;
247
248 /**
249 * Provides the ability to have the TO field process individual
250 * emails, instead of sending to entire TO addresses
251 * @var bool
252 */
253 public $SingleTo = false;
254
255 /**
256 * If SingleTo is true, this provides the array to hold the email addresses
257 * @var bool
258 */
259 public $SingleToArray = array();
260
261 /**
262 * Provides the ability to change the line ending
263 * @var string
264 */
265 public $LE = "\n";
266
267 /**
268 * Used with DKIM DNS Resource Record
269 * @var string
270 */
271 public $DKIM_selector = 'phpmailer';
272
273 /**
274 * Used with DKIM DNS Resource Record
275 * optional, in format of email address 'you@yourdomain.com'
276 * @var string
277 */
278 public $DKIM_identity = '';
279
280 /**
281 * Used with DKIM DNS Resource Record
282 * optional, in format of email address 'you@yourdomain.com'
283 * @var string
284 */
285 public $DKIM_domain = '';
286
287 /**
288 * Used with DKIM DNS Resource Record
289 * optional, in format of email address 'you@yourdomain.com'
290 * @var string
291 */
292 public $DKIM_private = '';
293
294 /**
295 * Callback Action function name
296 * the function that handles the result of the send email action. Parameters:
297 * bool $result result of the send action
298 * string $to email address of the recipient
299 * string $cc cc email addresses
300 * string $bcc bcc email addresses
301 * string $subject the subject
302 * string $body the email body
303 * @var string
304 */
305 public $action_function = ''; //'callbackAction';
306
307 /**
308 * Sets the PHPMailer Version number
309 * @var string
310 */
311 public $Version = '5.1';
312
313 /////////////////////////////////////////////////
314 // PROPERTIES, PRIVATE AND PROTECTED
315 /////////////////////////////////////////////////
316
317 private $smtp = NULL;
318 private $to = array();
319 private $cc = array();
320 private $bcc = array();
321 private $ReplyTo = array();
322 private $all_recipients = array();
323 private $attachment = array();
324 private $CustomHeader = array();
325 private $message_type = '';
326 private $boundary = array();
327 protected $language = array();
328 private $error_count = 0;
329 private $sign_cert_file = "";
330 private $sign_key_file = "";
331 private $sign_key_pass = "";
332 private $exceptions = false;
333
334 /////////////////////////////////////////////////
335 // CONSTANTS
336 /////////////////////////////////////////////////
337
338 const STOP_MESSAGE = 0; // message only, continue processing
339 const STOP_CONTINUE = 1; // message?, likely ok to continue processing
340 const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
341
342 /////////////////////////////////////////////////
343 // METHODS, VARIABLES
344 /////////////////////////////////////////////////
345
346 /**
347 * Constructor
348 * @param boolean $exceptions Should we throw external exceptions?
349 */
350 public function __construct($exceptions = false) {
351 $this->exceptions = ($exceptions == true);
352 }
353
354 /**
355 * Sets message type to HTML.
356 * @param bool $ishtml
357 * @return void
358 */
359 public function IsHTML($ishtml = true) {
360 $this->ContentType = 'text/plain';
361// if ($ishtml) {
362// $this->ContentType = 'text/html';
363// } else {
364// $this->ContentType = 'text/plain';
365// }
366 }
367
368 /**
369 * Sets Mailer to send message using SMTP.
370 * @return void
371 */
372 public function IsSMTP() {
373 $this->Mailer = 'smtp';
374 }
375
376 /**
377 * Sets Mailer to send message using PHP mail() function.
378 * @return void
379 */
380 public function IsMail() {
381 $this->Mailer = 'mail';
382 }
383
384 /**
385 * Sets Mailer to send message using the $Sendmail program.
386 * @return void
387 */
388 public function IsSendmail() {
389 if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
390 $this->Sendmail = '/var/qmail/bin/sendmail';
391 }
392 $this->Mailer = 'sendmail';
393 }
394
395 /**
396 * Sets Mailer to send message using the qmail MTA.
397 * @return void
398 */
399 public function IsQmail() {
400 if (stristr(ini_get('sendmail_path'), 'qmail')) {
401 $this->Sendmail = '/var/qmail/bin/sendmail';
402 }
403 $this->Mailer = 'sendmail';
404 }
405
406 /////////////////////////////////////////////////
407 // METHODS, RECIPIENTS
408 /////////////////////////////////////////////////
409
410 /**
411 * Adds a "To" address.
412 * @param string $address
413 * @param string $name
414 * @return boolean true on success, false if address already used
415 */
416 public function AddAddress($address, $name = '') {
417 return $this->AddAnAddress('to', $address, $name);
418 }
419
420 /**
421 * Adds a "Cc" address.
422 * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
423 * @param string $address
424 * @param string $name
425 * @return boolean true on success, false if address already used
426 */
427 public function AddCC($address, $name = '') {
428 return $this->AddAnAddress('cc', $address, $name);
429 }
430
431 /**
432 * Adds a "Bcc" address.
433 * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
434 * @param string $address
435 * @param string $name
436 * @return boolean true on success, false if address already used
437 */
438 public function AddBCC($address, $name = '') {
439 return $this->AddAnAddress('bcc', $address, $name);
440 }
441
442 /**
443 * Adds a "Reply-to" address.
444 * @param string $address
445 * @param string $name
446 * @return boolean
447 */
448 public function AddReplyTo($address, $name = '') {
449 return $this->AddAnAddress('ReplyTo', $address, $name);
450 }
451
452 /**
453 * Adds an address to one of the recipient arrays
454 * Addresses that have been added already return false, but do not throw exceptions
455 * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
456 * @param string $address The email address to send to
457 * @param string $name
458 * @return boolean true on success, false if address already used or invalid in some way
459 * @access private
460 */
461 private function AddAnAddress($kind, $address, $name = '') {
462 if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
463 echo 'Invalid recipient array: ' . kind;
464 return false;
465 }
466 $address = trim($address);
467 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
468 if (!self::ValidateAddress($address)) {
469 $this->SetError($this->Lang('invalid_address').': '. $address);
470 if ($this->exceptions) {
471 throw new phpmailerException($this->Lang('invalid_address').': '.$address);
472 }
473 echo $this->Lang('invalid_address').': '.$address;
474 return false;
475 }
476 if ($kind != 'ReplyTo') {
477 if (!isset($this->all_recipients[strtolower($address)])) {
478 array_push($this->$kind, array($address, $name));
479 $this->all_recipients[strtolower($address)] = true;
480 return true;
481 }
482 } else {
483 if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
484 $this->ReplyTo[strtolower($address)] = array($address, $name);
485 return true;
486 }
487 }
488 return false;
489}
490
491/**
492 * Set the From and FromName properties
493 * @param string $address
494 * @param string $name
495 * @return boolean
496 */
497 public function SetFrom($address, $name = '',$auto=1) {
498 $address = trim($address);
499 $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
500 if (!self::ValidateAddress($address)) {
501 $this->SetError($this->Lang('invalid_address').': '. $address);
502 if ($this->exceptions) {
503 throw new phpmailerException($this->Lang('invalid_address').': '.$address);
504 }
505 echo $this->Lang('invalid_address').': '.$address;
506 return false;
507 }
508 $this->From = $address;
509 $this->FromName = $name;
510 if ($auto) {
511 if (empty($this->ReplyTo)) {
512 $this->AddAnAddress('ReplyTo', $address, $name);
513 }
514 if (empty($this->Sender)) {
515 $this->Sender = $address;
516 }
517 }
518 return true;
519 }
520
521 /**
522 * Check that a string looks roughly like an email address should
523 * Static so it can be used without instantiation
524 * Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator
525 * Conforms approximately to RFC2822
526 * @link http://www.hexillion.com/samples/#Regex Original pattern found here
527 * @param string $address The email address to check
528 * @return boolean
529 * @static
530 * @access public
531 */
532 public static function ValidateAddress($address) {
533 if (function_exists('filter_var')) { //Introduced in PHP 5.2
534 if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
535 return false;
536 } else {
537 return true;
538 }
539 } else {
540 return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
541 }
542 }
543
544 /////////////////////////////////////////////////
545 // METHODS, MAIL SENDING
546 /////////////////////////////////////////////////
547
548 /**
549 * Creates message and assigns Mailer. If the message is
550 * not sent successfully then it returns false. Use the ErrorInfo
551 * variable to view description of the error.
552 * @return bool
553 */
554 public function Send() {
555 try {
556 if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
557 throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
558 }
559
560 // Set whether the message is multipart/alternative
561 if(!empty($this->AltBody)) {
562 $this->ContentType = 'multipart/alternative';
563 }
564
565 $this->error_count = 0; // reset errors
566 $this->SetMessageType();
567 $header = $this->CreateHeader();
568 $body = $this->CreateBody();
569
570 if (empty($this->Body)) {
571 throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
572 }
573
574 // digitally sign with DKIM if enabled
575 if ($this->DKIM_domain && $this->DKIM_private) {
576 $header_dkim = $this->DKIM_Add($header,$this->Subject,$body);
577 $header = str_replace("\r\n","\n",$header_dkim) . $header;
578 }
579
580 // Choose the mailer and send through it
581 switch($this->Mailer) {
582 case 'sendmail':
583 return $this->SendmailSend($header, $body);
584 case 'smtp':
585 return $this->SmtpSend($header, $body);
586 default:
587 return $this->MailSend($header, $body);
588 }
589
590 } catch (phpmailerException $e) {
591 $this->SetError($e->getMessage());
592 if ($this->exceptions) {
593 throw $e;
594 }
595 echo $e->getMessage()."\n";
596 return false;
597 }
598 }
599
600 /**
601 * Sends mail using the $Sendmail program.
602 * @param string $header The message headers
603 * @param string $body The message body
604 * @access protected
605 * @return bool
606 */
607 protected function SendmailSend($header, $body) {
608 if ($this->Sender != '') {
609 $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
610 } else {
611 $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
612 }
613 if ($this->SingleTo === true) {
614 foreach ($this->SingleToArray as $key => $val) {
615 if(!@$mail = popen($sendmail, 'w')) {
616 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
617 }
618 fputs($mail, "To: " . $val . "\n");
619 fputs($mail, $header);
620 fputs($mail, $body);
621 $result = pclose($mail);
622 // implement call back function if it exists
623 $isSent = ($result == 0) ? 1 : 0;
624 $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
625 if($result != 0) {
626 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
627 }
628 }
629 } else {
630 if(!@$mail = popen($sendmail, 'w')) {
631 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
632 }
633 fputs($mail, $header);
634 fputs($mail, $body);
635 $result = pclose($mail);
636 // implement call back function if it exists
637 $isSent = ($result == 0) ? 1 : 0;
638 $this->doCallback($isSent,$this->to,$this->cc,$this->bcc,$this->Subject,$body);
639 if($result != 0) {
640 throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
641 }
642 }
643 return true;
644 }
645
646 /**
647 * Sends mail using the PHP mail() function.
648 * @param string $header The message headers
649 * @param string $body The message body
650 * @access protected
651 * @return bool
652 */
653 protected function MailSend($header, $body) {
654 $toArr = array();
655 foreach($this->to as $t) {
656 $toArr[] = $this->AddrFormat($t);
657 }
658 $to = implode(', ', $toArr);
659
660 $params = sprintf("-oi -f %s", $this->Sender);
661 if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
662 $old_from = ini_get('sendmail_from');
663 ini_set('sendmail_from', $this->Sender);
664 if ($this->SingleTo === true && count($toArr) > 1) {
665 foreach ($toArr as $key => $val) {
666 $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
667 // implement call back function if it exists
668 $isSent = ($rt == 1) ? 1 : 0;
669 $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
670 }
671 } else {
672 $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
673 // implement call back function if it exists
674 $isSent = ($rt == 1) ? 1 : 0;
675 $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
676 }
677 } else {
678 if ($this->SingleTo === true && count($toArr) > 1) {
679 foreach ($toArr as $key => $val) {
680 $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
681 // implement call back function if it exists
682 $isSent = ($rt == 1) ? 1 : 0;
683 $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
684 }
685 } else {
686 $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
687 // implement call back function if it exists
688 $isSent = ($rt == 1) ? 1 : 0;
689 $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
690 }
691 }
692 if (isset($old_from)) {
693 ini_set('sendmail_from', $old_from);
694 }
695 if(!$rt) {
696 throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
697 }
698 return true;
699 }
700
701 /**
702 * Sends mail via SMTP using PhpSMTP
703 * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
704 * @param string $header The message headers
705 * @param string $body The message body
706 * @uses SMTP
707 * @access protected
708 * @return bool
709 */
710 protected function SmtpSend($header, $body) {
711// require_once $this->PluginDir . 'class.smtp.php';
712 $bad_rcpt = array();
713
714 if(!$this->SmtpConnect()) {
715 throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
716 }
717 $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
718 if(!$this->smtp->Mail($smtp_from)) {
719 throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
720 }
721
722 // Attempt to send attach all recipients
723 foreach($this->to as $to) {
724 if (!$this->smtp->Recipient($to[0])) {
725 $bad_rcpt[] = $to[0];
726 // implement call back function if it exists
727 $isSent = 0;
728 $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
729 } else {
730 // implement call back function if it exists
731 $isSent = 1;
732 $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
733 }
734 }
735 foreach($this->cc as $cc) {
736 if (!$this->smtp->Recipient($cc[0])) {
737 $bad_rcpt[] = $cc[0];
738 // implement call back function if it exists
739 $isSent = 0;
740 $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
741 } else {
742 // implement call back function if it exists
743 $isSent = 1;
744 $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
745 }
746 }
747 foreach($this->bcc as $bcc) {
748 if (!$this->smtp->Recipient($bcc[0])) {
749 $bad_rcpt[] = $bcc[0];
750 // implement call back function if it exists
751 $isSent = 0;
752 $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
753 } else {
754 // implement call back function if it exists
755 $isSent = 1;
756 $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
757 }
758 }
759
760
761 if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
762 $badaddresses = implode(', ', $bad_rcpt);
763 throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
764 }
765 if(!$this->smtp->Data($header . $body)) {
766 throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
767 }
768 if($this->SMTPKeepAlive == true) {
769 $this->smtp->Reset();
770 }
771 return true;
772 }
773
774 /**
775 * Initiates a connection to an SMTP server.
776 * Returns false if the operation failed.
777 * @uses SMTP
778 * @access public
779 * @return bool
780 */
781 public function SmtpConnect() {
782 if(is_null($this->smtp)) {
783 $this->smtp = new SMTP();
784 }
785
786 $this->smtp->do_debug = $this->SMTPDebug;
787 $hosts = explode(';', $this->Host);
788 $index = 0;
789 $connection = $this->smtp->Connected();
790
791 // Retry while there is no connection
792 try {
793 while($index < count($hosts) && !$connection) {
794 $hostinfo = array();
795 if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
796 $host = $hostinfo[1];
797 $port = $hostinfo[2];
798 } else {
799 $host = $hosts[$index];
800 $port = $this->Port;
801 }
802
803 $tls = ($this->SMTPSecure == 'tls');
804 $ssl = ($this->SMTPSecure == 'ssl');
805
806 if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
807
808 $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
809 $this->smtp->Hello($hello);
810
811 if ($tls) {
812 if (!$this->smtp->StartTLS()) {
813 throw new phpmailerException($this->Lang('tls'));
814 }
815
816 //We must resend HELO after tls negotiation
817 $this->smtp->Hello($hello);
818 }
819
820 $connection = true;
821 if ($this->SMTPAuth) {
822 if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
823 throw new phpmailerException($this->Lang('authenticate'));
824 }
825 }
826 }
827 $index++;
828 if (!$connection) {
829 throw new phpmailerException($this->Lang('connect_host'));
830 }
831 }
832 } catch (phpmailerException $e) {
833 $this->smtp->Reset();
834 throw $e;
835 }
836 return true;
837 }
838
839 /**
840 * Closes the active SMTP session if one exists.
841 * @return void
842 */
843 public function SmtpClose() {
844 if(!is_null($this->smtp)) {
845 if($this->smtp->Connected()) {
846 $this->smtp->Quit();
847 $this->smtp->Close();
848 }
849 }
850 }
851
852 /**
853 * Sets the language for all class error messages.
854 * Returns false if it cannot load the language file. The default language is English.
855 * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
856 * @param string $lang_path Path to the language file directory
857 * @access public
858 */
859 function SetLanguage($langcode = 'en', $lang_path = 'language/') {
860 //Define full set of translatable strings
861 $PHPMAILER_LANG = array(
862 'provide_address' => 'You must provide at least one recipient email address.',
863 'mailer_not_supported' => ' mailer is not supported.',
864 'execute' => 'Could not execute: ',
865 'instantiate' => 'Could not instantiate mail function.',
866 'authenticate' => 'SMTP Error: Could not authenticate.',
867 'from_failed' => 'The following From address failed: ',
868 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
869 'data_not_accepted' => 'SMTP Error: Data not accepted.',
870 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
871 'file_access' => 'Could not access file: ',
872 'file_open' => 'File Error: Could not open file: ',
873 'encoding' => 'Unknown encoding: ',
874 'signing' => 'Signing Error: ',
875 'smtp_error' => 'SMTP server error: ',
876 'empty_message' => 'Message body empty',
877 'invalid_address' => 'Invalid address',
878 'variable_set' => 'Cannot set or reset variable: '
879 );
880 //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
881 $l = true;
882 if ($langcode != 'en') { //There is no English translation file
883 $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
884 }
885 $this->language = $PHPMAILER_LANG;
886 return ($l == true); //Returns false if language not found
887 }
888
889 /**
890 * Return the current array of language strings
891 * @return array
892 */
893 public function GetTranslations() {
894 return $this->language;
895 }
896
897 /////////////////////////////////////////////////
898 // METHODS, MESSAGE CREATION
899 /////////////////////////////////////////////////
900
901 /**
902 * Creates recipient headers.
903 * @access public
904 * @return string
905 */
906 public function AddrAppend($type, $addr) {
907 $addr_str = $type . ': ';
908 $addresses = array();
909 foreach ($addr as $a) {
910 $addresses[] = $this->AddrFormat($a);
911 }
912 $addr_str .= implode(', ', $addresses);
913 $addr_str .= $this->LE;
914
915 return $addr_str;
916 }
917
918 /**
919 * Formats an address correctly.
920 * @access public
921 * @return string
922 */
923 public function AddrFormat($addr) {
924 if (empty($addr[1])) {
925 return $this->SecureHeader($addr[0]);
926 } else {
927 return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
928 }
929 }
930
931 /**
932 * Wraps message for use with mailers that do not
933 * automatically perform wrapping and for quoted-printable.
934 * Original written by philippe.
935 * @param string $message The message to wrap
936 * @param integer $length The line length to wrap to
937 * @param boolean $qp_mode Whether to run in Quoted-Printable mode
938 * @access public
939 * @return string
940 */
941 public function WrapText($message, $length, $qp_mode = false) {
942 $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
943 // If utf-8 encoding is used, we will need to make sure we don't
944 // split multibyte characters when we wrap
945 $is_utf8 = (strtolower($this->CharSet) == "utf-8");
946
947 $message = $this->FixEOL($message);
948 if (substr($message, -1) == $this->LE) {
949 $message = substr($message, 0, -1);
950 }
951
952 $line = explode($this->LE, $message);
953 $message = '';
954 for ($i=0 ;$i < count($line); $i++) {
955 $line_part = explode(' ', $line[$i]);
956 $buf = '';
957 for ($e = 0; $e<count($line_part); $e++) {
958 $word = $line_part[$e];
959 if ($qp_mode and (strlen($word) > $length)) {
960 $space_left = $length - strlen($buf) - 1;
961 if ($e != 0) {
962 if ($space_left > 20) {
963 $len = $space_left;
964 if ($is_utf8) {
965 $len = $this->UTF8CharBoundary($word, $len);
966 } elseif (substr($word, $len - 1, 1) == "=") {
967 $len--;
968 } elseif (substr($word, $len - 2, 1) == "=") {
969 $len -= 2;
970 }
971 $part = substr($word, 0, $len);
972 $word = substr($word, $len);
973 $buf .= ' ' . $part;
974 $message .= $buf . sprintf("=%s", $this->LE);
975 } else {
976 $message .= $buf . $soft_break;
977 }
978 $buf = '';
979 }
980 while (strlen($word) > 0) {
981 $len = $length;
982 if ($is_utf8) {
983 $len = $this->UTF8CharBoundary($word, $len);
984 } elseif (substr($word, $len - 1, 1) == "=") {
985 $len--;
986 } elseif (substr($word, $len - 2, 1) == "=") {
987 $len -= 2;
988 }
989 $part = substr($word, 0, $len);
990 $word = substr($word, $len);
991
992 if (strlen($word) > 0) {
993 $message .= $part . sprintf("=%s", $this->LE);
994 } else {
995 $buf = $part;
996 }
997 }
998 } else {
999 $buf_o = $buf;
1000 $buf .= ($e == 0) ? $word : (' ' . $word);
1001
1002 if (strlen($buf) > $length and $buf_o != '') {
1003 $message .= $buf_o . $soft_break;
1004 $buf = $word;
1005 }
1006 }
1007 }
1008 $message .= $buf . $this->LE;
1009 }
1010
1011 return $message;
1012 }
1013
1014 /**
1015 * Finds last character boundary prior to maxLength in a utf-8
1016 * quoted (printable) encoded string.
1017 * Original written by Colin Brown.
1018 * @access public
1019 * @param string $encodedText utf-8 QP text
1020 * @param int $maxLength find last character boundary prior to this length
1021 * @return int
1022 */
1023 public function UTF8CharBoundary($encodedText, $maxLength) {
1024 $foundSplitPos = false;
1025 $lookBack = 3;
1026 while (!$foundSplitPos) {
1027 $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1028 $encodedCharPos = strpos($lastChunk, "=");
1029 if ($encodedCharPos !== false) {
1030 // Found start of encoded character byte within $lookBack block.
1031 // Check the encoded byte value (the 2 chars after the '=')
1032 $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1033 $dec = hexdec($hex);
1034 if ($dec < 128) { // Single byte character.
1035 // If the encoded char was found at pos 0, it will fit
1036 // otherwise reduce maxLength to start of the encoded char
1037 $maxLength = ($encodedCharPos == 0) ? $maxLength :
1038 $maxLength - ($lookBack - $encodedCharPos);
1039 $foundSplitPos = true;
1040 } elseif ($dec >= 192) { // First byte of a multi byte character
1041 // Reduce maxLength to split at start of character
1042 $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1043 $foundSplitPos = true;
1044 } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
1045 $lookBack += 3;
1046 }
1047 } else {
1048 // No encoded character found
1049 $foundSplitPos = true;
1050 }
1051 }
1052 return $maxLength;
1053 }
1054
1055
1056 /**
1057 * Set the body wrapping.
1058 * @access public
1059 * @return void
1060 */
1061 public function SetWordWrap() {
1062 if($this->WordWrap < 1) {
1063 return;
1064 }
1065
1066 switch($this->message_type) {
1067 case 'alt':
1068 case 'alt_attachments':
1069 $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
1070 break;
1071 default:
1072 $this->Body = $this->WrapText($this->Body, $this->WordWrap);
1073 break;
1074 }
1075 }
1076
1077 /**
1078 * Assembles message header.
1079 * @access public
1080 * @return string The assembled header
1081 */
1082 public function CreateHeader() {
1083 $result = '';
1084
1085 // Set the boundaries
1086 $uniq_id = md5(uniqid(time()));
1087 $this->boundary[1] = 'b1_' . $uniq_id;
1088 $this->boundary[2] = 'b2_' . $uniq_id;
1089
1090 $result .= $this->HeaderLine('Date', self::RFCDate());
1091 if($this->Sender == '') {
1092 $result .= $this->HeaderLine('Return-Path', trim($this->From));
1093 } else {
1094 $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
1095 }
1096
1097 // To be created automatically by mail()
1098 if($this->Mailer != 'mail') {
1099 if ($this->SingleTo === true) {
1100 foreach($this->to as $t) {
1101 $this->SingleToArray[] = $this->AddrFormat($t);
1102 }
1103 } else {
1104 if(count($this->to) > 0) {
1105 $result .= $this->AddrAppend('To', $this->to);
1106 } elseif (count($this->cc) == 0) {
1107 $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
1108 }
1109 }
1110 }
1111
1112 $from = array();
1113 $from[0][0] = trim($this->From);
1114 $from[0][1] = $this->FromName;
1115 $result .= $this->AddrAppend('From', $from);
1116
1117 // sendmail and mail() extract Cc from the header before sending
1118 if(count($this->cc) > 0) {
1119 $result .= $this->AddrAppend('Cc', $this->cc);
1120 }
1121
1122 // sendmail and mail() extract Bcc from the header before sending
1123 if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
1124 $result .= $this->AddrAppend('Bcc', $this->bcc);
1125 }
1126
1127 if(count($this->ReplyTo) > 0) {
1128 $result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
1129 }
1130
1131 // mail() sets the subject itself
1132 if($this->Mailer != 'mail') {
1133 $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
1134 }
1135
1136 if($this->MessageID != '') {
1137 $result .= $this->HeaderLine('Message-ID',$this->MessageID);
1138 } else {
1139 $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
1140 }
1141 $result .= $this->HeaderLine('X-Priority', $this->Priority);
1142 $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (phpmailer.sourceforge.net)');
1143
1144 if($this->ConfirmReadingTo != '') {
1145 $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
1146 }
1147
1148 // Add custom headers
1149 for($index = 0; $index < count($this->CustomHeader); $index++) {
1150 $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
1151 }
1152 if (!$this->sign_key_file) {
1153 $result .= $this->HeaderLine('MIME-Version', '1.0');
1154 $result .= $this->GetMailMIME();
1155 }
1156
1157 return $result;
1158 }
1159
1160 /**
1161 * Returns the message MIME.
1162 * @access public
1163 * @return string
1164 */
1165 public function GetMailMIME() {
1166 $result = '';
1167 switch($this->message_type) {
1168 case 'plain':
1169 $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
1170 $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
1171 break;
1172 case 'attachments':
1173 case 'alt_attachments':
1174 if($this->InlineImageExists()){
1175 $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
1176 } else {
1177 $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
1178 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1179 }
1180 break;
1181 case 'alt':
1182 $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
1183 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1184 break;
1185 }
1186
1187 if($this->Mailer != 'mail') {
1188 $result .= $this->LE.$this->LE;
1189 }
1190
1191 return $result;
1192 }
1193
1194 /**
1195 * Assembles the message body. Returns an empty string on failure.
1196 * @access public
1197 * @return string The assembled message body
1198 */
1199 public function CreateBody() {
1200 $body = '';
1201
1202 if ($this->sign_key_file) {
1203 $body .= $this->GetMailMIME();
1204 }
1205
1206 $this->SetWordWrap();
1207
1208 switch($this->message_type) {
1209 case 'alt':
1210 $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
1211 $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1212 $body .= $this->LE.$this->LE;
1213 $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
1214 $body .= $this->EncodeString($this->Body, $this->Encoding);
1215 $body .= $this->LE.$this->LE;
1216 $body .= $this->EndBoundary($this->boundary[1]);
1217 break;
1218 case 'plain':
1219 $body .= $this->EncodeString($this->Body, $this->Encoding);
1220 break;
1221 case 'attachments':
1222 $body .= $this->GetBoundary($this->boundary[1], '', '', '');
1223 $body .= $this->EncodeString($this->Body, $this->Encoding);
1224 $body .= $this->LE;
1225 $body .= $this->AttachAll();
1226 break;
1227 case 'alt_attachments':
1228 $body .= sprintf("--%s%s", $this->boundary[1], $this->LE);
1229 $body .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
1230 $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
1231 $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1232 $body .= $this->LE.$this->LE;
1233 $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
1234 $body .= $this->EncodeString($this->Body, $this->Encoding);
1235 $body .= $this->LE.$this->LE;
1236 $body .= $this->EndBoundary($this->boundary[2]);
1237 $body .= $this->AttachAll();
1238 break;
1239 }
1240
1241 if ($this->IsError()) {
1242 $body = '';
1243 } elseif ($this->sign_key_file) {
1244 try {
1245 $file = tempnam('', 'mail');
1246 file_put_contents($file, $body); //TODO check this worked
1247 $signed = tempnam("", "signed");
1248 if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
1249 @unlink($file);
1250 @unlink($signed);
1251 $body = file_get_contents($signed);
1252 } else {
1253 @unlink($file);
1254 @unlink($signed);
1255 throw new phpmailerException($this->Lang("signing").openssl_error_string());
1256 }
1257 } catch (phpmailerException $e) {
1258 $body = '';
1259 if ($this->exceptions) {
1260 throw $e;
1261 }
1262 }
1263 }
1264
1265 return $body;
1266 }
1267
1268 /**
1269 * Returns the start of a message boundary.
1270 * @access private
1271 */
1272 private function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1273 $result = '';
1274 if($charSet == '') {
1275 $charSet = $this->CharSet;
1276 }
1277 if($contentType == '') {
1278 $contentType = $this->ContentType;
1279 }
1280 if($encoding == '') {
1281 $encoding = $this->Encoding;
1282 }
1283 $result .= $this->TextLine('--' . $boundary);
1284 $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
1285 $result .= $this->LE;
1286 $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1287 $result .= $this->LE;
1288
1289 return $result;
1290 }
1291
1292 /**
1293 * Returns the end of a message boundary.
1294 * @access private
1295 */
1296 private function EndBoundary($boundary) {
1297 return $this->LE . '--' . $boundary . '--' . $this->LE;
1298 }
1299
1300 /**
1301 * Sets the message type.
1302 * @access private
1303 * @return void
1304 */
1305 private function SetMessageType() {
1306 if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
1307 $this->message_type = 'plain';
1308 } else {
1309 if(count($this->attachment) > 0) {
1310 $this->message_type = 'attachments';
1311 }
1312 if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
1313 $this->message_type = 'alt';
1314 }
1315 if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
1316 $this->message_type = 'alt_attachments';
1317 }
1318 }
1319 }
1320
1321 /**
1322 * Returns a formatted header line.
1323 * @access public
1324 * @return string
1325 */
1326 public function HeaderLine($name, $value) {
1327 return $name . ': ' . $value . $this->LE;
1328 }
1329
1330 /**
1331 * Returns a formatted mail line.
1332 * @access public
1333 * @return string
1334 */
1335 public function TextLine($value) {
1336 return $value . $this->LE;
1337 }
1338
1339 /////////////////////////////////////////////////
1340 // CLASS METHODS, ATTACHMENTS
1341 /////////////////////////////////////////////////
1342
1343 /**
1344 * Adds an attachment from a path on the filesystem.
1345 * Returns false if the file could not be found
1346 * or accessed.
1347 * @param string $path Path to the attachment.
1348 * @param string $name Overrides the attachment name.
1349 * @param string $encoding File encoding (see $Encoding).
1350 * @param string $type File extension (MIME) type.
1351 * @return bool
1352 */
1353 public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1354 try {
1355 if ( !@is_file($path) ) {
1356 throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
1357 }
1358 $filename = basename($path);
1359 if ( $name == '' ) {
1360 $name = $filename;
1361 }
1362
1363 $this->attachment[] = array(
1364 0 => $path,
1365 1 => $filename,
1366 2 => $name,
1367 3 => $encoding,
1368 4 => $type,
1369 5 => false, // isStringAttachment
1370 6 => 'attachment',
1371 7 => 0
1372 );
1373
1374 } catch (phpmailerException $e) {
1375 $this->SetError($e->getMessage());
1376 if ($this->exceptions) {
1377 throw $e;
1378 }
1379 echo $e->getMessage()."\n";
1380 if ( $e->getCode() == self::STOP_CRITICAL ) {
1381 return false;
1382 }
1383 }
1384 return true;
1385 }
1386
1387 /**
1388 * Return the current array of attachments
1389 * @return array
1390 */
1391 public function GetAttachments() {
1392 return $this->attachment;
1393 }
1394
1395 /**
1396 * Attaches all fs, string, and binary attachments to the message.
1397 * Returns an empty string on failure.
1398 * @access private
1399 * @return string
1400 */
1401 private function AttachAll() {
1402 // Return text of body
1403 $mime = array();
1404 $cidUniq = array();
1405 $incl = array();
1406
1407 // Add all attachments
1408 foreach ($this->attachment as $attachment) {
1409 // Check for string attachment
1410 $bString = $attachment[5];
1411 if ($bString) {
1412 $string = $attachment[0];
1413 } else {
1414 $path = $attachment[0];
1415 }
1416
1417 if (in_array($attachment[0], $incl)) { continue; }
1418 $filename = $attachment[1];
1419 $name = $attachment[2];
1420 $encoding = $attachment[3];
1421 $type = $attachment[4];
1422 $disposition = $attachment[6];
1423 $cid = $attachment[7];
1424 $incl[] = $attachment[0];
1425 if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
1426 $cidUniq[$cid] = true;
1427
1428 $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1429 $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
1430 $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1431
1432 if($disposition == 'inline') {
1433 $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1434 }
1435
1436 $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
1437
1438 // Encode as string attachment
1439 if($bString) {
1440 $mime[] = $this->EncodeString($string, $encoding);
1441 if($this->IsError()) {
1442 return '';
1443 }
1444 $mime[] = $this->LE.$this->LE;
1445 } else {
1446 $mime[] = $this->EncodeFile($path, $encoding);
1447 if($this->IsError()) {
1448 return '';
1449 }
1450 $mime[] = $this->LE.$this->LE;
1451 }
1452 }
1453
1454 $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1455
1456 return join('', $mime);
1457 }
1458
1459 /**
1460 * Encodes attachment in requested format.
1461 * Returns an empty string on failure.
1462 * @param string $path The full path to the file
1463 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
1464 * @see EncodeFile()
1465 * @access private
1466 * @return string
1467 */
1468 private function EncodeFile($path, $encoding = 'base64') {
1469 try {
1470 if (!is_readable($path)) {
1471 throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
1472 }
1473 if (function_exists('get_magic_quotes')) {
1474 function get_magic_quotes() {
1475 return false;
1476 }
1477 }
1478 if (PHP_VERSION < 6) {
1479 $magic_quotes = get_magic_quotes_runtime();
1480 set_magic_quotes_runtime(0);
1481 }
1482 $file_buffer = file_get_contents($path);
1483 $file_buffer = $this->EncodeString($file_buffer, $encoding);
1484 if (PHP_VERSION < 6) { set_magic_quotes_runtime($magic_quotes); }
1485 return $file_buffer;
1486 } catch (Exception $e) {
1487 $this->SetError($e->getMessage());
1488 return '';
1489 }
1490 }
1491
1492 /**
1493 * Encodes string to requested format.
1494 * Returns an empty string on failure.
1495 * @param string $str The text to encode
1496 * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
1497 * @access public
1498 * @return string
1499 */
1500 public function EncodeString ($str, $encoding = 'base64') {
1501 $encoded = '';
1502 switch(strtolower($encoding)) {
1503 case 'base64':
1504 $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1505 break;
1506 case '7bit':
1507 case '8bit':
1508 $encoded = $this->FixEOL($str);
1509 //Make sure it ends with a line break
1510 if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1511 $encoded .= $this->LE;
1512 break;
1513 case 'binary':
1514 $encoded = $str;
1515 break;
1516 case 'quoted-printable':
1517 $encoded = $this->EncodeQP($str);
1518 break;
1519 default:
1520 $this->SetError($this->Lang('encoding') . $encoding);
1521 break;
1522 }
1523 return $encoded;
1524 }
1525
1526 /**
1527 * Encode a header string to best (shortest) of Q, B, quoted or none.
1528 * @access public
1529 * @return string
1530 */
1531 public function EncodeHeader($str, $position = 'text') {
1532 $x = 0;
1533
1534 switch (strtolower($position)) {
1535 case 'phrase':
1536 if (!preg_match('/[\200-\377]/', $str)) {
1537 // Can't use addslashes as we don't know what value has magic_quotes_sybase
1538 $encoded = addcslashes($str, "\0..\37\177\\\"");
1539 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1540 return ($encoded);
1541 } else {
1542 return ("\"$encoded\"");
1543 }
1544 }
1545 $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1546 break;
1547 case 'comment':
1548 $x = preg_match_all('/[()"]/', $str, $matches);
1549 // Fall-through
1550 case 'text':
1551 default:
1552 $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1553 break;
1554 }
1555
1556 if ($x == 0) {
1557 return ($str);
1558 }
1559
1560 $maxlen = 75 - 7 - strlen($this->CharSet);
1561 // Try to select the encoding which should produce the shortest output
1562 if (strlen($str)/3 < $x) {
1563 $encoding = 'B';
1564 if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1565 // Use a custom function which correctly encodes and wraps long
1566 // multibyte strings without breaking lines within a character
1567 $encoded = $this->Base64EncodeWrapMB($str);
1568 } else {
1569 $encoded = base64_encode($str);
1570 $maxlen -= $maxlen % 4;
1571 $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1572 }
1573 } else {
1574 $encoding = 'Q';
1575 $encoded = $this->EncodeQ($str, $position);
1576 $encoded = $this->WrapText($encoded, $maxlen, true);
1577 $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
1578 }
1579
1580 $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1581 $encoded = trim(str_replace("\n", $this->LE, $encoded));
1582
1583 return $encoded;
1584 }
1585
1586 /**
1587 * Checks if a string contains multibyte characters.
1588 * @access public
1589 * @param string $str multi-byte text to wrap encode
1590 * @return bool
1591 */
1592 public function HasMultiBytes($str) {
1593 if (function_exists('mb_strlen')) {
1594 return (strlen($str) > mb_strlen($str, $this->CharSet));
1595 } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
1596 return false;
1597 }
1598 }
1599
1600 /**
1601 * Correctly encodes and wraps long multibyte strings for mail headers
1602 * without breaking lines within a character.
1603 * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
1604 * @access public
1605 * @param string $str multi-byte text to wrap encode
1606 * @return string
1607 */
1608 public function Base64EncodeWrapMB($str) {
1609 $start = "=?".$this->CharSet."?B?";
1610 $end = "?=";
1611 $encoded = "";
1612
1613 $mb_length = mb_strlen($str, $this->CharSet);
1614 // Each line must have length <= 75, including $start and $end
1615 $length = 75 - strlen($start) - strlen($end);
1616 // Average multi-byte ratio
1617 $ratio = $mb_length / strlen($str);
1618 // Base64 has a 4:3 ratio
1619 $offset = $avgLength = floor($length * $ratio * .75);
1620
1621 for ($i = 0; $i < $mb_length; $i += $offset) {
1622 $lookBack = 0;
1623
1624 do {
1625 $offset = $avgLength - $lookBack;
1626 $chunk = mb_substr($str, $i, $offset, $this->CharSet);
1627 $chunk = base64_encode($chunk);
1628 $lookBack++;
1629 }
1630 while (strlen($chunk) > $length);
1631
1632 $encoded .= $chunk . $this->LE;
1633 }
1634
1635 // Chomp the last linefeed
1636 $encoded = substr($encoded, 0, -strlen($this->LE));
1637 return $encoded;
1638 }
1639
1640 /**
1641 * Encode string to quoted-printable.
1642 * Only uses standard PHP, slow, but will always work
1643 * @access public
1644 * @param string $string the text to encode
1645 * @param integer $line_max Number of chars allowed on a line before wrapping
1646 * @return string
1647 */
1648 public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
1649 $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1650 $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
1651 $eol = "\r\n";
1652 $escape = '=';
1653 $output = '';
1654 while( list(, $line) = each($lines) ) {
1655 $linlen = strlen($line);
1656 $newline = '';
1657 for($i = 0; $i < $linlen; $i++) {
1658 $c = substr( $line, $i, 1 );
1659 $dec = ord( $c );
1660 if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
1661 $c = '=2E';
1662 }
1663 if ( $dec == 32 ) {
1664 if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
1665 $c = '=20';
1666 } else if ( $space_conv ) {
1667 $c = '=20';
1668 }
1669 } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1670 $h2 = floor($dec/16);
1671 $h1 = floor($dec%16);
1672 $c = $escape.$hex[$h2].$hex[$h1];
1673 }
1674 if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1675 $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
1676 $newline = '';
1677 // check if newline first character will be point or not
1678 if ( $dec == 46 ) {
1679 $c = '=2E';
1680 }
1681 }
1682 $newline .= $c;
1683 } // end of for
1684 $output .= $newline.$eol;
1685 } // end of while
1686 return $output;
1687 }
1688
1689 /**
1690 * Encode string to RFC2045 (6.7) quoted-printable format
1691 * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version
1692 * Also results in same content as you started with after decoding
1693 * @see EncodeQPphp()
1694 * @access public
1695 * @param string $string the text to encode
1696 * @param integer $line_max Number of chars allowed on a line before wrapping
1697 * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function
1698 * @return string
1699 * @author Marcus Bointon
1700 */
1701 public function EncodeQP($string, $line_max = 76, $space_conv = false) {
1702 if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
1703 return quoted_printable_encode($string);
1704 }
1705 $filters = stream_get_filters();
1706 if (!in_array('convert.*', $filters)) { //Got convert stream filter?
1707 return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation
1708 }
1709 $fp = fopen('php://temp/', 'r+');
1710 $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks
1711 $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
1712 $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
1713 fputs($fp, $string);
1714 rewind($fp);
1715 $out = stream_get_contents($fp);
1716 stream_filter_remove($s);
1717 $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange
1718 fclose($fp);
1719 return $out;
1720 }
1721
1722 /**
1723 * Encode string to q encoding.
1724 * @link http://tools.ietf.org/html/rfc2047
1725 * @param string $str the text to encode
1726 * @param string $position Where the text is going to be used, see the RFC for what that means
1727 * @access public
1728 * @return string
1729 */
1730 public function EncodeQ ($str, $position = 'text') {
1731 // There should not be any EOL in the string
1732 $encoded = preg_replace('/[\r\n]*/', '', $str);
1733
1734 switch (strtolower($position)) {
1735 case 'phrase':
1736 $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1737 break;
1738 case 'comment':
1739 $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1740 case 'text':
1741 default:
1742 // Replace every high ascii, control =, ? and _ characters
1743 //TODO using /e (equivalent to eval()) is probably not a good idea
1744 $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1745 "'='.sprintf('%02X', ord('\\1'))", $encoded);
1746 break;
1747 }
1748
1749 // Replace every spaces to _ (more readable than =20)
1750 $encoded = str_replace(' ', '_', $encoded);
1751
1752 return $encoded;
1753 }
1754
1755 /**
1756 * Adds a string or binary attachment (non-filesystem) to the list.
1757 * This method can be used to attach ascii or binary data,
1758 * such as a BLOB record from a database.
1759 * @param string $string String attachment data.
1760 * @param string $filename Name of the attachment.
1761 * @param string $encoding File encoding (see $Encoding).
1762 * @param string $type File extension (MIME) type.
1763 * @return void
1764 */
1765 public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
1766 // Append to $attachment array
1767 $this->attachment[] = array(
1768 0 => $string,
1769 1 => $filename,
1770 2 => basename($filename),
1771 3 => $encoding,
1772 4 => $type,
1773 5 => true, // isStringAttachment
1774 6 => 'attachment',
1775 7 => 0
1776 );
1777 }
1778
1779 /**
1780 * Adds an embedded attachment. This can include images, sounds, and
1781 * just about any other document. Make sure to set the $type to an
1782 * image type. For JPEG images use "image/jpeg" and for GIF images
1783 * use "image/gif".
1784 * @param string $path Path to the attachment.
1785 * @param string $cid Content ID of the attachment. Use this to identify
1786 * the Id for accessing the image in an HTML form.
1787 * @param string $name Overrides the attachment name.
1788 * @param string $encoding File encoding (see $Encoding).
1789 * @param string $type File extension (MIME) type.
1790 * @return bool
1791 */
1792 public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1793
1794 if ( !@is_file($path) ) {
1795 $this->SetError($this->Lang('file_access') . $path);
1796 return false;
1797 }
1798
1799 $filename = basename($path);
1800 if ( $name == '' ) {
1801 $name = $filename;
1802 }
1803
1804 // Append to $attachment array
1805 $this->attachment[] = array(
1806 0 => $path,
1807 1 => $filename,
1808 2 => $name,
1809 3 => $encoding,
1810 4 => $type,
1811 5 => false, // isStringAttachment
1812 6 => 'inline',
1813 7 => $cid
1814 );
1815
1816 return true;
1817 }
1818
1819 /**
1820 * Returns true if an inline attachment is present.
1821 * @access public
1822 * @return bool
1823 */
1824 public function InlineImageExists() {
1825 foreach($this->attachment as $attachment) {
1826 if ($attachment[6] == 'inline') {
1827 return true;
1828 }
1829 }
1830 return false;
1831 }
1832
1833 /////////////////////////////////////////////////
1834 // CLASS METHODS, MESSAGE RESET
1835 /////////////////////////////////////////////////
1836
1837 /**
1838 * Clears all recipients assigned in the TO array. Returns void.
1839 * @return void
1840 */
1841 public function ClearAddresses() {
1842 foreach($this->to as $to) {
1843 unset($this->all_recipients[strtolower($to[0])]);
1844 }
1845 $this->to = array();
1846 }
1847
1848 /**
1849 * Clears all recipients assigned in the CC array. Returns void.
1850 * @return void
1851 */
1852 public function ClearCCs() {
1853 foreach($this->cc as $cc) {
1854 unset($this->all_recipients[strtolower($cc[0])]);
1855 }
1856 $this->cc = array();
1857 }
1858
1859 /**
1860 * Clears all recipients assigned in the BCC array. Returns void.
1861 * @return void
1862 */
1863 public function ClearBCCs() {
1864 foreach($this->bcc as $bcc) {
1865 unset($this->all_recipients[strtolower($bcc[0])]);
1866 }
1867 $this->bcc = array();
1868 }
1869
1870 /**
1871 * Clears all recipients assigned in the ReplyTo array. Returns void.
1872 * @return void
1873 */
1874 public function ClearReplyTos() {
1875 $this->ReplyTo = array();
1876 }
1877
1878 /**
1879 * Clears all recipients assigned in the TO, CC and BCC
1880 * array. Returns void.
1881 * @return void
1882 */
1883 public function ClearAllRecipients() {
1884 $this->to = array();
1885 $this->cc = array();
1886 $this->bcc = array();
1887 $this->all_recipients = array();
1888 }
1889
1890 /**
1891 * Clears all previously set filesystem, string, and binary
1892 * attachments. Returns void.
1893 * @return void
1894 */
1895 public function ClearAttachments() {
1896 $this->attachment = array();
1897 }
1898
1899 /**
1900 * Clears all custom headers. Returns void.
1901 * @return void
1902 */
1903 public function ClearCustomHeaders() {
1904 $this->CustomHeader = array();
1905 }
1906
1907 /////////////////////////////////////////////////
1908 // CLASS METHODS, MISCELLANEOUS
1909 /////////////////////////////////////////////////
1910
1911 /**
1912 * Adds the error message to the error container.
1913 * @access protected
1914 * @return void
1915 */
1916 protected function SetError($msg) {
1917 $this->error_count++;
1918 if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
1919 $lasterror = $this->smtp->getError();
1920 if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
1921 $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
1922 }
1923 }
1924 $this->ErrorInfo = $msg;
1925 }
1926
1927 /**
1928 * Returns the proper RFC 822 formatted date.
1929 * @access public
1930 * @return string
1931 * @static
1932 */
1933 public static function RFCDate() {
1934 $tz = date('Z');
1935 $tzs = ($tz < 0) ? '-' : '+';
1936 $tz = abs($tz);
1937 $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
1938 $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
1939
1940 return $result;
1941 }
1942
1943 /**
1944 * Returns the server hostname or 'localhost.localdomain' if unknown.
1945 * @access private
1946 * @return string
1947 */
1948 private function ServerHostname() {
1949 if (!empty($this->Hostname)) {
1950 $result = $this->Hostname;
1951 } elseif (isset($_SERVER['SERVER_NAME'])) {
1952 $result = $_SERVER['SERVER_NAME'];
1953 } else {
1954 $result = 'localhost.localdomain';
1955 }
1956
1957 return $result;
1958 }
1959
1960 /**
1961 * Returns a message in the appropriate language.
1962 * @access private
1963 * @return string
1964 */
1965 private function Lang($key) {
1966 if(count($this->language) < 1) {
1967 $this->SetLanguage('en'); // set the default language
1968 }
1969
1970 if(isset($this->language[$key])) {
1971 return $this->language[$key];
1972 } else {
1973 return 'Language string failed to load: ' . $key;
1974 }
1975 }
1976
1977 /**
1978 * Returns true if an error occurred.
1979 * @access public
1980 * @return bool
1981 */
1982 public function IsError() {
1983 return ($this->error_count > 0);
1984 }
1985
1986 /**
1987 * Changes every end of line from CR or LF to CRLF.
1988 * @access private
1989 * @return string
1990 */
1991 private function FixEOL($str) {
1992 $str = str_replace("\r\n", "\n", $str);
1993 $str = str_replace("\r", "\n", $str);
1994 $str = str_replace("\n", $this->LE, $str);
1995 return $str;
1996 }
1997
1998 /**
1999 * Adds a custom header.
2000 * @access public
2001 * @return void
2002 */
2003 public function AddCustomHeader($custom_header) {
2004 $this->CustomHeader[] = explode(':', $custom_header, 2);
2005 }
2006
2007 /**
2008 * Evaluates the message and returns modifications for inline images and backgrounds
2009 * @access public
2010 * @return $message
2011 */
2012 public function MsgHTML($message, $basedir = '') {
2013 preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
2014 if(isset($images[2])) {
2015 foreach($images[2] as $i => $url) {
2016 // do not change urls for absolute images (thanks to corvuscorax)
2017 if (!preg_match('#^[A-z]+://#',$url)) {
2018 $filename = basename($url);
2019 $directory = dirname($url);
2020 ($directory == '.')?$directory='':'';
2021 $cid = 'cid:' . md5($filename);
2022 $ext = pathinfo($filename, PATHINFO_EXTENSION);
2023 $mimeType = self::_mime_types($ext);
2024 if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
2025 if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; }
2026 if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
2027 $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
2028 }
2029 }
2030 }
2031 }
2032 $this->IsHTML(true);
2033 $this->Body = $message;
2034 $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
2035 if (!empty($textMsg) && empty($this->AltBody)) {
2036 $this->AltBody = html_entity_decode($textMsg);
2037 }
2038 if (empty($this->AltBody)) {
2039 $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
2040 }
2041 }
2042
2043 /**
2044 * Gets the MIME type of the embedded or inline image
2045 * @param string File extension
2046 * @access public
2047 * @return string MIME type of ext
2048 * @static
2049 */
2050 public static function _mime_types($ext = '') {
2051 $mimes = array(
2052 'hqx' => 'application/mac-binhex40',
2053 'cpt' => 'application/mac-compactpro',
2054 'doc' => 'application/msword',
2055 'bin' => 'application/macbinary',
2056 'dms' => 'application/octet-stream',
2057 'lha' => 'application/octet-stream',
2058 'lzh' => 'application/octet-stream',
2059 'exe' => 'application/octet-stream',
2060 'class' => 'application/octet-stream',
2061 'psd' => 'application/octet-stream',
2062 'so' => 'application/octet-stream',
2063 'sea' => 'application/octet-stream',
2064 'dll' => 'application/octet-stream',
2065 'oda' => 'application/oda',
2066 'pdf' => 'application/pdf',
2067 'ai' => 'application/postscript',
2068 'eps' => 'application/postscript',
2069 'ps' => 'application/postscript',
2070 'smi' => 'application/smil',
2071 'smil' => 'application/smil',
2072 'mif' => 'application/vnd.mif',
2073 'xls' => 'application/vnd.ms-excel',
2074 'ppt' => 'application/vnd.ms-powerpoint',
2075 'wbxml' => 'application/vnd.wap.wbxml',
2076 'wmlc' => 'application/vnd.wap.wmlc',
2077 'dcr' => 'application/x-director',
2078 'dir' => 'application/x-director',
2079 'dxr' => 'application/x-director',
2080 'dvi' => 'application/x-dvi',
2081 'gtar' => 'application/x-gtar',
2082 'php' => 'application/x-httpd-php',
2083 'php4' => 'application/x-httpd-php',
2084 'php3' => 'application/x-httpd-php',
2085 'phtml' => 'application/x-httpd-php',
2086 'phps' => 'application/x-httpd-php-source',
2087 'js' => 'application/x-javascript',
2088 'swf' => 'application/x-shockwave-flash',
2089 'sit' => 'application/x-stuffit',
2090 'tar' => 'application/x-tar',
2091 'tgz' => 'application/x-tar',
2092 'xhtml' => 'application/xhtml+xml',
2093 'xht' => 'application/xhtml+xml',
2094 'zip' => 'application/zip',
2095 'mid' => 'audio/midi',
2096 'midi' => 'audio/midi',
2097 'mpga' => 'audio/mpeg',
2098 'mp2' => 'audio/mpeg',
2099 'mp3' => 'audio/mpeg',
2100 'aif' => 'audio/x-aiff',
2101 'aiff' => 'audio/x-aiff',
2102 'aifc' => 'audio/x-aiff',
2103 'ram' => 'audio/x-pn-realaudio',
2104 'rm' => 'audio/x-pn-realaudio',
2105 'rpm' => 'audio/x-pn-realaudio-plugin',
2106 'ra' => 'audio/x-realaudio',
2107 'rv' => 'video/vnd.rn-realvideo',
2108 'wav' => 'audio/x-wav',
2109 'bmp' => 'image/bmp',
2110 'gif' => 'image/gif',
2111 'jpeg' => 'image/jpeg',
2112 'jpg' => 'image/jpeg',
2113 'jpe' => 'image/jpeg',
2114 'png' => 'image/png',
2115 'tiff' => 'image/tiff',
2116 'tif' => 'image/tiff',
2117 'css' => 'text/css',
2118 'html' => 'text/html',
2119 'htm' => 'text/html',
2120 'shtml' => 'text/html',
2121 'txt' => 'text/plain',
2122 'text' => 'text/plain',
2123 'log' => 'text/plain',
2124 'rtx' => 'text/richtext',
2125 'rtf' => 'text/rtf',
2126 'xml' => 'text/xml',
2127 'xsl' => 'text/xml',
2128 'mpeg' => 'video/mpeg',
2129 'mpg' => 'video/mpeg',
2130 'mpe' => 'video/mpeg',
2131 'qt' => 'video/quicktime',
2132 'mov' => 'video/quicktime',
2133 'avi' => 'video/x-msvideo',
2134 'movie' => 'video/x-sgi-movie',
2135 'doc' => 'application/msword',
2136 'word' => 'application/msword',
2137 'xl' => 'application/excel',
2138 'eml' => 'message/rfc822'
2139 );
2140 return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
2141 }
2142
2143 /**
2144 * Set (or reset) Class Objects (variables)
2145 *
2146 * Usage Example:
2147 * $page->set('X-Priority', '3');
2148 *
2149 * @access public
2150 * @param string $name Parameter Name
2151 * @param mixed $value Parameter Value
2152 * NOTE: will not work with arrays, there are no arrays to set/reset
2153 * @todo Should this not be using __set() magic function?
2154 */
2155 public function set($name, $value = '') {
2156 try {
2157 if (isset($this->$name) ) {
2158 $this->$name = $value;
2159 } else {
2160 throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
2161 }
2162 } catch (Exception $e) {
2163 $this->SetError($e->getMessage());
2164 if ($e->getCode() == self::STOP_CRITICAL) {
2165 return false;
2166 }
2167 }
2168 return true;
2169 }
2170
2171 /**
2172 * Strips newlines to prevent header injection.
2173 * @access public
2174 * @param string $str String
2175 * @return string
2176 */
2177 public function SecureHeader($str) {
2178 $str = str_replace("\r", '', $str);
2179 $str = str_replace("\n", '', $str);
2180 return trim($str);
2181 }
2182
2183 /**
2184 * Set the private key file and password to sign the message.
2185 *
2186 * @access public
2187 * @param string $key_filename Parameter File Name
2188 * @param string $key_pass Password for private key
2189 */
2190 public function Sign($cert_filename, $key_filename, $key_pass) {
2191 $this->sign_cert_file = $cert_filename;
2192 $this->sign_key_file = $key_filename;
2193 $this->sign_key_pass = $key_pass;
2194 }
2195
2196 /**
2197 * Set the private key file and password to sign the message.
2198 *
2199 * @access public
2200 * @param string $key_filename Parameter File Name
2201 * @param string $key_pass Password for private key
2202 */
2203 public function DKIM_QP($txt) {
2204 $tmp="";
2205 $line="";
2206 for ($i=0;$i<strlen($txt);$i++) {
2207 $ord=ord($txt[$i]);
2208 if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
2209 $line.=$txt[$i];
2210 } else {
2211 $line.="=".sprintf("%02X",$ord);
2212 }
2213 }
2214 return $line;
2215 }
2216
2217 /**
2218 * Generate DKIM signature
2219 *
2220 * @access public
2221 * @param string $s Header
2222 */
2223 public function DKIM_Sign($s) {
2224 $privKeyStr = file_get_contents($this->DKIM_private);
2225 if ($this->DKIM_passphrase!='') {
2226 $privKey = openssl_pkey_get_private($privKeyStr,$this->DKIM_passphrase);
2227 } else {
2228 $privKey = $privKeyStr;
2229 }
2230 if (openssl_sign($s, $signature, $privKey)) {
2231 return base64_encode($signature);
2232 }
2233 }
2234
2235 /**
2236 * Generate DKIM Canonicalization Header
2237 *
2238 * @access public
2239 * @param string $s Header
2240 */
2241 public function DKIM_HeaderC($s) {
2242 $s=preg_replace("/\r\n\s+/"," ",$s);
2243 $lines=explode("\r\n",$s);
2244 foreach ($lines as $key=>$line) {
2245 list($heading,$value)=explode(":",$line,2);
2246 $heading=strtolower($heading);
2247 $value=preg_replace("/\s+/"," ",$value) ; // Compress useless spaces
2248 $lines[$key]=$heading.":".trim($value) ; // Don't forget to remove WSP around the value
2249 }
2250 $s=implode("\r\n",$lines);
2251 return $s;
2252 }
2253
2254 /**
2255 * Generate DKIM Canonicalization Body
2256 *
2257 * @access public
2258 * @param string $body Message Body
2259 */
2260 public function DKIM_BodyC($body) {
2261 if ($body == '') return "\r\n";
2262 // stabilize line endings
2263 $body=str_replace("\r\n","\n",$body);
2264 $body=str_replace("\n","\r\n",$body);
2265 // END stabilize line endings
2266 while (substr($body,strlen($body)-4,4) == "\r\n\r\n") {
2267 $body=substr($body,0,strlen($body)-2);
2268 }
2269 return $body;
2270 }
2271
2272 /**
2273 * Create the DKIM header, body, as new header
2274 *
2275 * @access public
2276 * @param string $headers_line Header lines
2277 * @param string $subject Subject
2278 * @param string $body Body
2279 */
2280 public function DKIM_Add($headers_line,$subject,$body) {
2281 $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
2282 $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
2283 $DKIMquery = 'dns/txt'; // Query method
2284 $DKIMtime = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
2285 $subject_header = "Subject: $subject";
2286 $headers = explode("\r\n",$headers_line);
2287 foreach($headers as $header) {
2288 if (strpos($header,'From:') === 0) {
2289 $from_header=$header;
2290 } elseif (strpos($header,'To:') === 0) {
2291 $to_header=$header;
2292 }
2293 }
2294 $from = str_replace('|','=7C',$this->DKIM_QP($from_header));
2295 $to = str_replace('|','=7C',$this->DKIM_QP($to_header));
2296 $subject = str_replace('|','=7C',$this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
2297 $body = $this->DKIM_BodyC($body);
2298 $DKIMlen = strlen($body) ; // Length of body
2299 $DKIMb64 = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
2300 $ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
2301 $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
2302 "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
2303 "\th=From:To:Subject;\r\n".
2304 "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
2305 "\tz=$from\r\n".
2306 "\t|$to\r\n".
2307 "\t|$subject;\r\n".
2308 "\tbh=" . $DKIMb64 . ";\r\n".
2309 "\tb=";
2310 $toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
2311 $signed = $this->DKIM_Sign($toSign);
2312 return "X-PHPMAILER-DKIM: phpmailer.worxware.com\r\n".$dkimhdrs.$signed."\r\n";
2313 }
2314
2315 protected function doCallback($isSent,$to,$cc,$bcc,$subject,$body) {
2316 if (!empty($this->action_function) && function_exists($this->action_function)) {
2317 $params = array($isSent,$to,$cc,$bcc,$subject,$body);
2318 call_user_func_array($this->action_function,$params);
2319 }
2320 }
2321}
2322
2323class phpmailerException extends Exception {
2324 public function errorMessage() {
2325 $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
2326 return $errorMsg;
2327 }
2328}
2329//end class.phpmailer.php
2330
2331
2332
2333
2334/*~ class.smtp.php
2335.---------------------------------------------------------------------------.
2336| Software: PHPMailer - PHP email class |
2337| Version: 5.2.6 |
2338| Site: https://github.com/PHPMailer/PHPMailer/ |
2339| ------------------------------------------------------------------------- |
2340| Admins: Marcus Bointon |
2341| Admins: Jim Jagielski |
2342| Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
2343| : Marcus Bointon (coolbru) phpmailer@synchromedia.co.uk |
2344| : Jim Jagielski (jimjag) jimjag@gmail.com |
2345| Founder: Brent R. Matzelle (original founder) |
2346| Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved. |
2347| Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved. |
2348| Copyright (c) 2001-2003, Brent R. Matzelle |
2349| ------------------------------------------------------------------------- |
2350| License: Distributed under the Lesser General Public License (LGPL) |
2351| http://www.gnu.org/copyleft/lesser.html |
2352| This program is distributed in the hope that it will be useful - WITHOUT |
2353| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
2354| FITNESS FOR A PARTICULAR PURPOSE. |
2355'---------------------------------------------------------------------------'
2356*/
2357
2358/**
2359 * PHPMailer - PHP SMTP email transport class
2360 * NOTE: Designed for use with PHP version 5 and up
2361 * @package PHPMailer
2362 * @author Andy Prevost
2363 * @author Marcus Bointon
2364 * @copyright 2004 - 2008 Andy Prevost
2365 * @author Jim Jagielski
2366 * @copyright 2010 - 2012 Jim Jagielski
2367 * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
2368 */
2369
2370/**
2371 * PHP RFC821 SMTP client
2372 *
2373 * Implements all the RFC 821 SMTP commands except TURN which will always return a not implemented error.
2374 * SMTP also provides some utility methods for sending mail to an SMTP server.
2375 * @author Chris Ryan
2376 * @package PHPMailer
2377 */
2378
2379class SMTP {
2380 /**
2381 * SMTP server port
2382 * @var int
2383 */
2384 public $SMTP_PORT = 25;
2385
2386 /**
2387 * SMTP reply line ending (don't change)
2388 * @var string
2389 */
2390 public $CRLF = "\r\n";
2391
2392 /**
2393 * Debug output level; 0 for no output
2394 * @var int
2395 */
2396 public $do_debug = 0;
2397
2398 /**
2399 * Sets the function/method to use for debugging output.
2400 * Right now we only honor 'echo', 'html' or 'error_log'
2401 * @var string
2402 */
2403 public $Debugoutput = 'echo';
2404
2405 /**
2406 * Sets VERP use on/off (default is off)
2407 * @var bool
2408 */
2409 public $do_verp = false;
2410
2411 /**
2412 * Sets the SMTP timeout value for reads, in seconds
2413 * @var int
2414 */
2415 public $Timeout = 15;
2416
2417 /**
2418 * Sets the SMTP timelimit value for reads, in seconds
2419 * @var int
2420 */
2421 public $Timelimit = 30;
2422
2423 /**
2424 * Sets the SMTP PHPMailer Version number
2425 * @var string
2426 */
2427 public $Version = '5.2.6';
2428
2429 /////////////////////////////////////////////////
2430 // PROPERTIES, PRIVATE AND PROTECTED
2431 /////////////////////////////////////////////////
2432
2433 /**
2434 * @var resource The socket to the server
2435 */
2436 protected $smtp_conn;
2437 /**
2438 * @var string Error message, if any, for the last call
2439 */
2440 protected $error;
2441 /**
2442 * @var string The reply the server sent to us for HELO
2443 */
2444 protected $helo_rply;
2445
2446 /**
2447 * Outputs debugging info via user-defined method
2448 * @param string $str
2449 */
2450 protected function edebug($str) {
2451 switch ($this->Debugoutput) {
2452 case 'error_log':
2453 error_log($str);
2454 break;
2455 case 'html':
2456 //Cleans up output a bit for a better looking display that's HTML-safe
2457 echo htmlentities(preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, 'UTF-8')."<br>\n";
2458 break;
2459 case 'echo':
2460 default:
2461 //Just echoes exactly what was received
2462 echo $str;
2463 }
2464 }
2465
2466 /**
2467 * Initialize the class so that the data is in a known state.
2468 * @access public
2469 * @return SMTP
2470 */
2471 public function __construct() {
2472 $this->smtp_conn = 0;
2473 $this->error = null;
2474 $this->helo_rply = null;
2475
2476 $this->do_debug = 0;
2477 }
2478
2479 /////////////////////////////////////////////////
2480 // CONNECTION FUNCTIONS
2481 /////////////////////////////////////////////////
2482
2483 /**
2484 * Connect to an SMTP server
2485 *
2486 * SMTP CODE SUCCESS: 220
2487 * SMTP CODE FAILURE: 421
2488 * @access public
2489 * @param string $host SMTP server IP or host name
2490 * @param int $port The port number to connect to, or use the default port if not specified
2491 * @param int $timeout How long to wait for the connection to open
2492 * @param array $options An array of options compatible with stream_context_create()
2493 * @return bool
2494 */
2495 public function Connect($host, $port = 0, $timeout = 30, $options = array()) {
2496 // Clear errors to avoid confusion
2497 $this->error = null;
2498
2499 // Make sure we are __not__ connected
2500 if($this->connected()) {
2501 // Already connected, generate error
2502 $this->error = array('error' => 'Already connected to a server');
2503 return false;
2504 }
2505
2506 if(empty($port)) {
2507 $port = $this->SMTP_PORT;
2508 }
2509
2510 // Connect to the SMTP server
2511 $errno = 0;
2512 $errstr = '';
2513 $socket_context = stream_context_create($options);
2514 //Need to suppress errors here as connection failures can be handled at a higher level
2515 $this->smtp_conn = @stream_socket_client($host.":".$port, $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $socket_context);
2516
2517 // Verify we connected properly
2518 if(empty($this->smtp_conn)) {
2519 $this->error = array('error' => 'Failed to connect to server',
2520 'errno' => $errno,
2521 'errstr' => $errstr);
2522 if($this->do_debug >= 1) {
2523 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ": $errstr ($errno)");
2524 }
2525 return false;
2526 }
2527
2528 // SMTP server can take longer to respond, give longer timeout for first read
2529 // Windows does not have support for this timeout function
2530 if(substr(PHP_OS, 0, 3) != 'WIN') {
2531 $max = ini_get('max_execution_time');
2532 if ($max != 0 && $timeout > $max) { // Don't bother if unlimited
2533 @set_time_limit($timeout);
2534 }
2535 stream_set_timeout($this->smtp_conn, $timeout, 0);
2536 }
2537
2538 // get any announcement
2539 $announce = $this->get_lines();
2540
2541 if($this->do_debug >= 2) {
2542 $this->edebug('SMTP -> FROM SERVER:' . $announce);
2543 }
2544
2545 return true;
2546 }
2547
2548 /**
2549 * Initiate a TLS communication with the server.
2550 *
2551 * SMTP CODE 220 Ready to start TLS
2552 * SMTP CODE 501 Syntax error (no parameters allowed)
2553 * SMTP CODE 454 TLS not available due to temporary reason
2554 * @access public
2555 * @return bool success
2556 */
2557 public function StartTLS() {
2558 $this->error = null; # to avoid confusion
2559
2560 if(!$this->connected()) {
2561 $this->error = array('error' => 'Called StartTLS() without being connected');
2562 return false;
2563 }
2564
2565 $this->client_send('STARTTLS' . $this->CRLF);
2566
2567 $rply = $this->get_lines();
2568 $code = substr($rply, 0, 3);
2569
2570 if($this->do_debug >= 2) {
2571 $this->edebug('SMTP -> FROM SERVER:' . $rply);
2572 }
2573
2574 if($code != 220) {
2575 $this->error =
2576 array('error' => 'STARTTLS not accepted from server',
2577 'smtp_code' => $code,
2578 'smtp_msg' => substr($rply, 4));
2579 if($this->do_debug >= 1) {
2580 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2581 }
2582 return false;
2583 }
2584
2585 // Begin encrypted connection
2586 if(!stream_socket_enable_crypto($this->smtp_conn, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) {
2587 return false;
2588 }
2589
2590 return true;
2591 }
2592
2593 /**
2594 * Performs SMTP authentication. Must be run after running the
2595 * Hello() method. Returns true if successfully authenticated.
2596 * @access public
2597 * @param string $username
2598 * @param string $password
2599 * @param string $authtype
2600 * @param string $realm
2601 * @param string $workstation
2602 * @return bool
2603 */
2604 public function Authenticate($username, $password, $authtype='LOGIN', $realm='', $workstation='') {
2605 if (empty($authtype)) {
2606 $authtype = 'LOGIN';
2607 }
2608
2609 switch ($authtype) {
2610 case 'PLAIN':
2611 // Start authentication
2612 $this->client_send('AUTH PLAIN' . $this->CRLF);
2613
2614 $rply = $this->get_lines();
2615 $code = substr($rply, 0, 3);
2616
2617 if($code != 334) {
2618 $this->error =
2619 array('error' => 'AUTH not accepted from server',
2620 'smtp_code' => $code,
2621 'smtp_msg' => substr($rply, 4));
2622 if($this->do_debug >= 1) {
2623 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2624 }
2625 return false;
2626 }
2627 // Send encoded username and password
2628 $this->client_send(base64_encode("\0".$username."\0".$password) . $this->CRLF);
2629
2630 $rply = $this->get_lines();
2631 $code = substr($rply, 0, 3);
2632
2633 if($code != 235) {
2634 $this->error =
2635 array('error' => 'Authentication not accepted from server',
2636 'smtp_code' => $code,
2637 'smtp_msg' => substr($rply, 4));
2638 if($this->do_debug >= 1) {
2639 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2640 }
2641 return false;
2642 }
2643 break;
2644 case 'LOGIN':
2645 // Start authentication
2646 $this->client_send('AUTH LOGIN' . $this->CRLF);
2647
2648 $rply = $this->get_lines();
2649 $code = substr($rply, 0, 3);
2650
2651 if($code != 334) {
2652 $this->error =
2653 array('error' => 'AUTH not accepted from server',
2654 'smtp_code' => $code,
2655 'smtp_msg' => substr($rply, 4));
2656 if($this->do_debug >= 1) {
2657 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2658 }
2659 return false;
2660 }
2661
2662 // Send encoded username
2663 $this->client_send(base64_encode($username) . $this->CRLF);
2664
2665 $rply = $this->get_lines();
2666 $code = substr($rply, 0, 3);
2667
2668 if($code != 334) {
2669 $this->error =
2670 array('error' => 'Username not accepted from server',
2671 'smtp_code' => $code,
2672 'smtp_msg' => substr($rply, 4));
2673 if($this->do_debug >= 1) {
2674 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2675 }
2676 return false;
2677 }
2678
2679 // Send encoded password
2680 $this->client_send(base64_encode($password) . $this->CRLF);
2681
2682 $rply = $this->get_lines();
2683 $code = substr($rply, 0, 3);
2684
2685 if($code != 235) {
2686 $this->error =
2687 array('error' => 'Password not accepted from server',
2688 'smtp_code' => $code,
2689 'smtp_msg' => substr($rply, 4));
2690 if($this->do_debug >= 1) {
2691 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2692 }
2693 return false;
2694 }
2695 break;
2696 case 'NTLM':
2697 /*
2698 * ntlm_sasl_client.php
2699 ** Bundled with Permission
2700 **
2701 ** How to telnet in windows: http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
2702 ** PROTOCOL Documentation http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
2703 */
2704 require_once 'extras/ntlm_sasl_client.php';
2705 $temp = new stdClass();
2706 $ntlm_client = new ntlm_sasl_client_class;
2707 if(! $ntlm_client->Initialize($temp)){//let's test if every function its available
2708 $this->error = array('error' => $temp->error);
2709 if($this->do_debug >= 1) {
2710 $this->edebug('You need to enable some modules in your php.ini file: ' . $this->error['error']);
2711 }
2712 return false;
2713 }
2714 $msg1 = $ntlm_client->TypeMsg1($realm, $workstation);//msg1
2715
2716 $this->client_send('AUTH NTLM ' . base64_encode($msg1) . $this->CRLF);
2717
2718 $rply = $this->get_lines();
2719 $code = substr($rply, 0, 3);
2720
2721 if($code != 334) {
2722 $this->error =
2723 array('error' => 'AUTH not accepted from server',
2724 'smtp_code' => $code,
2725 'smtp_msg' => substr($rply, 4));
2726 if($this->do_debug >= 1) {
2727 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2728 }
2729 return false;
2730 }
2731
2732 $challenge = substr($rply, 3);//though 0 based, there is a white space after the 3 digit number....//msg2
2733 $challenge = base64_decode($challenge);
2734 $ntlm_res = $ntlm_client->NTLMResponse(substr($challenge, 24, 8), $password);
2735 $msg3 = $ntlm_client->TypeMsg3($ntlm_res, $username, $realm, $workstation);//msg3
2736 // Send encoded username
2737 $this->client_send(base64_encode($msg3) . $this->CRLF);
2738
2739 $rply = $this->get_lines();
2740 $code = substr($rply, 0, 3);
2741
2742 if($code != 235) {
2743 $this->error =
2744 array('error' => 'Could not authenticate',
2745 'smtp_code' => $code,
2746 'smtp_msg' => substr($rply, 4));
2747 if($this->do_debug >= 1) {
2748 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2749 }
2750 return false;
2751 }
2752 break;
2753 case 'CRAM-MD5':
2754 // Start authentication
2755 $this->client_send('AUTH CRAM-MD5' . $this->CRLF);
2756
2757 $rply = $this->get_lines();
2758 $code = substr($rply, 0, 3);
2759
2760 if($code != 334) {
2761 $this->error =
2762 array('error' => 'AUTH not accepted from server',
2763 'smtp_code' => $code,
2764 'smtp_msg' => substr($rply, 4));
2765 if($this->do_debug >= 1) {
2766 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2767 }
2768 return false;
2769 }
2770
2771 // Get the challenge
2772 $challenge = base64_decode(substr($rply, 4));
2773
2774 // Build the response
2775 $response = $username . ' ' . $this->hmac($challenge, $password);
2776
2777 // Send encoded credentials
2778 $this->client_send(base64_encode($response) . $this->CRLF);
2779
2780 $rply = $this->get_lines();
2781 $code = substr($rply, 0, 3);
2782
2783 if($code != 235) {
2784 $this->error =
2785 array('error' => 'Credentials not accepted from server',
2786 'smtp_code' => $code,
2787 'smtp_msg' => substr($rply, 4));
2788 if($this->do_debug >= 1) {
2789 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2790 }
2791 return false;
2792 }
2793 break;
2794 }
2795 return true;
2796 }
2797
2798 /**
2799 * Works like hash_hmac('md5', $data, $key) in case that function is not available
2800 * @access protected
2801 * @param string $data
2802 * @param string $key
2803 * @return string
2804 */
2805 protected function hmac($data, $key) {
2806 if (function_exists('hash_hmac')) {
2807 return hash_hmac('md5', $data, $key);
2808 }
2809
2810 // The following borrowed from http://php.net/manual/en/function.mhash.php#27225
2811
2812 // RFC 2104 HMAC implementation for php.
2813 // Creates an md5 HMAC.
2814 // Eliminates the need to install mhash to compute a HMAC
2815 // Hacked by Lance Rushing
2816
2817 $b = 64; // byte length for md5
2818 if (strlen($key) > $b) {
2819 $key = pack('H*', md5($key));
2820 }
2821 $key = str_pad($key, $b, chr(0x00));
2822 $ipad = str_pad('', $b, chr(0x36));
2823 $opad = str_pad('', $b, chr(0x5c));
2824 $k_ipad = $key ^ $ipad ;
2825 $k_opad = $key ^ $opad;
2826
2827 return md5($k_opad . pack('H*', md5($k_ipad . $data)));
2828 }
2829
2830 /**
2831 * Returns true if connected to a server otherwise false
2832 * @access public
2833 * @return bool
2834 */
2835 public function Connected() {
2836 if(!empty($this->smtp_conn)) {
2837 $sock_status = stream_get_meta_data($this->smtp_conn);
2838 if($sock_status['eof']) {
2839 // the socket is valid but we are not connected
2840 if($this->do_debug >= 1) {
2841 $this->edebug('SMTP -> NOTICE: EOF caught while checking if connected');
2842 }
2843 $this->Close();
2844 return false;
2845 }
2846 return true; // everything looks good
2847 }
2848 return false;
2849 }
2850
2851 /**
2852 * Closes the socket and cleans up the state of the class.
2853 * It is not considered good to use this function without
2854 * first trying to use QUIT.
2855 * @access public
2856 * @return void
2857 */
2858 public function Close() {
2859 $this->error = null; // so there is no confusion
2860 $this->helo_rply = null;
2861 if(!empty($this->smtp_conn)) {
2862 // close the connection and cleanup
2863 fclose($this->smtp_conn);
2864 $this->smtp_conn = 0;
2865 }
2866 }
2867
2868 /////////////////////////////////////////////////
2869 // SMTP COMMANDS
2870 /////////////////////////////////////////////////
2871
2872 /**
2873 * Issues a data command and sends the msg_data to the server
2874 * finializing the mail transaction. $msg_data is the message
2875 * that is to be send with the headers. Each header needs to be
2876 * on a single line followed by a <CRLF> with the message headers
2877 * and the message body being separated by and additional <CRLF>.
2878 *
2879 * Implements rfc 821: DATA <CRLF>
2880 *
2881 * SMTP CODE INTERMEDIATE: 354
2882 * [data]
2883 * <CRLF>.<CRLF>
2884 * SMTP CODE SUCCESS: 250
2885 * SMTP CODE FAILURE: 552, 554, 451, 452
2886 * SMTP CODE FAILURE: 451, 554
2887 * SMTP CODE ERROR : 500, 501, 503, 421
2888 * @access public
2889 * @param string $msg_data
2890 * @return bool
2891 */
2892 public function Data($msg_data) {
2893 $this->error = null; // so no confusion is caused
2894
2895 if(!$this->connected()) {
2896 $this->error = array(
2897 'error' => 'Called Data() without being connected');
2898 return false;
2899 }
2900
2901 $this->client_send('DATA' . $this->CRLF);
2902
2903 $rply = $this->get_lines();
2904 $code = substr($rply, 0, 3);
2905
2906 if($this->do_debug >= 2) {
2907 $this->edebug('SMTP -> FROM SERVER:' . $rply);
2908 }
2909
2910 if($code != 354) {
2911 $this->error =
2912 array('error' => 'DATA command not accepted from server',
2913 'smtp_code' => $code,
2914 'smtp_msg' => substr($rply, 4));
2915 if($this->do_debug >= 1) {
2916 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
2917 }
2918 return false;
2919 }
2920
2921 /* the server is ready to accept data!
2922 * according to rfc 821 we should not send more than 1000
2923 * including the CRLF
2924 * characters on a single line so we will break the data up
2925 * into lines by \r and/or \n then if needed we will break
2926 * each of those into smaller lines to fit within the limit.
2927 * in addition we will be looking for lines that start with
2928 * a period '.' and append and additional period '.' to that
2929 * line. NOTE: this does not count towards limit.
2930 */
2931
2932 // normalize the line breaks so we know the explode works
2933 $msg_data = str_replace("\r\n", "\n", $msg_data);
2934 $msg_data = str_replace("\r", "\n", $msg_data);
2935 $lines = explode("\n", $msg_data);
2936
2937 /* we need to find a good way to determine is headers are
2938 * in the msg_data or if it is a straight msg body
2939 * currently I am assuming rfc 822 definitions of msg headers
2940 * and if the first field of the first line (':' sperated)
2941 * does not contain a space then it _should_ be a header
2942 * and we can process all lines before a blank "" line as
2943 * headers.
2944 */
2945
2946 $field = substr($lines[0], 0, strpos($lines[0], ':'));
2947 $in_headers = false;
2948 if(!empty($field) && !strstr($field, ' ')) {
2949 $in_headers = true;
2950 }
2951
2952 $max_line_length = 998; // used below; set here for ease in change
2953
2954 while(list(, $line) = @each($lines)) {
2955 $lines_out = null;
2956 if($line == '' && $in_headers) {
2957 $in_headers = false;
2958 }
2959 // ok we need to break this line up into several smaller lines
2960 while(strlen($line) > $max_line_length) {
2961 $pos = strrpos(substr($line, 0, $max_line_length), ' ');
2962
2963 // Patch to fix DOS attack
2964 if(!$pos) {
2965 $pos = $max_line_length - 1;
2966 $lines_out[] = substr($line, 0, $pos);
2967 $line = substr($line, $pos);
2968 } else {
2969 $lines_out[] = substr($line, 0, $pos);
2970 $line = substr($line, $pos + 1);
2971 }
2972
2973 /* if processing headers add a LWSP-char to the front of new line
2974 * rfc 822 on long msg headers
2975 */
2976 if($in_headers) {
2977 $line = "\t" . $line;
2978 }
2979 }
2980 $lines_out[] = $line;
2981
2982 // send the lines to the server
2983 while(list(, $line_out) = @each($lines_out)) {
2984 if(strlen($line_out) > 0)
2985 {
2986 if(substr($line_out, 0, 1) == '.') {
2987 $line_out = '.' . $line_out;
2988 }
2989 }
2990 $this->client_send($line_out . $this->CRLF);
2991 }
2992 }
2993
2994 // message data has been sent
2995 $this->client_send($this->CRLF . '.' . $this->CRLF);
2996
2997 $rply = $this->get_lines();
2998 $code = substr($rply, 0, 3);
2999
3000 if($this->do_debug >= 2) {
3001 $this->edebug('SMTP -> FROM SERVER:' . $rply);
3002 }
3003
3004 if($code != 250) {
3005 $this->error =
3006 array('error' => 'DATA not accepted from server',
3007 'smtp_code' => $code,
3008 'smtp_msg' => substr($rply, 4));
3009 if($this->do_debug >= 1) {
3010 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
3011 }
3012 return false;
3013 }
3014 return true;
3015 }
3016
3017 /**
3018 * Sends the HELO command to the smtp server.
3019 * This makes sure that we and the server are in
3020 * the same known state.
3021 *
3022 * Implements from rfc 821: HELO <SP> <domain> <CRLF>
3023 *
3024 * SMTP CODE SUCCESS: 250
3025 * SMTP CODE ERROR : 500, 501, 504, 421
3026 * @access public
3027 * @param string $host
3028 * @return bool
3029 */
3030 public function Hello($host = '') {
3031 $this->error = null; // so no confusion is caused
3032
3033 if(!$this->connected()) {
3034 $this->error = array(
3035 'error' => 'Called Hello() without being connected');
3036 return false;
3037 }
3038
3039 // if hostname for HELO was not specified send default
3040 if(empty($host)) {
3041 // determine appropriate default to send to server
3042 $host = 'localhost';
3043 }
3044
3045 // Send extended hello first (RFC 2821)
3046 if(!$this->SendHello('EHLO', $host)) {
3047 if(!$this->SendHello('HELO', $host)) {
3048 return false;
3049 }
3050 }
3051
3052 return true;
3053 }
3054
3055 /**
3056 * Sends a HELO/EHLO command.
3057 * @access protected
3058 * @param string $hello
3059 * @param string $host
3060 * @return bool
3061 */
3062 protected function SendHello($hello, $host) {
3063 $this->client_send($hello . ' ' . $host . $this->CRLF);
3064
3065 $rply = $this->get_lines();
3066 $code = substr($rply, 0, 3);
3067
3068 if($this->do_debug >= 2) {
3069 $this->edebug('SMTP -> FROM SERVER: ' . $rply);
3070 }
3071
3072 if($code != 250) {
3073 $this->error =
3074 array('error' => $hello . ' not accepted from server',
3075 'smtp_code' => $code,
3076 'smtp_msg' => substr($rply, 4));
3077 if($this->do_debug >= 1) {
3078 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
3079 }
3080 return false;
3081 }
3082
3083 $this->helo_rply = $rply;
3084
3085 return true;
3086 }
3087
3088 /**
3089 * Starts a mail transaction from the email address specified in
3090 * $from. Returns true if successful or false otherwise. If True
3091 * the mail transaction is started and then one or more Recipient
3092 * commands may be called followed by a Data command.
3093 *
3094 * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
3095 *
3096 * SMTP CODE SUCCESS: 250
3097 * SMTP CODE SUCCESS: 552, 451, 452
3098 * SMTP CODE SUCCESS: 500, 501, 421
3099 * @access public
3100 * @param string $from
3101 * @return bool
3102 */
3103 public function Mail($from) {
3104 $this->error = null; // so no confusion is caused
3105
3106 if(!$this->connected()) {
3107 $this->error = array(
3108 'error' => 'Called Mail() without being connected');
3109 return false;
3110 }
3111
3112 $useVerp = ($this->do_verp ? ' XVERP' : '');
3113 $this->client_send('MAIL FROM:<' . $from . '>' . $useVerp . $this->CRLF);
3114
3115 $rply = $this->get_lines();
3116 $code = substr($rply, 0, 3);
3117
3118 if($this->do_debug >= 2) {
3119 $this->edebug('SMTP -> FROM SERVER:' . $rply);
3120 }
3121
3122 if($code != 250) {
3123 $this->error =
3124 array('error' => 'MAIL not accepted from server',
3125 'smtp_code' => $code,
3126 'smtp_msg' => substr($rply, 4));
3127 if($this->do_debug >= 1) {
3128 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
3129 }
3130 return false;
3131 }
3132 return true;
3133 }
3134
3135 /**
3136 * Sends the quit command to the server and then closes the socket
3137 * if there is no error or the $close_on_error argument is true.
3138 *
3139 * Implements from rfc 821: QUIT <CRLF>
3140 *
3141 * SMTP CODE SUCCESS: 221
3142 * SMTP CODE ERROR : 500
3143 * @access public
3144 * @param bool $close_on_error
3145 * @return bool
3146 */
3147 public function Quit($close_on_error = true) {
3148 $this->error = null; // so there is no confusion
3149
3150 if(!$this->connected()) {
3151 $this->error = array(
3152 'error' => 'Called Quit() without being connected');
3153 return false;
3154 }
3155
3156 // send the quit command to the server
3157 $this->client_send('quit' . $this->CRLF);
3158
3159 // get any good-bye messages
3160 $byemsg = $this->get_lines();
3161
3162 if($this->do_debug >= 2) {
3163 $this->edebug('SMTP -> FROM SERVER:' . $byemsg);
3164 }
3165
3166 $rval = true;
3167 $e = null;
3168
3169 $code = substr($byemsg, 0, 3);
3170 if($code != 221) {
3171 // use e as a tmp var cause Close will overwrite $this->error
3172 $e = array('error' => 'SMTP server rejected quit command',
3173 'smtp_code' => $code,
3174 'smtp_rply' => substr($byemsg, 4));
3175 $rval = false;
3176 if($this->do_debug >= 1) {
3177 $this->edebug('SMTP -> ERROR: ' . $e['error'] . ': ' . $byemsg);
3178 }
3179 }
3180
3181 if(empty($e) || $close_on_error) {
3182 $this->Close();
3183 }
3184
3185 return $rval;
3186 }
3187
3188 /**
3189 * Sends the command RCPT to the SMTP server with the TO: argument of $to.
3190 * Returns true if the recipient was accepted false if it was rejected.
3191 *
3192 * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
3193 *
3194 * SMTP CODE SUCCESS: 250, 251
3195 * SMTP CODE FAILURE: 550, 551, 552, 553, 450, 451, 452
3196 * SMTP CODE ERROR : 500, 501, 503, 421
3197 * @access public
3198 * @param string $to
3199 * @return bool
3200 */
3201 public function Recipient($to) {
3202 $this->error = null; // so no confusion is caused
3203
3204 if(!$this->connected()) {
3205 $this->error = array(
3206 'error' => 'Called Recipient() without being connected');
3207 return false;
3208 }
3209
3210 $this->client_send('RCPT TO:<' . $to . '>' . $this->CRLF);
3211
3212 $rply = $this->get_lines();
3213 $code = substr($rply, 0, 3);
3214
3215 if($this->do_debug >= 2) {
3216 $this->edebug('SMTP -> FROM SERVER:' . $rply);
3217 }
3218
3219 if($code != 250 && $code != 251) {
3220 $this->error =
3221 array('error' => 'RCPT not accepted from server',
3222 'smtp_code' => $code,
3223 'smtp_msg' => substr($rply, 4));
3224 if($this->do_debug >= 1) {
3225 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
3226 }
3227 return false;
3228 }
3229 return true;
3230 }
3231
3232 /**
3233 * Sends the RSET command to abort and transaction that is
3234 * currently in progress. Returns true if successful false
3235 * otherwise.
3236 *
3237 * Implements rfc 821: RSET <CRLF>
3238 *
3239 * SMTP CODE SUCCESS: 250
3240 * SMTP CODE ERROR : 500, 501, 504, 421
3241 * @access public
3242 * @return bool
3243 */
3244 public function Reset() {
3245 $this->error = null; // so no confusion is caused
3246
3247 if(!$this->connected()) {
3248 $this->error = array('error' => 'Called Reset() without being connected');
3249 return false;
3250 }
3251
3252 $this->client_send('RSET' . $this->CRLF);
3253
3254 $rply = $this->get_lines();
3255 $code = substr($rply, 0, 3);
3256
3257 if($this->do_debug >= 2) {
3258 $this->edebug('SMTP -> FROM SERVER:' . $rply);
3259 }
3260
3261 if($code != 250) {
3262 $this->error =
3263 array('error' => 'RSET failed',
3264 'smtp_code' => $code,
3265 'smtp_msg' => substr($rply, 4));
3266 if($this->do_debug >= 1) {
3267 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
3268 }
3269 return false;
3270 }
3271
3272 return true;
3273 }
3274
3275 /**
3276 * Starts a mail transaction from the email address specified in
3277 * $from. Returns true if successful or false otherwise. If True
3278 * the mail transaction is started and then one or more Recipient
3279 * commands may be called followed by a Data command. This command
3280 * will send the message to the users terminal if they are logged
3281 * in and send them an email.
3282 *
3283 * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
3284 *
3285 * SMTP CODE SUCCESS: 250
3286 * SMTP CODE SUCCESS: 552, 451, 452
3287 * SMTP CODE SUCCESS: 500, 501, 502, 421
3288 * @access public
3289 * @param string $from
3290 * @return bool
3291 */
3292 public function SendAndMail($from) {
3293 $this->error = null; // so no confusion is caused
3294
3295 if(!$this->connected()) {
3296 $this->error = array(
3297 'error' => 'Called SendAndMail() without being connected');
3298 return false;
3299 }
3300
3301 $this->client_send('SAML FROM:' . $from . $this->CRLF);
3302
3303 $rply = $this->get_lines();
3304 $code = substr($rply, 0, 3);
3305
3306 if($this->do_debug >= 2) {
3307 $this->edebug('SMTP -> FROM SERVER:' . $rply);
3308 }
3309
3310 if($code != 250) {
3311 $this->error =
3312 array('error' => 'SAML not accepted from server',
3313 'smtp_code' => $code,
3314 'smtp_msg' => substr($rply, 4));
3315 if($this->do_debug >= 1) {
3316 $this->edebug('SMTP -> ERROR: ' . $this->error['error'] . ': ' . $rply);
3317 }
3318 return false;
3319 }
3320 return true;
3321 }
3322
3323 /**
3324 * This is an optional command for SMTP that this class does not
3325 * support. This method is here to make the RFC821 Definition
3326 * complete for this class and __may__ be implimented in the future
3327 *
3328 * Implements from rfc 821: TURN <CRLF>
3329 *
3330 * SMTP CODE SUCCESS: 250
3331 * SMTP CODE FAILURE: 502
3332 * SMTP CODE ERROR : 500, 503
3333 * @access public
3334 * @return bool
3335 */
3336 public function Turn() {
3337 $this->error = array('error' => 'This method, TURN, of the SMTP '.
3338 'is not implemented');
3339 if($this->do_debug >= 1) {
3340 $this->edebug('SMTP -> NOTICE: ' . $this->error['error']);
3341 }
3342 return false;
3343 }
3344
3345 /**
3346 * Sends data to the server
3347 * @param string $data
3348 * @access public
3349 * @return Integer number of bytes sent to the server or FALSE on error
3350 */
3351 public function client_send($data) {
3352 if ($this->do_debug >= 1) {
3353 $this->edebug("CLIENT -> SMTP: $data");
3354 }
3355 return fwrite($this->smtp_conn, $data);
3356 }
3357
3358 /**
3359 * Get the current error
3360 * @access public
3361 * @return array
3362 */
3363 public function getError() {
3364 return $this->error;
3365 }
3366
3367 /////////////////////////////////////////////////
3368 // INTERNAL FUNCTIONS
3369 /////////////////////////////////////////////////
3370
3371 /**
3372 * Read in as many lines as possible
3373 * either before eof or socket timeout occurs on the operation.
3374 * With SMTP we can tell if we have more lines to read if the
3375 * 4th character is '-' symbol. If it is a space then we don't
3376 * need to read anything else.
3377 * @access protected
3378 * @return string
3379 */
3380 protected function get_lines() {
3381 $data = '';
3382 $endtime = 0;
3383 /* If for some reason the fp is bad, don't inf loop */
3384 if (!is_resource($this->smtp_conn)) {
3385 return $data;
3386 }
3387 stream_set_timeout($this->smtp_conn, $this->Timeout);
3388 if ($this->Timelimit > 0) {
3389 $endtime = time() + $this->Timelimit;
3390 }
3391 while(is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
3392 $str = @fgets($this->smtp_conn, 515);
3393 if($this->do_debug >= 4) {
3394 $this->edebug("SMTP -> get_lines(): \$data was \"$data\"");
3395 $this->edebug("SMTP -> get_lines(): \$str is \"$str\"");
3396 }
3397 $data .= $str;
3398 if($this->do_debug >= 4) {
3399 $this->edebug("SMTP -> get_lines(): \$data is \"$data\"");
3400 }
3401 // if 4th character is a space, we are done reading, break the loop
3402 if(substr($str, 3, 1) == ' ') { break; }
3403 // Timed-out? Log and break
3404 $info = stream_get_meta_data($this->smtp_conn);
3405 if ($info['timed_out']) {
3406 if($this->do_debug >= 4) {
3407 $this->edebug('SMTP -> get_lines(): timed-out (' . $this->Timeout . ' seconds)');
3408 }
3409 break;
3410 }
3411 // Now check if reads took too long
3412 if ($endtime) {
3413 if (time() > $endtime) {
3414 if($this->do_debug >= 4) {
3415 $this->edebug('SMTP -> get_lines(): timelimit reached (' . $this->Timelimit . ' seconds)');
3416 }
3417 break;
3418 }
3419 }
3420 }
3421 return $data;
3422 }
3423
3424}
3425//end class.smtp.php
3426
3427if ( isset($_SERVER["OS"]) && $_SERVER["OS"] == "Windows_NT" ) {
3428 $hostname = strtolower($_SERVER["COMPUTERNAME"]);
3429} else {
3430 $hostname = `hostname`;
3431 $hostnamearray = explode('.', $hostname);
3432 $hostname = $hostnamearray[0];
3433}
3434
3435if ( isset($_REQUEST['sendemail']) ) {
3436 header("Content-Type: text/plain");
3437 header("X-Node: $hostname");
3438 $from = $_REQUEST['from'];
3439 $toemail = $_REQUEST['toemail'];
3440 $subject = $_REQUEST['subject'];
3441 $message = $_REQUEST['message'];
3442 if ( $from == "" || $toemail == "" ) {
3443 header("HTTP/1.1 500 WhatAreYouDoing");
3444 header("Content-Type: text/plain");
3445 echo 'FAIL: You must fill in From: and To: fields.';
3446 exit;
3447 }
3448 if ( $_REQUEST['sendmethod'] == "mail" ) {
3449 $result = mail($toemail, $subject, $message, "From: $from" );
3450 if ( $result ) {
3451 echo 'OK';
3452 } else {
3453 echo 'FAIL';
3454 }
3455 } elseif ( $_REQUEST['sendmethod'] == "smtp" ) {
3456 ob_start(); //start capturing output buffer because we want to change output to html
3457
3458 $mail = new PHPMailer;
3459
3460 $mail->SMTPDebug = 2;
3461 $mail->IsSMTP();
3462 if ( strpos($hostname, 'cpnl') === FALSE ) //if not cPanel
3463 $mail->Host = 'relay-hosting.secureserver.net';
3464 else
3465 $mail->Host = 'localhost';
3466 $mail->SMTPAuth = false;
3467
3468 $mail->From = $from;
3469 $mail->FromName = 'Mailer';
3470 $mail->AddAddress($toemail);
3471
3472 $mail->Subject = $subject;
3473 $mail->Body = $message;
3474
3475 $mailresult = $mail->Send();
3476 $mailconversation = nl2br(htmlspecialchars(ob_get_clean())); //captures the output of PHPMailer and htmlizes it
3477 if ( !$mailresult ) {
3478 echo 'FAIL: ' . $mail->ErrorInfo . '<br />' . $mailconversation;
3479 } else {
3480 echo $mailconversation;
3481 }
3482 } elseif ( $_REQUEST['sendmethod'] == "sendmail" ) {
3483 $cmd = "cat - << EOF | /usr/sbin/sendmail -t 2>&1\nto:$toemail\nfrom:$from\nsubject:$subject\n\n$message\n\nEOF\n";
3484 $mailresult = shell_exec($cmd);
3485 if ( $mailresult == '' ) { //A blank result is usually successful
3486 echo 'OK';
3487 } else {
3488 echo "The sendmail command returned what appears to be an error: " . $mailresult . "<br />\n<br />";
3489 }
3490 } else {
3491 echo 'FAIL (Invalid sendmethod variable in POST data)';
3492 }
3493 exit;
3494}
3495?>
3496
3497<!DOCTYPE html>
3498<html>
3499
3500<head>
3501 <title>Does your PHP work?</title>
3502 <!-- Required meta tags -->
3503 <meta charset="utf-8">
3504 <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
3505
3506 <!-- Bootstrap CSS -->
3507 <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css" integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb" crossorigin="anonymous">
3508 <style media="screen">
3509 .wt-mt {
3510 margin-top: 75px;
3511 }
3512 .dbConnectionTest {
3513 width: 570px;
3514 }
3515
3516 </style>
3517</head>
3518<body>
3519 <header>
3520 <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
3521 <span class="navbar-brand mb-0 h1">Does PHP Work?</span>
3522 </nav>
3523 </header>
3524 <div class="container-fluid wt-mt">
3525 <div class="row">
3526 <div class="col-sm-2 text-center">
3527 <div class="nav flex-column" role="tablist" aria-orientation="vertical">
3528 <a class="nav-link" id="db-connect-link" data-toggle="pill" href="#db-connect" role="tab" aria-controls="db-connect" aria-selected="true">DB Connection Test</a>
3529 <a class="nav-link" id="form-mail-link" data-toggle="pill" href="#form-mail" role="tab" aria-controls="form-mail" aria-selected="false">Form Mailer Test</a>
3530 <a class="nav-link" id="php-info-link" data-toggle="pill" href="#php-info" role="tab" aria-controls="php-info" aria-selected="false">PHP Info</a>
3531 </div>
3532 </div>
3533 <div id="test_area" class="col-sm-8 tab-content">
3534 <div class="dbConnectionTest tab-pane" id="db-connect" role="tabpanel" aria-labelledby="db-connect-link">
3535 <?php
3536 // Check to see if the form was submitted
3537 if (isset($_POST['host'])) {
3538 $dbhost = $_POST['host'];
3539 $dbname = $_POST['database'];
3540 $dbuser = $_POST['user'];
3541 $dbpass = $_POST['pwd'];
3542 $dbport = $_POST['port'];
3543 if (strlen($dbport) < 4) { $dbport = 3306; }
3544 if (!function_exists('gethostname')) {
3545 $hostname = `hostname`;
3546 $hostnamearray = explode('.', $hostname);
3547 $hostname = $hostnamearray[0];
3548 }
3549 else $hostname = gethostname();
3550 // Check to see if mysqli is available
3551 if (!extension_loaded('mysqli') or $_POST['config'] == "mysql") {
3552 $dbhost = $dbhost.':'.$dbport;
3553 // Create connection
3554 $con = @mysql_connect($dbhost,$dbuser,$dbpass);
3555 // Check connection
3556 if (mysql_error()) {
3557 die("Failed to connect to MySQL using the PHP mysql extension: " . mysql_error());
3558 }
3559 mysql_select_db($dbname, $con);
3560 // Query the database to show all the tables.
3561 $query = 'SHOW tables;';
3562 $result = mysql_query($query);
3563 // Print the results of the query.
3564 echo "Here is a list of the tables in your database:<br>";
3565 echo "- $dbname <br>";
3566 while($row = mysql_fetch_array($result)) {
3567 echo "\ _ _ $row[0] <br>";
3568 }
3569 echo "<br>The connection to \"$dbname\" was successful!";
3570 $extension = "MySQL";
3571 mysql_close($con);
3572 }
3573 else {
3574 // Create connection
3575 $con = @mysqli_connect($dbhost,$dbuser,$dbpass,$dbname,$dbport);
3576 // Check connection
3577 if (mysqli_connect_errno()) {
3578 die ("Failed to connect to MySQL using the PHP mysqli extension: " . mysqli_connect_error());
3579 }
3580 // Query the database to show all the tables.
3581 $query = 'SHOW tables;';
3582 $result = mysqli_query($con, $query);
3583 // Print the results of the query.
3584 echo "Here is a list of the tables in your database:<br>";
3585 echo "- $dbname <br>";
3586 while($row = mysqli_fetch_array($result)) {
3587 echo "\ _ _ $row[0] <br>";
3588 }
3589 echo "<br>The connection to \"$dbname\" was successful!";
3590 $extension = "MySQLi";
3591 mysqli_close($con);
3592 }
3593 echo "<br>PHP extension used: " . $extension;
3594 echo "<br>Server Name: " . $hostname;
3595 unset($_POST);
3596 }
3597 // If we are not here because of a form submission, do the following.
3598 else { ?>
3599
3600 <div class="card">
3601 <div class="card-body">
3602 <h3 class="card-title">Database Connection Test</h3>
3603 <form method="post">
3604 <div class="form-group row">
3605 <label class="col-sm-3 col-form-label" for="config">Connection:</label>
3606 <div class="col-sm-9">
3607 <select class="form-control form-control-sm" name="config" id="config">
3608 <option value="auto" selected>Auto Select</option>
3609 <option value="mysqli">MySQLi</option>
3610 <option value="mysql">MySQL</option>
3611 </select>
3612 </div>
3613 </div>
3614 <div class="form-group row">
3615 <label class="col-sm-3 col-form-label" for="host">Host Name:</label>
3616 <div class="col-sm-9">
3617 <input type="text" class="form-control form-control-sm" id="host" name="host" autofocus>
3618 </div>
3619 </div>
3620 <div class="form-group row">
3621 <label class="col-sm-3 col-form-label" for="database">DB Name:</label>
3622 <div class="col-sm-9">
3623 <input type="text" class="form-control form-control-sm" id="database" name="database">
3624 </div>
3625 </div>
3626 <div class="form-group row">
3627 <label class="col-sm-3 col-form-label" for="user">User:</label>
3628 <div class="col-sm-9">
3629 <input type="text" class="form-control form-control-sm" id="user" name="user">
3630 </div>
3631 </div>
3632 <div class="form-group row">
3633 <label class="col-sm-3 col-form-label" for="pwd">Password:</label>
3634 <div class="col-sm-9">
3635 <input type="password" class="form-control form-control-sm" id="pwd" name="pwd">
3636 </div>
3637 </div>
3638 <div class="form-group row">
3639 <label class="col-sm-3 col-form-label" for="port">Port (optional):</label>
3640 <div class="col-sm-9">
3641 <input type="nubmer" class="form-control form-control-sm" id="port" name="port" min="1" max="65535" value="3306">
3642 </div>
3643 </div>
3644 <div class="text-center">
3645 <button type="submit" class="btn btn-primary">Connect</button>
3646 </div>
3647 </form>
3648 </div>
3649 </div>
3650 <?php
3651 }
3652 ?>
3653 </div>
3654 <div class="formMailTest tab-pane" id="form-mail" role="tabpanel" aria-labelledby="form-mail-link">
3655 <div class="card">
3656 <div class="card-body">
3657 <h3 class="card-title">Mail Test</h3>
3658 <form id="mailform" name="mailform">
3659 <div class="form-group row">
3660 <label class="col-sm-3 col-form-label" for="sendmethod">Method:</label>
3661 <div class="col-sm-9">
3662 <select onchange="AutoSubject();" class="form-control form-control-sm" name="sendmethod" id="sendmethod">
3663 <option value="mail">PHP mail()</option>
3664 <option value="smtp">SMTP</option>
3665 <? if ( !isset($_SERVER["OS"]) && $_SERVER["OS"] != "Windows_NT" ) { ?>
3666 <option value="sendmail">sendmail from shell</option>
3667 <? } ?>
3668 </select>
3669 </div>
3670 </div>
3671 <div class="form-group row">
3672 <label class="col-sm-3 col-form-label" for="toemail">To:</label>
3673 <div class="col-sm-9">
3674 <input type="text" class="form-control form-control-sm" id="toemail" name="toemail">
3675 </div>
3676 </div>
3677 <div class="form-group row">
3678 <label class="col-sm-3 col-form-label" for="from">From:</label>
3679 <div class="col-sm-9">
3680 <input type="text" class="form-control form-control-sm" id="from" name="from">
3681 </div>
3682 </div>
3683 <div class="form-group row">
3684 <label class="col-sm-3 col-form-label" for="subject">Subject:</label>
3685 <div class="col-sm-9">
3686 <input type="text" class="form-control form-control-sm" disabled id="subject" name="subject">
3687 <label for="autosubject" class="form-check-label">
3688 <input type="checkbox" onchange="AutoSubject();" name="autosubject" checked class="form-check-input" id="autosubject">Auto
3689 </label>
3690 </div>
3691 </div>
3692 <div class="form-group row">
3693 <label class="col-sm-3 col-form-label" for="message">Message:</label>
3694 <div class="col-sm-9">
3695 <textarea class="form-control" id="message" name="message" ></textarea>
3696 </div>
3697 </div>
3698 <div class="text-center">
3699 <button type="button" class="btn btn-primary" id="sendemail" onclick="GoSend(); AutoSubject();">Send</button>
3700 </div>
3701 </form>
3702 </div>
3703 </div>
3704 <table id="msglog" class="table table-striped">
3705 <thead class="thead-dark">
3706 <tr>
3707 <th scope="col">#</th>
3708 <th scope="col">TIME</th>
3709 <th scope="col">TO</th>
3710 <th scope="col">FROM</th>
3711 <th scope="col">SUBJECT</th>
3712 <th scope="col">MESSAGE</th>
3713 <th scope="col">METHOD</th>
3714 <th scope="col">NODE</th>
3715 <th scope="col">RESULT</th>
3716 </tr>
3717 </thead>
3718 </table>
3719 </div>
3720 <div class="phpInfoTest tab-pane" id="php-info" role="tabpanel" aria-labelledby="php-info-link">
3721 <?php phpinfo(); ?>
3722 </div>
3723 </div>
3724 </div>
3725 </div>
3726
3727 <script>
3728 var msgid = 1;
3729 AutoSubject();
3730
3731 function AutoSubject() {
3732 if ( document.mailform.autosubject.checked ) {
3733 document.mailform.subject.disabled=true;
3734 document.mailform.subject.value='PHP Mail '+document.mailform.sendmethod.value+' demo #'+msgid;
3735 } else {
3736 document.mailform.subject.disabled=false;
3737 }
3738 }
3739
3740 function GoSend() {
3741 var table=document.getElementById("msglog");
3742 var row = table.insertRow(1);
3743
3744 var NUMcell = row.insertCell(0);
3745 NUMcell.innerHTML=msgid++;
3746
3747 var DATEcell = row.insertCell(1);
3748 var d = new Date();
3749 DATEcell.innerHTML=d.toLocaleTimeString();
3750
3751 var TOcell = row.insertCell(2);
3752 TOcell.innerHTML=document.mailform.toemail.value;
3753
3754 var FROMcell = row.insertCell(3);
3755 FROMcell.innerHTML=document.mailform.from.value;
3756
3757 var SUBJECTcell = row.insertCell(4);
3758 SUBJECTcell.innerHTML=document.mailform.subject.value;
3759
3760 var MESSAGEcell = row.insertCell(5);
3761 MESSAGEcell.innerHTML=document.mailform.message.value;
3762
3763 var METHODcell = row.insertCell(6);
3764 METHODcell.innerHTML=document.mailform.sendmethod.value;
3765
3766 var NODEcell = row.insertCell(7);
3767
3768 var RESULTcell = row.insertCell(8);
3769 RESULTcell.innerHTML="<img height=\"24\" src=\"data:image/gif;base64,R0lGODlhEAAQAPYAAP///wAAANTU1JSUlGBgYEBAQERERG5ubqKiotzc3KSkpCQkJCgoKDAwMDY2Nj4+Pmpqarq6uhwcHHJycuzs7O7u7sLCwoqKilBQUF5eXr6+vtDQ0Do6OhYWFoyMjKqqqlxcXHx8fOLi4oaGhg4ODmhoaJycnGZmZra2tkZGRgoKCrCwsJaWlhgYGAYGBujo6PT09Hh4eISEhPb29oKCgqioqPr6+vz8/MDAwMrKyvj4+NbW1q6urvDw8NLS0uTk5N7e3s7OzsbGxry8vODg4NjY2PLy8tra2np6erS0tLKyskxMTFJSUlpaWmJiYkJCQjw8PMTExHZ2djIyMurq6ioqKo6OjlhYWCwsLB4eHqCgoE5OThISEoiIiGRkZDQ0NMjIyMzMzObm5ri4uH5+fpKSkp6enlZWVpCQkEpKSkhISCIiIqamphAQEAwMDKysrAQEBJqamiYmJhQUFDg4OHR0dC4uLggICHBwcCAgIFRUVGxsbICAgAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAHjYAAgoOEhYUbIykthoUIHCQqLoI2OjeFCgsdJSsvgjcwPTaDAgYSHoY2FBSWAAMLE4wAPT89ggQMEbEzQD+CBQ0UsQA7RYIGDhWxN0E+ggcPFrEUQjuCCAYXsT5DRIIJEBgfhjsrFkaDERkgJhswMwk4CDzdhBohJwcxNB4sPAmMIlCwkOGhRo5gwhIGAgAh+QQJCgAAACwAAAAAEAAQAAAHjIAAgoOEhYU7A1dYDFtdG4YAPBhVC1ktXCRfJoVKT1NIERRUSl4qXIRHBFCbhTKFCgYjkII3g0hLUbMAOjaCBEw9ukZGgidNxLMUFYIXTkGzOmLLAEkQCLNUQMEAPxdSGoYvAkS9gjkyNEkJOjovRWAb04NBJlYsWh9KQ2FUkFQ5SWqsEJIAhq6DAAIBACH5BAkKAAAALAAAAAAQABAAAAeJgACCg4SFhQkKE2kGXiwChgBDB0sGDw4NDGpshTheZ2hRFRVDUmsMCIMiZE48hmgtUBuCYxBmkAAQbV2CLBM+t0puaoIySDC3VC4tgh40M7eFNRdH0IRgZUO3NjqDFB9mv4U6Pc+DRzUfQVQ3NzAULxU2hUBDKENCQTtAL9yGRgkbcvggEq9atUAAIfkECQoAAAAsAAAAABAAEAAAB4+AAIKDhIWFPygeEE4hbEeGADkXBycZZ1tqTkqFQSNIbBtGPUJdD088g1QmMjiGZl9MO4I5ViiQAEgMA4JKLAm3EWtXgmxmOrcUElWCb2zHkFQdcoIWPGK3Sm1LgkcoPrdOKiOCRmA4IpBwDUGDL2A5IjCCN/QAcYUURQIJIlQ9MzZu6aAgRgwFGAFvKRwUCAAh+QQJCgAAACwAAAAAEAAQAAAHjIAAgoOEhYUUYW9lHiYRP4YACStxZRc0SBMyFoVEPAoWQDMzAgolEBqDRjg8O4ZKIBNAgkBjG5AAZVtsgj44VLdCanWCYUI3txUPS7xBx5AVDgazAjC3Q3ZeghUJv5B1cgOCNmI/1YUeWSkCgzNUFDODKydzCwqFNkYwOoIubnQIt244MzDC1q2DggIBACH5BAkKAAAALAAAAAAQABAAAAeJgACCg4SFhTBAOSgrEUEUhgBUQThjSh8IcQo+hRUbYEdUNjoiGlZWQYM2QD4vhkI0ZWKCPQmtkG9SEYJURDOQAD4HaLuyv0ZeB4IVj8ZNJ4IwRje/QkxkgjYz05BdamyDN9uFJg9OR4YEK1RUYzFTT0qGdnduXC1Zchg8kEEjaQsMzpTZ8avgoEAAIfkECQoAAAAsAAAAABAAEAAAB4iAAIKDhIWFNz0/Oz47IjCGADpURAkCQUI4USKFNhUvFTMANxU7KElAhDA9OoZHH0oVgjczrJBRZkGyNpCCRCw8vIUzHmXBhDM0HoIGLsCQAjEmgjIqXrxaBxGCGw5cF4Y8TnybglprLXhjFBUWVnpeOIUIT3lydg4PantDz2UZDwYOIEhgzFggACH5BAkKAAAALAAAAAAQABAAAAeLgACCg4SFhjc6RhUVRjaGgzYzRhRiREQ9hSaGOhRFOxSDQQ0uj1RBPjOCIypOjwAJFkSCSyQrrhRDOYILXFSuNkpjggwtvo86H7YAZ1korkRaEYJlC3WuESxBggJLWHGGFhcIxgBvUHQyUT1GQWwhFxuFKyBPakxNXgceYY9HCDEZTlxA8cOVwUGBAAA7AAAAAAAAAAAA\">";
3770
3771 var postdata= "sendemail=1&toemail="+document.mailform.toemail.value;
3772 postdata+="&from="+document.mailform.from.value;
3773 postdata+="&subject="+document.mailform.subject.value;
3774 postdata+="&sendmethod="+document.mailform.sendmethod.value;
3775 postdata+="&message="+encodeURIComponent(document.mailform.message.value).replace("%20", "+");
3776 var url="<?=$_SERVER['PHP_SELF']; ?>";
3777 var request=new XMLHttpRequest();
3778 request.open("POST",url,true);
3779 request.setRequestHeader("Content-type","application/x-www-form-urlencoded");
3780 request.overrideMimeType("text/plain");
3781 request.onreadystatechange=function() {
3782 if ( request.readyState==4 ) {
3783 NODEcell.innerHTML=request.getResponseHeader("X-Node");
3784 if ( request.responseText == "OK" || request.responseText == "FAIL" ) {
3785 RESULTcell.innerHTML=request.responseText;
3786 } else {
3787 if ( request.status == 0 ) {
3788 RESULTcell.innerHTML="ERR_EMPTY_RESPONSE";
3789 } else {
3790 RESULTcell.innerHTML="HTTP/1.1 "+request.status+" "+request.statusText+"<br /><br />"+request.responseText;
3791 }
3792 }
3793 }
3794 }
3795 request.send(postdata);
3796 }
3797 </script>
3798
3799 <!-- jQuery first, then Popper.js, then Bootstrap JS -->
3800 <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
3801 <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.3/umd/popper.min.js" integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh" crossorigin="anonymous"></script>
3802 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js" integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ" crossorigin="anonymous"></script>
3803</body>
3804
3805</html>