<?php /** * @package RSForm! Pro * @copyright (C) 2007-2019 www.rsjoomla.com * @license GPL, http://www.gnu.org/copyleft/gpl.html */ defined('_JEXEC') or die; use Joomla\CMS\Table\Table; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\File; use Joomla\CMS\Language\Text; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Editor\Editor; use Joomla\CMS\Uri\Uri; use Joomla\CMS\Router\Route; use Joomla\Registry\Registry; use Joomla\Utilities\IpHelper; use Joomla\CMS\Session\Session; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\User\UserHelper; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Log\Log; use Joomla\CMS\Mail\MailHelper; use Joomla\Database\DatabaseDriver; use Joomla\CMS\Http\HttpFactory; use Joomla\CMS\Access\Access; use Joomla\CMS\Form\FormHelper; use Joomla\CMS\Form\Form; require_once __DIR__.'/constants.php'; require_once __DIR__.'/config.php'; require_once __DIR__.'/version.php'; require_once __DIR__.'/assets.php'; Table::addIncludePath(JPATH_ADMINISTRATOR.'/components/com_rsform/tables'); // Let's run some workarounds // Disable caching for the current view (eg. com_content with Content Plugin) $cache = Factory::getCache(Factory::getApplication()->input->getCmd('option'), 'view'); $cache->setCaching(false); // Disable caching for the current component $cache = Factory::getCache(Factory::getApplication()->input->getCmd('option')); $cache->setCaching(false); $lang = Factory::getLanguage(); Factory::getLanguage()->load('com_rsform', JPATH_ADMINISTRATOR); class RSFormProHelper { public static $captchaFields = array( RSFORM_FIELD_CAPTCHA, RSFORM_FIELD_HASHCASH, ); public static $formShown; public static function getDate($date) { static $mask; if (!$mask) { $mask = RSFormProHelper::getConfig('global.date_mask'); if (!$mask) { $mask = 'Y-m-d H:i:s'; } } if ($date === null || $date === '0000-00-00 00:00:00' || $date === Factory::getDbo()->getNullDate()) { return ''; } return HTMLHelper::_('date', $date, $mask); } public static function getTooltipText($title, $content='') { return HTMLHelper::_('tooltipText', $title, $content, 0, 0); } public static function getTooltipClass() { static $class = false; if (!$class) { $class = 'hasTooltip'; HTMLHelper::_('bootstrap.tooltip', '.' . $class); } return $class; } public static function showEditor($name, $html, $options = array()) { if (!isset($options['syntax'])) { $options['syntax'] = 'html'; } if (!isset($options['readonly'])) { $options['readonly'] = false; } if (!isset($options['id'])) { $options['id'] = null; } $use_editor = RSFormProHelper::getConfig('global.codemirror'); $editor = 'codemirror'; if ($use_editor) { $plugin = PluginHelper::getPlugin('editors', $editor); if (empty($plugin)) { $use_editor = false; } else { if (!is_string($plugin->params) && is_callable(array($plugin->params, 'toString'))) { $plugin->params = $plugin->params->toString(); } } } if ($use_editor) { $instance = Editor::getInstance($editor); $html = $instance->display($name, static::htmlEscape($html), '100%', 300, 75, 20, $buttons = false, $options['id'], $asset = null, $author = null, array('syntax' => $options['syntax'], 'readonly' => $options['readonly'])); } else { if (empty($options['id'])) { $options['id'] = $name; } $readonly = ''; if (!empty($options['readonly'])) { $readonly = 'readonly'; } $html = '<textarea class="' . $options['classes'] . '" ' . $readonly . ' rows="20" cols="75" name="' . static::htmlEscape($name) . '" id="' . static::htmlEscape($options['id']) . '">' . static::htmlEscape($html) . '</textarea>'; } return $html; } public static function getComponentId($name, $formId=0) { static $cache = array(); if (empty($formId)) { $formId = Factory::getApplication()->input->getInt('formId'); if (empty($formId)) { $post = Factory::getApplication()->input->get('form', array(),'array'); $formId = isset($post['formId']) ? $post['formId'] : 0; } } if (!isset($cache[$formId][$name])) $cache[$formId][$name] = RSFormProHelper::componentNameExists($name, $formId, 0, 'ComponentId'); return $cache[$formId][$name]; } public static function getComponentTypeId($name, $formId=0) { static $cache = array(); if (empty($formId)) { $formId = Factory::getApplication()->input->getInt('formId'); if (empty($formId)) { $post = Factory::getApplication()->input->get('form', array(),'array'); $formId = isset($post['formId']) ? $post['formId'] : 0; } } if (!isset($cache[$formId][$name])) { $cache[$formId][$name] = RSFormProHelper::componentNameExists($name, $formId, 0, 'ComponentTypeId'); } return $cache[$formId][$name]; } public static function createList($results, $value = 'value', $text = 'text') { $list = array(); if (is_array($results)) { foreach ($results as $result) { if (is_object($result)) { $list[] = $result->{$value} . '|' . $result->{$text}; } elseif (is_array($result)) { $list[] = $result[$value] . '|' . $result[$text]; } } } return implode("\n", $list); } public static function displayForm($formId, $is_module=false) { static::$formShown = true; $mainframe = Factory::getApplication(); $doc = Factory::getDocument(); $session = Factory::getSession(); $form = RSFormProHelper::getForm($formId); if (empty($form) || !$form->Published) { if ($is_module) { $mainframe->enqueueMessage(Text::sprintf('RSFP_FORM_DOES_NOT_EXIST', $formId), 'warning'); return false; } else { throw new Exception(Text::sprintf('RSFP_FORM_DOES_NOT_EXIST', $formId), 404); } } // Check form access level if (!$is_module && $form->Access != '') { $canView = false; // Forms shown in the backend are accessible if ($mainframe->isClient('administrator')) { $canView = true; } else { // If we have a menu item, inherit access from that. if ($active = $mainframe->getMenu()->getActive()) { if ($query = $active->query) { if (isset($query['option']) && isset($query['view']) && isset($query['formId'])) { if ($query['option'] == 'com_rsform' && $query['view'] == 'rsform' && $query['formId'] == $formId) { $canView = true; } } } } } if (!$canView) { $user = Factory::getUser(); if (!in_array($form->Access,$user->getAuthorisedViewLevels())) { // Error, the form cannot be accessed $mainframe->enqueueMessage(Text::sprintf('RSFP_FORM_CANNOT_BE_ACCESSED', $formId), 'warning'); $mainframe->redirect(Uri::root()); return false; } } } $lang = RSFormProHelper::getCurrentLanguage($formId); $translations = RSFormProHelper::getTranslations('forms', $formId, $lang); if ($translations) { foreach ($translations as $field => $value) { if (isset($form->{$field})) $form->{$field} = $value; } } if (!$is_module) { if ($form->MetaDesc) { $doc->setMetaData('description', $form->MetaDesc); } if ($form->MetaKeywords) { $doc->setMetaData('keywords', $form->MetaKeywords); } if ($form->MetaTitle) { $doc->setTitle($form->FormTitle); } } $formparams = $session->get('com_rsform.formparams.formId'.$formId); // Form has been processed ? if ($formparams && !empty($formparams->formProcessed)) { // Must show Thank You Message if ($form->ShowThankyou) { return RSFormProHelper::showThankYouMessage($formId); } // Clear $session->clear('com_rsform.formparams.formId'.$formId); // Must show small message if ($formparams->showSystemMessage) { $mainframe->enqueueMessage(Text::_('RSFP_THANKYOU_SMALL')); } if ($form->ScrollToThankYou) { // scroll the window to the Thank You Message RSFormProAssets::addScriptDeclaration("RSFormProUtils.addEvent(window, 'load', function(){ RSFormPro.scrollToElement(document.getElementById('system-message-container')); });"); } } // Check if the configured limit of submissions has been reached if (!empty($form->LimitSubmissions)) { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('COUNT(*)') ->from($db->qn('#__rsform_submissions')) ->where($db->qn('FormId') . ' = ' . $db->q($formId)); $limit = $db->setQuery($query)->loadResult(); if ($limit >= $form->LimitSubmissions) { return Text::_('COM_RSFORM_LIMIT_SUBMISSIONS_HAS_BEEN_REACHED'); } } if ($form->DisableSubmitButton) { RSFormProAssets::addScriptDeclaration("RSFormProUtils.addEvent(window, 'load', function(){ RSFormPro.setDisabledSubmit('{$formId}', " . ($form->AjaxValidation ? 'true' : 'false') . "); });"); } // Must process form $post = $mainframe->input->post->get('form', array(), 'array'); if (isset($post['formId']) && $post['formId'] == $formId) { $invalid = RSFormProHelper::processForm($formId); // Did not pass validation - show the form if ($invalid) { if ($form->ScrollToError) { RSFormProAssets::addScriptDeclaration("RSFormProUtils.addEvent(window, 'load', function(){ RSFormPro.gotoErrorElement({$formId}); });"); } // We call this again because the array might have been modified by processForm() $post = $mainframe->input->post->get('form', array(), 'array'); return RSFormProHelper::showForm($formId, $post, $invalid); } } // Default - show the form $get = $mainframe->input->get->get('form', array(), 'array'); return RSFormProHelper::showForm($formId, $get); } public static function getEditor() { static $editor; // Get the editor configuration setting if (is_null($editor)) { $editor = Factory::getApplication()->get('editor'); } return Editor::getInstance($editor); } public static function WYSIWYG($name, $content, $hiddenField, $width, $height, $col, $row) { $editor = RSFormProHelper::getEditor(); $params = array('relative_urls' => '0', 'cleanup_save' => '0', 'cleanup_startup' => '0', 'cleanup_entities' => '0'); $id = trim(substr($name, 4), ']['); $content = $editor->display($name, $content , $width, $height, $col, $row, true, $id, null, null, $params); return $content; } public static function getOtherCalendars($type = RSFORM_FIELD_CALENDAR) { $list = array(); $formId = Factory::getApplication()->input->getInt('formId'); $componentId = Factory::getApplication()->input->getInt('componentId'); $list[] = array( 'value' => '', 'text' => 'NO_DATE_MODIFIER' ); if ($calendars = self::componentExists($formId, $type)) { // remove our current calendar from the list if ($componentId) { $pos = array_search($componentId, $calendars); if ($pos !== false) { unset($calendars[$pos]); } } // any calendars left? if ($calendars) { $all_data = self::getComponentProperties($calendars); foreach ($calendars as $calendar) { $data =& $all_data[$calendar]; $list[] = array( 'value' => 'min '.$calendar, 'text' => Text::sprintf('RSFP_CALENDAR_SETS_MINDATE', $data['NAME']) ); $list[] = array( 'value' => 'max '.$calendar, 'text' => Text::sprintf('RSFP_CALENDAR_SETS_MAXDATE', $data['NAME']) ); } } } return self::createList($list); } public static function getValidationClass() { if (file_exists(JPATH_SITE.'/components/com_rsform/helpers/customvalidation.php')) { require_once JPATH_SITE.'/components/com_rsform/helpers/customvalidation.php'; return 'RSFormProCustomValidations'; } else { require_once JPATH_SITE.'/components/com_rsform/helpers/validation.php'; return 'RSFormProValidations'; } } public static function getValidationRules($asArray = false, $removeMultiple = false) { $results = get_class_methods(static::getValidationClass()); // Add 'none' as first validation rule unset($results[array_search('none', $results)]); array_unshift($results, 'none'); // remove the multiple validation because the multiple rules has already been selected, also the none validation is not necessary // $removeMultiple can also be an array of rules to remove if ($removeMultiple) { if (!is_array($removeMultiple)) { $removeMultiple = array('multiplerules', 'none'); } foreach ($removeMultiple as $validationRule) { $pos = array_search($validationRule, $results); if ($pos !== false) { unset($results[$pos]); } } } if ($asArray) { return $results; } else { // Let's sort usort($results, array('RSFormProHelper', 'sortValidations')); return implode("\n", $results); } } public static function sortValidations($a, $b) { if ($a !== $b) { if ($a === 'none') { return -1; } if ($b === 'none') { return 1; } } $lang = Factory::getLanguage(); if ($lang->hasKey('RSFP_COMP_FVALUE_' . $a)) { $a = Text::_('RSFP_COMP_FVALUE_' . $a); } if ($lang->hasKey('RSFP_COMP_FVALUE_' . $b)) { $b = Text::_('RSFP_COMP_FVALUE_' . $b); } return strcmp($a, $b); } public static function getDateValidationClass() { if (file_exists(JPATH_SITE.'/components/com_rsform/helpers/customdatevalidation.php')) { require_once JPATH_SITE.'/components/com_rsform/helpers/customdatevalidation.php'; return 'RSFormProCustomDateValidations'; } else { require_once JPATH_SITE.'/components/com_rsform/helpers/datevalidation.php'; return 'RSFormProDateValidations'; } } public static function getDateValidationRules($asArray = false) { $results = get_class_methods(static::getDateValidationClass()); // Add 'none' as first validation rule unset($results[array_search('none', $results)]); array_unshift($results, 'none'); if ($asArray) { return $results; } else { return implode("\n", $results); } } public static function getEmailAttachOptions() { $formId = Factory::getApplication()->input->getInt('formId'); $db = Factory::getDbo(); $options = array( 'useremail', 'adminemail' ); $query = $db->getQuery(true) ->select($db->qn('id')) ->select($db->qn('subject')) ->from($db->qn('#__rsform_emails')) ->where($db->qn('type') . ' = ' . $db->q('additional')) ->where($db->qn('formId') . ' = ' . $db->q($formId)); if ($emails = $db->setQuery($query)->loadObjectList()) { foreach ($emails as $email) { $options[] = $email->id . '|' . $email->subject; } } return implode("\n", $options); } public static function readConfig($force = false) { $config = RSFormProConfig::getInstance(); if ($force) { $config->reload(); } return $config->getData(); } public static function getConfig($name = null) { $config = RSFormProConfig::getInstance(); if ($name === null) { return $config->getData(); } return $config->get($name); } public static function componentNameExists($componentName, $formId, $currentComponentId = 0, $column = 'ComponentId') { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select($db->qn('c.' . $column)) ->from($db->qn('#__rsform_properties', 'p')) ->join('left', $db->qn('#__rsform_components', 'c') . ' ON (' . $db->qn('p.ComponentId') . ' = ' . $db->qn('c.ComponentId') . ')') ->where($db->qn('c.FormId') . ' = ' . $db->q($formId)) ->where($db->qn('p.PropertyName') . ' = ' . $db->q('NAME')) ->where($db->qn('p.PropertyValue') . ' = ' . $db->q($componentName)); if ($currentComponentId) { $query->where($db->qn('c.ComponentId') . ' <> ' . $db->q($currentComponentId)); } return $db->setQuery($query)->loadResult(); } public static function getCurrentLanguage($formId=null) { $mainframe = Factory::getApplication(); $lang = Factory::getLanguage(); $session = Factory::getSession(); $formId = !$formId ? $mainframe->input->getInt('formId') || $mainframe->input->getInt('FormId') : $formId; // editing in backend ? if ($mainframe->isClient('administrator')) { if ($mainframe->input->getCmd('task') == 'submissions.edit' || ($mainframe->input->getCmd('view') == 'submissions' && $mainframe->input->getCmd('layout') == 'edit')) { $cid = $mainframe->input->get('cid', array(), 'array'); require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php'; if ($submission = RSFormProSubmissionsHelper::getSubmission(reset($cid), false)) { return $submission->Lang; } } if (RSFormProHelper::getConfig('global.disable_multilanguage')) { return RSFormProHelper::getConfig('global.default_language'); } return $session->get('com_rsform.form.formId'.$formId.'.lang', $lang->getTag()); } // frontend else { // If it's a directory, get the language of the submission if ($mainframe->isClient('site') && // only site app, ignore cli ($active = $mainframe->getMenu()->getActive()) && // get active menu isset($active->query, $active->query['option'], $active->query['view']) // make sure we have option & query && $active->query['option'] == 'com_rsform' && $active->query['view'] == 'directory' // make sure it's a Directory view && ($params = $active->getParams()) // we have params && $params->get('enable_directory') && $params->get('formId') == $formId // this form matches && ($id = $mainframe->input->getInt('id'))) // it's an edit request { require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php'; if ($submission = RSFormProSubmissionsHelper::getSubmission($id, false)) { return $submission->Lang; } } if (RSFormProHelper::getConfig('global.disable_multilanguage')) { return RSFormProHelper::getConfig('global.default_language'); } return $lang->getTag(); } } public static function &getComponentProperties($components, $translate = true) { static $cache = array( 0 => array(), 1 => array() ); $translate = (int) $translate; if (is_numeric($components)) { $componentIds = array($components); $single = $components; } else { $componentIds = array(); $single = false; if (!is_array($components)) { $components = array($components); } foreach ($components as $componentId) { if (is_object($componentId) && !empty($componentId->ComponentId)) { $componentIds[] = (int) $componentId->ComponentId; } elseif (is_array($componentId) && !empty($componentId['ComponentId'])) { $componentIds[] = (int) $componentId['ComponentId']; } else { $componentIds[] = (int) $componentId; } } } $componentIds = array_filter($componentIds); if ($componentIds) { if ($newComponentIds = array_diff($componentIds, array_keys($cache[$translate]))) { $all_data = &$cache[$translate]; $db = Factory::getDbo(); $query = $db->getQuery(true); $query->select($db->qn('PropertyName')) ->select($db->qn('PropertyValue')) ->select($db->qn('ComponentId')) ->from($db->qn('#__rsform_properties')) ->where($db->qn('ComponentId').' IN ('.implode(',', $newComponentIds).')'); if ($results = $db->setQuery($query)->loadObjectList()) { foreach ($results as $result) { if (!isset($all_data[$result->ComponentId])) { $all_data[$result->ComponentId] = array('componentId' => $result->ComponentId); } $all_data[$result->ComponentId][$result->PropertyName] = $result->PropertyValue; } } // Guess the form ID $query = $db->getQuery(true); $query->select($db->qn('FormId')) ->from($db->qn('#__rsform_components')) ->where($db->qn('ComponentId').'='.$db->q(reset($newComponentIds))); $formId = $db->setQuery($query)->loadResult(); // language if ($translate) { $lang = RSFormProHelper::getCurrentLanguage($formId); $translations = RSFormProHelper::getTranslations('properties', $formId, $lang); foreach ($all_data as $componentId => $properties) { // Don't translate again if not needed if (!in_array($componentId, $newComponentIds)) { continue; } foreach ($properties as $property => $value) { $reference_id = $componentId.'.'.$property; if (isset($translations[$reference_id])) { $properties[$property] = $translations[$reference_id]; } } $all_data[$componentId] = $properties; } } } } if ($single) { if (!empty($cache[$translate][$single])) { return $cache[$translate][$single]; } } else { $results = array(); foreach ($componentIds as $componentId) { $results[$componentId] = &$cache[$translate][$componentId]; } return $results; } $blank = array(); return $blank; } public static function isCode($value) { if (self::hasCode($value)) { return eval($value); } return $value; } public static function hasCode($value) { return (strpos($value, '<code>') !== false); } public static function getIcon($type) { $icon = ''; switch ($type) { case 'calendar': $icon = 'calendar-o'; break; case 'gmaps': $icon = 'map-marker'; break; case 'hidden': $icon = 'texture'; break; case 'jQueryCalendar': $icon = 'calendar'; break; case 'rangeSlider': $icon = 'th-list'; break; case 'php': $icon = 'code'; break; case 'support': $icon = 'ticket'; break; } return '<span class="rsficon rsficon-'.$icon.'" style="font-size:24px;margin-right:5px"></span>'; } public static function htmlEscape($val) { return empty($val) ? $val : htmlentities($val, ENT_COMPAT, 'UTF-8'); } public static function explode($value) { if (!is_array($value)) { $value = str_replace(array("\r\n", "\r"), "\n", $value); $value = explode("\n", $value); } return $value; } public static function readFile($file, $download_name = null, $die = true) { $ext = strtolower(File::getExt($file)); if ($ext == 'tgz' || $ext == 'gz') { // Needed when some servers with GZIP compression perform double encoding if (is_callable('ini_set')) { if (is_callable('ini_get') && ini_get('zlib.output_compression')) { ini_set('zlib.output_compression', 'Off'); } ini_set('output_buffering', 'Off'); ini_set('output_handler', ''); } header('Content-Encoding: none'); } if (empty($download_name)) { $download_name = basename($file); } $fsize = filesize($file); header("Cache-Control: public, must-revalidate"); header('Cache-Control: pre-check=0, post-check=0, max-age=0'); if (!preg_match('#MSIE#', $_SERVER['HTTP_USER_AGENT'])) header("Pragma: no-cache"); header("Expires: 0"); header("Content-Description: File Transfer"); header("Expires: Sat, 01 Jan 2000 01:00:00 GMT"); if (preg_match('#Opera#', $_SERVER['HTTP_USER_AGENT'])) header("Content-Type: application/octetstream"); else header("Content-Type: application/octet-stream"); header("Content-Length: ".(string) ($fsize)); header('Content-Disposition: attachment; filename="'.$download_name.'"'); header("Content-Transfer-Encoding: binary\n"); ob_end_flush(); RSFormProHelper::readFileChunked($file); if ($die) { exit(); } } public static function readFileChunked($filename, $retbytes=true) { $chunksize = 1*(1024*1024); // how many bytes per chunk $cnt = 0; $handle = fopen($filename, 'rb'); if ($handle === false) { return false; } while (!feof($handle)) { $buffer = fread($handle, $chunksize); echo $buffer; if ($retbytes) { $cnt += strlen($buffer); } } $status = fclose($handle); if ($retbytes && $status) { return $cnt; // return num. bytes delivered like readfile() does. } return $status; } public static function getReplacements($SubmissionId, $skip_globals=false) { // Small hack return RSFormProHelper::sendSubmissionEmails($SubmissionId, true, $skip_globals); } public static function sendSubmissionEmails($SubmissionId, $only_return_replacements=false, $skip_globals=false) { $db = Factory::getDbo(); $mainframe = Factory::getApplication(); $secret = $mainframe->get('secret'); $u = Uri::getInstance(); $SubmissionId = (int) $SubmissionId; $placeholders = array(); $values = array(); $Itemid = $mainframe->input->getInt('Itemid'); $Itemid = $Itemid ? '&Itemid='.$Itemid : ''; $root = Uri::getInstance()->toString(array('scheme', 'host', 'port')); // Get the submission require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php'; $submission = RSFormProSubmissionsHelper::getSubmission($SubmissionId); if (!$submission) { return false; } $formId = $submission->FormId; // Load our form $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__rsform_forms')) ->where($db->qn('FormId') . ' = ' . $db->q($formId)); $form = $db->setQuery($query)->loadObject(); // Multiple items separators $form->MultipleSeparator = str_replace(array('\n', '\r', '\t'), array("\n", "\r", "\t"), $form->MultipleSeparator); // If our submission has no language, simply inherit it from the form if (empty($submission->Lang)) { if (!empty($form->Lang)) { $submission->Lang = $form->Lang; } else { $submission->Lang = Factory::getLanguage()->getDefault(); } $object = (object) array( 'SubmissionId' => $submission->SubmissionId, 'Lang' => $submission->Lang ); $db->updateObject('#__rsform_submissions', $object, array('SubmissionId')); } // Get translations $translations = RSFormProHelper::getTranslations('forms', $form->FormId, $submission->Lang); if ($translations) { foreach ($translations as $field => $value) { if (isset($form->{$field})) { $form->{$field} = $value; } } } $userEmailUploads = array(); $adminEmailUploads = array(); $additionalEmailUploads = array(); $nodecimals = (int) RSFormProHelper::getConfig('calculations.nodecimals'); $decimal = RSFormProHelper::getConfig('calculations.decimal'); $thousands = RSFormProHelper::getConfig('calculations.thousands'); if ($components = RSFormProHelper::getComponents($formId)) { // Get all properties (default to English) $all_data = RSFormProHelper::getComponentProperties($components, false); // Translate properties in requested language if ($translations = RSFormProHelper::getTranslations('properties', $form->FormId, $submission->Lang)) { foreach ($all_data as $componentId => $properties) { foreach ($properties as $property => $value) { $reference_id = $componentId.'.'.$property; if (isset($translations[$reference_id])) { $properties[$property] = $translations[$reference_id]; } } $all_data[$componentId] = $properties; } } foreach ($components as $component) { if (!isset($all_data[$component->ComponentId])) { continue; } $property = $all_data[$component->ComponentId]; // {component:caption} $placeholders[] = '{'.$property['NAME'].':caption}'; // Hidden fields don't have a caption if (in_array($component->ComponentTypeId, array(RSFORM_FIELD_HIDDEN, RSFORM_FIELD_TICKET))) { $values[] = $property['NAME']; } else { $values[] = isset($property['CAPTION']) ? $property['CAPTION'] : ''; } // {component:description} $placeholders[] = '{'.$property['NAME'].':description}'; $values[] = isset($property['DESCRIPTION']) ? $property['DESCRIPTION'] : ''; // {component:descriptionhtml} $placeholders[] = '{'.$property['NAME'].':descriptionhtml}'; $values[] = isset($property['DESCRIPTION']) ? self::htmlEscape($property['DESCRIPTION']) : ''; // {component:name} $placeholders[] = '{'.$property['NAME'].':name}'; $values[] = $property['NAME']; // {component:value} $placeholders[] = '{'.$property['NAME'].':value}'; $value = ''; if (isset($submission->values[$property['NAME']])) { $value = $submission->values[$property['NAME']]; // Check if this is an upload field if ($component->ComponentTypeId == RSFORM_FIELD_FILEUPLOAD) { $separator = '<br />'; if (!empty($property['FILESSEPARATOR'])) { $separator = str_replace(array('\n', '\r', '\t'), array("\n", "\r", "\t"), $property['FILESSEPARATOR']); } if (!empty($property['MULTIPLE']) && $property['MULTIPLE'] === 'YES') { $value = RSFormProHelper::explode($value); } else { $value = array($value); } $actualValues = array(); foreach ($value as $actualValue) { // If we have a value, create a link, otherwise no point in doing that if (strlen($actualValue)) { $fileUrl = Route::_('index.php?option=com_rsform&task=submissions.viewfile&hash=' . md5($submission->SubmissionId . $secret . $property['NAME']) . '&file=' . md5($actualValue) . $Itemid); if ($mainframe->isClient('administrator')) { $fileUrl = str_replace(Uri::root(true) . '/administrator/', Uri::root(true) . '/', $fileUrl); } $actualValues[] = '<a href="'. $root . $fileUrl . '">'.RSFormProHelper::htmlEscape(basename($actualValue)).'</a>'; } else { $actualValues[] = ''; } } $actualValues = array_filter($actualValues); $value = implode($separator, $actualValues); } // Check if this is a multiple field if (in_array($component->ComponentTypeId, array(RSFORM_FIELD_SELECTLIST, RSFORM_FIELD_CHECKBOXGROUP)) || isset($property['ITEMS'])) { $value = str_replace("\n", $form->MultipleSeparator, $value); } if ($component->ComponentTypeId == RSFORM_FIELD_TEXTAREA && $form->TextareaNewLines && $property['WYSIWYG'] == 'NO') { $value = nl2br($value); } } if ($component->ComponentTypeId == RSFORM_FIELD_FREETEXT) { $value = $property['TEXT']; } $values[] = $value; // {component:text} // {component:price} if (isset($property['ITEMS'])) { $placeholders[] = '{'.$property['NAME'].':text}'; $placeholders[] = '{'.$property['NAME'].':price}'; if (isset($submission->values[$property['NAME']])) { $all_texts = array(); $all_prices = array(); require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/fields/fielditem.php'; require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/fieldmultiple.php'; $field = new RSFormProFieldMultiple(array( 'formId' => $formId, 'componentId' => $component->ComponentId, 'data' => $property, 'value' => array('formId' => $formId, $property['NAME'] => explode("\n", $submission->values[$property['NAME']])), 'invalid' => false )); if ($items = $field->getItems()) { foreach ($items as $item) { $item = new RSFormProFieldItem($item); if ($item->value === $field->getItemValue($item)) { $all_texts[] = $item->label; $all_prices[] = $item->flags['price'] !== false ? (float) $item->flags['price'] : 0; } } } if ($all_texts) { $values[] = implode($form->MultipleSeparator, $all_texts); $values[] = number_format(array_sum($all_prices), $nodecimals, $decimal, $thousands); } else { $values[] = $submission->values[$property['NAME']]; $values[] = ''; } } else { $values[] = ''; $values[] = ''; } } // {component:map} if ($component->ComponentTypeId == RSFORM_FIELD_GMAPS) { $placeholders[] = '{'.$property['NAME'].':map}'; $mapw = str_replace('px', '', $property['MAPWIDTH']); $maph = str_replace('px', '', $property['MAPHEIGHT']); if (!empty($submission->values[$property['NAME']])) { $values[] = '<img width="' . self::htmlEscape($mapw) . '" height="' . self::htmlEscape($maph) . '" class="rsfp-gmap-image" src="https://maps.googleapis.com/maps/api/staticmap?key=' . urlencode(RSFormProHelper::getConfig('google.api_key')) . '&markers=' . urlencode($submission->values[$property['NAME']]) . '&center=' . urlencode($submission->values[$property['NAME']]) . '&zoom=' . urlencode($property['MAPZOOM']) . '&size=' . urlencode($mapw . 'x' . $maph) . '&maptype=' . urlencode(strtolower($property['MAPTYPE'])) . '">'; } else { $values[] = ''; } } // {component:path} // {component:localpath} // {component:filename} // {component:image} if ($component->ComponentTypeId == RSFORM_FIELD_FILEUPLOAD) { $hasMultiple = !empty($property['MULTIPLE']) && $property['MULTIPLE'] === 'YES'; $separator = '<br />'; if (!empty($property['FILESSEPARATOR'])) { $separator = str_replace(array('\n', '\r', '\t'), array("\n", "\r", "\t"), $property['FILESSEPARATOR']); } if (!empty($submission->values[$property['NAME']])) { if ($hasMultiple) { $value = RSFormProHelper::explode($submission->values[$property['NAME']]); } else { $value = array($submission->values[$property['NAME']]); } } else { $value = array(); } $placeholders[] = '{'.$property['NAME'].':path}'; $placeholders[] = '{'.$property['NAME'].':localpath}'; $placeholders[] = '{'.$property['NAME'].':filename}'; $placeholders[] = '{'.$property['NAME'].':image}'; $placeholders[] = '{'.$property['NAME'].':localimage}'; $placeholders[] = '{'.$property['NAME'].':count}'; $parsed = array( 'path' => array(), 'localpath' => array(), 'filename' => array(), 'image' => array(), 'localimage' => array() ); foreach ($value as $actualValue) { $filepath = substr_replace($actualValue, Uri::root(), 0, strlen(JPATH_SITE)+1); $filepath = str_replace(array('\\', '\\/', '//\\'), '/', $filepath); $parsed['path'][] = $filepath; $parsed['localpath'][] = $actualValue; $parsed['filename'][] = basename($actualValue); $parsed['image'][] = '<img src="' . self::htmlEscape($filepath) . '">'; $parsed['localimage'][] = '<img src="' . self::htmlEscape($actualValue) . '">'; } $values[] = implode($separator, $parsed['path']); $values[] = implode($separator, $parsed['localpath']); $values[] = implode($separator, $parsed['filename']); $values[] = implode($separator, $parsed['image']); $values[] = implode($separator, $parsed['localimage']); $values[] = count($value); // Handle attach to email settings. if (!empty($property['EMAILATTACH'])) { if ($parts = explode(',', trim($property['EMAILATTACH']))) { if (in_array('useremail', $parts)) { $userEmailUploads[] = $property['NAME']; } if (in_array('adminemail', $parts)) { $adminEmailUploads[] = $property['NAME']; } if ($filtered = array_filter($parts, 'intval')) { foreach ($filtered as $emailId) { if (!isset($additionalEmailUploads[$emailId])) { $additionalEmailUploads[$emailId] = array(); } $additionalEmailUploads[$emailId][] = $property['NAME']; } } } } if ($hasMultiple) { foreach ($value as $index => $actualValue) { $placeholders[] = '{'.$property['NAME'] . '_' . $index . ':value}'; $placeholders[] = '{'.$property['NAME'] . '_' . $index . ':path}'; $placeholders[] = '{'.$property['NAME'] . '_' . $index . ':localpath}'; $placeholders[] = '{'.$property['NAME'] . '_' . $index . ':filename}'; $placeholders[] = '{'.$property['NAME'] . '_' . $index . ':image}'; $placeholders[] = '{'.$property['NAME'] . '_' . $index . ':localimage}'; $fileUrl = Route::_('index.php?option=com_rsform&task=submissions.viewfile&hash=' . md5($submission->SubmissionId . $secret . $property['NAME']) . '&file=' . md5($actualValue) . $Itemid); if ($mainframe->isClient('administrator')) { $fileUrl = str_replace(Uri::root(true) . '/administrator/', Uri::root(true) . '/', $fileUrl); } $values[] = '<a href="'. $root . $fileUrl . '">'.RSFormProHelper::htmlEscape(basename($actualValue)).'</a>'; $values[] = $parsed['path'][$index]; $values[] = $parsed['localpath'][$index]; $values[] = $parsed['filename'][$index]; $values[] = $parsed['image'][$index]; $values[] = $parsed['localimage'][$index]; } } } } } $user = Factory::getUser($submission->UserId); if (empty($user->id)) { $user = Factory::getUser(0); } $root = $mainframe->isClient('administrator') ? Uri::root() : $u->toString(array('scheme','host', 'port')); $confirmation_hash = md5($submission->SubmissionId.$formId.$submission->DateSubmitted); $hash_link = 'index.php?option=com_rsform&task=confirm&hash='.$confirmation_hash; $delete_link = 'index.php?option=com_rsform&view=deletesubmission&hash='.$submission->SubmissionHash; $confirmation = $root.($mainframe->isClient('administrator') ? $hash_link : Route::_($hash_link)); $deletion = $root.($mainframe->isClient('administrator') ? $delete_link : Route::_($delete_link)); if (!$skip_globals) { $global_placeholders = array( '{global:username}' => $user->username, '{global:userid}' => $user->id, '{global:useremail}' => $user->email, '{global:fullname}' => $user->name, '{global:userip}' => $submission->UserIp, '{global:date_added}' => RSFormProHelper::getDate($submission->DateSubmitted), '{global:utc_date_added}' => $submission->DateSubmitted, '{global:sitename}' => $mainframe->get('sitename'), '{global:siteurl}' => Uri::root(), '{global:confirmation}' => $confirmation, '{global:confirmation_hash}' => $confirmation_hash, '{global:confirmedip}' => $submission->ConfirmedIp, '{global:confirmeddate}' => $submission->ConfirmedDate ? RSFormProHelper::getDate($submission->ConfirmedDate) : '', '{global:utc_confirmeddate}' => $submission->ConfirmedDate, '{global:deletion}' => $deletion, '{global:deletion_hash}' => $submission->SubmissionHash, '{global:submissionid}' => $submission->SubmissionId, '{global:submission_id}' => $submission->SubmissionId, '{global:mailfrom}' => $mainframe->get('mailfrom'), '{global:fromname}' => $mainframe->get('fromname'), '{global:formid}' => $formId, '{global:language}' => $submission->Lang, '{global:formtitle}' => $form->FormTitle ); $placeholders = array_merge($placeholders, array_keys($global_placeholders)); $values = array_merge($values, array_values($global_placeholders)); } $mainframe->triggerEvent('onRsformAfterCreatePlaceholders', array(array('form' => &$form, 'placeholders' => &$placeholders, 'values' => &$values, 'submission' => $submission))); if ($only_return_replacements) { return array($placeholders, $values); } if ($form->ConfirmSubmission && !empty($form->ConfirmSubmissionDefer)) { $defer = json_decode($form->ConfirmSubmissionDefer); if (!is_array($defer)) { $defer = array(); } // If submission is confirmed, do not resend emails that have been already sent before user confirmed if ($submission->confirmed) { $defer = array_diff(array('UserEmail', 'AdminEmail', 'AdditionalEmails'), $defer); } } if (empty($defer)) { $defer = array(); } // We do this here again so we grab all placeholders, even those injected by plugins if ($form->UserEmailGenerate || $form->AdminEmailGenerate) { foreach ($components as $component) { if (!isset($all_data[$component->ComponentId])) { continue; } $property = $all_data[$component->ComponentId]; $captionPlaceholder = '{' . $property['NAME'] . ':caption}'; $valuePlaceholder = '{' . $property['NAME'] . ':value}'; if ($component->ComponentTypeId == RSFORM_FIELD_GMAPS) { $valuePlaceholder = '{' . $property['NAME'] . ':map}'; } $mainframe->triggerEvent('onRsformCreateEmailLine', array(array('form' => &$form, 'submission' => $submission, 'typeId' => $component->ComponentTypeId, 'captionPlaceholder' => &$captionPlaceholder, 'valuePlaceholder' => &$valuePlaceholder))); if (Factory::getDocument()->getDirection() === 'rtl') { $htmlTemplate = '<p dir="rtl"><strong>%s</strong> %s</p>' . "\n"; $textTemplate = "%s: %s\n"; } else { $htmlTemplate = "<p><strong>%s</strong> %s</p>\n"; $textTemplate = "%s: %s\n"; } if ($form->UserEmailGenerate) { $emailLine = $form->UserEmailMode ? $htmlTemplate : $textTemplate; $form->UserEmailText .= "{if {$valuePlaceholder}}" . sprintf($emailLine, $captionPlaceholder, $valuePlaceholder) . "{/if}"; } if ($form->AdminEmailGenerate) { $emailLine = $form->AdminEmailMode ? $htmlTemplate : $textTemplate; $form->AdminEmailText .= "{if {$valuePlaceholder}}" . sprintf($emailLine, $captionPlaceholder, $valuePlaceholder) . "{/if}"; } } } // RSForm! Pro Scripting - User Email Text // performance check if (strpos($form->UserEmailText, '{/if}') !== false) { require_once __DIR__.'/scripting.php'; RSFormProScripting::compile($form->UserEmailText, $placeholders, $values); } $userEmail = array( 'to' => str_replace($placeholders, $values, $form->UserEmailTo), 'cc' => str_replace($placeholders, $values, $form->UserEmailCC), 'bcc' => str_replace($placeholders, $values, $form->UserEmailBCC), 'from' => str_replace($placeholders, $values, $form->UserEmailFrom), 'replyto' => str_replace($placeholders, $values, $form->UserEmailReplyTo), 'replytoName' => str_replace($placeholders, $values, $form->UserEmailReplyToName), 'fromName' => str_replace($placeholders, $values, $form->UserEmailFromName), 'text' => str_replace($placeholders, $values, $form->UserEmailText), 'subject' => str_replace($placeholders, $values, $form->UserEmailSubject), 'mode' => $form->UserEmailMode, 'files' => array(), 'recipientName' => '' ); // user cc if (strpos($userEmail['cc'], ',') !== false) { $userEmail['cc'] = explode(',', $userEmail['cc']); } // user bcc if (strpos($userEmail['bcc'], ',') !== false) { $userEmail['bcc'] = explode(',', $userEmail['bcc']); } $file = str_replace($placeholders, $values, $form->UserEmailAttachFile); if ($form->UserEmailAttach && file_exists($file)) { $userEmail['files'][] = $file; } // Need to attach files // User Email if ($userEmailUploads) { foreach ($userEmailUploads as $name) { if (!empty($submission->values[$name])) { $userEmail['files'] = array_merge($userEmail['files'], RSFormProHelper::explode($submission->values[$name])); } } } // RSForm! Pro Scripting - Admin Email Text // performance check if (strpos($form->AdminEmailText, '{/if}') !== false) { require_once __DIR__.'/scripting.php'; RSFormProScripting::compile($form->AdminEmailText, $placeholders, $values); } $adminEmail = array( 'to' => str_replace($placeholders, $values, $form->AdminEmailTo), 'cc' => str_replace($placeholders, $values, $form->AdminEmailCC), 'bcc' => str_replace($placeholders, $values, $form->AdminEmailBCC), 'from' => str_replace($placeholders, $values, $form->AdminEmailFrom), 'replyto' => str_replace($placeholders, $values, $form->AdminEmailReplyTo), 'replytoName' => str_replace($placeholders, $values, $form->AdminEmailReplyToName), 'fromName' => str_replace($placeholders, $values, $form->AdminEmailFromName), 'text' => str_replace($placeholders, $values, $form->AdminEmailText), 'subject' => str_replace($placeholders, $values, $form->AdminEmailSubject), 'mode' => $form->AdminEmailMode, 'files' => array(), 'recipientName' => '' ); // admin cc if (strpos($adminEmail['cc'], ',') !== false) { $adminEmail['cc'] = explode(',', $adminEmail['cc']); } // admin bcc if (strpos($adminEmail['bcc'], ',') !== false) { $adminEmail['bcc'] = explode(',', $adminEmail['bcc']); } // Admin Email if ($adminEmailUploads) { foreach ($adminEmailUploads as $name) { if (!empty($submission->values[$name])) { $adminEmail['files'] = array_merge($adminEmail['files'], RSFormProHelper::explode($submission->values[$name])); } } } $mainframe->triggerEvent('onRsformBeforeUserEmail', array(array('form' => &$form, 'placeholders' => &$placeholders, 'values' => &$values, 'submissionId' => $SubmissionId, 'SubmissionId' => $SubmissionId, 'userEmail'=>&$userEmail))); if ($defer && in_array('UserEmail', $defer)) { $userEmail['to'] = ''; } // Script called before the User Email is sent. eval($form->UserEmailScript); // mail users if ($userEmail['to']) { $recipients = !is_array($userEmail['to']) ? explode(',', $userEmail['to']) : $userEmail['to']; RSFormProHelper::sendMail($userEmail['from'], $userEmail['fromName'], $recipients, $userEmail['subject'], $userEmail['text'], $userEmail['mode'], !empty($userEmail['cc']) ? $userEmail['cc'] : null, !empty($userEmail['bcc']) ? $userEmail['bcc'] : null, $userEmail['files'], !empty($userEmail['replyto']) ? $userEmail['replyto'] : '', !empty($userEmail['replytoName']) ? $userEmail['replytoName'] : null, $userEmail['recipientName'], $formId); $mainframe->triggerEvent('onRsformAfterUserEmail', array(array('form' => &$form, 'placeholders' => &$placeholders, 'values' => &$values, 'submissionId' => $SubmissionId, 'SubmissionId' => $SubmissionId, 'userEmail'=>&$userEmail))); } $mainframe->triggerEvent('onRsformBeforeAdminEmail', array(array('form' => &$form, 'placeholders' => &$placeholders, 'values' => &$values, 'submissionId' => $SubmissionId, 'SubmissionId' => $SubmissionId, 'adminEmail'=>&$adminEmail))); if ($defer && in_array('AdminEmail', $defer)) { $adminEmail['to'] = ''; } // Script called before the Admin Email is sent. eval($form->AdminEmailScript); //mail admins if ($adminEmail['to']) { $recipients = !is_array($adminEmail['to']) ? explode(',', $adminEmail['to']) : $adminEmail['to']; RSFormProHelper::sendMail($adminEmail['from'], $adminEmail['fromName'], $recipients, $adminEmail['subject'], $adminEmail['text'], $adminEmail['mode'], !empty($adminEmail['cc']) ? $adminEmail['cc'] : null, !empty($adminEmail['bcc']) ? $adminEmail['bcc'] : null, $adminEmail['files'], !empty($adminEmail['replyto']) ? $adminEmail['replyto'] : '', !empty($adminEmail['replytoName']) ? $adminEmail['replytoName'] : null, $adminEmail['recipientName'], $formId); $mainframe->triggerEvent('onRsformAfterAdminEmail', array(array('form' => &$form, 'placeholders' => &$placeholders, 'values' => &$values, 'submissionId' => $SubmissionId, 'SubmissionId' => $SubmissionId, 'adminEmail'=>&$adminEmail))); } // Additional emails $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__rsform_emails')) ->where($db->qn('type') . ' = ' . $db->q('additional')) ->where($db->qn('formId') . ' = ' . $db->q($formId)) ->where($db->qn('from') . ' != ' . $db->q('')); if ($emails = $db->setQuery($query)->loadObjectList()) { $translations = RSFormProHelper::getTranslations('emails', $formId, $submission->Lang); foreach ($emails as $email) { foreach (array('fromname', 'subject', 'message', 'replytoname') as $value) { if (isset($translations[$email->id . '.' . $value])) { $email->{$value} = $translations[$email->id . '.' . $value]; } } if (empty($email->fromname) || empty($email->subject) || empty($email->message)) { continue; } // RSForm! Pro Scripting - Additional Email Text // performance check if (strpos($email->message, '{/if}') !== false) { require_once __DIR__.'/scripting.php'; RSFormProScripting::compile($email->message, $placeholders, $values); } $additionalEmail = array( 'to' => str_replace($placeholders, $values, $email->to), 'cc' => str_replace($placeholders, $values, $email->cc), 'bcc' => str_replace($placeholders, $values, $email->bcc), 'from' => str_replace($placeholders, $values, $email->from), 'replyto' => str_replace($placeholders, $values, $email->replyto), 'replytoName' => str_replace($placeholders, $values, $email->replytoname), 'fromName' => str_replace($placeholders, $values, $email->fromname), 'text' => str_replace($placeholders, $values, $email->message), 'subject' => str_replace($placeholders, $values, $email->subject), 'mode' => $email->mode, 'files' => array(), 'recipientName' => '' ); if (isset($additionalEmailUploads, $additionalEmailUploads[$email->id])) { foreach ($additionalEmailUploads[$email->id] as $name) { if (!empty($submission->values[$name])) { $additionalEmail['files'] = array_merge($additionalEmail['files'], RSFormProHelper::explode($submission->values[$name])); } } } // additional cc if (strpos($additionalEmail['cc'], ',') !== false) { $additionalEmail['cc'] = explode(',', $additionalEmail['cc']); } // additional bcc if (strpos($additionalEmail['bcc'], ',') !== false) { $additionalEmail['bcc'] = explode(',', $additionalEmail['bcc']); } $mainframe->triggerEvent('onRsformBeforeAdditionalEmail', array(array('form' => &$form, 'placeholders' => &$placeholders, 'values' => &$values, 'submissionId' => $SubmissionId, 'SubmissionId' => $SubmissionId, 'additionalEmail'=>&$additionalEmail))); if ($defer && in_array('AdditionalEmails', $defer)) { $additionalEmail['to'] = ''; } eval($form->AdditionalEmailsScript); // mail users if ($additionalEmail['to']) { $recipients = !is_array($additionalEmail['to']) ? explode(',', $additionalEmail['to']) : $additionalEmail['to']; RSFormProHelper::sendMail($additionalEmail['from'], $additionalEmail['fromName'], $recipients, $additionalEmail['subject'], $additionalEmail['text'], $additionalEmail['mode'], !empty($additionalEmail['cc']) ? $additionalEmail['cc'] : null, !empty($additionalEmail['bcc']) ? $additionalEmail['bcc'] : null, $additionalEmail['files'], !empty($additionalEmail['replyto']) ? $additionalEmail['replyto'] : '', !empty($additionalEmail['replytoName']) ? $additionalEmail['replytoName'] : null, $additionalEmail['recipientName'], $formId); $mainframe->triggerEvent('onRsformAfterAdditionalEmail', array(array('form' => &$form, 'placeholders' => &$placeholders, 'values' => &$values, 'submissionId' => $SubmissionId, 'SubmissionId' => $SubmissionId, 'additionalEmail'=>&$additionalEmail))); } } } return array($placeholders, $values); } public static function escapeArray(&$val, &$key) { $db = Factory::getDbo(); $val = $db->escape($val); $key = $db->escape($key); } public static function quoteArray(&$val, $key) { static $db; if (!$db) { $db = Factory::getDbo(); } $val = $db->q($val); } public static function componentExists($formId, $componentTypeId, $published = 1) { $formId = (int) $formId; $db = Factory::getDbo(); if (is_array($componentTypeId)) { $componentTypeId = array_map('intval', $componentTypeId); } else { $componentTypeId = array((int) $componentTypeId); } $query = $db->getQuery(true) ->select($db->qn('ComponentId')) ->from($db->qn('#__rsform_components')) ->where($db->qn('ComponentTypeId') . ' IN (' . implode(',', $componentTypeId) . ')') ->where($db->qn('FormId') . ' = ' . $db->q($formId)); if ($published) { $query->where($db->qn('Published') . ' = ' . $db->q(1)); } return $db->setQuery($query)->loadColumn(); } // conditions public static function getConditions($formId, $lang=null) { require_once __DIR__ . '/conditions.php'; return RSFormProConditions::getConditions($formId, $lang); } public static function showForm($formId, $val=array(), $validation=array()) { $mainframe = Factory::getApplication(); $doc = Factory::getDocument(); $user = Factory::getUser(); $u = RSFormProHelper::getURL(); $formId = (int) $formId; $logged = $user->id; $form = RSFormProHelper::getForm($formId); $lang = RSFormProHelper::getCurrentLanguage(); $translations = RSFormProHelper::getTranslations('forms', $form->FormId, $lang); if ($translations) { foreach ($translations as $field => $value) { if (isset($form->{$field})) { $form->{$field} = $value; } } } $mainframe->triggerEvent('onRsformFrontendBeforeShowForm', array($formId, &$form)); $nonce = ''; if (PluginHelper::isEnabled('system', 'httpheaders')) { $app = Factory::getApplication(); $plugin = PluginHelper::getPlugin('system', 'httpheaders'); $params = new Registry(); $params->loadString($plugin->params); $cspEnabled = (int) $params->get('contentsecuritypolicy', 0); $cspClient = (string) $params->get('contentsecuritypolicy_client', 'site'); $nonceEnabled = (int) $params->get('nonce_enabled', 0); if ($cspEnabled && ($app->isClient($cspClient) || $cspClient === 'both')) { if ($nonceEnabled) { $nonce = Factory::getApplication()->get('csp_nonce'); } } } if ($form->JS) { if (strpos($form->JS, '{nonce}') !== false) { $form->JS = str_replace('{nonce}', $nonce, $form->JS); } RSFormProAssets::addCustomTag($form->JS); } if ($form->CSS) { if (strpos($form->CSS, '{nonce}') !== false) { $form->CSS = str_replace('{nonce}', $nonce, $form->CSS); } RSFormProAssets::addCustomTag($form->CSS); } if ($form->ScrollToError) { RSFormProAssets::addScriptDeclaration('RSFormPro.scrollToError = true;'); } RSFormProAssets::addStyleSheet(HTMLHelper::_('stylesheet', 'com_rsform/front.css', array('pathOnly' => true, 'relative' => true))); RSFormProAssets::addScript(HTMLHelper::_('script', 'com_rsform/script.js', array('pathOnly' => true, 'relative' => true))); // calendars $YUICalendars = RSFormProHelper::componentExists($formId, RSFORM_FIELD_CALENDAR); $jQueryCalendars = RSFormProHelper::componentExists($formId, RSFORM_FIELD_JQUERY_CALENDAR); $rangeSliders = RSFormProHelper::componentExists($formId, RSFORM_FIELD_RANGE_SLIDER); $formLayout = $form->FormLayout; unset($form->FormLayout); $errorMessage = $form->ErrorMessage; unset($form->ErrorMessage); $components = RSFormProHelper::getComponents($formId); $pages = array(); $page_progress = array(); $submits = array(); foreach ($components as $component) { if ($component->ComponentTypeId == RSFORM_FIELD_PAGEBREAK) $pages[] = $component->ComponentId; elseif ($component->ComponentTypeId == RSFORM_FIELD_SUBMITBUTTON) $submits[] = $component->ComponentId; } $find = array(); $replace = array(); eval($form->ScriptBeforeDisplay); $start_page = 0; if (!empty($validation)) { foreach ($components as $component) { if (in_array($component->ComponentId, $validation)) { break; } if ($component->ComponentTypeId == RSFORM_FIELD_PAGEBREAK) $start_page++; } } // stores the error class names found in the form layout $layoutErrorClass = array(); $fieldErrorClass = array(); $layoutName = (string) preg_replace('/[^A-Z0-9]/i', '', $form->FormLayoutName); // keep the loaded framework class for further purpose $layoutClassLoaded = false; if (file_exists(__DIR__.'/formlayouts/'.$layoutName.'.php')) { require_once __DIR__.'/formlayouts/'.$layoutName.'.php'; $class = 'RSFormProFormLayout'.$layoutName; if (class_exists($class)) { $layout = new $class(); $layoutClassLoaded = $layout; if ($form->LoadFormLayoutFramework) { $layout->loadFramework(); } // Return the specific layout error class $layoutErrorClass[$layoutName] = $layout->errorClass; $fieldErrorClass[$layoutName] = $layout->fieldErrorClass; } } else { $layoutErrorClass[$layoutName] = ''; $fieldErrorClass[$layoutName] = 'rsform-error'; } if ($doc->getDirection() == 'rtl') RSFormProAssets::addStyleSheet(HTMLHelper::_('stylesheet', 'com_rsform/front-rtl.css', array('pathOnly' => true, 'relative' => true))); $hasAjax = (bool) $form->AjaxValidation; static $hasAjaxRoot = false; $all_data = RSFormProHelper::getComponentProperties($components); foreach ($components as $component) { if (in_array($component->ComponentTypeId, RSFormProHelper::$captchaFields)) { if ($logged && $form->RemoveCaptchaLogged) { continue; } } $data = $all_data[$component->ComponentId]; $data['componentTypeId'] = $component->ComponentTypeId; $data['ComponentTypeName'] = $component->ComponentTypeName; $data['Order'] = $component->Order; // Pagination if ($component->ComponentTypeId == RSFORM_FIELD_PAGEBREAK) { // Set flag to load Ajax scripts if (!empty($data['VALIDATENEXTPAGE']) && $data['VALIDATENEXTPAGE'] == 'YES') { $hasAjax = true; } $data['PAGES'] = $pages; $page_progress[] = array( 'show' => !empty($data['DISPLAYPROGRESS']) && in_array($data['DISPLAYPROGRESS'], array('YES', 'AUTO')), 'text' => !empty($data['DISPLAYPROGRESSMSG']) ? $data['DISPLAYPROGRESSMSG'] : '', 'auto' => !empty($data['DISPLAYPROGRESS']) && $data['DISPLAYPROGRESS'] == 'AUTO' ); } elseif ($component->ComponentTypeId == RSFORM_FIELD_SUBMITBUTTON) { $data['SUBMITS'] = $submits; if ($component->ComponentId == end($submits)) { $page_progress[] = array( 'show' => !empty($data['DISPLAYPROGRESS']) && in_array($data['DISPLAYPROGRESS'], array('YES', 'AUTO')), 'text' => !empty($data['DISPLAYPROGRESSMSG']) ? $data['DISPLAYPROGRESSMSG'] : '', 'auto' => !empty($data['DISPLAYPROGRESS']) && $data['DISPLAYPROGRESS'] == 'AUTO' ); } } // Error classes $errorClass = ''; if (!empty($validation) && in_array($component->ComponentId, $validation)) { $errorClass = $layoutErrorClass[$layoutName]; } $find[] = '{'.$component->name.':errorClass}'; $replace[] = $errorClass; // Caption $caption = ''; if (isset($data['SHOW']) && $data['SHOW'] == 'NO') { $caption = ''; } elseif (isset($data['CAPTION'])) { $caption = $data['CAPTION']; } $find[] = '{'.$component->name.':caption}'; $replace[] = $caption; // Body $out = ''; $invalid = in_array($component->ComponentId, $validation); // Some filtering in the field type $type = (string) preg_replace('/[^A-Z0-9_\.-]/i', '', (string) $data['ComponentTypeName']); $type = ltrim($type, '.'); $layouts = array( // Path to the layout (overridden) class 'RSFormProField'.$layoutName.$type => __DIR__.'/fields/'.strtolower($layoutName).'/'.strtolower($type).'.php', // Path to the fallback (basic) class 'RSFormProField'.$type => __DIR__.'/fields/'.strtolower($type).'.php' ); // For legacy reasons... $r = array( 'ComponentTypeId' => $data['componentTypeId'], 'Order' => isset($data['Order']) ? $data['Order'] : 0 ); $mainframe->triggerEvent('onRsformBackendBeforeCreateFrontComponentBody', array(array( 'out' => &$out, 'formId' => $formId, 'componentId' => $component->ComponentId, 'data' => &$data, 'value' => &$val ))); $config = array( 'formId' => $formId, 'componentId' => $component->ComponentId, 'data' => $data, 'value' => $val, 'invalid' => $invalid, 'errorClass' => $layoutErrorClass[$layoutName], 'fieldErrorClass' => $fieldErrorClass[$layoutName] ); foreach ($layouts as $class => $file) { if (file_exists($file)) { // If class doesn't exist, load the file if (!class_exists($class)) { require_once $file; } // Create the field $field = new $class($config); // Return the output $out .= $field->output; // do not load the other class again if one is already initiated break; } } $mainframe->triggerEvent('onRsformBackendAfterCreateFrontComponentBody', array(array( 'out' => &$out, 'formId' => $formId, 'componentId' => $component->ComponentId, 'data' => $data, 'value' => $val, 'r' => $r, 'invalid' => $invalid ))); $find[] = '{'.$component->name.':body}'; $replace[] = $out; // Description $description = ''; if (isset($data['SHOW']) && $data['SHOW'] == 'NO') { $description = ''; } elseif (isset($data['DESCRIPTION'])) { $description = $data['DESCRIPTION']; } $find[] = '{'.$component->name.':description}'; $replace[] = $description; // {component:descriptionhtml} $find[] = '{'.$component->name.':descriptionhtml}'; $replace[] = self::htmlEscape($description); // Validation message $validationMessage = ''; if (isset($data['SHOW']) && $data['SHOW'] == 'NO') { $validationMessage = ''; } elseif (isset($data['VALIDATIONMESSAGE'])) { if (!empty($validation) && in_array($component->ComponentId, $validation)) { $validationMessage = '<span id="component'.$component->ComponentId.'" class="formError">'.$data['VALIDATIONMESSAGE'].'</span>'; } else { $validationMessage = '<span id="component'.$component->ComponentId.'" class="formNoError">'.$data['VALIDATIONMESSAGE'].'</span>'; } } $find[] = '{'.$component->name.':validation}'; $replace[] = $validationMessage; } unset($all_data); $mainframe->triggerEvent('onRsformFrontendInitFormDisplay', array(array( 'find' => &$find, 'replace' => &$replace, 'formLayout' => &$formLayout, 'formId' => $formId ))); // Global placeholders $global = array( '{global:formid}' => $form->FormId, '{global:formtitle}' => $form->FormTitle, '{global:username}' => $user->get('username'), '{global:userip}' => IpHelper::getIp(), '{global:userid}' => $user->get('id'), '{global:useremail}' => $user->get('email'), '{global:fullname}' => $user->get('name'), '{global:sitename}' => $mainframe->get('sitename'), '{global:siteurl}' => Uri::root(), '{global:mailfrom}' => $mainframe->get('mailfrom'), '{global:fromname}' => $mainframe->get('fromname') ); $find = array_merge($find, array_keys($global)); $replace = array_merge($replace, array_values($global)); // Error placeholder $error = ''; if (!empty($validation)) { $error = $errorMessage; } elseif ($hasAjax) { $error = '<div id="rsform_error_'.$formId.'" style="display: none;">'.$errorMessage.'</div>'; } $find[] = '{error}'; $replace[] = $error; // Check for {if} scripting inside Form Layout if (strpos($formLayout, '{/if}') !== false) { require_once __DIR__ . '/scripting.php'; RSFormProScripting::compile($formLayout, $find, $replace); } // Replace all placeholders $formLayout = str_replace($find, $replace, $formLayout); $formLayout .= '<input type="hidden" name="form[formId]" value="'.$formId.'"/>'; if ($layoutClassLoaded && is_callable(array($layoutClassLoaded, 'modifyForm'))) { $layoutClassLoaded->modifyForm($form); } $CSSClass = $form->CSSClass ? ' class="'.RSFormProHelper::htmlEscape(trim($form->CSSClass)).'"' : ''; $CSSId = $form->CSSId ? ' id="'.RSFormProHelper::htmlEscape(trim($form->CSSId)).'"' : ''; $CSSName = $form->CSSName ? ' name="'.RSFormProHelper::htmlEscape(trim($form->CSSName)).'"' : ''; $u = $form->CSSAction ? $form->CSSAction : $u; $CSSAdditionalAttributes = $form->CSSAdditionalAttributes ? ' '.trim($form->CSSAdditionalAttributes) : ''; if (!empty($pages)) { $total_pages = count($pages)+1; $step = round(100/$total_pages, 2); $replace_progress = array('{page}', '{total}', '{percent}'); $with_progress = array(1, $total_pages, $step*1); $progress = reset($page_progress); $progress_script = ''; if ($layoutClassLoaded && $progress['auto']) { $progress['text'] = $layoutClassLoaded->progressContent; } $formLayout = '<div id="rsform_progress_'.$formId.'" class="rsformProgress">'.($progress['show'] ? str_replace($replace_progress, $with_progress, $progress['text']) : '').'</div>'."\n".$formLayout; foreach ($page_progress as $p => $progress) { $progress['text'] = str_replace(array("\r", "\n"), array('', '\n'), addcslashes($progress['text'], "'")); if ($layoutClassLoaded && $progress['auto']) { $progress['text'] = $layoutClassLoaded->progressContent; } $replace_progress = array('{page}', '{total}', '{percent}'); $with_progress = array($p+1, $total_pages, $p+1 == $total_pages ? 100 : $step*($p+1)); $progress_script .= "if (page == ".$p.") document.getElementById('rsform_progress_".$formId."').innerHTML = '".($progress['show'] ? str_replace($replace_progress, $with_progress, $progress['text']) : '')."';"; } RSFormProAssets::addScriptDeclaration('function rsfp_showProgress_' . $formId . '(page) { ' . $progress_script . ' }'); } $encType = ''; if (RSFormProHelper::componentExists($formId, RSFORM_FIELD_FILEUPLOAD)) { $encType = ' enctype="multipart/form-data"'; } $useCsrf = RSFormProHelper::getConfig('use_csrf'); $token = $useCsrf ? HTMLHelper::_('form.token') : ''; // Try to keep session alive, using try because Joomla! 4 will trigger exceptions when used in onAfterRender() if ($useCsrf) { try { HTMLHelper::_('behavior.keepalive'); } catch (Exception $e) { } } $formLayout = '<form method="post" '.$CSSId.$CSSClass.$CSSName.$CSSAdditionalAttributes.$encType.' action="'.RSFormProHelper::htmlEscape($u).'">' . $formLayout . $token . '</form>'; require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/prices.php'; if ($prices = RSFormProPrices::getInstance($formId)->getPrices()) { $script = ''; foreach ($prices as $componentName => $values) { $script .= "RSFormProPrices['".addslashes($formId.'_'.$componentName)."'] = ".json_encode($values).";\n"; } RSFormProAssets::addScriptDeclaration($script); } if ($YUICalendars || $jQueryCalendars) { require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/calendar.php'; // render the YUI Calendars if ($YUICalendars) { $calendar = RSFormProCalendar::getInstance('YUICalendar'); RSFormProAssets::addScriptDeclaration($calendar->printInlineScript($formId)); } // render the jQuery Calendars if ($jQueryCalendars) { $calendar = RSFormProCalendar::getInstance('jQueryCalendar'); RSFormProAssets::addScriptDeclaration($calendar->printInlineScript($formId)); } } if (!empty($rangeSliders)) { require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/rangeslider.php'; $rangeSlider = RSFormProRangeSlider::getInstance(); RSFormProAssets::addScriptDeclaration($rangeSlider->printInlineScript($formId)); } if (!empty($pages)) { RSFormProAssets::addScriptDeclaration(sprintf('window.addEventListener(\'DOMContentLoaded\', function(){ rsfp_changePage(%d, %d, %d); });', $formId, $start_page, count($pages))); } if ($hasAjax && !$hasAjaxRoot) { $hasAjaxRoot = true; RSFormProAssets::addScriptDeclaration('RSFormPro.Ajax.URL = ' . json_encode(Route::_('index.php?option=com_rsform&task=ajaxValidate', false)) . ';'); } $validationParams = array( 'parent' => $layoutErrorClass[$layoutName], 'field' => $fieldErrorClass[$layoutName] ); if ($form->AjaxValidation) { RSFormProAssets::addScriptDeclaration( "RSFormProUtils.addEvent(window, 'load', function(){ RSFormPro.Ajax.overrideSubmit(" . $formId . ", " . json_encode($validationParams) . ", " . ($form->DisableSubmitButton ? 'true' : 'false') . "); });"); } else { RSFormProAssets::addScriptDeclaration( "RSFormProUtils.addEvent(window, 'load', function(){ RSFormPro.setHTML5Validation('" . $formId . "', " . ($form->DisableSubmitButton ? 'true' : 'false') . ", " . json_encode($validationParams) . ", " . count($pages) . "); });"); } // Allow plugins to inject code with their own Ajax script $ajaxScript = ''; $mainframe->triggerEvent('onRsformFrontendAJAXScriptCreate', array(array('script' => &$ajaxScript, 'formId' => $formId))); if ($hasAjax || $ajaxScript) { $script = 'ajaxExtraValidationScript['.$formId.'] = function(task, formId, data){ '."\n"; $script .= 'var formComponents = {};'."\n"; foreach ($components as $component) { if (in_array($component->ComponentTypeId, array(RSFORM_FIELD_BUTTON, RSFORM_FIELD_FILEUPLOAD, RSFORM_FIELD_FREETEXT, RSFORM_FIELD_HIDDEN, RSFORM_FIELD_SUBMITBUTTON, RSFORM_FIELD_TICKET, RSFORM_FIELD_PAGEBREAK))) { continue; } $script .= "formComponents[".$component->ComponentId."]='".$component->name."';"; } $script .= "\n".'RSFormPro.Ajax.displayValidationErrors(formComponents, task, formId, data);'."\n"; // has this been modified? if ($ajaxScript) { $script .= $ajaxScript; } $script .= '};'."\n"; RSFormProAssets::addScriptDeclaration($script); } require_once __DIR__ . '/conditions.php'; if ($conditions = RSFormProConditions::getConditions($formId, $lang)) { RSFormProAssets::addScriptDeclaration(RSFormProConditions::buildJS($formId, $conditions)); } unset($conditions); if ($calculations = RSFormProHelper::getCalculations($formId)) { require_once __DIR__.'/calculations.php'; $script = 'function rsfp_Calculations' . $formId . '(){' . "\n"; $script .= "\t var i, thevalue;\n"; foreach ($calculations as $calculation) { $expression = RSFormProCalculations::expression($calculation, $formId); $script .= "\n".$expression."\n"; } $script .= "\n".'}'; $script .= RSFormProCalculations::getFields($calculations,$formId); $script .= "\n".'RSFormPro.Calculations.addEvents('.$formId.',rsfpCalculationFields'.$formId.');'; $script .= "\n" . 'window.addEventListener(\'DOMContentLoaded\', rsfp_Calculations' . $formId . ');'; RSFormProAssets::addScriptDeclaration($script); } eval($form->ScriptDisplay); //Trigger Event - onBeforeFormDisplay $mainframe->triggerEvent('onRsformFrontendBeforeFormDisplay', array(array('formLayout'=>&$formLayout,'formId'=>$formId,'formLayoutName' => $form->FormLayoutName))); return $formLayout; } public static function showThankYouMessage($formId) { $mainframe = Factory::getApplication(); $db = Factory::getDbo(); $doc = Factory::getDocument(); $session = Factory::getSession(); $formId = (int) $formId; $query = $db->getQuery(true) ->select($db->qn(array('ScrollToThankYou', 'ThankYouMessagePopUp', 'FormLayoutName'))) ->from($db->qn('#__rsform_forms')) ->where($db->qn('FormId') . ' = ' . $db->q($formId)); $form = $db->setQuery($query)->loadObject(); RSFormProAssets::addStyleSheet(HTMLHelper::_('stylesheet', 'com_rsform/front.css', array('pathOnly' => true, 'relative' => true))); if ($doc->getDirection() == 'rtl') { RSFormProAssets::addStyleSheet(HTMLHelper::_('stylesheet', 'com_rsform/front-rtl.css', array('pathOnly' => true, 'relative' => true))); } $formparams = $session->get('com_rsform.formparams.formId'.$formId); $output = isset($formparams->thankYouMessage) ? base64_decode($formparams->thankYouMessage) : ''; if ($formparams->loadLayoutFramework) { $layoutName = $form->FormLayoutName; if (file_exists(__DIR__ . '/formlayouts/' . $layoutName . '.php')) { require_once __DIR__ . '/formlayouts/' . $layoutName . '.php'; $class = 'RSFormProFormLayout' . $layoutName; if (class_exists($class)) { $layout = new $class(); if (is_callable(array($layout, 'loadFramework'))) { $layout->loadFramework(); } } } } // Clear $session->clear('com_rsform.formparams.formId'.$formId); //Trigger Event - onAfterShowThankyouMessage $mainframe->triggerEvent('onRsformFrontendAfterShowThankyouMessage', array(array('output'=>&$output,'formId'=>&$formId))); if ($form->ScrollToThankYou) { // scroll the window to the Thank You Message RSFormProAssets::addScript(HTMLHelper::_('script', 'com_rsform/script.js', array('pathOnly' => true, 'relative' => true))); RSFormProAssets::addScriptDeclaration("RSFormProUtils.addEvent(window, 'load', function(){ RSFormPro.scrollToElement(document.getElementById('rsfp-thankyou-scroll{$formId}')); });"); } if ($form->ThankYouMessagePopUp && !$form->ScrollToThankYou) { RSFormProAssets::addScript(HTMLHelper::_('script', 'com_rsform/script.js', array('pathOnly' => true, 'relative' => true))); RSFormProAssets::addScriptDeclaration("RSFormProUtils.addEvent(window, 'load', function(){ RSFormPro.showThankYouPopup(document.getElementById('rsfp-thankyou-popup-container{$formId}')); });"); } return $output; } public static function processForm($formId) { $invalid = array(); $mainframe = Factory::getApplication(); $db = Factory::getDbo(); $formId = (int) $formId; // Let's check the token if (RSFormProHelper::getConfig('use_csrf') && !Session::checkToken()) { $invalid[] = true; $mainframe->enqueueMessage(Text::_('JINVALID_TOKEN_NOTICE'), 'warning'); return $invalid; } $form = RSFormProHelper::getForm($formId); $lang = RSFormProHelper::getCurrentLanguage(); $translations = RSFormProHelper::getTranslations('forms', $formId, $lang); if ($translations) { foreach ($translations as $field => $value) { if (isset($form->{$field})) { $form->{$field} = $value; } } } $invalid = RSFormProHelper::validateForm($formId); $post = Factory::getApplication()->input->post->get('form', array(), 'array'); //Trigger Event - onBeforeFormValidation $mainframe->triggerEvent('onRsformFrontendBeforeFormValidation', array(array('invalid'=>&$invalid, 'formId' => $formId, 'post' => &$post))); $_POST['form'] = $post; $isAjax = false; eval($form->ScriptProcess); if (!empty($invalid)) { return $invalid; } $post = $_POST['form']; //Trigger Event - onBeforeFormProcess $mainframe->triggerEvent('onRsformFrontendBeforeFormProcess', array(array('post' => &$post))); if (empty($invalid)) { $user = Factory::getUser(); $SubmissionHash = ApplicationHelper::getHash(UserHelper::genRandomPassword()); // Add to db (submission) $date = Factory::getDate(); $submission = (object) array( 'FormId' => $formId, 'DateSubmitted' => $date->toSql(), 'UserIp' => IpHelper::getIp(), 'Username' => $user->username, 'UserId' => $user->id, 'Lang' => RSFormProHelper::getCurrentLanguage(), 'confirmed' => $form->ConfirmSubmission ? 0 : 1, 'ConfirmedIP' => '', 'ConfirmedDate' => null, 'SubmissionHash' => $SubmissionHash ); $db->insertObject('#__rsform_submissions', $submission, 'SubmissionId'); $SubmissionId = $submission->SubmissionId; // get the form components $formComponents = RSFormProHelper::getComponents($formId); // check if files have been submitted $files = Factory::getApplication()->input->files->get('form', null, 'raw'); foreach ($formComponents as $component) { $type = (string) preg_replace('/[^A-Z0-9_\.-]/i', '', $component->ComponentTypeName); $type = ltrim($type, '.'); $fieldTypeClass = 'RSFormProField' . $type; $fieldTypeFile = __DIR__ . '/fields/' . strtolower($type) . '.php'; if (file_exists($fieldTypeFile)) { // If class doesn't exist, load the file if (!class_exists($fieldTypeClass)) { require_once $fieldTypeFile; } $config = array( 'formId' => $formId, 'componentId' => $component->ComponentId, 'data' => RSFormProHelper::getComponentProperties($component->ComponentId) ); // access the field class $field = new $fieldTypeClass($config); $field->processBeforeStore($SubmissionId, $post, $files); } } //Trigger Event - onBeforeStoreSubmissions $mainframe->triggerEvent('onRsformFrontendBeforeStoreSubmissions', array(array('formId'=>$formId,'post'=>&$post,'SubmissionId'=>$SubmissionId))); // Add to db (values) foreach ($post as $key => $val) { $val = is_array($val) ? implode("\n", $val) : $val; $val = RSFormProHelper::stripJava($val); $object = (object) array( 'SubmissionId' => $SubmissionId, 'FormId' => $formId, 'FieldName' => $key, 'FieldValue' => $val ); $db->insertObject('#__rsform_submission_values', $object); } //Trigger Event - onAfterStoreSubmissions $mainframe->triggerEvent('onRsformFrontendAfterStoreSubmissions', array(array('SubmissionId'=>$SubmissionId, 'formId'=>$formId))); // Send emails list($replace, $with) = RSFormProHelper::sendSubmissionEmails($SubmissionId); // RSForm! Pro Scripting - Thank You Message // performance check if (strpos($form->Thankyou, '{/if}') !== false) { require_once __DIR__.'/scripting.php'; RSFormProScripting::compile($form->Thankyou, $replace, $with); } // Thank You Message $thankYouMessage = str_replace($replace, $with, $form->Thankyou); $form->ReturnUrl = str_replace($replace, $with, $form->ReturnUrl); // Set redirect link $u = RSFormProHelper::getURL(); // Create the Continue button $continueButton = ''; if ($form->ShowContinue) { // Create goto link $goto = 'document.location.reload(true);'; if (!empty($form->ReturnUrl)) $goto = "document.location='".addslashes($form->ReturnUrl)."';"; // Continue button $continueButtonLabel = Text::_('RSFP_THANKYOU_BUTTON'); $continueButton = '<input type="button" class="rsform-submit-button btn btn-primary" name="continue" value="'.Text::_('RSFP_THANKYOU_BUTTON').'" onclick="'.$goto.'"/>'; if (strpos($continueButtonLabel, 'input')) { $continueButton = Text::sprintf('RSFP_THANKYOU_BUTTON',$goto); } else { $layoutName = $form->FormLayoutName; if (file_exists(__DIR__.'/formlayouts/'.$layoutName.'.php')) { require_once __DIR__.'/formlayouts/'.$layoutName.'.php'; $class = 'RSFormProFormLayout'.$layoutName; if (class_exists($class)) { $layout = new $class(); $loadLayoutFramework = $form->LoadFormLayoutFramework; if (is_callable(array($layout, 'generateButton'))) { $continueButton = $layout->generateButton($goto); } } } } } // get mappings data $mappings = RSFormProHelper::getMappings($formId); // get Post to another location $silentPost = RSFormProHelper::getSilentPost($formId); if ($form->Keepdata && !$form->KeepIP) { $query = $db->getQuery(true) ->update($db->qn('#__rsform_submissions')) ->set($db->qn('UserIp') . ' = ' . $db->q('0.0.0.0')) ->where($db->qn('SubmissionId') . ' = ' . $db->q($SubmissionId)); $db->setQuery($query)->execute(); } if (!$form->Keepdata) { require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php'; register_shutdown_function(array('RSFormProSubmissionsHelper', 'deleteSubmissions'), $SubmissionId); } eval($form->ScriptProcess2); if ($form->ScrollToThankYou) { $scrollToElement = '<div id="rsfp-thankyou-scroll' . $formId . '"></div>'; $thankYouMessage = $scrollToElement . $thankYouMessage . $continueButton; } else if ($form->ThankYouMessagePopUp && !$form->ScrollToThankYou) { // Create goto link $gotoLink = ''; if ($form->ShowContinue) { if (!empty($form->ReturnUrl)) { $gotoLink = $form->ReturnUrl; } } $gotoLink = '<input type="hidden" id="rsfp-thankyou-popup-return-link" value="'.RSFormProHelper::htmlEscape($gotoLink).'"/>'; $thankYouMessage = '<div id="rsfp-thankyou-popup-container'.$formId.'">'.$thankYouMessage.$continueButton.$gotoLink.'</div>'; } else { $thankYouMessage .= $continueButton; } // Mappings $mainframe->triggerEvent('onRsformBeforeMappings', array('SubmissionId' => $SubmissionId, 'formId' => $formId, 'mappings' => &$mappings)); RSFormProHelper::doMappings($mappings, array('replace' => $replace, 'with' => $with)); $mainframe->triggerEvent('onRsformBeforeSilentPost', array('SubmissionId' => $SubmissionId, 'formId' => $formId, 'silentPost' => &$silentPost)); RSFormProHelper::doSilentPost($silentPost, array('replace' => $replace, 'with' => $with, 'post' => $post)); // Get session object $session = Factory::getSession(); // Populate data $formparams = (object) array( 'loadLayoutFramework' => !empty($loadLayoutFramework) ? 1 : 0, 'submissionId' => $SubmissionId, 'redirectUrl' => !$form->ShowThankyou && $form->ReturnUrl ? $form->ReturnUrl : $u, 'showSystemMessage' => $form->ShowSystemMessage ); // Store the Thank You Message if option is set if ($form->ShowThankyou) { $formparams->thankYouMessage = base64_encode($thankYouMessage); } // Store session data $session->set('com_rsform.formparams.formId'.$formId, $formparams); // Trigger - After form process $mainframe->triggerEvent('onRsformFrontendAfterFormProcess', array(array('SubmissionId' => $SubmissionId, 'formId' => $formId))); // If we didn't get redirected through a plugin, mark form as processed to display Thank You Message on next page load $formparams->formProcessed = true; // Store new session data $session->set('com_rsform.formparams.formId'.$formId, $formparams); if (!$form->ShowThankyou && $form->ReturnUrl) { $u = $form->ReturnUrl; } $mainframe->triggerEvent('onRsformBeforeReturnUrl', array($formId, $SubmissionId, $form, $u)); $mainframe->redirect($u); } return false; } public static function getPreviewFields() { $formId = Factory::getApplication()->input->getInt('formId'); $list[] = array( 'value' => '', 'text' => 'PLEASE_SELECT_FIELD' ); if ($components = RSFormProHelper::getComponents($formId)) { foreach ($components as $component) { if (!in_array($component->ComponentTypeId, array(RSFORM_FIELD_PREVIEW, RSFORM_FIELD_BUTTON, RSFORM_FIELD_SUBMITBUTTON, RSFORM_FIELD_PAGEBREAK, RSFORM_FIELD_TICKET, RSFORM_FIELD_HIDDEN, RSFORM_FIELD_FREETEXT)) && !in_array($component->ComponentTypeId, RSFormProHelper::$captchaFields)) { $list[] = array( 'value' => $component->ComponentId, 'text' => ' ' . $component->name // space in front so that this field doesn't get translated ); } } } return self::createList($list); } public static function getComponents($formId) { static $components = array(); if (!isset($components[$formId])) { $db = Factory::getDbo(); $query = $db->getQuery(true); // need to get the component type name so that we can load the specific class $query->clear() ->select($db->qn('p.PropertyValue', 'name')) ->select($db->qn('c.ComponentId')) ->select($db->qn('c.ComponentTypeId')) ->select($db->qn('ct.ComponentTypeName')) ->select($db->qn('c.Order')) ->from($db->qn('#__rsform_properties', 'p')) ->join('LEFT', $db->qn('#__rsform_components', 'c').' ON ('.$db->qn('c.ComponentId').' = '.$db->qn('p.ComponentId').')') ->join('LEFT', $db->qn('#__rsform_component_types', 'ct').' ON ('.$db->qn('ct.ComponentTypeId').' = '.$db->qn('c.ComponentTypeId').')') ->where($db->qn('c.FormId') . ' = ' . $db->q($formId)) ->where($db->qn('p.PropertyName') . ' = ' . $db->q('NAME')) ->where($db->qn('c.Published') . ' = ' . $db->q('1')) ->order($db->qn('c.Order') . ' ASC'); $db->setQuery($query); $components[$formId] = $db->loadObjectList(); } return $components[$formId]; } public static function getURL() { $uri = Uri::getInstance(); return $uri->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment')); } public static function verifyChecked($componentName, $value, $post) { if (isset($post[$componentName])) { if (is_array($post[$componentName]) && in_array($value, $post[$componentName])) return 1; if (!is_array($post[$componentName]) && $post[$componentName] == $value) return 1; return 0; } return 0; } /** * @param $formId * @param string $validationType * @param int $SubmissionId * @return array * @throws Exception */ public static function validateForm($formId, $validationType = 'form', $SubmissionId = 0) { $db = Factory::getDbo(); $invalid = array(); $formId = (int) $formId; $post = Factory::getApplication()->input->post->get('form', array(), 'array'); if ($validationType == 'form') { $form = RSFormProHelper::getForm($formId); $_POST['form'] = $post; eval($form->ScriptBeforeValidation); $post = $_POST['form']; Factory::getApplication()->input->post->set('form', $post); } $query = $db->getQuery(true); $query->select($db->qn('c.ComponentId')) ->select($db->qn('c.ComponentTypeId')) ->select($db->qn('ct.ComponentTypeName')) ->from($db->qn('#__rsform_components', 'c')) ->join('left', $db->qn('#__rsform_component_types', 'ct') . ' ON (' . $db->qn('c.ComponentTypeId') . ' = ' . $db->qn('ct.ComponentTypeId') . ')') ->where($db->qn('FormId').'='.$db->q($formId)) ->where($db->qn('Published').'='.$db->q(1)) ->order($db->qn('Order').' '.$db->escape('asc')); // if $type is directory, we need to validate the fields that are editable in the directory if ($validationType == 'directory') { $subquery = $db->getQuery(true); $subquery->select($db->qn('componentId')) ->from($db->qn('#__rsform_directory_fields')) ->where($db->qn('formId').'='.$db->q($formId)) ->where($db->qn('editable').'='.$db->q(1)); $query->where($db->qn('ComponentId').' IN ('.(string) $subquery.')'); } $db->setQuery($query); if ($components = $db->loadObjectList('ComponentId')) { $componentIds = array_keys($components); // load properties $all_data = RSFormProHelper::getComponentProperties($componentIds); if (empty($all_data)) { return $invalid; } // load conditions if ($conditions = RSFormProHelper::getConditions($formId)) { foreach ($conditions as $condition) { if ($condition->details) { $condition_vars = array(); foreach ($condition->details as $detail) { $isChecked = RSFormProHelper::verifyChecked($detail->ComponentName, $detail->value, $post); $condition_vars[] = $detail->operator == 'is' ? $isChecked : !$isChecked; } // this check is performed like this // 'all' must be true (ie. no 0s in the array); 'any' can be true (ie. one value of 1 in the array will do) $result = $condition->condition == 'all' ? !in_array(0, $condition_vars) : in_array(1, $condition_vars); // if the item is hidden, no need to validate it if (($condition->action == 'show' && !$result) || ($condition->action == 'hide' && $result)) { foreach ($components as $i => $component) { if (in_array($component->ComponentId, $condition->component_id)) { // ... just remove it from the components array unset($components[$i]); } } } } } } // load validation rules $validations = array_flip(RSFormProHelper::getValidationRules(true)); $validationClass = RSFormProHelper::getValidationClass(); // validate through components foreach ($components as $component) { $data = $all_data[$component->ComponentId]; $required = !empty($data['REQUIRED']) && $data['REQUIRED'] == 'YES'; $validationRule = !empty($data['VALIDATIONRULE']) ? $data['VALIDATIONRULE'] : ''; $type = (string) preg_replace('/[^A-Z0-9_\.-]/i', '', (string) $component->ComponentTypeName); $type = ltrim($type, '.'); $fieldTypeClass = 'RSFormProField' . $type; $fieldTypeFile = __DIR__ . '/fields/' . strtolower($type) . '.php'; if (file_exists($fieldTypeFile)) { // If class doesn't exist, load the file if (!class_exists($fieldTypeClass)) { require_once $fieldTypeFile; } $config = array( 'formId' => $formId, 'componentId' => $component->ComponentId, 'data' => $data, 'value' => $post ); // access the field class $field = new $fieldTypeClass($config); if (is_callable(array($field, 'processValidation'))) { if (!$field->processValidation($validationType, $SubmissionId)) { $invalid[] = $data['componentId']; } continue; } } // flag to check if we need to run the validation functions $runValidations = false; // Must have a value if it's required if ($required) { // Field is missing from request if (!isset($post[$data['NAME']])) { $invalid[] = $data['componentId']; continue; } // For convenience $value = $post[$data['NAME']]; // If it's an array, implode it if (is_array($value)) { $value = implode('', $value); } // Remove unwanted spaces $value = trim($value); // Field has no length if (!strlen($value)) { $invalid[] = $data['componentId']; continue; } $runValidations = true; } else { // not required, perform checks only when something is selected // we have a value, make sure it's the correct one if (isset($post[$data['NAME']]) && !is_array($post[$data['NAME']]) && strlen(trim($post[$data['NAME']]))) { $runValidations = true; } } if ($runValidations && isset($validations[$validationRule]) && !call_user_func(array($validationClass, $validationRule), $post[$data['NAME']], isset($data['VALIDATIONEXTRA']) ? $data['VALIDATIONEXTRA'] : '', $data)) { $invalid[] = $data['componentId']; continue; } } } return $invalid; } public static function addClass(&$attributes, $className) { if (preg_match('#class="(.*?)"#is', $attributes, $matches)) $attributes = str_replace($matches[0], str_replace($matches[1], $matches[1].' '.$className, $matches[0]), $attributes); else $attributes .= ' class="'.$className.'"'; return $attributes; } public static function addOnClick(&$attributes, $onClick) { if (preg_match('#onclick="(.*?)"#is', $attributes, $matches)) $attributes = str_replace($matches[0], str_replace($matches[1], $matches[1].'; '.$onClick, $matches[0]), $attributes); else $attributes .= ' onclick="'.$onClick.'"'; return $attributes; } public static function stripJava($val) { $filtering = RSFormProHelper::getConfig('global.filtering'); switch ($filtering) { default: case 'joomla': return ComponentHelper::filterText($val); break; case 'rsform': // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed // this prevents some character re-spacing such as <java\0script> // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs $val = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $val); // straight replacements, the user should never need these since they're normal characters // this prevents like <IMG SRC=@avascript:alert('XSS')> $search = 'abcdefghijklmnopqrstuvwxyz'; $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $search .= '1234567890!@#$%^&*()'; $search .= '~`";:?+/={}[]-_|\'\\'; for ($i = 0; $i < strlen($search); $i++) { // ;? matches the ;, which is optional // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars // @ @ search for the hex values $val = preg_replace('/(&#[x|X]0{0,8}'.dechex(ord($search[$i])).';?)/i', $search[$i], $val); // with a ; // @ @ 0{0,7} matches '0' zero to seven times $val = preg_replace('/(�{0,8}'.ord($search[$i]).';?)/', $search[$i], $val); // with a ; } // now the only remaining whitespace attacks are \t, \n, and \r // ([ \t\r\n]+)? $ra1 = Array('\/([ \t\r\n]+)?javascript', '\/([ \t\r\n]+)?vbscript', ':([ \t\r\n]+)?expression', '<([ \t\r\n]+)?applet', '<([ \t\r\n]+)?meta', '<([ \t\r\n]+)?xml', '<([ \t\r\n]+)?blink', '<([ \t\r\n]+)?link', '<([ \t\r\n]+)?style', '<([ \t\r\n]+)?script', '<([ \t\r\n]+)?embed', '<([ \t\r\n]+)?object', '<([ \t\r\n]+)?iframe', '<([ \t\r\n]+)?frame', '<([ \t\r\n]+)?frameset', '<([ \t\r\n]+)?ilayer', '<([ \t\r\n]+)?layer', '<([ \t\r\n]+)?bgsound', '<([ \t\r\n]+)?title', '<([ \t\r\n]+)?base'); $ra2 = Array('onabort([ \t\r\n]+)?=', 'onactivate([ \t\r\n]+)?=', 'onafterprint([ \t\r\n]+)?=', 'onafterupdate([ \t\r\n]+)?=', 'onbeforeactivate([ \t\r\n]+)?=', 'onbeforecopy([ \t\r\n]+)?=', 'onbeforecut([ \t\r\n]+)?=', 'onbeforedeactivate([ \t\r\n]+)?=', 'onbeforeeditfocus([ \t\r\n]+)?=', 'onbeforepaste([ \t\r\n]+)?=', 'onbeforeprint([ \t\r\n]+)?=', 'onbeforeunload([ \t\r\n]+)?=', 'onbeforeupdate([ \t\r\n]+)?=', 'onblur([ \t\r\n]+)?=', 'onbounce([ \t\r\n]+)?=', 'oncellchange([ \t\r\n]+)?=', 'onchange([ \t\r\n]+)?=', 'onclick([ \t\r\n]+)?=', 'oncontextmenu([ \t\r\n]+)?=', 'oncontrolselect([ \t\r\n]+)?=', 'oncopy([ \t\r\n]+)?=', 'oncut([ \t\r\n]+)?=', 'ondataavailable([ \t\r\n]+)?=', 'ondatasetchanged([ \t\r\n]+)?=', 'ondatasetcomplete([ \t\r\n]+)?=', 'ondblclick([ \t\r\n]+)?=', 'ondeactivate([ \t\r\n]+)?=', 'ondrag([ \t\r\n]+)?=', 'ondragend([ \t\r\n]+)?=', 'ondragenter([ \t\r\n]+)?=', 'ondragleave([ \t\r\n]+)?=', 'ondragover([ \t\r\n]+)?=', 'ondragstart([ \t\r\n]+)?=', 'ondrop([ \t\r\n]+)?=', 'onerror([ \t\r\n]+)?=', 'onerrorupdate([ \t\r\n]+)?=', 'onfilterchange([ \t\r\n]+)?=', 'onfinish([ \t\r\n]+)?=', 'onfocus([ \t\r\n]+)?=', 'onfocusin([ \t\r\n]+)?=', 'onfocusout([ \t\r\n]+)?=', 'onhelp([ \t\r\n]+)?=', 'onkeydown([ \t\r\n]+)?=', 'onkeypress([ \t\r\n]+)?=', 'onkeyup([ \t\r\n]+)?=', 'onlayoutcomplete([ \t\r\n]+)?=', 'onload([ \t\r\n]+)?=', 'onlosecapture([ \t\r\n]+)?=', 'onmousedown([ \t\r\n]+)?=', 'onmouseenter([ \t\r\n]+)?=', 'onmouseleave([ \t\r\n]+)?=', 'onmousemove([ \t\r\n]+)?=', 'onmouseout([ \t\r\n]+)?=', 'onmouseover([ \t\r\n]+)?=', 'onmouseup([ \t\r\n]+)?=', 'onmousewheel([ \t\r\n]+)?=', 'onmove([ \t\r\n]+)?=', 'onmoveend([ \t\r\n]+)?=', 'onmovestart([ \t\r\n]+)?=', 'onpaste([ \t\r\n]+)?=', 'onpropertychange([ \t\r\n]+)?=', 'onreadystatechange([ \t\r\n]+)?=', 'onreset([ \t\r\n]+)?=', 'onresize([ \t\r\n]+)?=', 'onresizeend([ \t\r\n]+)?=', 'onresizestart([ \t\r\n]+)?=', 'onrowenter([ \t\r\n]+)?=', 'onrowexit([ \t\r\n]+)?=', 'onrowsdelete([ \t\r\n]+)?=', 'onrowsinserted([ \t\r\n]+)?=', 'onscroll([ \t\r\n]+)?=', 'onselect([ \t\r\n]+)?=', 'onselectionchange([ \t\r\n]+)?=', 'onselectstart([ \t\r\n]+)?=', 'onstart([ \t\r\n]+)?=', 'onstop([ \t\r\n]+)?=', 'onsubmit([ \t\r\n]+)?=', 'onunload([ \t\r\n]+)?=', 'style([ \t\r\n]+)?='); $ra = array_merge($ra1, $ra2); foreach ($ra as $tag) { $pattern = '#'.$tag.'#i'; preg_match_all($pattern, $val, $matches); foreach ($matches[0] as $match) $val = str_replace($match, substr($match, 0, 2).'<x>'.substr($match, 2), $val); } return $val; break; case 'none': return $val; break; } } public static function getTranslations($reference, $formId, $lang, $select = 'value') { static $selections = array(); static $langs = array(); $formId = (int) $formId; $db = Factory::getDbo(); $query = $db->getQuery(true); // Do not grab translations if the form is in the same language as the translation. if (!isset($langs[$formId])) { $query->clear() ->select($db->qn('Lang')) ->from('#__rsform_forms') ->where($db->qn('FormId').' = '.$db->q($formId)); $db->setQuery($query); $langs[$formId] = $db->loadResult(); } $disable_multilanguage = RSFormProHelper::getConfig('global.disable_multilanguage'); $default_language = RSFormProHelper::getConfig('global.default_language'); if ($disable_multilanguage && $default_language == 'en-GB') { return false; } elseif (!$disable_multilanguage && $langs[$formId] == $lang) { return false; } elseif ($disable_multilanguage && $default_language != 'en-GB') { $lang = $default_language; } // build the reference hash $hash = md5($reference.$formId.$lang.$select); if (!isset($selections[$hash])) { $selections[$hash] = array(); // build the proper SQL Query $query->clear() ->select('*') ->from('#__rsform_translations') ->where($db->qn('form_id').' = '.$db->q($formId)) ->where($db->qn('lang_code').' = '.$db->q($lang)) ->where($db->qn('reference').' = '.$db->q($reference)); $db->setQuery($query); if ($results = $db->loadObjectList()) { foreach ($results as $result) { $selections[$hash][$result->reference_id] = ($select == '*') ? $result : (isset($result->$select) ? $result->$select : false); } } } return $selections[$hash]; } public static function getTranslatableProperties() { static $translatable; if (!$translatable) { $translatable = array('LABEL', 'RESETLABEL', 'PREVBUTTON', 'NEXTBUTTON', 'CAPTION', 'DESCRIPTION', 'VALIDATIONMESSAGE', 'DEFAULTVALUE', 'ITEMS', 'TEXT', 'REFRESHTEXT', 'DISPLAYPROGRESSMSG', 'WIRE', 'SHOWDAYPLEASE', 'SHOWMONTHPLEASE', 'SHOWYEARPLEASE', 'POPUPLABEL', 'PLACEHOLDER'); Factory::getApplication()->triggerEvent('onRsformBackendGetTranslatableProperties', array(&$translatable)); } return $translatable; } public static function translateIcon() { if (RSFormProHelper::getConfig('global.disable_multilanguage')) { return ''; } return '<span class="rsficon rsficon-flag fieldHasTooltip rsfp-translatable" data-title="' . Text::_('RSFP_TRANSLATABLE_TITLE') . '" data-content="' . Text::_('RSFP_THIS_ITEM_IS_TRANSLATABLE') . '"></span>'; } public static function mappingsColumns($config, $method, $row = null) { require_once __DIR__.'/mappings.php'; return RSFormProMappings::mappingsColumns($config, $method, $row); } public static function getMappingQuery($row) { require_once __DIR__.'/mappings.php'; return RSFormProMappings::getMappingQuery($row); } public static function escapeSql(&$value) { static $db; if (!$db) { $db = Factory::getDbo(); } $value = $db->escape($value); } public static function sendMail($from, $fromname, $recipient, $subject, $body, $mode = 0, $cc = null, $bcc = null, $attachment = null, $replyto = null, $replytoname = null, $recipientname = '', $formId = null) { static $initLogging; static $hasLogging; static $verboseLogging; if (!$initLogging) { $initLogging = true; $hasLogging = RSFormProHelper::getConfig('logging'); $verboseLogging = RSFormProHelper::getConfig('logging_verbose'); Log::addLogger(array('text_file' => 'rsform_email_log.php'), Log::ALL, array('com_rsform')); } try { // Get a Mail instance $mail = Factory::getMailer(); // Allow this to be overridden Factory::getApplication()->triggerEvent('onRsformCreateMailer', array(array( 'mailer' => &$mail, 'from' => &$from, 'fromname' => &$fromname, 'recipient' => &$recipient, 'subject' => &$subject, 'body' => &$body, 'mode' => &$mode, 'cc' => &$cc, 'bcc' => &$bcc, 'attachment' => &$attachment, 'replyto' => &$replyto, 'replytoname' => &$replytoname, 'formId' => $formId ))); $mail->ClearReplyTos(); /** * Apparently there are 2 issues: * 1) Some hosts use these in disable_functions and PHPMailer calls them when specifying $this->Sender * 2) Some hosts need to specify $this->Sender otherwise Return-Path gets set to whatever the server address is and fails SPF checks * 3) Some hosts DO NOT ALLOW $this->Sender to be specified and throw a "Could not instantiate mail function" error unless you guess the correct email address that's allowed - in this case leaving $from and $fromname blank will not touch the inherited properties from the Factory::createMailer() and should work **/ if (function_exists('escapeshellcmd') && is_callable('escapeshellcmd') && function_exists('escapeshellarg') && is_callable('escapeshellarg')) { $autoSender = true; } else { $autoSender = false; } if ($from) { $mail->setSender(array($from, $fromname, $autoSender)); } $mail->setSubject($subject); $mail->setBody($body); // Are we sending the email as HTML? if ($mode) { $mail->IsHTML(true); $textBody = str_ireplace(array('<p>', '<br>', '<br/>', '<br />'), "\n", $body); $mail->AltBody = strip_tags($textBody); } // Some cleanup foreach (array('recipient', 'cc', 'bcc') as $array) { if (is_array($$array)) { // Remove empty values $$array = array_filter($$array); // Remove whitespace $$array = array_filter(array_map('trim', $$array)); // If it's not an email, remove it $newArray = array(); foreach ($$array as $item) { try { if (MailHelper::isEmailAddress($item)) { $newArray[] = $item; } } catch (Exception $e) { } } $$array = $newArray; } } $mail->addRecipient($recipient, $recipientname); $mail->addCC($cc); $mail->addBCC($bcc); // If we leave $type = '' then PHPMailer will try to auto-detect the mime type. if ($attachment) { $mail->addAttachment($attachment, '', 'base64', ''); } // Take care of reply email addresses $mail->ClearReplyTos(); if ($replyto || $replytoname) { if ($replyto === null) { $replyto = array(); } if ($replytoname === null) { $replytoname = array(); } if (!is_array($replyto)) { $replyto = explode(',', $replyto); } if (!is_array($replytoname)) { $replytoname = explode(',', $replytoname); } foreach ($replyto as $i => $replyToEmail) { $replyToEmail = trim($replyToEmail); // Remove empty lines or if it's not an email address try { if (empty($replyToEmail) || !MailHelper::isEmailAddress($replyToEmail)) { continue; } } catch (Exception $e) { continue; } $mail->addReplyTo($replyToEmail, isset($replytoname[$i]) ? trim($replytoname[$i]) : ''); } } if ($hasLogging) { try { Log::add(sprintf('Form ID #%d Sending email from %s to %s', $formId, (string) $from, is_array($recipient) ? implode(', ', array_values($recipient)) : (string) $recipient), Log::INFO, 'com_rsform'); if ($verboseLogging) { Log::add(sprintf('Arguments:\n%s', print_r(func_get_args(), true)), Log::DEBUG, 'com_rsform'); } } catch (Exception $logException) { Factory::getApplication()->enqueueMessage($logException->getMessage(), 'warning'); } } return $mail->Send(); } catch (Exception $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning'); if ($hasLogging) { try { Log::add(sprintf('Form ID #%d Error sending email from %s to %s - message returned is %s', $formId, (string) $from, is_array($recipient) ? implode(', ', array_values($recipient)) : (string) $recipient, $e->getMessage()), Log::ERROR, 'com_rsform'); } catch (Exception $logException) { Factory::getApplication()->enqueueMessage($logException->getMessage(), 'warning'); return false; } } return false; } } public static function renderHTML() { $args = func_get_args(); if ($args[0] == 'select.booleanlist') { // 0 - type // 1 - name // 2 - additional // 3 - value // 4 - yes // 5 - no // get the radio element $radio = FormHelper::loadFieldType('radio'); // setup the properties $name = htmlspecialchars($args[1], ENT_COMPAT, 'utf-8'); $additional = isset($args[2]) ? (string) $args[2] : ''; $value = $args[3]; $yes = isset($args[4]) ? htmlspecialchars($args[4], ENT_COMPAT, 'utf-8') : 'JYES'; $no = isset($args[5]) ? htmlspecialchars($args[5], ENT_COMPAT, 'utf-8') : 'JNO'; static $form; if (is_null($form)) { $form = new Form('rsformradioform'); } $radio->setForm($form); // prepare the xml $element = new SimpleXMLElement('<field name="'.$name.'" type="radio" class="btn-group btn-group-yesno"><option '.$additional.' value="0">'.$no.'</option><option '.$additional.' value="1">'.$yes.'</option></field>'); // run $radio->setup($element, $value); return $radio->input; } } public static function getAllDirectoryFields($formId) { $db = Factory::getDbo(); static $cache = array(); if (!isset($cache[$formId])) { $excludedFields = array( RSFORM_FIELD_BUTTON, RSFORM_FIELD_CAPTCHA, RSFORM_FIELD_HASHCASH, RSFORM_FIELD_SUBMITBUTTON, RSFORM_FIELD_BUTTON, RSFORM_FIELD_PAGEBREAK, RSFORM_FIELD_PREVIEW ); Factory::getApplication()->triggerEvent('onRsformBackendGetDirectoryExcludedFields', array(&$excludedFields, $formId)); $query = $db->getQuery(true); $query->select($db->qn('p.PropertyValue','FieldName')) ->select($db->qn('p.ComponentId','FieldId')) ->select($db->qn('c.ComponentTypeId','FieldType')) ->from($db->qn('#__rsform_components','c')) ->join('left', $db->qn('#__rsform_properties','p').' ON '.$db->qn('c.ComponentId').' = '.$db->qn('p.ComponentId')) ->where($db->qn('c.FormId').'='.$db->q($formId)) ->where($db->qn('p.PropertyName').' = '.$db->q('NAME')) ->where($db->qn('c.ComponentTypeId').' NOT IN (' . implode(',', $excludedFields) . ')') ->where($db->qn('c.Published').'='.$db->q(1)) ->order($db->qn('c.Order').' '.$db->escape('asc')); $db->setQuery($query); $cache[$formId] = $db->loadObjectList('FieldId'); $data = RSFormProHelper::getComponentProperties(array_keys($cache[$formId])); foreach ($cache[$formId] as $FieldId => $field) { $properties =& $data[$FieldId]; $caption = isset($properties['CAPTION']) ? $properties['CAPTION'] : ''; $cache[$formId][$FieldId]->FieldCaption = $caption; } // Add #__rsform_submissions headers. $headers = self::getDirectoryStaticHeaders(); $form = RSFormProHelper::getForm($formId); if (!$form->ConfirmSubmission) { unset($headers[RSFORM_STATIC_CONFIRMED], $headers[RSFORM_STATIC_CONFIRMEDIP], $headers[RSFORM_STATIC_CONFIRMEDDATE]); } foreach ($headers as $index => $header) { $cache[$formId][$index] = (object) array( 'FieldName' => $header, 'FieldId' => $index, 'FieldType' => 0, 'FieldCaption' => Text::_('RSFP_'.$header) ); } Factory::getApplication()->triggerEvent('onRsformBackendGetAllDirectoryFields', array(&$cache[$formId], $formId)); } return $cache[$formId]; } public static function getDirectoryStaticHeaders() { return array( RSFORM_STATIC_DATESUBMITTED => 'DateSubmitted', RSFORM_STATIC_USERIP => 'UserIp', RSFORM_STATIC_USERNAME => 'Username', RSFORM_STATIC_USERID => 'UserId', RSFORM_STATIC_LANGUAGE => 'Lang', RSFORM_STATIC_CONFIRMED => 'confirmed', RSFORM_STATIC_SUBMISSIONID => 'SubmissionId', RSFORM_STATIC_CONFIRMEDIP => 'ConfirmedIp', RSFORM_STATIC_CONFIRMEDDATE => 'ConfirmedDate' ); } public static function getDirectoryFields($formId) { static $cache = array(); if (!isset($cache[$formId])) { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__rsform_directory_fields')) ->where($db->qn('formId') . ' = ' . $db->q($formId)) ->order($db->qn('ordering') . ' ' . $db->escape('ASC')); $db->setQuery($query); $currentFields = $db->loadObjectList('componentId'); $allFields = self::getAllDirectoryFields($formId); if ($diffFields = array_diff(array_keys($currentFields), array_keys($allFields))) { foreach ($diffFields as $fieldId) { unset($currentFields[$fieldId]); } } foreach ($allFields as $field) { // Hidden fields don't have a caption if (in_array($field->FieldType, array(RSFORM_FIELD_HIDDEN, RSFORM_FIELD_TICKET, RSFORM_FIELD_FREETEXT))) { $field->FieldCaption = $field->FieldName; } // Submission ID is not editable. if ($field->FieldId == RSFORM_STATIC_SUBMISSIONID) { $allowEdit = false; } else { $allowEdit = true; } if (!isset($currentFields[$field->FieldId])) { // field has been added after, add it to the end of the list $currentFields[] = (object) array( 'FieldId' => $field->FieldId, 'FieldName' => $field->FieldName, 'FieldType' => $field->FieldType, 'FieldCaption' => $field->FieldCaption, 'formId' => $formId, 'componentId' => $field->FieldId, 'viewable' => 0, 'searchable' => 0, 'editable' => 0, 'indetails' => 0, 'incsv' => 0, 'sort' => 0, 'ordering' => count($currentFields)+1, 'allowEdit' => $allowEdit, ); } else { // just set the name & id for reference $currentFields[$field->FieldId]->FieldId = $field->FieldId; $currentFields[$field->FieldId]->FieldName = $field->FieldName; $currentFields[$field->FieldId]->FieldCaption = $field->FieldCaption; $currentFields[$field->FieldId]->FieldType = $field->FieldType; $currentFields[$field->FieldId]->allowEdit = $allowEdit; } } // this is to reset the indexes (0, 1, 2, 3) $cache[$formId] = array_merge($currentFields, array()); } return $cache[$formId]; } public static function getDirectoryFormProperties($formId, $raw = false) { static $results = array(); if (!isset($results[$formId])) { $results[$formId] = array(); $db = Factory::getDbo(); // form multiple separator $query = $db->getQuery(true) ->select($db->qn('MultipleSeparator')) ->from($db->qn('#__rsform_forms')) ->where($db->qn('FormId') . ' = ' . $db->q($formId)); $results[$formId]['multipleSeparator'] = str_replace(array('\n', '\r', '\t'), array("\n", "\r", "\t"), $db->setQuery($query)->loadResult()); $query = $db->getQuery(true) ->select($db->qn('ComponentId')) ->select($db->qn('ComponentTypeId')) ->from($db->qn('#__rsform_components')) ->where($db->qn('FormId') . ' = ' . $db->q($formId)) ->order($db->qn('Order') . ' ASC'); $results[$formId]['uploadFields'] = array(); $results[$formId]['multipleFields'] = array(); $results[$formId]['textareaFields'] = array(); if ($components = $db->setQuery($query)->loadObjectList('ComponentId')) { $properties = RSFormProHelper::getComponentProperties(array_keys($components), false); foreach ($properties as $componentId => $data) { // Upload fields if ($components[$componentId]->ComponentTypeId == RSFORM_FIELD_FILEUPLOAD) { $results[$formId]['uploadFields'][] = $data['NAME']; } // Multiple fields elseif (in_array($components[$componentId]->ComponentTypeId, array(RSFORM_FIELD_SELECTLIST, RSFORM_FIELD_CHECKBOXGROUP)) || isset($data['ITEMS'])) { $results[$formId]['multipleFields'][] = $data['NAME']; } elseif ($components[$componentId]->ComponentTypeId == RSFORM_FIELD_TEXTAREA) { if (!empty($data['WYSIWYG']) && $data['WYSIWYG'] =='NO') { $results[$formId]['textareaFields'][] = $data['NAME']; } } } } $results[$formId]['secret'] = Factory::getApplication()->get('secret'); } return $raw ? $results[$formId] : array( $results[$formId]['multipleSeparator'], $results[$formId]['uploadFields'], $results[$formId]['multipleFields'], $results[$formId]['textareaFields'], $results[$formId]['secret'] ); } public static function canEdit($formId, $submissionId) { $user = Factory::getUser(); $user_groups = Access::getGroupsByUser($user->get('id')); require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php'; $submission = RSFormProSubmissionsHelper::getSubmission($submissionId, false); // Submission does not exist, can't allow editing if (!$submission) { return false; } if ($groups = static::getDirectoryGroups($formId, 'edit')) { $registry = new Registry; $registry->loadString($groups); if ($groups = $registry->toArray()) { // Check if the user can edit its own submissions if (in_array('own', $groups) && $submission->UserId == $user->get('id') && !$user->get('guest')) { return true; } // Check if the current group can edit submissions if ($user_groups && $groups && array_intersect($user_groups, $groups)) { return true; } } } return false; } public static function canDelete($formId, $submissionId) { $user = Factory::getUser(); $user_groups = Access::getGroupsByUser($user->get('id')); require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php'; $submission = RSFormProSubmissionsHelper::getSubmission($submissionId, false); // Submission does not exist, can't allow deleting if (!$submission) { return false; } if ($groups = static::getDirectoryGroups($formId, 'delete')) { $registry = new Registry; $registry->loadString($groups); if ($groups = $registry->toArray()) { // Check if the user can delete its own submissions if (in_array('own', $groups) && $submission->UserId == $user->get('id') && !$user->get('guest')) { return true; } // Check if the current user can delete submissions if ($user_groups && $groups && array_intersect($user_groups, $groups)) { return true; } } } return false; } public static function getDirectoryGroups($formId, $type = 'edit') { static $cache = array(); if (!isset($cache[$formId])) { $cache[$formId] = (object) array( 'edit' => null, 'delete' => null ); $db = Factory::getDbo(); $query = $db->getQuery(true) ->select($db->qn('groups')) ->select($db->qn('DeletionGroups')) ->from($db->qn('#__rsform_directory')) ->where($db->qn('formId') . ' = ' . $db->q($formId)); if ($result = $db->setQuery($query)->loadObject()) { $cache[$formId]->edit = $result->groups; $cache[$formId]->delete = $result->DeletionGroups; } } return $cache[$formId]->{$type}; } public static function getCalculations($formId) { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__rsform_calculations')) ->where($db->qn('formId') . ' = '. $db->q($formId)) ->order($db->qn('ordering')); return $db->setQuery($query)->loadObjectList(); } public static function getRelativeUploadPath($destination) { // Relative path // First check - Unix server and the path doesn't start with / // Second check - Windows server, path doesn't start with DRIVE: if (strlen($destination)) { if ((DIRECTORY_SEPARATOR === '/' && substr($destination, 0, 1) !== '/') || (DIRECTORY_SEPARATOR === '\\' && substr($destination, 1, 1) != ':')) { $destination = JPATH_SITE . '/' . $destination; } } return $destination; } public static function getForm($formId){ static $form = array(); $formId = (int) $formId; if (!isset($form[$formId])) { $db = Factory::getDbo(); $query = $db->getQuery(true); $query->clear() ->select('*') ->from($db->qn('#__rsform_forms')) ->where($db->qn('FormId').'='.$db->q($formId)); $db->setQuery($query); $form[$formId] = $db->loadObject(); } return is_object($form[$formId]) ? clone $form[$formId] : false; } public static function getRawPost() { return Factory::getApplication()->input->post->getArray(array(), null, 'raw'); } public static function generateQuickAddGlobal($type = 'display', $justArray = false) { switch ($type) { default: case 'display': $placeholders = array( '{global:formid}', '{global:username}', '{global:userip}', '{global:userid}', '{global:useremail}', '{global:fullname}', '{global:sitename}', '{global:siteurl}', '{global:mailfrom}', '{global:fromname}', '{global:confirmation}', '{global:confirmation_hash}', '{global:confirmedip}', '{global:confirmeddate}', '{global:utc_confirmeddate}', '{global:deletion}', '{global:deletion_hash}', '{global:submissionid}', '{global:submission_id}', '{global:date_added}', '{global:utc_date_added}', '{global:language}', '{global:formtitle}' ); break; case 'generate': $placeholders = array( '{error}', '{global:formid}', '{global:formtitle}', '{global:username}', '{global:userip}', '{global:userid}', '{global:useremail}', '{global:fullname}', '{global:sitename}', '{global:siteurl}', '{global:mailfrom}', '{global:fromname}' ); break; } $html = '<strong><u>' . Text::_('COM_RSFORM_GLOBAL_PLACEHOLDERS') . '</u></strong><br />'; Factory::getApplication()->triggerEvent('onRsformAfterCreateQuickAddGlobalPlaceholders', array(&$placeholders, $type)); if ($justArray) { return $placeholders; } $html .= '<pre>' . implode("\n", $placeholders) . '</pre><br />'; return $html; } public static function generateQuickAdd($field, $key) { return '<strong>' . $field['name'] . '</strong><br/><pre>' . implode("\n", $field[$key]) . '</pre><br />'; } public static function getFormLayouts($formId = 0) { $layouts = array( 'html5Layouts' => array('responsive', 'bootstrap2', 'bootstrap3', 'bootstrap4', 'bootstrap5', 'uikit', 'uikit3', 'foundation') ); Factory::getApplication()->triggerEvent('onRsformBackendLayoutsDefine', array(&$layouts, $formId)); return $layouts; } public static function doSilentPost($silentPost, $config = array()) { if (array_key_exists('replace', $config)) { $replace = $config['replace']; } if (array_key_exists('with', $config)) { $with = $config['with']; } if (array_key_exists('post', $config)) { $post = $config['post']; } if (array_key_exists('SubmissionId', $config)) { list($replace, $with) = RSFormProHelper::getReplacements($config['SubmissionId']); require_once JPATH_ADMINISTRATOR . '/components/com_rsform/helpers/submissions.php'; $submission = RSFormProSubmissionsHelper::getSubmission($config['SubmissionId']); $db = Factory::getDbo(); $query = $db->getQuery(true); $query->select($db->qn('p.PropertyValue', 'ComponentName')) ->select($db->qn('ct.ComponentTypeName')) ->select($db->qn('ct.ComponentTypeId')) ->from($db->qn('#__rsform_components','c')) ->join('left', $db->qn('#__rsform_properties','p').' ON '.$db->qn('p.ComponentId').' = '.$db->qn('c.ComponentId')) ->join('left', $db->qn('#__rsform_component_types','ct').' ON '.$db->qn('c.ComponentTypeId').' = '.$db->qn('ct.ComponentTypeId')) ->where($db->qn('c.FormId') . ' = ' . $db->q($submission->FormId)) ->where($db->qn('p.PropertyName') . ' = ' . $db->q('NAME')) ->where($db->qn('c.Published') . ' = ' . $db->q(1)) ->order($db->qn('c.Order') . ' ' . $db->escape('asc')); $fields = $db->setQuery($query)->loadObjectList(); // Generate POST $post = array(); foreach ($fields as $field) { if (!isset($submission->values[$field->ComponentName])) { continue; } $post[$field->ComponentName] = $submission->values[$field->ComponentName]; if (strpos($field->ComponentTypeName, 'checkbox') !== false || strpos($field->ComponentTypeName, 'select') !== false) { $post[$field->ComponentName] = RSFormProHelper::explode($submission->values[$field->ComponentName]); } } } if (empty($replace) || empty($with) || empty($post)) { return false; } if ($silentPost && !empty($silentPost->url) && !in_array($silentPost->url, array('http://', 'https://'))) { // Set URL to send data to $url = $silentPost->url; // Prepare data if (!empty($silentPost->fields)) { $data = ''; foreach ($silentPost->fields as $field) { $field->name = str_replace($replace, $with, $field->name); $field->value = str_replace($replace, $with, $field->value); if (strlen($field->name)) { $data .= urlencode($field->name).'='.urlencode($field->value).'&'; } } $data = rtrim($data, '&'); } else { $data = http_build_query($post); } try { // Do we need to send data silently? if ($silentPost->silent) { // Map headers $silentPostHeaders = array(); if (!empty($silentPost->headers)) { $hasJson = false; foreach ($silentPost->headers as $field) { $headerName = str_replace($replace, $with, $field->name); $headerValue = str_replace($replace, $with, $field->value); $silentPostHeaders[$headerName] = $headerValue; if (strtolower($headerName) === 'content-type' && strpos(strtolower($headerValue), 'json') !== false) { $hasJson = true; } } if ($hasJson) { parse_str($data, $dataArray); $data = json_encode($dataArray); } } // Get HTTP connector $http = HttpFactory::getHttp(); if ($silentPost->method) { // POST $http->post($url, $data, $silentPostHeaders); } else { // GET $http->get($url.(strpos($url, '?') === false ? '?' : '&').$data, $silentPostHeaders); } } else { // Try to follow the URL if ($silentPost->method) { @ob_end_clean(); $dataArray = explode('&', $data); // Create a hidden form that we submit through Javascript ?> <form id="formSubmit" method="post" action="<?php echo RSFormProHelper::htmlEscape($url); ?>"> <?php if (!empty($dataArray) && is_array($dataArray)) { foreach ($dataArray as $value) { list($key, $value) = explode('=', $value, 2); ?> <input type="hidden" name="<?php echo RSFormProHelper::htmlEscape(urldecode($key)); ?>" value="<?php echo RSFormProHelper::htmlEscape(urldecode($value)); ?>" /> <?php } } ?> </form> <script type="text/javascript"> function formSubmit() { if (typeof document.getElementById("formSubmit").submit == "function") { document.getElementById("formSubmit").submit() } else { document.createElement("form").submit.call(document.getElementById("formSubmit")); } } try { window.addEventListener ? window.addEventListener("load",formSubmit,false) : window.attachEvent("onload",formSubmit); } catch (err) { formSubmit(); } </script> <?php Factory::getApplication()->close(); } else { Factory::getApplication()->redirect($url.(strpos($url, '?') === false ? '?' : '&').$data); } } } catch (Exception $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning'); return false; } } return true; } public static function getSilentPost($formId) { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__rsform_posts')) ->where($db->qn('form_id') . ' = ' . $db->q($formId)) ->where($db->qn('enabled') . ' = ' . $db->q(1)); $silentPost = $db->setQuery($query)->loadObject(); if ($silentPost && !empty($silentPost->fields)) { $silentPost->fields = json_decode($silentPost->fields); if (!is_array($silentPost->fields)) { $silentPost->fields = array(); } } if ($silentPost && !empty($silentPost->headers)) { $silentPost->headers = json_decode($silentPost->headers); if (!is_array($silentPost->headers)) { $silentPost->headers = array(); } } return $silentPost; } public static function doMappings($mappings, $config = array()) { if (empty($mappings)) { return false; } $db = Factory::getDbo(); if (array_key_exists('replace', $config)) { $replace = $config['replace']; } if (array_key_exists('with', $config)) { $with = $config['with']; } if (array_key_exists('SubmissionId', $config)) { list($replace, $with) = RSFormProHelper::getReplacements($config['SubmissionId']); } if (empty($replace) || empty($with)) { return false; } $lastinsertid = ''; array_walk($with, array('RSFormProHelper', 'escapeSql')); foreach ($mappings as $mapping) { try { //get the query $query = RSFormProHelper::getMappingQuery($mapping); //replace the placeholders $query = str_replace($replace, $with, $query); //replace the last insertid placeholder $query = str_replace('{last_insert_id}', $lastinsertid, $query); if ($mapping->connection) { $options = array( 'driver' => isset($mapping->driver) ? $mapping->driver : 'mysql', 'host' => $mapping->host, 'port' => $mapping->port, 'user' => $mapping->username, 'password' => $mapping->password, 'database' => $mapping->database ); $database = DatabaseDriver::getInstance($options); $database->setQuery($query)->execute(); $lastinsertid = $database->insertid(); } else { $db->setQuery($query)->execute(); $lastinsertid = $db->insertid(); } } catch (Exception $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'warning'); } } return true; } public static function getMappings($formId) { $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('*') ->from($db->qn('#__rsform_mappings')) ->where($db->qn('formId') . ' = ' . $db->q($formId)) ->order($db->qn('ordering') . ' ' . $db->escape('asc')); return $db->setQuery($query)->loadObjectList(); } }