%PDF- %PDF-
Direktori : /home/eirtvhdf/public_html/testbeta-atif/mail/ |
Current File : //home/eirtvhdf/public_html/testbeta-atif/mail/form.lib.php |
<?php namespace JF; /** Copyright 2018 JQueryForm.com License: http://www.jqueryform.com/license.php FormID: eirtech-cform Date: 2018-10-23 15:23:57 Version: v2.1.4 Generated by http://www.jqueryform.com PHP 5.3+ is required. If mailgun is used AND the form has file upload field, PHP 5.5+ is required. */ require_once( __DIR__ . '/form.config.php' ); $dbFile = __DIR__ . '/form.db.php'; if( file_exists( $dbFile ) ){ require_once( $dbFile ); } use JF\Config; // -------------------------------------------------------------- class Form { public static function setDataDir( $dir ){ self::$dataDir = $dir ; } public static function getFormDataFile(){ return self::$dataDir . '/form-data.php' ; } public static function getEmailLogFile(){ return self::$dataDir . '/email-log.php' ; } public static function getSmsLogFile(){ return self::$dataDir . '/sms-log.php' ; } public static function validate( $post = array() ){ if( empty($post) ){ $post = $_POST; }; self::$post = $post; self::$values = array(); self::$attachments = array(); self::$invalid = array(); self::$columns = array( self::csvfield('RecordID'), self::csvfield('Date'), self::csvfield('IP') ); self::$csvValues = array( self::csvfield(self::getRecordID()), self::csvfield(date("Y-m-d H:i:s")), self::csvfield($_SERVER['REMOTE_ADDR']) ); self::$serverValidationFields = empty(self::$post['serverValidationFields']) ? array(): explode(',', self::$post['serverValidationFields']); // add preset tags self::presetTags(); if( self::hasField('page_break') ){ self::$serverValidationFields = array('skip-serverside-validation'); }; self::$style = 'font-family:Verdana, Arial, Helvetica, sans-serif; font-size : 13px; color:#474747;padding:6px;border:1px solid #cccccc;' ; self::$rows = array(); self::$sms = array(); $config = self::getConfig(); foreach( $config['fields'] as $f ){ switch ($f['field_type']) { case 'section_break': case 'page_navigation': case 'page_break': case 'submit': // are not data fields, ignore them, do nothing break; case 'recaptcha': $ok = self::validateReCaptcha( $post, $f['recaptcha']['secretKey'], $f['field_options']['hidden'] ); if( !$ok ) { self::reCaptchaInvalidHandler( $f ); }; break; // creditcard field contains extra fields, have to validate them one by one case 'creditcard': self::_validateCreditcardFields( $f ); break; case 'payment': self::_validatePaymentField( $f ); break; case 'address': self::_validateAddressField( $f ); break; default: self::_validateField( $f ); }; }; // foreach self::$values['dataTable'] = empty(self::$rows) ? '' : '<table cellspacing="0" cellpadding="0" border="1" bordercolor="#cccccc" style="border:1px solid #cccccc;"><tbody>' . join( "\n", self::$rows ). '</table>'; self::$values['dataText'] = join( "\n\n", self::$sms ); self::validateOneEntry(); // save form data to file if( self::isValid() ){ self::saveRecord(); }; self::$isValidated = true; // validation checked } public static function isMySite(){ return false !== stripos( $_SERVER['HTTP_HOST'],'jqueryform.com'); } private static function _validateCreditcardFields($field){ foreach ($field['subfields'] as $name => $f ) { // remove spaces that are created by javascript jquery.payment plugin self::$post[$name] = str_replace(' ', '', self::$post[$name]); self::_validateField( $f ); }; } private static function _validatePaymentField( $field ){ $paymentClasses = array( 'stripe' => '\JF\StripePayment', 'paypal' => '\JF\PaypalPayment', 'braintree' => '\JF\BraintreePayment', ); $method = $field['payments']['method']; $class = $paymentClasses[$method]; $include = __DIR__ . "/{$method}/validate.php"; if( !file_exists($include) ){ return false; }; require_once( $include ); $payment = new $class( $field ); $payment->validate( self::$post ); if( !$payment->isPaid() ){ self::$invalid[] = $field['id']; self::exitError( $payment->getErrMsg() ); }; } private static function _validateAddressField($field){ foreach ($field['subfields'] as $name => $f ) { if( ! $f['field_options']['enabled'] ){ continue; }; $f['id'] = $field['id'] . '_' . $name; self::_validateField( $f ); }; } private static function _validateField($f){ $key = $f['id']; $value = ""; switch ($f['field_type']) { case 'file': $value = self::handleUploadFile($f); break; case 'phone': $value = self::$post[$key]; $value = self::un_quotes( $value ); $dialCode = self::$post[$key . '_phonelib_dialcode']; if( !empty($dialCode) ){ $value = '+' . $dialCode . $value; }; break; default: if( !array_key_exists( $key, self::$post ) ){ self::$values[ $key ] = ''; continue; }; $value = self::$post[$key]; // checkboxes or select-multiple if( is_array($value) ){ $tmp = array(); foreach( $value as $v ){ $tmp[] = self::un_quotes($v); }; $value = join(" | \n", $tmp); // other input/textarea ... }else{ $value = self::un_quotes( $value ); }; break; }; // switch // sanitize input value $value = trim(self::stripTags($value)); if( !empty($f['field_options']['sender']) ){ switch (true){ case ( 'verify_sender' == $f['field_type'] && true == $f['field_options']['sender'] && stripos($value,'@') !== false ) : case ( 'email' == $f['field_type'] && true == $f['field_options']['sender'] ) : $f['field_options']['sender'] = 'email'; break; case ( 'verify_sender' == $f['field_type'] && true == $f['field_options']['sender'] && stripos($value,'@') === false ) : case ( 'phone' == $f['field_type'] && true == $f['field_options']['sender'] ) : $f['field_options']['sender'] = 'phone'; break; }; self::$values[ 'sender.' . $f['field_options']['sender'] ] = $value; }; if( self::isRequired($f) && "" == $value ){ if( empty(self::$serverValidationFields) || (!empty(self::$serverValidationFields) && in_array($key, self::$serverValidationFields)) ){ self::$invalid[] = $key; }; }; self::addColumnValue( $key, $f['label'], $value ); /* self::$columns[] = self::csvfield( $f['label'] ); self::$csvValues[] = self::csvfield( $value ); if( "" == $value ){ $config = self::getConfig(); if( !empty(self::$config['email']['skipEmptyFields']) ){ // skip adding field with empty value to {dataTable} and {dataText} return; }; // if }; // if self::$rows[] = "<tr> <td valign=top style='" . self::$style."font-weight:bold;width:25%;'>" . $f['label'] . " </td> <td valign=top style='" . self::$style.";'>" . nl2br($value) . " </td></tr>" ; self::$sms[] = strip_tags($f['label']) . ":\n" . strip_tags($value); */ } // _validateField // add field or its' sub fields label and value, for saving to csv file, to email, and to sms public static function addColumnValue( $key, $label, $value ){ self::$values[ $key ] = $value; self::$columns[] = self::csvfield( $label ); self::$csvValues[] = self::csvfield( $value ); if( "" == $value ){ $config = self::getConfig(); if( !empty(self::$config['email']['skipEmptyFields']) ){ // skip adding field with empty value to {dataTable} and {dataText} return; }; // if }; // if self::$rows[] = "<tr> <td valign=top style='" . self::$style."font-weight:bold;width:25%;'>" . $label . " </td> <td valign=top style='" . self::$style.";'>" . nl2br($value) . " </td></tr>" ; self::$sms[] = strip_tags($label) . ":\n" . strip_tags($value); } private static function validateReCaptcha( $post, $secretKey, $invisible = false ){ if( self::isMySite() ){ $secretKey = $invisible ? '6LeXoRkUAAAAALn90rgTb0L2vUBtQZH5uC6p_4LA' : '6LdopwYTAAAAAGJ8yZ6xM-dZkyXTj2SYbRtwCOcY' ; }; if( !empty($secretKey) && isset($post['g-recaptcha-response']) ){ $get = 'https://www.google.com/recaptcha/api/siteverify?secret=' . $secretKey. '&response=' . $post['g-recaptcha-response']; $response = file_get_contents( $get ); //echo $get . "\n" . $response; $success = false; if( function_exists('json_decode') ){ $json = json_decode( $response, true ); //var_dump($json); $success = $json['success'] === true; }else{ $success = preg_match( '/success[\"\']*\\:\\s*(true|1|y)/i', $response ); }; return $success; }; return true; // recaptcha is not enabled } // $f : field config private static function reCaptchaInvalidHandler( $f ){ //self::$invalid[] = 'recaptcha'; if( !isset($_SESSION['recaptcha_fail_counter']) ){ $_SESSION['recaptcha_fail_counter'] = 0; }; $_SESSION['recaptcha_fail_counter'] ++; $maxFailed = intval($f['recaptcha']['maxFailed']) >= 0 ? $f['recaptcha']['maxFailed'] : 3; if( $maxFailed > 0 && $_SESSION['recaptcha_fail_counter'] <= $maxFailed ){ $errMsg = empty($f['recaptcha']['errMsg']) ? 'Google reCaptcha validation error. Please try again.' : $f['recaptcha']['errMsg']; self::exitError( $errMsg ); }; } private static function hasField( $type ){ $config = self::getConfig(); foreach( $config['fields'] as $field ){ if( $type == $field['field_type'] ){ return true; }; // if }; // foreach return false; } public static function exitError( $msg ){ $msg = self::replaceTags( $msg, self::$values ); echo $msg; exit; } private static function validateOneEntry(){ if( self::hasEntry() ){ $config = self::getConfig(); $msg = empty($config['admin']['limitActivity']['message']) ? 'Multiple submissions not accepted.' : $config['admin']['limitActivity']['message']; self::exitError( $msg ); }; } private static function hasEntry(){ $config = self::getConfig(); $la = $config['admin']['limitActivity']; if( $la['enabled'] !== true ){ return false; }; $dataFile = self::getFormDataFile(); if( !file_exists($dataFile) ){ return false; }; $found = false ; $query = $la['by'] == 'email' ? self::getSenderEmail() : $_SERVER['REMOTE_ADDR'] ; if( empty($query) ){ return false ; }; $query = '"'. strtolower( $query ) . '"'; $handle = fopen($dataFile,'r'); if (!$handle) { return false; }; while (!feof($handle)) { $entry = strtolower(fgets($handle, 4096)); if( strpos($entry,$query) !== false ){ $found = true ; break; }; }; fclose($handle); return $found ; } private static function presetTags(){ self::setValue( 'AutoID', self::getRecordID() ); self::setValue( 'HTTP_HOST', $_SERVER['HTTP_HOST'] ); self::setValue( 'IP', $_SERVER['REMOTE_ADDR'] ); self::setValue( 'Date', date("Y-m-d") ); self::setValue( 'Time', date("H:i:s") ); self::setValue( 'HTTP_REFERER', $_SERVER['HTTP_REFERER'] ); //self::setValue( 'FormURL', '' ); //self::setValue( 'AdminURL', '' ); // sender.email // sender.firstname // sender.lastname // sender.fullname } private static function un_quotes($str){ return str_replace( array('"', '''), array('"', "'"), $str ); } private static function handleUploadFile($field){ if( !isset($_FILES[ $field['id'] ]) ){ return ''; }; $dir = self::getDataDir(); $files = self::getUploadFileArray($field); $names = array(); // iOS image upload always use same name image.jpeg for all uploads, need to rename it with counter $counter = 1; $isMultiple = count($files) > 1; foreach( $files as $file ){ $prefix = $isMultiple ? $counter . '-' : ''; $fileName = $prefix . $file['name']; if( !is_uploaded_file($file['tmp_name']) ){ continue; }; // is_uploaded $safeName = $prefix . self::renameHarmfulFile($file['name']); $safeName = preg_replace( "/[^0-9a-zA-Z\.]+/", "-", $safeName ); $filePath = $dir . '/' . self::getRecordID() . '-' . $field['id'] . '-' . $safeName ; $ok = @move_uploaded_file( $file['tmp_name'], $filePath ); $link = false; if( $ok ) { $link = self::checkFile2Link( $field, $filePath ); if( !empty($link) ){ self::setValue( $field['id'] . '.name' . $prefix, $fileName ); $fileName = "<a href='{$link}' target='_blank'>{$fileName}</a>"; }; }; // if the file is not a link, then send it as attachment if( empty($link) ){ self::$attachments[] = array('path' => $ok ? $filePath : $file['tmp_name'], 'name' => $fileName ); }; $names[] = $fileName; $counter ++; }; // for each return join(", ",$names); } private static function getUploadFileArray($field){ $upload = $_FILES[ $field['id'] ]; $isMultiple = is_array( $upload['tmp_name'] ); if( !$isMultiple ) { return array( $upload ); }; $names = array(); foreach( $upload as $key => $values ){ for( $i = 0, $n = count($values); $i < $n; $i ++){ $names[$i][$key] = $values[$i]; }; } return $names; } private static function checkFile2Link($field, $filepath){ $kb = $field['field_options']['file']['fileToLinkSize']; if( empty($kb) ){ return false ; }; $filesize = filesize($filepath); if( $filesize >= $kb ){ $link = self::getFileLink( $filepath ); self::setValue( $field['id'] . '.link', $link ); return $link; }; return false; } private static function getFileLink($filepath){ $realpath = self::dir2unix( realpath($filepath) ); $link = self::getAdminUrl() . '?method=downloadAttachment&id=' . urlencode(basename($filepath)); return $link; } public static function dir2unix( $dir ){ return str_replace( array("\\", '//'), '/', $dir ); } // parse full admin url to view large size uploaded file online public static function getAdminUrl(){ $url = 'admin.php'; $http = 'http' . ( empty($_SERVER['HTTPS']) ? '' : 's' ) . '://' ; $http_host = $http . "{$_SERVER['HTTP_HOST']}"; switch( true ){ case (0 === strpos($url, $http )) : $url = $url; break; case ( '/' == substr($url,0,1) ) : $url = $http_host . $url ; break; default: $uri = self::requestUri(); $pos = strrpos( $uri, '/' ); $vdir = substr( $uri, 0, $pos ); $url = $http_host . $vdir . '/' . $url ; }; return $url; } public static function requestUri(){ $uri = getEnv('REQUEST_URI'); // apache has this if( false !== $uri && strlen($uri) > 0 ){ return $uri ; } else { $uri = ($uri = getEnv('SCRIPT_NAME')) !== false ? $uri : getEnv('PATH_INFO') ; $qs = getEnv('QUERY_STRING'); // IIS and Apache has this return $uri . ( empty($qs) ? '' : '?' . $qs ); }; return "" ; } public static function getAttachments(){ return self::$attachments; } public static function isValid(){ return empty(self::$invalid); } public static function isValidated(){ return self::$isValidated; } public static function getInvalidFields(){ return self::$invalid; } public static function getValue( $id ){ return array_key_exists( $id, self::$values ) ? self::$values[$id] : ''; } public static function getAdminUsers(){ $config = self::getConfig(); $default = array(); $admin = empty($config['admin']['users']) ? $default : $config['admin']; $users = array(); $parts = explode(',', $admin['users']); foreach( $parts as $part ){ $pos = strpos( $part, ':' ); if( false === $pos ){ continue; }; $user = trim(substr($part,0,$pos)); $pass = trim(substr($part,$pos+1)); $users[$user] = array('user' => $user, 'password' => $pass); }; return $users; } // avoid email header injection by removing line breaks for email headers private static function removeLineBreaks( $str ){ return trim(preg_replace('/[\r\n]+/', '', $str)); } // Email for mail header public static function getFromEmail( $forAutoResponse = false ){ $email = self::getSenderEmail(); if( $forAutoResponse || empty($email) ){ $email = self::$config['email']['to']; }; $sendmail_from = self::$config['email']['sendmail_from']; if( !empty($sendmail_from) ){ ini_set("sendmail_from", $sendmail_from); $email = $sendmail_from; }; return self::removeLineBreaks( $email ); } // Name for mail header public static function getFromName( $forAutoResponse = false ){ if( $forAutoResponse ){ $fromName = self::$config['email']['fromName']; return self::removeLineBreaks( self::renderContent($fromName) ); }; $fromName = self::getSenderName(); return self::removeLineBreaks( self::renderContent( $fromName ) ); } public static function getSenderEmail(){ $email = self::getValue('sender.email'); return self::removeLineBreaks( $email ); } public static function getFormOwnerPhone(){ $config = self::getConfig(); $phone = trim(self::$config['twilio']['toPhone']); return $phone; } public static function getSenderPhone(){ $phone = self::getValue('sender.phone'); return $phone; } public static function getSenderName(){ $fullname = self::getValue('sender.fullname'); $name = !empty($fullname) ? $fullname : trim(self::getValue('sender.firstname') . ' ' . self::getValue('sender.lastname')) ; return $name; } public static function getToEmail(){ self::getConfig(); return self::removeLineBreaks( self::renderContent(self::$config['email']['to']) ); } public static function getReplyToEmail(){ self::getConfig(); return self::removeLineBreaks( self::$config['autoResponse']['replyTo'] ); } public static function getReplyToName(){ self::getConfig(); return self::removeLineBreaks( self::renderContent( self::$config['autoResponse']['replyToName'] ) ); } public static function getId(){ return 'test-form-id'; } public static function getDataDelivery(){ $config = self::getConfig(); return self::$config['admin']['dataDelivery']; } public static function getValues(){ return self::$values; } public static function getMailSubject(){ return self::removeLineBreaks( self::renderContent( self::$config['email']['subject'] ) ); } public static function getMailBody(){ return self::getHtmlHeader() . self::renderContent( self::mailTemplate() ) . self::getHtmlFooter(); } public static function getAutoResponseMailSubject(){ return self::removeLineBreaks( self::renderContent( self::$config['autoResponse']['subject'] ) ); } public static function getAutoResponseMailBody(){ $body = self::autoResponseTemplate(); return empty($body) ? "" : self::getHtmlHeader() . self::renderContent( $body ) . self::getHtmlFooter(); } public static function setValue( $key, $value ){ self::$values[$key] = $value ; } public static function replaceTags( $content, $tags, $start='{', $end='}' ){ $attrs = array(); foreach ($tags as $tag => $value) { $attrs[$start.$tag.$end] = $value; }; $names = array_keys($attrs); $values = array_values($attrs); return str_replace( $names, $values, $content ); } public static function renderContent( $content ){ $content = self::replaceTags( $content, self::$values ); $content = preg_replace_callback( '/\\\u[a-zA-Z0-9]{4}/', array('Form', 'utf8codeToChar'), $content ); return $content; } public static function utf8codeToChar( $code ){ $json = json_decode( "\"{$code}\"" ); return $json ? $json : $code; } private static function getHtmlHeader(){ ob_start(); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <?php $output = ob_get_contents(); ob_end_clean(); return $output; } private static function getHtmlFooter(){ ob_start(); ?> </body> </html> <?php $output = ob_get_contents(); ob_end_clean(); return $output; } private static function mailTemplate(){ $default = "{dataTable}"; $config = self::getConfig(); $template = nl2br( trim(self::$config['email']['template']) ); return empty($template) ? $default : $template; } private static function autoResponseTemplate(){ $config = self::getConfig(); $template = nl2br( trim(self::$config['autoResponse']['template']) ); return $template; } private static function smsTemplate(){ $default = "{dataText}"; $config = self::getConfig(); $template = trim(self::$config['twilio']['toTemplate']); return empty($template) ? $default : $template; } private static function smsAutoResponseTemplate(){ $config = self::getConfig(); $template = trim(self::$config['twilio']['autoResponseTemplate']); return $template; } public static function getSmsBody(){ return self::renderContent( self::smsTemplate() ); } public static function getAutoResponseSmsBody(){ return self::renderContent( self::smsAutoResponseTemplate() ); } public static function getDataDir(){ $dir = dirname( self::getFormDataFile() ); if( !is_dir($dir) ){ @mkdir( $dir ); }; return $dir; } public static function canSaveData(){ // admin trun on save data for debug purpose during this browser session if( self::canSaveDataSession() ){ return true; } $method = self::getDataDelivery(); if( 'emailOnly' == $method ){ return false; }; $config = self::getConfig(); switch( self::$config['gdpr']['saveData'] ){ case 'always': return true; case 'consent': $fid = self::$config['gdpr']['consentFieldId']; $value = self::getValue( $fid ); $yes = preg_match( "/^(yes|true|agree|1)\$/i", trim($value) ); return $yes; default: case 'no': return false; } return false; } public static function canSaveDataSession(){ return isset($_SESSION['canSaveData']) ? $_SESSION['canSaveData'] : false; } private static function saveRecord(){ if( !self::canSaveData() ){ return; }; if( class_exists('\JF\Form2DB') ){ $form2db = new \JF\Form2DB(); $form2db->saveFormData( self::$values ); } // if there are any real data rather then only 3 columns: ID, Date, and IP if( count(self::$csvValues) <= 3 ){ return; }; $sep = chr(0x09); $recordCols = self::data2record( join($sep, self::$columns) ) . PHP_EOL; $record = self::data2record( join($sep, self::$csvValues) ) . PHP_EOL; self::getDataDir(); $dataFile = self::getFormDataFile(); if( !file_exists($dataFile) ){ self::secureFile( $dataFile ); file_put_contents($dataFile, $recordCols, FILE_APPEND ); }; file_put_contents($dataFile, $record, FILE_APPEND ); } public static function secureFile( $file ){ self::getDataDir(); if( !file_exists($file) ){ file_put_contents($file, "<?php exit(); /* For security reason. To avoid public user downloading below data! */?>" . PHP_EOL); }; } private static function getRecordID(){ if( !isset($GLOBALS['RecordID']) ){ $GLOBALS['RecordID'] = date("Ymd") . '-'. substr( md5(uniqid(rand(), true)), 0,4 ); }; return $GLOBALS['RecordID']; } private static function data2record( $s, $b=true ){ $from = array( "\r", "\n"); $to = array( "\\r", "\\n" ); return $b ? str_replace( $from, $to, $s ) : str_replace( $to, $from, $s ) ; } private static function csvfield( $str ){ $str = str_replace( '"', '""', $str ); return '"' . trim($str) . '"'; } private static function isRequired($field){ return true === $field['field_options']['validators']['required']['enabled']; } private static function renameHarmfulFile( $name ){ $ext = strrchr(strtolower($name), '.'); if( $ext !== false ){ $n = strpos( strtolower(self::$harmfulExts), $ext ); if( $n !== false ){ return $name . '.bak' ; }; }; return $name; } private static function stripTags( $str ){ return strip_tags( $str, self::$allowable_tags ); } private static $config; private static $post; private static $values; private static $invalid; private static $isValidated = false; private static $attachments; private static $dataDir = './data/'; // folder that stores form data file, email traffic log, and upload files private static $columns; private static $csvValues; private static $serverValidationFields; private static $style; private static $rows; private static $sms; private static $allowable_tags = "<a><b><blockquote><br><del><div><em><h1><h2><h3><h4><h5><h6><hr><i><img><label><li><ol><p><pre><small><span><strong><style><sub><sup><table><tbody><td><tfoot><th><thead><title><tr><u><ul>"; private static $harmfulExts = ".php, .php2, .php3, .php4, .php5, .php6, .php7, .html, .css, .js, .exe, .com, .bat, .vb, .vbs, scr, .inf, .reg, .lnk, .pif, .ade, .adp, .app, .bas, .chm, .cmd, .cpl, .crt, .csh, .fxp, .hlp, .hta, .ins, .isp, .jse, .ksh, .Lnk, .mda, .mdb, .mde, .mdt, .mdw, .mdz, .msc, .msi, .msp, .mst, .ops, .pcd, .prf, .prg, .pst, .scf, .scr, .sct, .shb, .shs, .url, .vbe, .wsc, .wsf, .wsh"; public static function getConfig( $decode = true ){ self::$config = Config::getConfig($decode); self::overwriteConfig( $decode ); return self::$config; } private static function overwriteConfig( $decode = true ){ if( !$decode ){ return; }; $file = __DIR__.'/myconfig.php'; if( !file_exists($file) ){ return; }; $config = include($file); if( !is_array($config) ){ return; }; foreach( $config as $sectionName => $var ){ if( is_array($var) ){ foreach( $var as $key => $val ){ if( !empty($val) ){ self::$config[$sectionName][$key] = $config[$sectionName][$key]; }; };// }else{ if( !empty($var) ){ self::$config[$sectionName] = $config[$sectionName]; }; }; // if }; // foreac } // overwriteConfig }// end of Form class // -------------------------------------------------------------- // -------------------------------------------------------------- class Mailer { private $config; private $mailer = 'local'; private $logs = array(); public $From; public $FromName; public $TO; public $Subject; public $Body; public $CC; public $BCC; public $ReplyTo; public $ReplyToName; private $isSent = false; private $sendError = ''; private $sentMIMEMessage = ''; private $includeAttachments = true; function __construct(){ $this->config = Form::getConfig(); } public function Send(){ $this->mailer = empty($this->config['mailer']) ? 'local' : $this->config['mailer']; switch ( $this->mailer ) { case 'local': case 'smtp': $this->SendByPHPMailer(); break; case 'mailgun': if ( function_exists('curl_init') ){ $this->SendByMailGun(); } else { $this->addLog( "CURL module is not avaiable. Can't use mailgun mailer, use normal sendmail mailer."); $this->SendByPHPMailer(); }; break; default: break; }; // switch $this->saveLogs(); } public function mail( $to , $subject , $message, $from = '', $fromName = '' ){ $this->TO = $to; $this->From = $from; $this->FromName = $fromName; $this->Subject = $subject; $this->Body = $message; return $this->Send(); } public function setIncludeAttachments( $yes ){ $this->includeAttachments = $yes; } public function validateForm( $post = array() ){ if( !Form::isValidated() ){ Form::validate($post); }; $this->From = Form::getFromEmail(); $this->FromName = Form::getFromName(); $this->Subject = Form::getMailSubject(); $this->Body = Form::getMailBody(); $email = $this->config['email']; $this->TO = Form::getToEmail(); $this->CC = empty($email['cc']) ? '' : $email['cc']; $this->BCC = empty($email['bcc']) ? '' : $email['bcc']; } private function SendByPHPMailer(){ $email = $this->config['email']; $mailer = new \PHPMailer(); $mailer->From = $this->From; $mailer->FromName = $this->FromName; $mailer->Subject = $this->Subject; $mailer->Body = $this->Body; $mailer->CharSet = 'UTF-8'; $mailer->msgHTML($mailer->Body); $mailer->IsHtml(true); $mailer->AddAddress($this->TO); if( empty($this->ReplyTo) ){ $senderEmail = Form::getSenderEmail(); $this->ReplyTo = empty($senderEmail) ? $this->From : $senderEmail; $this->ReplyToName = $this->FromName; }; $mailer->AddReplyTo($this->ReplyTo, $this->ReplyToName); if( !empty($this->CC) ){ $CCs = explode(',',$this->CC ); foreach($CCs as $c){ $mailer->AddCC( $c ); }; }; if( !empty($this->BCC) ){ $BCCs = explode(',',$this->BCC); foreach($BCCs as $b){ $mailer->AddBCC( $b ); }; }; $attachments = Form::getAttachments(); //$this->addLog($attachments); if( $this->includeAttachments && is_array($attachments) ){ foreach($attachments as $f){ $mailer->AddAttachment( $f['path'], basename($f['name']) ); }; }; $smtp = $this->config['smtp']; $isSMTP = $this->mailer == 'smtp' && !empty($smtp); if( $isSMTP ){ $mailer->IsSMTP(); $mailer->Host = $smtp['host']; $mailer->Username = $smtp['user']; $mailer->Password = $smtp['password']; $mailer->SMTPAuth = !empty($mailer->Password); $mailer->SMTPSecure = $smtp['security']; $mailer->Port = empty($smtp['port']) ? 25 : $smtp['port']; $mailer->SMTPDebug = empty($smtp['debug']) ? 0 : 2; }; if( $isSMTP && $mailer->SMTPDebug > 0 ){ ob_start(); }; $this->isSent = $mailer->Send(); if( $isSMTP && $mailer->SMTPDebug > 0 ){ $debug = ob_get_contents(); ob_end_clean(); $this->addLog($debug); }; if( !$sent ){ $this->sendError = $mailer->ErrorInfo; }; $this->sentMIMEMessage = $mailer->getSentMIMEMessage(); return $this->isSent; } private function SendByMailGun(){ $mg = $this->config['mailgun']; $api_key= $mg['apiKey']; /* Api Key got from https://mailgun.com/cp/my_account */ $domain = $mg['domain']; /* Domain Name you given to Mailgun*/ if( empty($this->ReplyTo) ){ $this->ReplyTo = $this->From; $this->ReplyToName = $this->FromName; }; $ch = curl_init(); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, "api:".$api_key); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($ch, CURLOPT_URL, "https://api.mailgun.net/v3/".$domain."/messages"); $fields = array( "from" => ( empty($this->FromName) ? $mg['fromName'] : $this->FromName ) . " <" . $mg['fromEmail'] . ">", "to" => $this->TO, "subject" => $this->Subject, "h:Reply-To" => $this->ReplyToName . " <" . $this->ReplyTo . ">", "html" => $this->Body ); // php 5.5+ if( class_exists("\\CURLFile") ){ // process inline images $result = $this->extractEmbededImages( $this->Body ); if( !empty($result['imgFiles']) ){ $fields['html'] = $result['message']; $inlines = $this->mailgunAddFiles( $result['imgFiles'], 'inline' ); $fields = array_merge( $fields, $inlines ); }; // process normal attachments if( $this->includeAttachments ){ $attachments = Form::getAttachments(); $fields = array_merge( $fields, $this->mailgunAddFiles($attachments,'attachment') ); } }; if( !empty($this->CC) ){ $fields['cc'] = $this->CC; }; if( !empty($this->BCC) ){ $fields['bcc'] = $this->BCC; }; curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); $result = curl_exec($ch); $this->isSent = $result ? true : false; $this->sentMIMEMessage = "CURL paramenters:\n" . var_export($fields,true) . "\n" . var_export($result,true); if( !$this->isSent ){ $this->sendError = curl_error($ch); } curl_close($ch); return $this->isSent; } private function mailgunAddFiles( $files, $type = 'attachment' ){ $fields = array(); if( is_array($files) ){ $n = count($files); for( $i = 0; $i < $n; $i ++ ) { $f = $files[$i]; //$key = "attachment" . ( $i == 0 ? '' : "[{$i}]" ); $key = $type . ( $i == 0 ? '' : "[{$i}]" ); $fields[$key] = new \CURLFile($f['path'], null, basename($f['name']) ); }; }; return $fields; } // for mailgun inline images, ported from phpmailer private function extractEmbededImages($message) { $imgFiles = array(); preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images); if (isset($images[2])) { $dir = Form::getDataDir(); foreach ($images[2] as $imgindex => $url) { // Convert data URIs into embedded images if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) { $data = substr($url, strpos($url, ',')); if ($match[2]) { $data = base64_decode($data); } else { $data = rawurldecode($data); }; $type = basename($match[1]); $id = md5(uniqid(rand(), true)); $file = $dir . '/' . $id . '.' . $type; $ok = file_put_contents($file, $data); //$cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2 //$cid = md5( $file ) . '@mailgun.0'; // RFC2392 S 2 $cid = basename($file); $imgFiles[] = array( 'path' => $file, 'name' => $cid ); $message = str_replace( $images[0][$imgindex], $images[1][$imgindex] . '="cid:' . $cid . '"', $message ); } // if } // foreach }; // if return array( 'imgFiles' => $imgFiles, 'message' => $message ); } private function saveLogs(){ if( !Form::canSaveData() ){ return; } $line = str_repeat('--------', 8); $this->addLog( "\n\n" . $line ); $this->addLog( date("Y-m-d H:i:s") ); $this->addLog( "Email Sent: " . ( $this->isSent ? 'OK' : 'Failed (' . $this->sendError . ')' ) ); $this->addLog($this->sentMIMEMessage); $this->addLog( $line . "\n\n" ); $logFile = Form::getEmailLogFile(); Form::secureFile( $logFile ); file_put_contents($logFile, join("\n", $this->logs), FILE_APPEND); $this->logs = array(); // clear } private function addLog($msg){ $this->logs[] = is_string($msg) ? $msg : var_export($msg,true); } } // end of class Mailer // -------------------------------------------------------------- class Twilio { private $logs = array(); public function sendSms(){ if( !self::smsEnabled() ){ return; }; $this->addLog( "Sending text message to form owner's phone...\n\n" ); $this->sendSmsToFormOwner(); $this->addLog( "\n\nSending auto-response text message to form sender's phone...\n\n" ); $this->sendSmsToFormSender(); $this->saveLogs(); } public static function smsEnabled(){ $config = Form::getConfig(); $twilio = $config['twilio']; $accountSid = $twilio['accountSid']; $authToken = $twilio['authToken']; $phone = $twilio['phoneNumber']; // twilio verified number return !empty($accountSid) && !empty($authToken) && !empty($phone); } private function sendSmsToFormOwner(){ $phone = Form::getFormOwnerPhone(); $message = Form::getSmsBody(); return $this->sendMessage( $phone, $message ); } private function sendSmsToFormSender(){ $phone = Form::getSenderPhone(); $message = Form::getAutoResponseSmsBody(); return $this->sendMessage( $phone, $message ); } public function sendMessage( $toPhone, $message ){ if( empty($toPhone) || empty($message) ){ $this->addLog( "Phone: $toPhone\nMessage:$message\nEmpty phone or message, no text message to be sent.\n" ); return false; }; $config = Form::getConfig(); $twilio = $config['twilio']; $accountSid = $twilio['accountSid']; $authToken = $twilio['authToken']; $url = "https://api.twilio.com/2010-04-01/Accounts/$accountSid/Messages"; $from = $twilio['phoneNumber']; // twilio verified number $data = array ( 'From' => $from, 'To' => $toPhone, 'Body' => $message, ); $post = http_build_query($data); $ch = curl_init($url ); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, "$accountSid:$authToken"); curl_setopt($ch, CURLOPT_POSTFIELDS, $post); $result = curl_exec($ch); curl_close($ch); $this->isSmsSent = $result ? true : false; $this->addLog( "twilioSendMessage paramenters:\n" . var_export($data,true) . "\nSend result:\n" . var_export($result,true) ); $this->saveLogs(); return $result; } private function saveLogs(){ if( !Form::canSaveData() ){ return; } $line = str_repeat('--------', 8); $str = "\n\n" . $line . "\n" . date("Y-m-d H:i:s"). "\n" . $line . "\n\n"; $logFile = Form::getSmsLogFile(); Form::secureFile( $logFile ); file_put_contents($logFile, $str . join("\n", $this->logs), FILE_APPEND); $this->logs = array(); // clear } private function addLog($msg){ $this->logs[] = is_string($msg) ? $msg : var_export($msg,true); } } # end of class Twilio class VerifcationCode { public static function send(){ Form::getConfig(); $vsSendTo = $_REQUEST['vsSendTo']; $code = self::generate( true ); if( empty($vsSendTo) || empty($code) ){ return; }; if( stripos( $vsSendTo, '@' ) !== false ){ self::sendByEmail( $vsSendTo, $code ); }else{ $vsSendTo = preg_replace( '/[^0-9]/', '', $vsSendTo ); self::sendBySms( $vsSendTo, $code ); }; echo "Sent verification code to " . $vsSendTo; // . ", code: " . $code; } public static function verify(){ $userInputCode = $_REQUEST['vsCode']; $vcode = self::generate( false ); if( empty($userInputCode) || empty($vcode) ){ return; }; $ok = $userInputCode == $vcode; echo ($ok ? "OK: code verified!" : "code failed to verify"); // .": .... session code = " . $vcode . ", userInput= " . $userInputCode; if( $ok ) self::generate( true ); // destory verified code } private static function sendByEmail( $to, $code ){ $field = self::getVerifySenderFieldConfig(); $from = Form::getFromEmail(false); $fromName = Form::getFromName(false); $subject = Form::replaceTags( $field['field_options']['mailSuject'], array('code' => $code) ); $message = nl2br(Form::replaceTags( $field['field_options']['mailTemplate'], array('code' => $code) )); $mailer = new Mailer(); $ok = $mailer->mail( $to , $subject, $message, $from , $fromName ); return $ok; } private static function sendBySms( $to, $code ){ $field = self::getVerifySenderFieldConfig(); if( !$field['field_options']['smsEnabled'] ){ return false; }; $phone = preg_replace( '/[^0-9]/', '', $to ); $message = Form::replaceTags( $field['field_options']['smsTemplate'], array('code' => $code) ); $sms = new Twilio(); $ok = $sms->sendMessage( $phone, $message ); return $ok; } private static function generate( $new = false ){ if( $new || empty($_SESSION['verification_code']) ){ $_SESSION['verification_code'] = rand(1000, 9999); $_SESSION['verification_code_created'] = time(); }; return $_SESSION['verification_code']; } private static function getVerifySenderFieldConfig(){ $config = Form::getConfig(); foreach( $config['fields'] as $f ){ if( 'verify_sender' == $f['field_type'] ){ return $f; }; }; return false; } } # end of class VerifcationCode class PaymentBase{ protected $config; protected $isPaid; protected $errmsg; function __construct( $paymentFieldConfig ) { $this->config = $paymentFieldConfig; } // $data is $_POST public function validate( $data ){ return false; } public function getAmount( $data ){ $payment = $this->config['payment']; $amount = $payment['amount']; $userAmount = 0; if( $payment['changeable'] ){ $userAmount = $data['payment_amount']; }; $amount = abs( empty($userAmount) ? $amount : $userAmount ); return $amount; } public function isPaid(){ return $this->isPaid; } public function getErrMsg(){ return $this->errmsg; } public function log( $s ){ $line = str_repeat('--------', 8); $str = "\n\n" . $line . "\n" . date("Y-m-d H:i:s"). "\n" . $line . "\n\n"; $logFile = Form::getDataDir() . '/payment-log.php'; Form::secureFile( $logFile ); $log = is_string($s) ? $s : var_export( $s, true ); file_put_contents($logFile, $str . $log, FILE_APPEND); } } # end of class PaymentBase