1: <?php
2:
3: 4: 5:
6: class Quform_Form_Processor
7: {
8: 9: 10:
11: protected $repository;
12:
13: 14: 15:
16: protected $session;
17:
18: 19: 20:
21: protected $uploader;
22:
23: 24: 25:
26: protected $options;
27:
28: 29: 30: 31: 32: 33:
34: public function __construct(
35: Quform_Repository $repository,
36: Quform_Session $session,
37: Quform_Uploader $uploader,
38: Quform_Options $options
39: ) {
40: $this->repository = $repository;
41: $this->session = $session;
42: $this->uploader = $uploader;
43: $this->options = $options;
44: }
45:
46: 47: 48: 49: 50: 51:
52: public function process(Quform_Form $form)
53: {
54:
55: $_POST = wp_unslash($_POST);
56:
57:
58: if ($this->options->get('csrfProtection') && ( ! isset($_POST['quform_csrf_token']) || $this->session->getToken() != $_POST['quform_csrf_token'])) {
59: return apply_filters(
60: 'quform_csrf_failure_response',
61: array(
62: 'type' => 'error',
63: 'error' => array(
64: 'enabled' => true,
65: 'title' => __('An error occurred', 'quform'),
66: 'content' => __('Refresh the page and try again.', 'quform')
67: )
68: ),
69: $form
70: );
71: }
72:
73:
74: if ($this->options->get('timeBasedProtection') && isset($_POST['quform_loaded'])) {
75: $parts = explode('|', sanitize_text_field($_POST['quform_loaded']), 2);
76:
77:
78: if (count($parts) === 2) {
79: list($timestamp, $hash) = $parts;
80:
81:
82: if (hash_equals(wp_hash($timestamp . '|'), $hash)) {
83: $elapsed = time() - (int) $timestamp;
84:
85:
86: $minTime = apply_filters('quform_time_based_min_time', 2);
87: $minTime = apply_filters('quform_time_based_min_time_' . $form->getId(), $minTime, $form);
88:
89: if ($elapsed < $minTime) {
90: return apply_filters(
91: 'quform_time_based_failure_response',
92: array(
93: 'type' => 'error',
94: 'error' => array(
95: 'enabled' => true,
96: 'title' => __('An error occurred', 'quform'),
97: 'content' => __('Please wait a moment before submitting.', 'quform')
98: )
99: ),
100: $form
101: );
102: }
103: } else {
104:
105: return apply_filters(
106: 'quform_time_based_failure_response',
107: array(
108: 'type' => 'error',
109: 'error' => array(
110: 'enabled' => true,
111: 'title' => __('An error occurred', 'quform'),
112: 'content' => __('Refresh the page and try again.', 'quform')
113: )
114: ),
115: $form
116: );
117: }
118: } else {
119:
120: return apply_filters(
121: 'quform_time_based_failure_response',
122: array(
123: 'type' => 'error',
124: 'error' => array(
125: 'enabled' => true,
126: 'title' => __('An error occurred', 'quform'),
127: 'content' => __('Refresh the page and try again.', 'quform')
128: )
129: ),
130: $form
131: );
132: }
133: }
134:
135:
136: $result = apply_filters('quform_pre_process', array(), $form);
137: $result = apply_filters('quform_pre_process_' . $form->getId(), $result, $form);
138:
139: if (is_array($result) && ! empty($result)) {
140: return $result;
141: }
142:
143: $result = $this->checkEntryLimits( $form);
144:
145: if (is_array($result) && ! empty($result)) {
146: return $result;
147: }
148:
149: $result = $this->checkFormSchedule( $form);
150:
151: if (is_array($result) && ! empty($result)) {
152: return $result;
153: }
154:
155: $this->uploader->mergeSessionFiles($form);
156:
157:
158: $form->setValues($_POST, true);
159:
160: $result = apply_filters('quform_post_set_form_values', array(), $form);
161: $result = apply_filters('quform_post_set_form_values_' . $form->getId(), $result, $form);
162:
163: if (is_array($result) && ! empty($result)) {
164: return $result;
165: }
166:
167:
168: $form->calculateElementVisibility();
169:
170: $form->setCurrentPageById((int) $_POST['quform_current_page_id']);
171:
172:
173: $result = apply_filters('quform_pre_validate', array(), $form);
174: $result = apply_filters('quform_pre_validate_' . $form->getId(), $result, $form);
175:
176: if (is_array($result) && ! empty($result)) {
177: return $result;
178: }
179:
180:
181: if ($form->hasPages()) {
182: if (isset($_POST['quform_submit']) && $_POST['quform_submit'] === 'back') {
183:
184: return array('type' => 'page', 'page' => $form->getNextPageId(true));
185: } else {
186:
187: if (($nextPageId = $form->getNextPageId()) !== null) {
188: if ($form->getCurrentPage()->isValid()) {
189: return array('type' => 'page', 'page' => $nextPageId);
190: } else {
191:
192: return array('type' => 'error', 'error' => $form->getGlobalError(), 'errors' => $form->getCurrentPage()->getErrors(), 'page' => $form->getCurrentPage()->getId());
193: }
194: }
195: }
196: }
197:
198:
199: list($valid, $firstErrorPage) = $form->isValid();
200:
201: if ($valid) {
202:
203: $result = apply_filters('quform_post_validate', array(), $form);
204: $result = apply_filters('quform_post_validate_' . $form->getId(), $result, $form);
205:
206: if (is_array($result) && ! empty($result)) {
207: return $result;
208: }
209:
210:
211: $entryId = $this->saveEntry($form);
212: $form->setEntryId($entryId);
213:
214: $result = apply_filters('quform_post_set_entry_id', array(), $form);
215: $result = apply_filters('quform_post_set_entry_id_' . $form->getId(), $result, $form);
216:
217: if (is_array($result) && ! empty($result)) {
218: return $result;
219: }
220:
221:
222: $this->uploader->process($form);
223:
224:
225: $this->saveEntryData($entryId, $form);
226:
227: $result = apply_filters('quform_post_save_entry_data', array(), $form);
228: $result = apply_filters('quform_post_save_entry_data_' . $form->getId(), $result, $form);
229:
230: if (is_array($result) && ! empty($result)) {
231: return $result;
232: }
233:
234:
235: $this->sendNotifications($form);
236:
237:
238: $form->setConfirmation();
239:
240:
241: $this->saveToCustomDatabase($form);
242:
243:
244: if ($this->session->has($form->getSessionKey())) {
245: $this->session->forget($form->getSessionKey());
246: }
247:
248:
249: $result = apply_filters('quform_post_process', array(), $form);
250: $result = apply_filters('quform_post_process_' . $form->getId(), $result, $form);
251:
252: if (is_array($result) && ! empty($result)) {
253: return $result;
254: }
255:
256: $result = array(
257: 'type' => 'success',
258: 'confirmation' => $form->getConfirmation()->getData()
259: );
260: } else {
261: $result = array(
262: 'type' => 'error',
263: 'error' => $form->getGlobalError(),
264: 'errors' => $form->getErrors(),
265: 'page' => $firstErrorPage->getId()
266: );
267: }
268:
269: return $result;
270: }
271:
272: 273: 274: 275: 276: 277:
278: protected function checkEntryLimits(Quform_Form $form) {
279: if ( ! $this->options->get('saveEntries') || ! $form->config('saveEntry')) {
280: return true;
281: }
282:
283: if (apply_filters('quform_bypass_entry_limits', current_user_can('quform_edit_forms'), $form)) {
284: return true;
285: }
286:
287: if ($form->config('oneEntryPerUser')) {
288: $entryExists = false;
289:
290: if ($form->config('oneEntryPer') == 'logged-in-user') {
291: if (is_user_logged_in()) {
292: $entryExists = $this->repository->entryExistsByFormIdAndCreatedBy(
293: $form->getId(),
294: get_current_user_id()
295: );
296: }
297: } elseif ($form->config('oneEntryPer') == 'ip-address') {
298: $entryExists = $this->repository->entryExistsByFormIdAndIpAddress(
299: $form->getId(),
300: Quform::getClientIp()
301: );
302: }
303:
304: $entryExists = apply_filters('quform_one_entry_per_user_entry_exists', $entryExists, $form);
305:
306: if ($entryExists) {
307: return apply_filters('quform_one_entry_per_user_error', array(
308: 'type' => 'error',
309: 'error' => array(
310: 'enabled' => true,
311: 'title' => '',
312: 'content' => $form->getTranslation(
313: 'onlyOneSubmissionAllowed',
314: __('Only one submission is allowed.', 'quform')
315: )
316: )
317: ), $form);
318: }
319: }
320:
321: if ($form->config('limitEntries') && is_numeric($form->config('entryLimit')) && $form->config('entryLimit') > 0) {
322: $entryCount = $this->repository->getEntryCount($form->getId());
323:
324: $entryCount = apply_filters('quform_entry_count', $entryCount, $form);
325: $entryCount = apply_filters('quform_entry_count_' . $form->getId(), $entryCount, $form);
326:
327: if ($entryCount >= $form->config('entryLimit')) {
328: return apply_filters('quform_entry_limit_reached_error', array(
329: 'type' => 'error',
330: 'error' => array(
331: 'enabled' => true,
332: 'title' => '',
333: 'content' => $form->getTranslation(
334: 'thisFormIsCurrentlyClosed',
335: __('This form is currently closed for submissions.', 'quform')
336: )
337: )
338: ), $form);
339: }
340: }
341:
342: return true;
343: }
344:
345: 346: 347: 348: 349: 350:
351: public function checkFormSchedule(Quform_Form $form)
352: {
353: if (
354: ! $form->config('enableSchedule') ||
355: (
356: ! Quform::isNonEmptyString('scheduleStart') &&
357: ! Quform::isNonEmptyString('scheduleEnd')
358: )
359: ) {
360: return true;
361: }
362:
363: if (apply_filters('quform_bypass_form_schedule', current_user_can('quform_edit_forms'), $form)) {
364: return true;
365: }
366:
367: try {
368: $now = new DateTime('now', new DateTimeZone('UTC'));
369:
370: if (Quform::isNonEmptyString($form->config('scheduleStart'))) {
371: $start = DateTime::createFromFormat('Y-m-d H:i:s', $form->config('scheduleStart'));
372:
373: if ($start instanceof DateTime && $now < $start) {
374: return apply_filters('quform_schedule_start_error', array(
375: 'type' => 'error',
376: 'error' => array(
377: 'enabled' => true,
378: 'title' => '',
379: 'content' => $form->getTranslation(
380: 'formIsNotYetOpenForSubmissions',
381: __('This form is not yet open for submissions.', 'quform')
382: )
383: )
384: ), $form);
385: }
386: }
387:
388: if (Quform::isNonEmptyString($form->config('scheduleEnd'))) {
389: $end = DateTime::createFromFormat('Y-m-d H:i:s', $form->config('scheduleEnd'));
390:
391: if ($end instanceof DateTime && $now > $end) {
392: return apply_filters('quform_schedule_end_error', array(
393: 'type' => 'error',
394: 'error' => array(
395: 'enabled' => true,
396: 'title' => '',
397: 'content' => $form->getTranslation(
398: 'formIsNoLongerOpenForSubmissions',
399: __('This form is no longer open for submissions.', 'quform')
400: )
401: )
402: ), $form);
403: }
404: }
405: } catch (Exception $e) {
406:
407: }
408:
409: return true;
410: }
411:
412: 413: 414: 415:
416: protected function sendNotifications(Quform_Form $form)
417: {
418: foreach ($form->getNotifications() as $notification) {
419: if ( ! $notification->config('enabled')) {
420: continue;
421: }
422:
423: if ($notification->config('logicEnabled') && count($notification->config('logicRules'))) {
424: if ($form->checkLogicAction($notification->config('logicAction'), $notification->config('logicMatch'), $notification->config('logicRules'))) {
425: $notification->send();
426: }
427: } else {
428: $notification->send();
429: }
430: }
431:
432: return $this;
433: }
434:
435: 436: 437: 438: 439: 440:
441: protected function saveEntry(Quform_Form $form)
442: {
443: if ( ! $this->options->get('saveEntries') || ! $form->config('saveEntry')) {
444: return null;
445: }
446:
447: $currentTime = Quform::date('Y-m-d H:i:s', null, new DateTimeZone('UTC'));
448:
449: $entry = array(
450: 'form_id' => $form->getId(),
451: 'ip' => $this->options->get('saveIpAddresses') ? Quform::substr(Quform::getClientIp(), 0, 45) : '',
452: 'form_url' => isset($_POST['form_url']) ? Quform::substr($_POST['form_url'], 0, 512) : '',
453: 'referring_url' => isset($_POST['referring_url']) ? Quform::substr($_POST['referring_url'], 0, 512) : '',
454: 'post_id' => is_numeric($postId = Quform::get($_POST, 'post_id')) && $postId > 0 ? (int) $postId : null,
455: 'created_by' => is_user_logged_in() ? (int) Quform::getUserProperty('ID') : null,
456: 'created_at' => $currentTime,
457: 'updated_at' => $currentTime,
458: );
459:
460: $entry = $this->repository->saveEntry($entry);
461:
462: return $entry['id'];
463: }
464:
465: 466: 467: 468: 469: 470:
471: protected function saveEntryData($entryId, Quform_Form $form)
472: {
473: if ( ! ($entryId > 0) || ! $this->options->get('saveEntries') || ! $form->config('saveEntry')) {
474: return;
475: }
476:
477: $data = array();
478:
479: foreach ($form->getRecursiveIterator() as $element) {
480: if ($element->config('saveToDatabase') && ! $element->isConditionallyHidden()) {
481: if ( ! $element->isEmpty()) {
482: $data[$element->getId()] = $element->getValueForStorage();
483: }
484: }
485: }
486:
487: if (count($data)) {
488: $this->repository->saveEntryData($entryId, $data);
489: }
490: }
491:
492: 493: 494: 495: 496:
497: protected function saveToCustomDatabase(Quform_Form $form)
498: {
499: if ( ! $form->config('databaseEnabled') ||
500: ! count($columns = $form->config('databaseColumns')) ||
501: ! Quform::isNonEmptyString($table = $form->config('databaseTable'))
502: ) {
503: return;
504: }
505:
506: $data = array();
507: foreach ($columns as $column) {
508: if ( ! Quform::isNonEmptyString($column['name'])) {
509: continue;
510: }
511:
512: $data[$column['name']] = $form->replaceVariables($column['value']);
513: }
514:
515: if ($form->config('databaseWordpress')) {
516: global $wpdb;
517: $wpdb->insert($table, $data);
518: } else {
519: $customWpdb = new wpdb(
520: $form->config('databaseUsername'),
521: $form->config('databasePassword'),
522: $form->config('databaseDatabase'),
523: $form->config('databaseHost')
524: );
525:
526: $customWpdb->insert($table, $data);
527: }
528: }
529: }
530: