· 9 years ago · Aug 31, 2016, 09:50 AM
1<?php
2
3class GF_Submission_Limit {
4
5 var $_args;
6 var $_notification_event;
7
8 private static $forms_with_individual_settings = array();
9
10 function __construct($args) {
11
12 if (!property_exists('GFCommon', 'version') || !version_compare(GFCommon::$version, '1.8', '>='))
13 return;
14
15 $this->_args = wp_parse_args($args, array(
16 'form_id' => false,
17 'limit' => 1,
18 'limit_by' => 'ip',
19 'time_period' => 60 * 60 * 24,
20 'limit_message' => __('Sorry, you have reached the submission limit for this form.'),
21 'apply_limit_per_form' => true
22 ));
23
24 if (!is_array($this->_args['limit_by'])) {
25 $this->_args['limit_by'] = array(
26 $this->_args['limit_by']
27 );
28 }
29
30 if ($this->_args['form_id']) {
31 self::$forms_with_individual_settings[] = $this->_args['form_id'];
32 }
33
34 add_action('init', array(
35 $this,
36 'init'
37 ));
38
39 }
40
41 function init() {
42
43 add_filter('gform_pre_render', array(
44 $this,
45 'pre_render'
46 ));
47 add_filter('gform_validation', array(
48 $this,
49 'validate'
50 ));
51
52 }
53
54 function pre_render($form) {
55
56 if (!$this->is_applicable_form($form) || !$this->is_limit_reached($form['id'])) {
57 return $form;
58 }
59
60 $submission_info = rgar(GFFormDisplay::$submission, $form['id']);
61
62 if ((!$submission_info || !rgar($submission_info, 'is_valid')) && !$this->is_limited_by_field_value()) {
63 add_filter('gform_get_form_filter_' . $form['id'], create_function('', 'return \'<div class="limit-message">' . $this->_args['limit_message'] . '</div>\';'));
64 }
65
66 return $form;
67
68 }
69
70 function validate($validation_result) {
71
72 if (!$this->is_applicable_form($validation_result['form']) || !$this->is_limit_reached($validation_result['form']['id'])) {
73 return $validation_result;
74 }
75
76 $validation_result['is_valid'] = false;
77
78 if ($this->is_limited_by_field_value()) {
79 $field_ids = array_map('intval', $this->get_limit_field_ids());
80 foreach ($validation_result['form']['fields'] as &$field) {
81 if (in_array($field['id'], $field_ids)) {
82 $field['failed_validation'] = true;
83 $field['validation_message'] = do_shortcode($this->_args['limit_message']);
84 }
85 }
86 }
87
88 return $validation_result;
89 }
90
91 public function is_limit_reached($form_id) {
92 global $wpdb;
93
94 $where = array();
95 $join = array();
96
97 $where[] = 'l.status = "active"';
98
99 foreach ($this->_args['limit_by'] as $limiter) {
100 switch ($limiter) {
101 case 'role':
102 case 'user_id':
103 $where[] = $wpdb->prepare('l.created_by = %s', get_current_user_id());
104 break;
105 case 'embed_url':
106 $where[] = $wpdb->prepare('l.source_url = %s', GFFormsModel::get_current_page_url());
107 break;
108 case 'field_value':
109
110 $values = $this->get_limit_field_values($form_id, $this->get_limit_field_ids());
111
112 if (empty($values)) {
113 return false;
114 }
115
116 foreach ($values as $field_id => $value) {
117 $table_slug = sprintf('ld%s', str_replace('.', '_', $field_id));
118 $join[] = "INNER JOIN {$wpdb->prefix}rg_lead_detail {$table_slug} ON {$table_slug}.lead_id = l.id";
119 $where[] = $wpdb->prepare("\n( ( {$table_slug}.field_number BETWEEN %s AND %s ) AND {$table_slug}.value = %s )", doubleval($field_id) - 0.001, doubleval($field_id) + 0.001, $value);
120 }
121
122 break;
123 default:
124 $where[] = $wpdb->prepare('ip = %s', GFFormsModel::get_ip());
125 }
126 }
127
128 if ($this->_args['apply_limit_per_form']) {
129 $where[] = $wpdb->prepare('l.form_id = %d', $form_id);
130 }
131
132 $time_period = $this->_args['time_period'];
133 $time_period_sql = false;
134
135 if ($time_period === false) {
136 } else if (intval($time_period) > 0) {
137 $time_period_sql = $wpdb->prepare('date_created BETWEEN DATE_SUB(utc_timestamp(), INTERVAL %d SECOND) AND utc_timestamp()', $this->_args['time_period']);
138 } else {
139 switch ($time_period) {
140 case 'per_day':
141 case 'day':
142 $time_period_sql = 'DATE( date_created ) = DATE( utc_timestamp() )';
143 break;
144 case 'per_week':
145 case 'week':
146 $time_period_sql = 'WEEK( date_created ) = WEEK( utc_timestamp() )';
147 break;
148 case 'per_month':
149 case 'month':
150 $time_period_sql = 'MONTH( date_created ) = MONTH( utc_timestamp() )';
151 break;
152 case 'per_year':
153 case 'year':
154 $time_period_sql = 'YEAR( date_created ) = YEAR( utc_timestamp() )';
155 break;
156 }
157 }
158
159 if ($time_period_sql) {
160 $where[] = $time_period_sql;
161 }
162
163 $where = implode(' AND ', $where);
164 $join = implode("\n", $join);
165
166 $sql = "SELECT count( l.id )
167 FROM {$wpdb->prefix}rg_lead l
168 $join
169 WHERE $where";
170
171 $entry_count = $wpdb->get_var($sql);
172
173 return $entry_count >= $this->get_limit();
174 }
175
176 public function is_limited_by_field_value() {
177 return in_array('field_value', $this->_args['limit_by']);
178 }
179
180 public function get_limit_field_ids() {
181
182 $limit = $this->_args['limit'];
183
184 if (is_array($limit)) {
185 $field_ids = array(
186 call_user_func('array_shift', array_keys($this->_args['limit']))
187 );
188 } else {
189 $field_ids = $this->_args['fields'];
190 }
191
192 return $field_ids;
193 }
194
195 public function get_limit_field_values($form_id, $field_ids) {
196
197 $form = GFAPI::get_form($form_id);
198 $values = array();
199
200 foreach ($field_ids as $field_id) {
201
202 $field = GFFormsModel::get_field($form, $field_id);
203 $input_name = 'input_' . str_replace('.', '_', $field_id);
204 $value = GFFormsModel::prepare_value($form, $field, rgpost($input_name), $input_name, null);
205
206 if (!rgblank($value)) {
207 $values[$field_id] = $value;
208 }
209
210 }
211
212 return $values;
213 }
214
215 public function get_limit() {
216
217 $limit = $this->_args['limit'];
218
219 if ($this->is_limited_by_field_value()) {
220 $limit = is_array($limit) ? array_shift($limit) : intval($limit);
221 } else if (in_array('role', $this->_args['limit_by'])) {
222 $limit = rgar($limit, $this->get_user_role());
223 }
224
225 return intval($limit);
226 }
227
228 public function get_user_role() {
229
230 $user = wp_get_current_user();
231 $role = reset($user->roles);
232
233 return $role;
234 }
235
236 function is_applicable_form($form) {
237
238 $form_id = isset($form['id']) ? $form['id'] : $form;
239 $is_global_form = empty($this->_args['form_id']) && !in_array($form_id, self::$forms_with_individual_settings);
240 $is_specific_form = $form_id == $this->_args['form_id'];
241
242 return $is_global_form || $is_specific_form;
243 }
244
245}
246
247class GFSubmissionLimit extends GF_Submission_Limit {}
248
249class GF_Email_Domain_Validator {
250
251 private $_args;
252
253 function __construct($args) {
254
255 $this->_args = wp_parse_args($args, array(
256 'form_id' => false,
257 'field_id' => false,
258 'domains' => false,
259 'validation_message' => __('Sorry, <strong>%s</strong> email accounts are not eligible for this form.'),
260 'mode' => 'ban'
261 ));
262
263 if ($this->_args['field_id'] && !is_array($this->_args['field_id']))
264 $this->_args['field_id'] = array(
265 $this->_args['field_id']
266 );
267
268 $form_filter = $this->_args['form_id'] ? "_{$this->_args['form_id']}" : '';
269
270 add_filter("gform_validation{$form_filter}", array(
271 $this,
272 'validate'
273 ));
274
275 }
276
277 function validate($validation_result) {
278
279 $form = $validation_result['form'];
280
281 foreach ($form['fields'] as &$field) {
282
283 if (RGFormsModel::get_input_type($field) != 'email')
284 continue;
285
286 if ($this->_args['field_id'] && !in_array($field['id'], $this->_args['field_id']))
287 continue;
288
289 $page_number = GFFormDisplay::get_source_page($form['id']);
290 if ($page_number > 0 && $field->pageNumber != $page_number) {
291 continue;
292 }
293
294 $domain = $this->get_email_domain($field);
295
296 if ($this->is_domain_valid($domain) || empty($domain))
297 continue;
298
299 $validation_result['is_valid'] = false;
300 $field['failed_validation'] = true;
301 $field['validation_message'] = sprintf($this->_args['validation_message'], $domain);
302
303 }
304
305 $validation_result['form'] = $form;
306 return $validation_result;
307 }
308
309 function get_email_domain($field) {
310 $email = explode('@', rgpost("input_{$field['id']}"));
311 return rgar($email, 1);
312 }
313
314 function is_domain_valid($domain) {
315
316 $mode = $this->_args['mode'];
317 $domain = strtolower($domain);
318
319 foreach ($this->_args['domains'] as $_domain) {
320
321 $_domain = strtolower($_domain);
322
323 $full_match = $domain == $_domain;
324 $suffix_match = strpos($domain, '.') === 0 && $this->str_ends_with($domain, $_domain);
325 $has_match = $full_match || $suffix_match;
326
327 if ($mode == 'ban' && $has_match) {
328 return false;
329 } else if ($mode == 'limit' && $has_match) {
330 return true;
331 }
332
333 }
334
335 return $mode == 'limit' ? false : true;
336 }
337
338 function str_ends_with($string, $text) {
339
340 $length = strlen($string);
341 $text_length = strlen($text);
342
343 if ($text_length > $length) {
344 return false;
345 }
346
347 return substr_compare($string, $text, $length - $text_length, $text_length) === 0;
348 }
349
350}
351
352class GFEmailDomainControl extends GF_Email_Domain_Validator {}
353
354class GFPreviewConfirmation {
355
356 private static $lead;
357
358 public static function init() {
359 add_filter('gform_pre_render', array(
360 __class__,
361 'replace_merge_tags'
362 ));
363 }
364
365 public static function replace_merge_tags($form) {
366
367 $current_page = isset(GFFormDisplay::$submission[$form['id']]) ? GFFormDisplay::$submission[$form['id']]['page_number'] : 1;
368 $fields = array();
369
370 foreach ($form['fields'] as &$field) {
371
372 if (rgar($field, 'pageNumber') <= 1)
373 continue;
374
375 $default_value = rgar($field, 'defaultValue');
376 preg_match_all('/{.+}/', $default_value, $matches, PREG_SET_ORDER);
377 if (!empty($matches)) {
378 if (rgar($field, 'pageNumber') != $current_page) {
379 $field['defaultValue'] = '';
380 } else {
381 $field['defaultValue'] = self::preview_replace_variables($default_value, $form);
382 }
383 }
384
385 if (rgar($field, 'pageNumber') != $current_page)
386 continue;
387
388 $html_content = rgar($field, 'content');
389 preg_match_all('/{.+}/', $html_content, $matches, PREG_SET_ORDER);
390 if (!empty($matches)) {
391 $field['content'] = self::preview_replace_variables($html_content, $form);
392 }
393
394 }
395
396 return $form;
397 }
398
399 public static function preview_special_merge_tags($value, $input_id, $merge_tag, $field) {
400
401 if (!$value)
402 return $value;
403
404 $input_type = RGFormsModel::get_input_type($field);
405
406 $is_upload_field = in_array($input_type, array(
407 'post_image',
408 'fileupload'
409 ));
410 $is_multi_input = is_array(rgar($field, 'inputs'));
411 $is_input = intval($input_id) != $input_id;
412
413 if (!$is_upload_field && !$is_multi_input)
414 return $value;
415
416 if ($is_input)
417 return $value;
418
419 $form = RGFormsModel::get_form_meta($field['formId']);
420 $lead = self::create_lead($form);
421 $currency = GFCommon::get_currency();
422
423 if (is_array(rgar($field, 'inputs'))) {
424 $value = RGFormsModel::get_lead_field_value($lead, $field);
425 return GFCommon::get_lead_field_display($field, $value, $currency);
426 }
427
428 switch ($input_type) {
429 case 'fileupload':
430 $value = self::preview_image_value("input_{$field['id']}", $field, $form, $lead);
431 $value = self::preview_image_display($field, $form, $value);
432 break;
433 default:
434 $value = self::preview_image_value("input_{$field['id']}", $field, $form, $lead);
435 $value = GFCommon::get_lead_field_display($field, $value, $currency);
436 break;
437 }
438
439 return $value;
440 }
441
442 public static function preview_image_value($input_name, $field, $form, $lead) {
443
444 $field_id = $field['id'];
445 $file_info = RGFormsModel::get_temp_filename($form['id'], $input_name);
446 $source = RGFormsModel::get_upload_url($form['id']) . "/tmp/" . $file_info["temp_filename"];
447
448 if (!$file_info)
449 return '';
450
451 switch (RGFormsModel::get_input_type($field)) {
452
453 case "post_image":
454 list(, $image_title, $image_caption, $image_description) = explode("|:|", $lead[$field['id']]);
455 $value = !empty($source) ? $source . "|:|" . $image_title . "|:|" . $image_caption . "|:|" . $image_description : "";
456 break;
457
458 case "fileupload":
459 $value = $source;
460 break;
461
462 }
463
464 return $value;
465 }
466
467 public static function preview_image_display($field, $form, $value) {
468
469 $input_name = "input_" . str_replace('.', '_', $field['id']);
470 $file_info = RGFormsModel::get_temp_filename($form['id'], $input_name);
471
472 $file_path = $value;
473 if (!empty($file_path)) {
474 $file_path = esc_attr(str_replace(" ", "%20", $file_path));
475 $value = "<a href='$file_path' target='_blank' title='" . __("Click to view", "gravityforms") . "'>" . $file_info['uploaded_filename'] . "</a>";
476 }
477 return $value;
478
479 }
480
481 public static function create_lead($form) {
482
483 if (empty(self::$lead)) {
484 self::$lead = GFFormsModel::create_lead($form);
485 self::clear_field_value_cache($form);
486 }
487
488 return self::$lead;
489 }
490
491 public static function preview_replace_variables($content, $form) {
492
493 $lead = self::create_lead($form);
494
495 add_filter('gform_merge_tag_filter', array(
496 'GFPreviewConfirmation',
497 'preview_special_merge_tags'
498 ), 10, 4);
499
500 $content = GFCommon::replace_variables($content, $form, $lead, false, false, false);
501
502 remove_filter('gform_merge_tag_filter', array(
503 'GFPreviewConfirmation',
504 'preview_special_merge_tags'
505 ));
506
507 return $content;
508 }
509
510 public static function clear_field_value_cache($form) {
511
512 if (!class_exists('GFCache'))
513 return;
514
515 foreach ($form['fields'] as &$field) {
516 if (GFFormsModel::get_input_type($field) == 'total')
517 GFCache::delete('GFFormsModel::get_lead_field_value__' . $field['id']);
518 }
519
520 }
521
522}
523
524GFPreviewConfirmation::init();
525
526new GFEmailDomainControl(array(
527 'domains' => array(
528 'gmail.com',
529 'hotmail.com',
530 'yahoo.com'
531 ),
532 'validation_message' => __('Oh no! <strong>%s</strong> email accounts are banned from submitting, please use a real email address.'),
533 'mode' => 'ban'
534));
535
536new GF_Submission_Limit(array(
537 'limit' => 1,
538 'limit_message' => 'Only 1 submission per 24 hours!',
539 'time_period' => 'per_day'
540));