t('Formula'), 'description' => t('Computes values of other fields.'), 'features' => array( 'required' => FALSE, ), 'file' => 'components/formula.inc', 'conditional_type' => 'numeric', ); return $components; } /** * Implements hook_webform_submission_presave(). */ function webform_calculator_webform_submission_presave($node, &$submission) { foreach ($node->webform['components'] as $component) { if ($component['type'] == 'formula') { $submission->data[$component['cid']][0] = webform_calculator_replace_formula_values($component, $node, $submission); } } } /** * Evaluate math formula. * * @param $formula * Mathematical formula (without tokens). * @param int $precision * Round precision. * * @return float * Calculated value for given formula. */ function webform_calculator_eval($formula, $precision = 1) { eval("\$result = $formula;"); return round($result, $precision); } /** * Implements hook_theme(). */ function webform_calculator_theme() { return array(webform_component_invoke('formula', 'theme')); } /** * Get list of component names inside formula. * * @param $formula * Formula to be searched in (with tokens). * * @return array * Names of components that are used in formula as tokens. */ function webform_calculator_get_components_from_formula($formula) { $components = array(); if (preg_match_all(WEBFORM_CALCULATOR_REGEX, $formula, $matches)) { foreach ((array)$matches[0] as $match) { $components[] = str_replace(array('{', '}'), array('', ''), $match); } } return $components; } /** * Replace tokens in formula with values of components and evaluate formula. * * @param $formula_component * Formula compont. * @param $webform_node * Webform's node. * @param $submission * Webform submission. * * @return float|int * Value of evaluated formula. */ function webform_calculator_replace_formula_values($formula_component, $webform_node, $submission) { $formula = $formula_component['value']; $components_from_formula = webform_calculator_get_components_from_formula($formula); // Get webform components keyed by form key. $components_by_key = array(); foreach ($webform_node->webform['components'] as $component) { $components_by_key[$component['form_key']] = $component; } foreach ($components_from_formula as $component_key) { if (isset($components_by_key[$component_key])) { $component = $components_by_key[$component_key]; $values = $submission->data[$component['cid']]; $sum = 0; foreach ($values as $value) { $sum += $value; } $formula = str_replace('{' . $component_key . '}', '(' . $sum . ')', $formula); } } try { webform_calculator_validate_php($formula); return webform_calculator_eval($formula, $formula_component['extra']['precision']); } catch (Exception $e) { watchdog_exception('webform_calculator', $e); return 0; } } /** * Validate if code that will be used with eval is secure and valid. * * @param $code * PHP code to check. * * @return bool * TRUE if code is valid, FALSE otherwise. * * @throws Exception */ function webform_calculator_validate_php($code) { $allowed_tokens = array(T_LNUMBER, T_DNUMBER, T_WHITESPACE); $allowed_chars = array('+', '-', '*', '/', '(', ')', '%'); $tokens = token_get_all(' $token))); } continue; } // Checking for allowed tokens. if (!in_array($token[0], $allowed_tokens)) { throw new Exception(t('Using %token is disallowed.', array('%token' => token_name($token[0])))); } } // Check PHP syntax. ob_start(); if (@eval("\$return_array = $code;") === FALSE) { throw new Exception(t('Error occurred while parsing code.')); } else { ob_end_clean(); return TRUE; } } /** * Implements hook_form_builder_element_types(). * @param string $form_type * @param int $form_id * @return array */ function webform_calculator_form_builder_element_types($form_type, $form_id) { if ($form_type == 'webform') { drupal_add_css(drupal_get_path('module', 'webform_calculator') . '/formula.css'); $fields = array( 'formula' => array( 'title' => t('Formula'), 'weight' => -30, 'properties' => array( 'title', 'value', 'description', 'field_prefix', 'field_suffix', 'hidden', 'size', 'title_display', 'error_message', 'precision', ), ), ); if (function_exists('_form_builder_webform_default')) { $fields['formula']['default'] = _form_builder_webform_default('formula', array(), array('name' => t('New formula'))); } return $fields; } } /** * Implements hook_form_builder_preview_alter(). */ function webform_calculator_form_builder_preview_alter(&$element, $form_type, $form_id) { if ($form_type == 'webform' && $element['#webform_component']['type'] == 'formula') { $element['#attributes']['placeholder'] = $element['#webform_component']['value']; } }