/** * Execute the action * * @return void */ public function execute() { // call parent, this will probably add some general CSS/JS or other required files parent::execute(); // user is god? $isGod = BackendAuthentication::getUser()->isGod(); // get possible languages if ($isGod) { $possibleLanguages = array_unique(array_merge(BL::getWorkingLanguages(), BL::getInterfaceLanguages())); } else { $possibleLanguages = BL::getWorkingLanguages(); } // get parameters $language = SpoonFilter::getPostValue('language', array_keys($possibleLanguages), null, 'string'); $module = SpoonFilter::getPostValue('module', BackendModel::getModules(false), null, 'string'); $name = SpoonFilter::getPostValue('name', null, null, 'string'); $type = SpoonFilter::getPostValue('type', BackendModel::getDB()->getEnumValues('locale', 'type'), null, 'string'); $application = SpoonFilter::getPostValue('application', array('backend', 'frontend'), null, 'string'); $value = SpoonFilter::getPostValue('value', null, null, 'string'); // validate values if (trim($value) == '' || $language == '' || $module == '' || $type == '' || $application == '' || $application == 'frontend' && $module != 'core') { $error = BL::err('InvalidValue'); } // in case this is a 'act' type, there are special rules concerning possible values if ($type == 'act' && !isset($error)) { if (!SpoonFilter::isValidAgainstRegexp('|^([a-z0-9\\-\\_])+$|', $value)) { $error = BL::err('InvalidActionValue', $this->getModule()); } } // no error? if (!isset($error)) { // build item $item['language'] = $language; $item['module'] = $module; $item['name'] = $name; $item['type'] = $type; $item['application'] = $application; $item['value'] = $value; $item['edited_on'] = BackendModel::getUTCDate(); $item['user_id'] = BackendAuthentication::getUser()->getUserId(); // does the translation exist? if (BackendLocaleModel::existsByName($name, $type, $module, $language, $application)) { // add the id to the item $item['id'] = (int) BackendLocaleModel::getByName($name, $type, $module, $language, $application); // update in db BackendLocaleModel::update($item); } else { // insert in db BackendLocaleModel::insert($item); } // output OK $this->output(self::OK); } else { $this->output(self::ERROR, null, $error); } }
/** * Validate the form * * @return void */ private function validateForm() { // is the form submitted? if ($this->frm->isSubmitted()) { // cleanup the submitted fields, ignore fields that were added by hackers $this->frm->cleanupFields(); // shorten the fields $txtName = $this->frm->getField('name'); $txtEmail = $this->frm->getField('email'); $ddmMethod = $this->frm->getField('method'); $txtSuccessMessage = $this->frm->getField('success_message'); $txtIdentifier = $this->frm->getField('identifier'); // validate fields $txtName->isFilled(BL::getError('NameIsRequired')); $txtSuccessMessage->isFilled(BL::getError('SuccessMessageIsRequired')); if ($ddmMethod->isFilled(BL::getError('NameIsRequired')) && $ddmMethod->getValue() == 'database_email') { $txtEmail->isEmail(BL::getError('EmailIsRequired')); } // identifier if ($txtIdentifier->isFilled()) { // invalid characters if (!SpoonFilter::isValidAgainstRegexp('/^[a-zA-Z0-9\\.\\_\\-]+$/', $txtIdentifier->getValue())) { $txtIdentifier->setError(BL::getError('InvalidIdentifier')); } elseif (BackendFormBuilderModel::existsIdentifier($txtIdentifier->getValue())) { $txtIdentifier->setError(BL::getError('UniqueIdentifier')); } } // no errors? if ($this->frm->isCorrect()) { // build array $values['language'] = BL::getWorkingLanguage(); $values['user_id'] = BackendAuthentication::getUser()->getUserId(); $values['name'] = $txtName->getValue(); $values['method'] = $ddmMethod->getValue(); $values['email'] = $values['method'] == 'database_email' ? $txtEmail->getValue() : null; $values['success_message'] = $txtSuccessMessage->getValue(true); $values['identifier'] = $txtIdentifier->isFilled() ? $txtIdentifier->getValue() : BackendFormBuilderModel::createIdentifier(); $values['created_on'] = BackendModel::getUTCDate(); $values['edited_on'] = BackendModel::getUTCDate(); // insert the item $id = BackendFormBuilderModel::insert($values); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_add', array('item' => $values)); // set frontend locale FL::setLocale(BL::getWorkingLanguage()); // create submit button $field['form_id'] = $id; $field['type'] = 'submit'; $field['settings'] = serialize(array('values' => ucfirst(FL::getLabel('Send')))); BackendFormBuilderModel::insertField($field); // everything is saved, so redirect to the editform $this->redirect(BackendModel::createURLForAction('edit') . '&id=' . $id . '&report=added&var=' . urlencode($values['name']) . '#tabFields'); } } }
/** * Validate the form */ private function validateForm() { if ($this->frm->isSubmitted()) { $this->frm->cleanupFields(); // shorten the fields $txtName = $this->frm->getField('name'); $txtEmail = $this->frm->getField('email'); $ddmMethod = $this->frm->getField('method'); $txtSuccessMessage = $this->frm->getField('success_message'); $txtIdentifier = $this->frm->getField('identifier'); $emailAddresses = (array) explode(',', $txtEmail->getValue()); // validate fields $txtName->isFilled(BL::getError('NameIsRequired')); $txtSuccessMessage->isFilled(BL::getError('SuccessMessageIsRequired')); if ($ddmMethod->isFilled(BL::getError('NameIsRequired')) && $ddmMethod->getValue() == 'database_email') { $error = false; // check the addresses foreach ($emailAddresses as $address) { $address = trim($address); if (!SpoonFilter::isEmail($address)) { $error = true; break; } } // add error if ($error) { $txtEmail->addError(BL::getError('EmailIsInvalid')); } } // identifier if ($txtIdentifier->isFilled()) { // invalid characters if (!SpoonFilter::isValidAgainstRegexp('/^[a-zA-Z0-9\\.\\_\\-]+$/', $txtIdentifier->getValue())) { $txtIdentifier->setError(BL::getError('InvalidIdentifier')); } elseif (BackendFormBuilderModel::existsIdentifier($txtIdentifier->getValue(), $this->id)) { $txtIdentifier->setError(BL::getError('UniqueIdentifier')); } } if ($this->frm->isCorrect()) { // build array $values['name'] = $txtName->getValue(); $values['method'] = $ddmMethod->getValue(); $values['email'] = $ddmMethod->getValue() == 'database_email' ? serialize($emailAddresses) : null; $values['success_message'] = $txtSuccessMessage->getValue(true); $values['identifier'] = $txtIdentifier->isFilled() ? $txtIdentifier->getValue() : BackendFormBuilderModel::createIdentifier(); $values['edited_on'] = BackendModel::getUTCDate(); // insert the item $id = (int) BackendFormBuilderModel::update($this->id, $values); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_edit', array('item' => $values)); // everything is saved, so redirect to the overview $this->redirect(BackendModel::createURLForAction('index') . '&report=edited&var=' . urlencode($values['name']) . '&highlight=row-' . $id); } } }
public function testIsValidAgainstRegexp() { $this->assertTrue(SpoonFilter::isValidAgainstRegexp('/(^[a-z]+$)/', 'alphabet')); $this->assertFalse(SpoonFilter::isValidAgainstRegexp('/(^[a-z]+$)/', 'alphabet my ass!')); $this->assertFalse(SpoonFilter::isValidAgainstRegexp('/(boobies)/', 'I like babies')); }
/** * Checks if the field validates against the regexp. * * @return bool * @param string $regexp The regular expresion to test the value. * @param string[optional] $error The error message to set. */ public function isValidAgainstRegexp($regexp, $error = null) { // filled if ($this->isFilled()) { // post/get data $data = $this->getMethod(true); // validate if (!isset($data[$this->attributes['name']]) || !SpoonFilter::isValidAgainstRegexp((string) $regexp, $data[$this->attributes['name']])) { if ($error !== null) { $this->setError($error); } return false; } return true; } // not submitted if ($error !== null) { $this->setError($error); } return false; }
/** * Load the form */ private function loadForm() { // create form $this->frm = new BackendForm('edit'); // init var $defaultId = BackendModel::getModuleSetting('pages', 'default_template'); // build available themes $themes = array(); foreach (BackendExtensionsModel::getThemes() as $theme) { $themes[$theme['value']] = $theme['label']; } // create elements $this->frm->addDropdown('theme', $themes, BackendModel::getModuleSetting('core', 'theme', 'core')); $this->frm->addText('label', $this->record['label']); $this->frm->addText('file', str_replace('core/layout/templates/', '', $this->record['path'])); $this->frm->addTextarea('format', str_replace('],[', "],\n[", $this->record['data']['format'])); $this->frm->addCheckbox('active', $this->record['active'] == 'Y'); $this->frm->addCheckbox('default', $this->record['id'] == $defaultId); $this->frm->addCheckbox('overwrite', false); // if this is the default template we can't alter the active/default state if ($this->record['id'] == $defaultId) { $this->frm->getField('active')->setAttributes(array('disabled' => 'disabled')); $this->frm->getField('default')->setAttributes(array('disabled' => 'disabled')); } // if the template is in use we cant alter the active state if (BackendExtensionsModel::isTemplateInUse($this->id)) { $this->frm->getField('active')->setAttributes(array('disabled' => 'disabled')); } // init vars $positions = array(); $blocks = array(); $widgets = array(); $extras = BackendExtensionsModel::getExtras(); // loop extras to populate the default extras foreach ($extras as $item) { if ($item['type'] == 'block') { $blocks[$item['id']] = SpoonFilter::ucfirst(BL::lbl($item['label'])); if (isset($item['data']['extra_label'])) { $blocks[$item['id']] = SpoonFilter::ucfirst($item['data']['extra_label']); } } elseif ($item['type'] == 'widget') { $widgets[$item['id']] = SpoonFilter::ucfirst(BL::lbl(SpoonFilter::toCamelCase($item['module']))) . ': ' . SpoonFilter::ucfirst(BL::lbl($item['label'])); if (isset($item['data']['extra_label'])) { $widgets[$item['id']] = SpoonFilter::ucfirst(BL::lbl(SpoonFilter::toCamelCase($item['module']))) . ': ' . $item['data']['extra_label']; } } } // sort asort($blocks, SORT_STRING); asort($widgets, SORT_STRING); // create array $defaultExtras = array('' => array(0 => SpoonFilter::ucfirst(BL::lbl('Editor'))), SpoonFilter::ucfirst(BL::lbl('Widgets')) => $widgets); // create default position field $position = array(); $position['i'] = 0; $position['formElements']['txtPosition'] = $this->frm->addText('position_' . $position['i'], null, 255, 'inputText positionName', 'inputTextError positionName'); $position['blocks'][]['formElements']['ddmType'] = $this->frm->addDropdown('type_' . $position['i'] . '_' . 0, $defaultExtras, null, false, 'positionBlock', 'positionBlockError'); $positions[] = $position; // content has been submitted: re-create submitted content rather than the db-fetched content if (isset($_POST['position_0'])) { // init vars $this->names = array(); $this->extras = array(); $i = 1; $errors = array(); // loop submitted positions while (isset($_POST['position_' . $i])) { // init vars $j = 0; $extras = array(); // gather position names $name = $_POST['position_' . $i]; // loop submitted blocks while (isset($_POST['type_' . $i . '_' . $j])) { // gather blocks id $extras[] = (int) $_POST['type_' . $i . '_' . $j]; // increment counter; go fetch next block $j++; } // increment counter; go fetch next position $i++; // position already exists -> error if (in_array($name, $this->names)) { $errors[] = sprintf(BL::getError('DuplicatePositionName'), $name); } // position name == fallback -> error if ($name == 'fallback') { $errors[] = sprintf(BL::getError('ReservedPositionName'), $name); } // not alphanumeric -> error if (!SpoonFilter::isValidAgainstRegexp('/^[a-z0-9]+$/i', $name)) { $errors[] = sprintf(BL::getError('NoAlphaNumPositionName'), $name); } // save positions $this->names[] = $name; $this->extras[$name] = $extras; } // add errors if ($errors) { $this->frm->addError(implode('<br />', array_unique($errors))); } } // build blocks array foreach ($this->names as $i => $name) { // create default position field $position = array(); $position['i'] = $i + 1; $position['formElements']['txtPosition'] = $this->frm->addText('position_' . $position['i'], $name, 255, 'inputText positionName', 'inputTextError positionName'); if (isset($this->extras[$name])) { foreach ($this->extras[$name] as $y => $extra) { $position['blocks'][]['formElements']['ddmType'] = $this->frm->addDropdown('type_' . $position['i'] . '_' . $y, $defaultExtras, $extra, false, 'positionBlock', 'positionBlockError'); } } $positions[] = $position; } // assign $this->tpl->assign('positions', $positions); }
/** * Maps a specific modifier to a function/method. * * @param string $name The name of the modifier that you want to map. * @param mixed $function The function or method that you want to map to the provided name. To map a method provided this argument as an array containing class and method. */ public static function mapModifier($name, $function) { // validate modifier if (!SpoonFilter::isValidAgainstRegexp('/[a-zA-Z0-9\\_\\-]+/', (string) $name)) { throw new SpoonTemplateException('Modifier names can only contain a-z, 0-9 and - and _'); } // class method if (is_array($function)) { // not enough elements if (count($function) != 2) { throw new SpoonTemplateException('The array should contain the class and static method.'); } // method doesn't exist if (!is_callable(array($function[0], $function[1]))) { throw new SpoonTemplateException('The method "' . $function[1] . '" in the class ' . $function[0] . ' does not exist.'); } // all fine self::$modifiers[(string) $name] = $function; } else { // function doesn't exist if (!function_exists((string) $function)) { throw new SpoonTemplateException('The function "' . (string) $function . '" does not exist.'); } // all fine self::$modifiers[(string) $name] = $function; } }
/** * Load the form */ private function loadForm() { // create form $this->frm = new BackendForm('add'); // create elements $this->frm->addDropdown('theme', $this->availableThemes, $this->selectedTheme); $this->frm->addText('label'); $this->frm->addText('file'); $this->frm->addTextarea('format'); $this->frm->addCheckbox('active', true); $this->frm->addCheckbox('default'); $this->frm->addCheckbox('image'); // init vars $positions = array(); $blocks = array(); $widgets = array(); $extras = BackendExtensionsModel::getExtras(); // loop extras to populate the default extras foreach ($extras as $item) { if ($item['type'] == 'block') { $blocks[$item['id']] = \SpoonFilter::ucfirst(BL::lbl($item['label'])); if (isset($item['data']['extra_label'])) { $blocks[$item['id']] = \SpoonFilter::ucfirst($item['data']['extra_label']); } } elseif ($item['type'] == 'widget') { $widgets[$item['id']] = \SpoonFilter::ucfirst(BL::lbl(\SpoonFilter::toCamelCase($item['module']))) . ': ' . \SpoonFilter::ucfirst(BL::lbl($item['label'])); if (isset($item['data']['extra_label'])) { $widgets[$item['id']] = \SpoonFilter::ucfirst(BL::lbl(\SpoonFilter::toCamelCase($item['module']))) . ': ' . $item['data']['extra_label']; } } } // sort asort($blocks, SORT_STRING); asort($widgets, SORT_STRING); // create array $defaultExtras = array('' => array(0 => \SpoonFilter::ucfirst(BL::lbl('Editor'))), \SpoonFilter::ucfirst(BL::lbl('Widgets')) => $widgets); // create default position field $position = array(); $position['i'] = 0; $position['formElements']['txtPosition'] = $this->frm->addText('position_' . $position['i'], null, 255, 'form-control positionName', 'form-control danger positionName'); $position['blocks'][]['formElements']['ddmType'] = $this->frm->addDropdown('type_' . $position['i'] . '_' . 0, $defaultExtras, null, false, 'form-control positionBlock', 'form-control danger positionBlockError'); $positions[] = $position; // content has been submitted: re-create submitted content rather than the db-fetched content if (isset($_POST['position_0'])) { // init vars $this->names = array(); $this->extras = array(); $i = 1; $errors = array(); // loop submitted positions while (isset($_POST['position_' . $i])) { // init vars $j = 0; $extras = array(); // gather position names $name = $_POST['position_' . $i]; // loop submitted blocks while (isset($_POST['type_' . $i . '_' . $j])) { // gather blocks id $extras[] = (int) $_POST['type_' . $i . '_' . $j]; // increment counter; go fetch next block ++$j; } // increment counter; go fetch next position ++$i; // position already exists -> error if (in_array($name, $this->names)) { $errors[] = sprintf(BL::getError('DuplicatePositionName'), $name); } // position name == fallback -> error if ($name == 'fallback') { $errors[] = sprintf(BL::getError('ReservedPositionName'), $name); } // not alphanumeric -> error if (!\SpoonFilter::isValidAgainstRegexp('/^[a-z0-9]+$/i', $name)) { $errors[] = sprintf(BL::getError('NoAlphaNumPositionName'), $name); } // save positions $this->names[] = $name; $this->extras[$name] = $extras; } // add errors if ($errors) { $this->frm->addError(implode('<br />', array_unique($errors))); } } // build blocks array foreach ($this->names as $i => $name) { // create default position field $position = array(); $position['i'] = $i + 1; $position['formElements']['txtPosition'] = $this->frm->addText('position_' . $position['i'], $name, 255, 'form-control positionName', 'form-control danger positionName'); foreach ($this->extras[$name] as $extra) { $position['blocks'][]['formElements']['ddmType'] = $this->frm->addDropdown('type_' . $position['i'] . '_' . 0, $defaultExtras, $extra, false, 'form-control positionBlock', 'form-control danger positionBlockError'); } $positions[] = $position; } // assign $this->tpl->assign('positions', $positions); }
/** * Validate the form. */ private function validateForm() { // submitted if ($this->frm->isSubmitted()) { // does the key exists? if (\SpoonSession::exists('formbuilder_' . $this->item['id'])) { // calculate difference $diff = time() - (int) \SpoonSession::get('formbuilder_' . $this->item['id']); // calculate difference, it it isn't 10 seconds the we tell the user to slow down if ($diff < 10 && $diff != 0) { $this->frm->addError(FL::err('FormTimeout')); } } // validate fields foreach ($this->item['fields'] as $field) { // field name $fieldName = 'field' . $field['id']; // skip if ($field['type'] == 'submit' || $field['type'] == 'paragraph' || $field['type'] == 'heading') { continue; } // loop other validations foreach ($field['validations'] as $rule => $settings) { // already has an error so skip if ($this->frm->getField($fieldName)->getErrors() !== null) { continue; } // required if ($rule == 'required') { $this->frm->getField($fieldName)->isFilled($settings['error_message']); } elseif ($rule == 'email') { // only check this if the field is filled, if the field is required it will be validated before if ($this->frm->getField($fieldName)->isFilled()) { $this->frm->getField($fieldName)->isEmail($settings['error_message']); } } elseif ($rule == 'numeric') { // only check this if the field is filled, if the field is required it will be validated before if ($this->frm->getField($fieldName)->isFilled()) { $this->frm->getField($fieldName)->isNumeric($settings['error_message']); } } elseif ($rule == 'time') { $regexTime = '/^(([0-1][0-9]|2[0-3]|[0-9])|([0-1][0-9]|2[0-3]|[0-9])(:|h)[0-5]?[0-9]?)$/'; if (!\SpoonFilter::isValidAgainstRegexp($regexTime, $this->frm->getField($fieldName)->getValue())) { $this->frm->getField($fieldName)->setError($settings['error_message']); } } } } // valid form if ($this->frm->isCorrect()) { // item $data['form_id'] = $this->item['id']; $data['session_id'] = \SpoonSession::getSessionId(); $data['sent_on'] = FrontendModel::getUTCDate(); $data['data'] = serialize(array('server' => $_SERVER)); // insert data $dataId = FrontendFormBuilderModel::insertData($data); // init fields array $fields = array(); // loop all fields foreach ($this->item['fields'] as $field) { // skip if ($field['type'] == 'submit' || $field['type'] == 'paragraph' || $field['type'] == 'heading') { continue; } // field data $fieldData['data_id'] = $dataId; $fieldData['label'] = $field['settings']['label']; $fieldData['value'] = $this->frm->getField('field' . $field['id'])->getValue(); if ($field['type'] == 'radiobutton') { $values = array(); foreach ($field['settings']['values'] as $value) { $values[$value['value']] = $value['label']; } $fieldData['value'] = $values[$fieldData['value']]; } // clean up if (is_array($fieldData['value']) && empty($fieldData['value'])) { $fieldData['value'] = null; } // serialize if ($fieldData['value'] !== null) { $fieldData['value'] = serialize($fieldData['value']); } // save fields data $fields[$field['id']] = $fieldData; // insert FrontendFormBuilderModel::insertDataField($fieldData); } $this->get('event_dispatcher')->dispatch(FormBuilderEvents::FORM_SUBMITTED, new FormBuilderSubmittedEvent($this->item, $fields, $dataId)); // trigger event FrontendModel::triggerEvent('FormBuilder', 'after_submission', array('form_id' => $this->item['id'], 'data_id' => $dataId, 'data' => $data, 'fields' => $fields, 'visitorId' => FrontendModel::getVisitorId())); // store timestamp in session so we can block excessive usage \SpoonSession::set('formbuilder_' . $this->item['id'], time()); // redirect $redirect = SITE_URL . $this->URL->getQueryString(); $redirect .= stripos($redirect, '?') === false ? '?' : '&'; $redirect .= 'identifier=' . $this->item['identifier']; $redirect .= '#' . $this->formName; throw new RedirectException('Redirect', new RedirectResponse($redirect)); } else { // not correct, show errors // global form errors set if ($this->frm->getErrors() != '') { $this->tpl->assign('formBuilderError', $this->frm->getErrors()); } else { // general error $this->tpl->assign('formBuilderError', FL::err('FormError')); } } } }
/** * Sets the type, which will be used as the name for the logfile. * * @return SpoonLog * @param string $value The value for this type. Only a-z, 0-9, underscores and hyphens are allowed. */ public function setType($value) { // redefine $value = (string) $value; // check for invalid characters if (!SpoonFilter::isValidAgainstRegexp('/(^[a-z0-9\\-_]+$)/i', $value)) { throw new SpoonLogException('The log type should only contain a-z, 0-9, underscores and hyphens. Your value "' . $value . '" is invalid.'); } // set type & return object $this->type = $value; return $this; }