芝麻web文件管理V1.00
编辑当前文件:/home/royashxg/www/wp-content/plugins/fluentform/app/Services/Form/FormValidationService.php
app = App::getInstance(); } public function setForm($form) { $this->form = $form; } public function setFormData($formData) { $this->formData = $formData; } /** * @param $fields * @param $formData * @return bool * @throws ValidationException */ public function validateSubmission(&$fields, &$formData) { do_action('fluentform/before_form_validation', $fields, $formData); $this->preventMaliciousAttacks(); $this->validateRestrictions($fields); $this->validateNonce(); $this->validateReCaptcha(); $this->validateHCaptcha(); $this->validateTurnstile(); foreach ($fields as $fieldName => $field) { if (isset($formData[$fieldName])) { $element = $field['element']; $formData[$fieldName] = apply_filters_deprecated('fluentform_input_data_' . $element, [ $formData[$fieldName], $field, $formData, $this->form ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/input_data_' . $element, 'Use fluentform/input_data_' . $element . ' instead of fluentform_input_data_' . $element ); $formData[$fieldName] = apply_filters('fluentform/input_data_' . $element, $formData[$fieldName], $field, $formData, $this->form); } } $originalValidations = FormFieldsParser::getValidations($this->form, $formData, $fields); // Fire an event so that one can hook into it to work with the rules & messages. $originalValidations = apply_filters_deprecated('fluentform_validations', [ $originalValidations, $this->form, $formData ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/validations', 'Use fluentform/validations instead of fluentform_validations.' ); $validations = apply_filters('fluentform/validations', $originalValidations, $this->form, $formData); /* * Clean talk fix for now * They should not hook fluentform_validations and return nothing! * We will remove this extra check once it's done */ if ($originalValidations && (!$validations || !array_filter($validations))) { $validations = $originalValidations; } $validator = wpFluentForm('validator')->make($formData, $validations[0], $validations[1]); $errors = []; if ($validator->validate()->fails()) { 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 = apply_filters_deprecated('fluentform_validation_error', [ $errors, $this->form, $fields, $formData ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/validation_error', 'Use fluentform/validation_error instead of fluentform_validation_error.' ); $errors = $this->app->applyFilters('fluentform/validation_error', $errors, $this->form, $fields, $formData); } foreach ($fields as $fieldKey => $field) { $field['data_key'] = $fieldKey; $inputName = Arr::get($field, 'raw.attributes.name'); $field['name'] = $inputName; $error = $this->validateInput($field, $formData, $this->form); $error = apply_filters_deprecated('fluentform_validate_input_item_' . $field['element'], [ $error, $field, $formData, $fields, $this->form, $errors ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/validate_input_item_' . $field['element'], 'Use fluentform/validate_input_item_' . $field['element'] . ' instead of fluentform_validate_input_item_' . $field['element'] ); $error = apply_filters('fluentform/validate_input_item_' . $field['element'], $error, $field, $formData, $fields, $this->form, $errors); if ($error) { if (empty($errors[$inputName])) { $errors[$inputName] = []; } if (is_string($error)) { $error = [$error]; } $errors[$inputName] = array_merge($error, $errors[$inputName]); } } $errors = apply_filters_deprecated('fluentform_validation_errors', [ $errors, $formData, $this->form, $fields ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/validation_errors', 'Use fluentform/validation_errors instead of fluentform_validation_errors.' ); $errors = apply_filters('fluentform/validation_errors', $errors, $formData, $this->form, $fields); if ('yes' == Helper::getFormMeta($this->form->id, '_has_user_registration') && !get_current_user_id()) { $errors = apply_filters_deprecated('fluentform_validation_user_registration_errors', [ $errors, $formData, $this->form, $fields ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/validation_user_registration_errors', 'Use fluentform/validation_user_registration_errors instead of fluentform_validation_user_registration_errors.' ); $errors = apply_filters('fluentform/validation_user_registration_errors', $errors, $formData, $this->form, $fields); } if ('yes' == Helper::getFormMeta($this->form->id, '_has_user_update') && get_current_user_id()) { $errors = apply_filters_deprecated('fluentform_validation_user_update_errors', [ $errors, $formData, $this->form, $fields ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/validation_user_update_errors', 'Use fluentform/validation_user_update_errors instead of fluentform_validation_user_update_errors.' ); $errors = apply_filters('fluentform/validation_user_update_errors', $errors, $formData, $this->form, $fields); } if ('update' == Arr::get(Helper::getFormMeta($this->form->id, 'postFeeds'), 'post_form_type')) { $errors = apply_filters('fluentform/validation_post_update_errors', $errors, $formData, $this->form, $fields); } if ($errors) { throw new ValidationException('', 423, null, ['errors' => $errors]); } return true; } protected function validateInput($field, $formData, $form, $fieldName = '', $inputValue = []) { return Helper::validateInput($field, $formData, $form, $fieldName, $inputValue); } /** * Prevents malicious attacks when the submission * count exceeds in an allowed interval. * @throws ValidationException */ public function preventMaliciousAttacks() { $prevent = apply_filters('fluentform/prevent_malicious_attacks', true, $this->form->id); if ($prevent) { $maxSubmissionCount = apply_filters('fluentform/max_submission_count', 5, $this->form->id); $minSubmissionInterval = apply_filters('fluentform/min_submission_interval', 30, $this->form->id); $interval = date('Y-m-d H:i:s', strtotime(current_time('mysql')) - $minSubmissionInterval); $submissionCount = wpFluent()->table('fluentform_submissions') ->where('status', '!=', 'trashed') ->where('ip', $this->app->request->getIp()) ->where('created_at', '>=', $interval) ->count(); if ($submissionCount >= $maxSubmissionCount) { throw new ValidationException('', 429, null, [ 'errors' => [ 'restricted' => [ __(apply_filters('fluentform/too_many_requests', 'Too Many Requests.', $this->form->id), 'fluentform'), ], ] ]); } } } /** * Validate form data based on the form restrictions settings. * * @param $fields * @throws ValidationException */ private function validateRestrictions(&$fields) { $formSettings = FormMeta::retrieve('formSettings', $this->form->id); $this->form->settings = is_array($formSettings) ? $formSettings : []; $isAllowed = [ 'status' => true, 'message' => '', ]; // This will check the following restriction settings. // 1. limitNumberOfEntries // 2. scheduleForm // 3. requireLogin // 4. restricted submission based on ip, country and keywords /* This filter is deprecated and will be removed soon */ $isAllowed = apply_filters('fluentform_is_form_renderable', $isAllowed, $this->form); $isAllowed = apply_filters('fluentform/is_form_renderable', $isAllowed, $this->form); if (!$isAllowed['status']) { throw new ValidationException('', 422, null, [ 'errors' => [ 'restricted' => [ $isAllowed['message'], ], ], ]); } // Since we are here, we should now handle if the form should be allowed to submit empty. $restrictions = Arr::get($this->form->settings, 'restrictions.denyEmptySubmission', []); $this->handleDenyEmptySubmission($restrictions, $fields); $formRestrictions = Arr::get($this->form->settings, 'restrictions.restrictForm', []); $this->handleRestrictedSubmission($formRestrictions, $fields); } /** * Handle response when empty form submission is not allowed. * * @param array $settings * @param $fields * @throws ValidationException */ private function handleDenyEmptySubmission($settings, &$fields) { // Determine whether empty form submission is allowed or not. if (Arr::get($settings, 'enabled')) { // confirm this form has no required fields. if (!FormFieldsParser::hasRequiredFields($this->form, $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(Helper::arrayFilterRecursive($filteredFormData))) { $defaultMessage = __('Sorry! You can\'t submit an empty form.','fluentform'); $customMessage = Arr::get($settings, 'message'); throw new ValidationException('', 422, null, [ 'errors' => [ 'restricted' => [ !empty($customMessage) ? $customMessage : $defaultMessage, ], ], ]); } } } } /** * Handle response when form submission is restricted based on ip, country or keywords. * * @param array $settings * @param $fields * @throws ValidationException */ protected function handleRestrictedSubmission($settings, &$fields) { // Determine this restriction is enabled ot not if (!Arr::get($settings, 'enabled')) { return; } $ip = $this->app->request->getIp(); if (is_array($ip)) { $ip = Arr::get($ip, '0'); } $this->checkIpRestriction($settings, $ip); $isCountryRestrictionEnabled = Arr::get($settings, 'fields.country.status'); if ($ipInfo = $this->getIpInfo()) { $country = Arr::get($ipInfo, 'country'); if ($isCountryRestrictionEnabled) { $this->checkCountryRestriction($settings, $country); } } else { if ($isCountryRestrictionEnabled) { $country = $this->getIpBasedOnCountry($ip); $this->checkCountryRestriction($settings, $country); } } $this->checkKeyWordRestriction($settings); } /** * Validate nonce. * @throws ValidationException */ protected function validateNonce() { $formId = $this->form->id; $shouldVerifyNonce = false; /* This filter is deprecated and will be removed soon. */ $shouldVerifyNonce = $this->app->applyFilters('fluentform_nonce_verify', $shouldVerifyNonce, $formId); $shouldVerifyNonce = $this->app->applyFilters('fluentform/nonce_verify', $shouldVerifyNonce, $formId); if ($shouldVerifyNonce) { $nonce = Arr::get($this->formData, '_fluentform_' . $formId . '_fluentformnonce'); if (!wp_verify_nonce($nonce, 'fluentform-submit-form')) { $errors = apply_filters_deprecated( 'fluentForm_nonce_error', [ '_fluentformnonce' => [ __('Nonce verification failed, please try again.', 'fluentform'), ], ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentForm/nonce_error', 'Use fluentForm/nonce_error instead of fluentForm_nonce_error.' ); $errors = $this->app->applyFilters('fluentForm/nonce_error', $errors); throw new ValidationException('', 422, null, ['errors' => $errors]); } } } /** Validate Spam * @throws ValidationException */ public function handleSpamError() { $settings = get_option('_fluentform_global_form_settings'); if (!$settings || 'validation_failed' != Arr::get($settings, 'misc.akismet_validation')) { return; } $errors = [ '_fluentformakismet' => __('Submission marked as spammed. Please try again', 'fluentform'), ]; throw new ValidationException('', 422, null, ['errors' => $errors]); } public function isSpam($formData, $form) { if (!AkismetHandler::isEnabled()) { return false; } $isSpamCheck = apply_filters_deprecated( 'fluentform_akismet_check_spam', [ true, $form->id, $formData ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/akismet_check_spam', 'Use fluentform/akismet_check_spam instead of fluentform_akismet_check_spam.' ); $isSpamCheck = apply_filters('fluentform/akismet_check_spam', $isSpamCheck, $form->id, $formData); if (!$isSpamCheck) { return false; } // Let's validate now $isSpam = AkismetHandler::isSpamSubmission($formData, $form); $isSpam = apply_filters_deprecated( 'fluentform_akismet_spam_result', [ $isSpam, $form->id, $formData ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/akismet_spam_result', 'Use fluentform/akismet_spam_result instead of fluentform_akismet_spam_result.' ); return apply_filters('fluentform/akismet_spam_result', $isSpam, $form->id, $formData); } /** * Validate reCaptcha. * @throws ValidationException */ private function validateReCaptcha() { $hasAutoRecap = apply_filters_deprecated( 'ff_has_auto_recaptcha', [ false ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/has_recaptcha', 'Use fluentform/has_recaptcha instead of ff_has_auto_recaptcha.' ); $autoInclude = apply_filters('fluentform/has_recaptcha', $hasAutoRecap); if (FormFieldsParser::hasElement($this->form, 'recaptcha') || $autoInclude) { $keys = get_option('_fluentform_reCaptcha_details'); $token = Arr::get($this->formData, 'g-recaptcha-response'); $version = 'v2_visible'; if (!empty($keys['api_version'])) { $version = $keys['api_version']; } $isValid = ReCaptcha::validate($token, $keys['secretKey'], $version); if (!$isValid) { throw new ValidationException('', 422, null, [ 'errors' => [ 'g-recaptcha-response' => [ __('reCaptcha verification failed, please try again.', 'fluentform'), ], ], ]); } } } /** * Validate hCaptcha. * @throws ValidationException */ private function validateHCaptcha() { $hasAutoHcap = apply_filters_deprecated( 'ff_has_auto_hcaptcha', [ false ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/has_hcaptcha', 'Use fluentform/has_hcaptcha instead of ff_has_auto_hcaptcha.' ); $autoInclude = apply_filters('fluentform/has_hcaptcha', $hasAutoHcap); FormFieldsParser::resetData(); if (FormFieldsParser::hasElement($this->form, 'hcaptcha') || $autoInclude) { $keys = get_option('_fluentform_hCaptcha_details'); $token = Arr::get($this->formData, 'h-captcha-response'); $isValid = HCaptcha::validate($token, $keys['secretKey']); if (!$isValid) { throw new ValidationException('', 422, null, [ 'errors' => [ 'h-captcha-response' => [ __('hCaptcha verification failed, please try again.', 'fluentform'), ], ], ]); } } } /** * Validate turnstile. * @throws ValidationException */ private function validateTurnstile() { $hasAutoTurnsTile = apply_filters_deprecated( 'ff_has_auto_turnstile', [ false ], FLUENTFORM_FRAMEWORK_UPGRADE, 'fluentform/has_turnstile', 'Use fluentform/has_turnstile instead of ff_has_auto_turnstile.' ); $autoInclude = apply_filters('fluentform/has_turnstile', $hasAutoTurnsTile); if (FormFieldsParser::hasElement($this->form, 'turnstile') || $autoInclude) { $keys = get_option('_fluentform_turnstile_details'); $token = Arr::get($this->formData, 'cf-turnstile-response'); $isValid = Turnstile::validate($token, $keys['secretKey']); if (!$isValid) { throw new ValidationException('', 422, null, [ 'errors' => [ 'cf-turnstile-response' => [ __('Turnstile verification failed, please try again.', 'fluentform'), ], ], ]); } } } /** * Delegate the validation rules & messages to the * ones that the validation library recognizes. * * @param $rules * @param $messages * @param array $search * @param array $replace * @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]; } /** * Get IP info from ipinfo.io * * @throws ValidationException */ private function getIpInfo() { $token = Helper::getIpinfo(); $url = 'https://ipinfo.io'; if ($token) { $url = 'https://ipinfo.io/?token=' . $token; } $data = wp_remote_get($url); $code = wp_remote_retrieve_response_code($data); $body = wp_remote_retrieve_body($data); $result = \json_decode($body, true); if ($code === 200) { return $result; } else { $message = __('Sorry! There is an error in your geocode IP address settings. Please check the token', 'fluentform'); self::throwValidationException($message); } } /** * Get IP and Country from geoplugin * * @throws ValidationException */ private function getIpBasedOnCountry($ip) { $request = wp_remote_get("http://www.geoplugin.net/php.gp?ip={$ip}"); $code = wp_remote_retrieve_response_code($request); $message = __('Sorry! There is an error occurred in getting Country using geoplugin.net. Please check form settings and try again.', 'fluentform'); if ($code === 200) { $body = wp_remote_retrieve_body($request); $body = unserialize($body); if ($country = Arr::get($body,'geoplugin_countryCode')) { return $country; } else { self::throwValidationException($message); } } else { self::throwValidationException($message); } } /** * @param $value * @param $providedKeywords * @return bool */ public static function containsRestrictedKeywords($value, $providedKeywords) { preg_match_all('/\b[\p{L}\d\s]+\b/u', $value, $matches); $words = $matches[0] ?? []; foreach ($providedKeywords as $keyword) { foreach ($words as $word) { if ( strtoupper($word) === strtoupper($keyword) || preg_match('/\b' . strtoupper($keyword) . '\b/', strtoupper($word)) ) { return true; } } } return false; } /** * @throws ValidationException */ private function checkIpRestriction($settings, $ip) { if (Arr::get($settings, 'fields.ip.status') && $ip) { $providedIp = array_map('trim', explode(',', Arr::get($settings, 'fields.ip.values'))); $isFailed = Arr::get($settings, 'fields.ip.validation_type') === 'fail_on_condition_met'; $failedSubmissionIfExists = $isFailed && in_array($ip, $providedIp); $allowSubmissionIfNotExists = !$isFailed && !in_array($ip, $providedIp); if ($failedSubmissionIfExists || $allowSubmissionIfNotExists) { $defaultMessage = __('Sorry! You can\'t submit a form from your IP address.', 'fluentform'); $message = Arr::get($settings, 'fields.ip.message', $defaultMessage); self::throwValidationException($message); } } } /** * @throws ValidationException */ private function checkCountryRestriction($settings, $country) { if ($country) { $providedCountry = Arr::get($settings, 'fields.country.values'); $isFailed = Arr::get($settings, 'fields.country.validation_type') === 'fail_on_condition_met'; $failedSubmissionIfExists = $isFailed && in_array($country, $providedCountry); $allowSubmissionIfNotExists = !$isFailed && !in_array($country, $providedCountry); if ($failedSubmissionIfExists || $allowSubmissionIfNotExists) { $defaultMessage = __('Sorry! You can\'t submit this form from the country you are residing.', 'fluentform'); $message = Arr::get($settings, 'fields.country.message', $defaultMessage); self::throwValidationException($message); } } } private function checkKeyWordRestriction($settings) { if (!Arr::get($settings, 'fields.keywords.status')) { return; } $providedKeywords = explode(',', Arr::get($settings, 'fields.keywords.values')); $providedKeywords = array_map('trim', $providedKeywords); $inputSubmission = array_intersect_key( $this->formData, array_flip( array_keys( FormFieldsParser::getInputs($this->form) ) ) ); $defaultMessage = __('Sorry! Your submission contains some restricted keywords.', 'fluentform'); $message = Arr::get($settings, 'fields.keywords.message', $defaultMessage); self::checkKeywordsMatching($inputSubmission, $message, $providedKeywords); } private static function checkKeywordsMatching($inputSubmission, $message, $providedKeywords) { foreach ($inputSubmission as $value) { if (!empty($value)) { if (is_array($value)) { self::checkKeywordsMatching($value, $message, $providedKeywords); } else { if (self::containsRestrictedKeywords($value, $providedKeywords)) { self::throwValidationException($message); } } } } } /** * @throws ValidationException */ public static function throwValidationException($message) { throw new ValidationException('', 422, null, [ 'errors' => [ 'restricted' => [ $message ], ], ]); } }