# fluentform/1.2.4/app/Modules/Form/FormHandler.php

Fluent Forms – Customizable Contact Forms, Survey, Quiz, &amp; Conversational Form Builder, version 1.2.4. 384 lines.

- Page: https://pluginprobe.com/plugins/fluentform/1.2.4/code/app/Modules/Form/FormHandler.php
- Raw: https://pluginprobe.com/plugins/fluentform/1.2.4/raw/app/Modules/Form/FormHandler.php
- Modified: 2018-02-03T11:29:32+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/fluentform/1.2.4/code/app/Modules/Form/FormHandler.php#L10-L20`.

```php
<?php

namespace FluentForm\App\Modules\Form;

use FluentForm\App\Services\FormParser;
use FluentForm\App\Services\Browser\Browser;
use FluentForm\Framework\Helpers\ArrayHelper;
use FluentForm\App\Modules\ReCaptcha\ReCaptcha;
use FluentForm\Framework\Foundation\Application;
use FluentForm\App\Services\FormBuilder\MessageShortCodeParser;

class FormHandler
{
    /**
     * @var \FluentForm\Framework\Foundation\Application
     */
    protected $app;

    /**
     * @var \FluentForm\Framework\Request\Request
     */
    protected $request;

    /**
     * @var \FluentForm\App\Services\FormParser
     */
    protected $parser;

    /**
     * @var array $formData
     */
    protected $formData;

    /**
     * Form Handler constructor.
     *
     * @param \FluentForm\Framework\Foundation\Application $app
     */
    public function __construct(Application $app)
    {
        $this->app = $app;
        $this->request = $app->request;
    }

    /**
     * Find the form using it's ID.
     *
     * @param $formId
     *
     * @return null|\stdClass
     */
    public function findForm($formId)
    {
        return wpFluent()->table('fluentform_forms')->find($formId);
    }

    /**
     * Handle form submition
     *
     * @return \Exception
     */
    public function onSubmit()
    {
        // Parse the url encoded data from the request object.
        parse_str($this->app->request->get('data'), $data);

        // Merge it back again to the request object.
        $this->app->request->merge(['data' => $data]);

        $formId = intval($this->app->request->get('form_id'));

        $form = $this->findForm($formId);

        // Parse the form and get the flat inputs with validations.
        $this->parser = (new FormParser($form));
        $fields = $this->parser->getInputs(['rules']);

        // Sanitize the data properly.
        $this->formData = fluentFormSanitizer($data, null, $fields);

        // Now validate the data using the previous validations.
        $this->validate($form, $fields);

        // Prepare the data to be inserted to the DB.
        $insertData = $this->prepareInsertData($formId);

        $insertId = wpFluent()->table('fluentform_submissions')->insert($insertData);

        try {
            $this->app->doAction('fluentform_submission_inserted', $insertId, $this->formData, $form);
        } catch (\Exception $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                return $e;
            }
        }

        $this->sendResponse($insertId, $form);
    }

    /**
     * Prepare response and do actions/filters
     * and send the response to the client.
     *
     * @param  int $insertId
     * @param  \StdClass $form
     *
     * @return void
     */
    private function sendResponse($insertId, $form)
    {
        $formSettings = wpFluent()->table('fluentform_form_meta')
            ->where('form_id', $form->id)
            ->where('meta_key', 'formSettings')
            ->first();

        $formSettings = json_decode($formSettings->value, true);

        $confirmation = $formSettings['confirmation'];

        $message = MessageShortCodeParser::parseMessageShortCode(
            array(array('message' => $confirmation['messageToShow'])),
            $insertId,
            $this->formData,
            $form,
            false
        );

        if ($confirmation['redirectTo'] == 'samePage') {
            $returnData = array(
                'message' => $message[0]['message'],
                'formBehavior' => $confirmation['samePageFormBehavior'],
            );
        } else {
            $redirectUrl = $confirmation['customUrl'];
            if ($confirmation['redirectTo'] == 'customPage') {
                $redirectUrl = get_permalink($confirmation['customPage']);
            }
            
            $returnData = array(
                'message' => $message[0]['message'],
                'redirectUrl' => $redirectUrl
            );
        }

        $returnData = $this->app->applyFilters(
            'fluentform_submission_confirmation', $returnData, $form, $confirmation
        );

        wp_send_json_success(array(
            'insert_id' => $insertId,
            'result'    => $returnData
        ), 200);
    }

    /**
     * Validate form data.
     *
     * @param $form
     * @param $fields
     *
     * @return bool
     */
    private function validate($form, &$fields)
    {
        $this->validateRestrictions($form, $fields);

        $this->validateNonce($form->id);

        $this->validateReCaptcha();

        $validations = $this->parser->getValidations($this->formData, $fields);

        // Fire an event so that one can hook into it to work with the rules & messages.
        $validations = $this->app->applyFilters('fluentform_validations', $validations, $form, $this->parser);

        $validator = \FluentValidator\Validator::make($this->formData, $validations[0], $validations[1]);

        if ($validator->validate()->fails()) {
            $errors = [];

            foreach ($validator->errors() as $attribute => $rules) {
                $position = strpos($attribute, ']');

                if ($position) {
                    $attribute = substr($attribute, 0, strpos($attribute, ']') + 1);
                }

                $errors[$attribute] = $rules;
            }

            // Fire an event so that one can hook into it to work with the errors.
            $errors = $this->app->applyFilters('fluentform_validation_error', $errors, $form);

            wp_send_json(['errors' => $errors], 423);
        }

        return true;
    }

    /**
     * Validate nonce.
     *
     * @param $formId
     */
    protected function validateNonce($formId)
    {
        $shouldVerifyNonce = $this->app->applyFilters('fluentform_nonce_verify', true, $formId);

        if ($shouldVerifyNonce) {
            $nonce = ArrayHelper::get($this->formData, '_fluentform_'.$formId.'_fluentformnonce');
            if (! wp_verify_nonce($nonce, 'fluentform-submit-form')) {
                $errors = $this->app->applyFilters('fluentForm_nonce_error', [
                    '_fluentformnonce' => [
                        __('Nonce verification failed, please try again.', 'fluentform')
                    ]
                ]);

                wp_send_json(['errors' => $errors], 423);
            }
        }
    }

    /**
     * Validate reCaptcha.
     *
     * @param $formId
     */
    private function validateReCaptcha()
    {
        if ($this->parser->hasElement('recaptcha')) {
            $isValid = ReCaptcha::validate(ArrayHelper::get($this->formData, 'g-recaptcha-response'));

            if (! $isValid) {
                wp_send_json([
                    'errors' => [
                        'g-recaptcha-response' => [
                            __('reCaptcha verification failed, please try again.', 'fluentform')
                        ]
                    ]
                ], 423);
            }
        }
    }

    /**
     * Validate form data based on the form restrictions settings.
     *
     * @param \stdClass $form
     * @param $fields
     */
    private function validateRestrictions($form, &$fields)
    {
        $formSettings = wpFluent()->table('fluentform_form_meta')->where('form_id', $form->id)
            ->where('meta_key', 'formSettings')
            ->first();

        $form->settings = $formSettings ? json_decode($formSettings->value, true) : [];

        $isAllowed = [
            'status'  => true,
            'message' => ''
        ];

        // This will check the following restriction settings.
        // 1. limitNumberOfEntries
        // 2. scheduleForm
        // 3. requireLogin
        $isAllowed = apply_filters('fluentform_is_form_renderable', $isAllowed, $form);

        if (! $isAllowed['status']) {
            wp_send_json([
                'errors' => [
                    'restricted' => [
                        __($isAllowed['message'], 'fluentform')
                    ]
                ]
            ], 423);
        }

        // Since we are here, we should now handle if the form should be allowed to submit empty.
        $restrictions = ArrayHelper::get($form->settings, 'restrictions.denyEmptySubmission', []);
        $this->handleDenyEmptySubmission($restrictions, $fields);
    }

    /**
     * Handle response when empty form submission is not allowed.
     *
     * @param array $settings
     * @param $fields
     */
    private function handleDenyEmptySubmission($settings = [], &$fields)
    {
        // Determine whether empty form submission is allowed or not.
        if (ArrayHelper::get($settings, 'enabled')) {
            // confirm this form has no required fields.
            if (! $this->parser->hasRequiredFields($fields)) {
                // Filter out the form data which doesn't have values.
                $filteredFormData = array_filter(
                // Filter out the other meta fields that aren't actual inputs.
                    array_intersect_key($this->formData, $fields)
                );

                if (! count($filteredFormData)) {
                    wp_send_json([
                        'errors' => [
                            'restricted' => [
                                __(ArrayHelper::get($settings, 'message'), 'fluentform')
                            ]
                        ]
                    ], 423);
                }
            }
        }
    }

    /**
     * Prepare the data to be inserted to the database.
     *
     * @param $formId
     *
     * @return array
     */
    public function prepareInsertData($formId, $formData = false)
    {
    	if(!$formData) {
		    $formData = $this->formData;
	    }
        $previousItem = wpFluent()->table('fluentform_submissions')
            ->where('form_id', $formId)
            ->orderBy('id', 'DESC')
            ->first();

        $serialNumber = 1;

        if ($previousItem) {
            $serialNumber = $previousItem->serial_number + 1;
        }

        $browser = new Browser;

	    $formData = apply_filters('fluentform_insert_response_data', $formData, $formId);
        
        return [
            'form_id'       => $formId,
            'serial_number' => $serialNumber,
            'response'      => json_encode($formData),
            'source_url'    => site_url(ArrayHelper::get($formData, '_wp_http_referer')),
            'user_id'       => get_current_user_id(),
            'browser'       => $browser->getBrowser(),
            'device'        => $browser->getPlatform(),
            'ip'            => $this->app->request->getIp(),
            'created_at'    => date("Y-m-d H:i:s"),
            'updated_at'    => date("Y-m-d H:i:s")
        ];
    }

    /**
     * Delegate the validation rules & messages to the
     * ones that the validation library recognizes.
     *
     * @param $rules
     * @param $messages
     *
     * @return array
     */
    protected function delegateValidations($rules, $messages, $search = [], $replace = [])
    {
        $search = $search ?: ['max_file_size', 'allowed_file_types'];
        $replace = $replace ?: ['max', 'mimes'];

        foreach ($rules as &$rule) {
            $rule = str_replace($search, $replace, $rule);
        }

        foreach ($messages as $key => $message) {
            $newKey = str_replace($search, $replace, $key);
            $messages[$newKey] = $message;
            unset($messages[$key]);
        }

        return [$rules, $messages];
    }
}

```
