PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 3.0.61
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v3.0.61
5.6.2 5.6.3 5.6.1 5.6.0 5.5.0 5.4.0 5.3.2 5.3.1 5.1.6 5.1.5 trunk 2.1.5 2.11 2.12 2.13 2.15 3.0.0 3.0.1 3.0.2 3.0.3 3.0.5 3.0.51 3.0.60 3.0.61 3.0.62 All 38 releases
double-opt-in / core / OptIn.class.php

OptIn.class.php in Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification 3.0.61, at core/OptIn.class.php

1,488 lines 44.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace forge12\contactform7\CF7DoubleOptIn {
4 if (!defined('ABSPATH')) {
5 exit;
6 }
7
8 /**
9 * Class Frontend
10 * Responsible to handle the frontend of the Double OptIn
11 *
12 * @package forge12\contactform7\CF7DoubleOptIn
13 */
14 class OptIn
15 {
16 /**
17 * Stores the DB ID for the entry
18 *
19 * @var int
20 */
21 private $id = 0;
22
23 /**
24 * Stores the ID of the contact form 7 form.
25 *
26 * @var int
27 */
28 private $cf_form_id = 0;
29 /**
30 * Stores if the optin has been confirmed (1) or not (0)
31 *
32 * @var int
33 */
34 private $doubleoptin = 0;
35 /**
36 * Stores the content of the contact form 7 form content as a serialized string.
37 *
38 * @var string
39 */
40 private $content = "";
41 /**
42 * Stores the unique hash used to identify the opt-ins
43 *
44 * @var string
45 */
46 private $hash = "";
47 /**
48 * Stores the timestamp the opt-in mail has been sent to the user.
49 *
50 * @var string
51 */
52 private $createtime = "";
53 /**
54 * Stores the timestamp the opt-in has been confirmed by the user.
55 */
56 private $updatetime = "";
57 /**
58 * Stores the timestamp the opt-out has been confirmed by the user.
59 */
60 private $optouttime = "";
61 /**
62 * IP Address used to trigger the opt-in mail.
63 *
64 * @var string
65 */
66 private $ipaddr_register = "";
67 /**
68 * IP Address used to confirm the opt-in mail.
69 */
70 private $ipaddr_confirmation = "";
71 /**
72 * IP Address used to output.
73 */
74 private $ipaddr_optout = "";
75 /**
76 * Stores the files used within this form as a serialized string.
77 */
78 private $files = "";
79 /**
80 * Store the Category ID
81 */
82 private $category = 0;
83 /**
84 * Stores the form as html
85 */
86 private $form = '';
87 /**
88 * Stores the Mail send for the optin
89 *
90 * @var string
91 */
92 private $mail_optin = '';
93 /**
94 * Stores the E-Mail
95 *
96 * @var string
97 */
98 private $email = '';
99
100 /**
101 * The constructor
102 */
103 public function __construct(array $properties)
104 {
105 foreach ($properties as $name => $value) {
106 if (isset($this->{$name})) {
107 $this->{$name} = $value;
108 }
109 }
110 }
111
112 /**
113 * @param int $cf_form_id
114 */
115 public function set_cf_form_id($cf_form_id)
116 {
117 $this->cf_form_id = (int)$cf_form_id;
118 }
119
120 /**
121 * @return int
122 */
123 public function get_cf_form_id()
124 {
125 return $this->cf_form_id;
126 }
127
128 /**
129 * Return the ID of the Optin
130 *
131 * @return int
132 */
133 public function get_id()
134 {
135 return $this->id;
136 }
137
138 /**
139 * Return the hash of the optin.
140 *
141 * @return string
142 */
143 public function get_hash()
144 {
145 return $this->hash;
146 }
147
148 /**
149 * Return true|false depending on confirm status
150 *
151 * @return bool
152 */
153 public function is_confirmed()
154 {
155 return (bool)$this->get_doubleoptin();
156 }
157
158 /**
159 * Return true|false wether the form has been confirmed or not.
160 *
161 * @return bool
162 */
163 public function is_optout()
164 {
165 if (true != $this->get_doubleoptin() && !empty($this->get_ipaddr_optout()) && !empty($this->get_optouttime())) {
166 return true;
167 }
168
169 return false;
170 }
171
172 /**
173 * update the optin value
174 *
175 * @param int $confirmed
176 */
177 public function set_doubleoptin($confirmed)
178 {
179 $this->doubleoptin = (int)$confirmed;
180 }
181
182 /**
183 * Return the optin value for the form.
184 *
185 * @return int
186 */
187 public function get_doubleoptin()
188 {
189 return $this->doubleoptin;
190 }
191
192 /**
193 * @param string $timestamp
194 */
195 public function set_createtime($timestamp)
196 {
197 $this->createtime = $timestamp;
198 }
199
200 /**
201 * Return the Date how long the opt in will be valid
202 *
203 * @return string
204 */
205 public function get_valid_until()
206 {
207 $settings = CF7DoubleOptIn::getInstance()->getSettings();
208
209 $createtime = $this->get_createtime();
210 $dt = new \DateTime();
211 $dt->setTimestamp($createtime);
212
213 if ($this->is_confirmed()) {
214 $month = (int)$settings['delete'];
215 $period = $settings['delete_period'];
216 } else {
217 $month = (int)$settings['delete_unconfirmed'];
218 $period = $settings['delete_unconfirmed_period'];
219 }
220
221 $dt->modify('+' . (int)$month . ' ' . $period);
222 $dt->modify('+1 day');
223
224 return $dt->format('d.m.Y');
225 }
226
227 /**
228 * Return a timestamp
229 *
230 * @param string $view Select how to return the content. raw is the stored db value. use formatted to return a
231 * formatted string.
232 *
233 * @return string
234 */
235 public function get_createtime($view = "raw")
236 {
237 if ($view != "raw") {
238 if (!is_numeric($this->createtime)) {
239 $date = date('d.m.Y', strtotime($this->createtime));
240 $time = date('H:i:s', strtotime($this->createtime));
241 } else {
242 $date = date('d.m.Y', $this->createtime);
243 $time = date('H:i:s', $this->createtime);
244 }
245
246 return $date . ' ' . __('/', 'double-opt-in') . ' ' . $time;
247 } else {
248 return $this->createtime;
249 }
250 }
251
252 /**
253 * @param string $timestamp
254 */
255 public function set_updatetime($timestamp)
256 {
257 $this->updatetime = $timestamp;
258 }
259
260 /**
261 * Return a timestamp
262 *
263 * @param string $view Select how to return the content. raw is the stored db value. use formatted to return a
264 * formatted string.
265 *
266 * @return string
267 */
268 public function get_updatetime($view = 'raw')
269 {
270 if ($view != "raw") {
271 if (!is_numeric($this->updatetime)) {
272 $date = date('d.m.Y', strtotime($this->updatetime));
273 $time = date('H:i:s', strtotime($this->updatetime));
274 } else {
275 $date = date('d.m.Y', $this->updatetime);
276 $time = date('H:i:s', $this->updatetime);
277 }
278
279 return $date . ' ' . __('/', 'double-opt-in') . ' ' . $time;
280 } else {
281 return $this->updatetime;
282 }
283 }
284
285 /**
286 * @param string $timestamp
287 */
288 public function set_optouttime($timestamp)
289 {
290 $this->optouttime = $timestamp;
291 }
292
293 /**
294 * Return a timestamp
295 *
296 * @param string $view Select how to return the content. raw is the stored db value. use formatted to return a
297 * formatted string.
298 *
299 * @return string
300 */
301 public function get_optouttime($view = 'raw')
302 {
303 if ($view != "raw") {
304 if (!is_numeric($this->optouttime)) {
305 $date = date('d.m.Y', strtotime($this->optouttime));
306 $time = date('H:i:s', strtotime($this->optouttime));
307 } else {
308 $date = date('d.m.Y', $this->optouttime);
309 $time = date('H:i:s', $this->optouttime);
310 }
311
312 return $date . ' ' . __('/', 'f12-cf7-doubleoptin') . ' ' . $time;
313 } else {
314 return $this->optouttime;
315 }
316 }
317
318 /**
319 * @param string $ip_addr
320 */
321 public function set_ipaddr_optout($ip_addr)
322 {
323 $this->ipaddr_optout = $ip_addr;
324 }
325
326 /**
327 * @return string
328 */
329 public function get_ipaddr_optout()
330 {
331 return $this->ipaddr_optout;
332 }
333
334 /**
335 * @param string $ip_addr
336 */
337 public function set_ipaddr_register($ip_addr)
338 {
339 $this->ipaddr_register = $ip_addr;
340 }
341
342 /**
343 * @return string
344 */
345 public function get_ipaddr_register()
346 {
347 return $this->ipaddr_register;
348 }
349
350 /**
351 * @param string $ip_addr
352 */
353 public function set_ipaddr_confirmation($ip_addr)
354 {
355 $this->ipaddr_confirmation = $ip_addr;
356 }
357
358 /**
359 * @return string
360 */
361 public function get_ipaddr_confirmation()
362 {
363 return $this->ipaddr_confirmation;
364 }
365
366 /**
367 * Return a serialized string
368 *
369 * @return mixed
370 */
371 public function get_content()
372 {
373 return $this->content;
374 }
375
376 /**
377 * @param string - a serialized string
378 */
379 public function set_content($content)
380 {
381 $this->content = $content;
382 }
383
384 /**
385 * @param string - a serialized string
386 */
387 public function set_files($files)
388 {
389 $this->files = $files;
390 }
391
392 /**
393 * @return string use maybe_unserialize to deserialize the string
394 */
395 public function get_files()
396 {
397 return $this->files;
398 }
399
400 /**
401 * Return the assigned Category ID
402 *
403 * @return int
404 */
405 public function get_category()
406 {
407 if (!is_numeric($this->category)) {
408 return 0;
409 }
410
411 return $this->category;
412 }
413
414 /**
415 * Assign a ID to the category
416 *
417 * @param int $id
418 *
419 * @return void
420 */
421 public function set_category($id)
422 {
423 $this->category = $id;
424 }
425
426 /**
427 * Check if the given Opt In was created by Contact Form 7
428 *
429 * @return bool
430 */
431 public function isTypeCF7()
432 {
433 $form_id = $this->get_cf_form_id();
434 $form = get_post($form_id);
435
436 if ('wpcf7_contact_form' === $form->post_type) {
437 return true;
438 }
439
440 return false;
441 }
442
443 /**
444 * Check if the given Opt In was created by Elementor
445 *
446 * @return bool
447 */
448 public function isTypeElementor()
449 {
450 if (!class_exists('ElementorPro\Plugin')) {
451 return false;
452 }
453
454 $page_id = $this->get_cf_form_id();
455
456 $post = get_post($page_id);
457
458 // skip if post not existing anymore
459 if (null === $post) {
460 return false;
461 }
462
463 // skip if page is not build with elementor
464 if (!\Elementor\Plugin::$instance->documents->get($page_id)->is_built_with_elementor()) {
465 return false;
466 }
467
468 // Load the page's data
469 $document = \Elementor\Plugin::$instance->documents->get($page_id);
470
471 // Skip if document not exist
472 if (!$document) {
473 return false;
474 }
475
476 // Loop through the elements
477 $elements_data = $document->get_elements_data();
478
479 $content = maybe_unserialize($this->get_content());
480
481 // skip if form id not available
482 if (!isset($content['form_id'])) {
483 return false;
484 }
485
486 $form_id = $content['form_id'];
487
488 // Find the Form Element
489 foreach ($elements_data as $element) {
490 if (isset($element['elements'])) {
491 foreach ($element['elements'] as $el) {
492 if ($form_id !== $el['id'] || 'form' !== $el['widgetType']) {
493 continue;
494 }
495
496 return true;
497 }
498 return true;
499 }
500
501 // Check if this is the form widget
502 if (isset($element['widgetType']) && isset($element['id']) && $element['widgetType'] === 'form' && $element['id'] === $form_id) {
503 // Return the form settings
504 return true;
505 }
506 }
507 return false;
508 }
509
510 /**
511 * Check if the given Opt In was created by Avada
512 *
513 * @return bool|void
514 */
515 public function isTypeAvada()
516 {
517 $form_id = $this->get_cf_form_id();
518 $form = get_post($form_id);
519
520 if ('fusion_form' === $form->post_type) {
521 return true;
522 }
523
524 return false;
525 }
526
527 /**
528 * Check if the Opt In was created by 'cf7' or 'avada'.
529 *
530 * @param string $type use either 'cf7' or 'avada'
531 *
532 * @return bool
533 */
534 public function isType($type)
535 {
536 if ($type == 'cf7') {
537 return $this->isTypeCF7();
538 } elseif ($type == 'elementor') {
539 return $this->isTypeElementor();
540 } else {
541 return $this->isTypeAvada();
542 }
543 }
544
545 /**
546 * Load an OptIn by the given hash code. Returns either an Object of Type OptIn or null if not found.
547 *
548 * @param string $hash
549 *
550 * @return OptIn|null
551 */
552 public static function get_by_hash(string $hash)
553 {
554 global $wpdb;
555 $table = $wpdb->prefix . 'f12_cf7_doubleoptin';
556
557 if (null == $wpdb) {
558 return null;
559 }
560
561 $row = $wpdb->get_row('SELECT * FROM ' . $table . ' WHERE hash="' . $hash . '"', ARRAY_A);
562
563 if (null == $row) {
564 return null;
565 }
566
567 return new OptIn($row);
568 }
569
570 /**
571 * Get number of optins for the given post.
572 *
573 * @param $post_id
574 *
575 * @return int
576 */
577 public static function get_count($post_id)
578 {
579 global $wpdb;
580
581 if (!$wpdb) {
582 return 0;
583 }
584
585 $tableName = $wpdb->prefix . 'f12_cf7_doubleoptin';
586 $result = $wpdb->get_results($wpdb->prepare('SELECT count(*) AS counter FROM ' . $tableName . ' WHERE cf_form_id=%d ', $post_id));
587
588 if (is_array($result)) {
589 return $result[0]->counter;
590 }
591
592 return 0;
593 }
594
595 /**
596 * Return a list of opt ins stored in the database.
597 *
598 * @param int $category_id
599 *
600 * @param array $atts array (
601 * 'perPage' => 10, // Posts per page
602 * 'page' => 0, // Current page
603 * 'order' => DESC, // Order (ASC/DESC)
604 * );
605 *
606 * @param null $numberOfPages - Stores the number of pages found if limited
607 *
608 * @return array
609 */
610 public static function get_list_by_category_id($category_id, $atts = [], &$numberOfPages = null)
611 {
612 global $wpdb;
613
614 $attr = [
615 'perPage' => 10,
616 'page' => 1,
617 'order' => 'DESC',
618 'keyword' => ''
619 ];
620
621 /**
622 * Parameter
623 */
624 foreach ($atts as $key => $value) {
625 if (isset($attr[$key])) {
626 $attr[$key] = $atts[$key];
627 }
628 }
629
630 /*
631 * Update keyword
632 */
633 $where = '';
634 if (!empty($attr['keyword'])) {
635 $where = ' AND content LIKE "%%' . $attr['keyword'] . '%%"';
636 }
637
638
639 $tableName = $wpdb->prefix . 'f12_cf7_doubleoptin';
640 $pageNum = (int)$attr['page'] - 1;
641
642 if ($numberOfPages !== null) {
643 $result = $wpdb->get_results($wpdb->prepare('SELECT count(*) AS counter FROM ' . $tableName . ' WHERE category=%d ' . $where, $category_id));
644
645 $itemCounter = 0;
646
647 if (is_array($result)) {
648 $itemCounter = $result[0]->counter;
649 }
650
651 $numberOfPages = 0;
652
653 if ($itemCounter != 0) {
654 $numberOfPages = ceil($itemCounter / (int)$attr['perPage']);
655 }
656 }
657
658 $list = [];
659
660 if ($numberOfPages == 0) {
661 return $list;
662 }
663
664 $offset = $pageNum * (int)$attr['perPage'];
665
666 $rows = $wpdb->get_results($wpdb->prepare('SELECT * FROM ' . $tableName . ' WHERE category=%d ' . $where . ' ORDER BY ID ' . $attr['order'] . ' LIMIT ' . $attr['perPage'] . ' OFFSET %d', $category_id, $offset), ARRAY_A);
667
668 foreach ($rows as $row) {
669 $list[] = new OptIn($row);
670 }
671
672 return $list;
673 }
674
675 /**
676 * Return a list of opt ins stored in the database.
677 *
678 * @param string $email
679 * @param int $confirmed Either recieve confirmed or unconfirmed only
680 *
681 * @return array
682 */
683 public static function get_list_by_email($email)
684 {
685 global $wpdb;
686
687 $tableName = $wpdb->prefix . 'f12_cf7_doubleoptin';
688
689 $list = [];
690
691 $rows = $wpdb->get_results($wpdb->prepare('SELECT * FROM ' . $tableName . ' WHERE email=%s', $email), ARRAY_A);
692
693 foreach ($rows as $row) {
694 $list[] = new OptIn($row);
695 }
696
697 return $list;
698 }
699
700 /**
701 * Return a list of opt ins stored in the database.
702 *
703 * @param $atts array (
704 * 'perPage' => 10, // Posts per page
705 * 'page' => 0, // Current page
706 * 'order' => DESC, // Order (ASC/DESC)
707 * );
708 *
709 * @param null $numberOfPages - Stores the number of pages found if limited
710 *
711 * @return array
712 */
713 public static function get_list($atts = [], &$numberOfPages = null)
714 {
715 global $wpdb;
716
717 $attr = [
718 'perPage' => 10,
719 'page' => 1,
720 'order' => 'DESC',
721 'keyword' => '',
722 'cf_form_id' => '',
723 ];
724
725 /*
726 * Update atts
727 */
728 foreach ($atts as $key => $value) {
729 if (isset($attr[$key])) {
730 $attr[$key] = $atts[$key];
731 }
732 }
733
734 /*
735 * Update WHERE for Query
736 */
737 $where = '';
738 $where_condition = [];
739
740 /*
741 * Add Keyword
742 */
743 if (!empty($attr['keyword'])) {
744 $where_condition[] = 'content LIKE "%%' . $attr['keyword'] . '%%"';
745 }
746
747 /*
748 * Add Form ID
749 */
750 if (!empty($attr['cf_form_id'])) {
751 $where_condition[] = 'cf_form_id="' . $attr['cf_form_id'] . '"';
752 }
753
754 /*
755 * build where string
756 */
757 if (!empty($where_condition)) {
758 $where = ' WHERE ' . implode(' AND ', $where_condition);
759 }
760
761 /*
762 * set table
763 */
764 $tableName = $wpdb->prefix . 'f12_cf7_doubleoptin';
765 $pageNum = (int)$attr['page'] - 1;
766
767 if ($numberOfPages !== null) {
768 $result = $wpdb->get_results('SELECT count(*) as counter FROM ' . $tableName . $where);
769
770 $itemCounter = 0;
771
772 if (is_array($result)) {
773 $itemCounter = $result[0]->counter;
774 }
775
776 $numberOfPages = 0;
777
778 if ($itemCounter != 0) {
779 $numberOfPages = ceil($itemCounter / (int)$attr['perPage']);
780 }
781 }
782
783 $list = [];
784
785 if ($numberOfPages == 0) {
786 return $list;
787 }
788
789 $offset = $pageNum * (int)$attr['perPage'];
790
791 $rows = $wpdb->get_results($wpdb->prepare('SELECT * FROM ' . $tableName . $where . ' ORDER BY ID ' . $attr['order'] . ' LIMIT ' . $attr['perPage'] . ' OFFSET % d', $offset), ARRAY_A);
792
793 foreach ($rows as $row) {
794 $list[] = new OptIn($row);
795 }
796
797 return $list;
798 }
799
800 /**
801 * This will update all categories from A to B, e.g.: All Opt-Ins with id 1 to category id 2.
802 *
803 * @param int $from_id The origin Category ID
804 * @param int $to_id The new Category ID
805 *
806 * @return bool|int|\mysqli_result|resource|null Return the number of rows affected by the query.
807 */
808 public static function bulk_update_category($from_id, $to_id)
809 {
810 global $wpdb;
811 $table = $wpdb->prefix . 'f12_cf7_doubleoptin';
812
813 return $wpdb->query($wpdb->prepare('UPDATE ' . $table . ' SET category =%d WHERE category =%d', $to_id, $from_id));
814 }
815
816 /**
817 * Update the category of the given opt in id.
818 *
819 * @param int $optin_id The ID of the OptIn
820 * @param int $category_id The ID of the Category
821 *
822 * @return bool|int|\mysqli_result|resource|null
823 */
824 public static function update_category_by_id($optin_id, $category_id)
825 {
826 global $wpdb;
827 $table = $wpdb->prefix . 'f12_cf7_doubleoptin';
828
829 return $wpdb->query($wpdb->prepare('UPDATE ' . $table . ' SET category =%d WHERE id =%d', $category_id, $optin_id));
830 }
831
832 /**
833 * Update or create the given Object
834 */
835 public function save()
836 {
837 global $wpdb;
838 $table = $wpdb->prefix . 'f12_cf7_doubleoptin';
839
840 f12_debug_log('save method called', [
841 'table' => $table,
842 'hash' => $this->get_hash(),
843 ]);
844
845 /**
846 * Wenn ein Hash existiert, wird die Zeile aktualisiert
847 */
848 if (!empty($this->get_hash())) {
849 f12_debug_log('Updating existing record', [
850 'hash' => $this->get_hash(),
851 'cf_form_id' => $this->get_cf_form_id(),
852 'doubleoptin' => $this->get_doubleoptin(),
853 ]);
854
855 $result = $wpdb->update($table, [
856 'doubleoptin' => $this->get_doubleoptin(),
857 'createtime' => $this->get_createtime(),
858 'updatetime' => $this->get_updatetime(),
859 'ipaddr_confirmation' => $this->get_ipaddr_confirmation(),
860 'ipaddr_register' => $this->get_ipaddr_register(),
861 'cf_form_id' => $this->get_cf_form_id(),
862 'content' => $this->get_content(),
863 'files' => $this->get_files(),
864 'category' => $this->get_category(),
865 'optouttime' => $this->get_optouttime(),
866 'ipaddr_optout' => $this->get_ipaddr_optout(),
867 'mail_optin' => $this->get_mail_optin(),
868 ], [
869 'hash' => $this->get_hash()
870 ]);
871
872 f12_debug_log('Update operation completed', ['result' => $result]);
873
874 return $result;
875 }
876
877 /**
878 * Wenn kein Hash existiert, wird ein neuer Datensatz eingefügt
879 */
880 f12_debug_log('Inserting new record', [
881 'cf_form_id' => $this->get_cf_form_id(),
882 'email' => $this->get_email(),
883 'doubleoptin' => $this->get_doubleoptin(),
884 ]);
885
886 $result = $wpdb->insert(
887 $table,
888 $data = [ // Daten in einer Variablen speichern, um sie anschließend zu loggen
889 'cf_form_id' => $this->get_cf_form_id(),
890 'doubleoptin' => $this->get_doubleoptin(),
891 'createtime' => $this->get_createtime(),
892 'updatetime' => $this->get_updatetime(),
893 'ipaddr_confirmation' => $this->get_ipaddr_confirmation(),
894 'ipaddr_register' => $this->get_ipaddr_register(),
895 'content' => $this->get_content(),
896 'files' => $this->get_files(),
897 'category' => $this->get_category(),
898 'form' => $this->get_form(true),
899 'mail_optin' => $this->get_mail_optin(),
900 'email' => $this->get_email(),
901 ]
902 );
903
904 $formValue = $this->get_form();
905 f12_debug_log('Form Data Information', [
906 'form_length' => strlen($formValue), // Länge des Inhalts
907 'form_data_sample' => substr($formValue, 0, 500), // Nur die ersten 500 Zeichen loggen
908 ]);
909
910 $log_data = $data;
911 $log_data['form'] = substr($formValue, 0, 200);
912
913 f12_debug_log('Preparing to insert new record', [
914 'table' => $table,
915 'data' => $log_data
916 ]);
917
918 if (false === $result) {
919 f12_debug_log('Insert operation failed', [
920 'mysql_error' => $wpdb->last_error
921 ]);
922
923 $this->validateEncoding($formValue);
924 $this->validateMaxAllowedPacket($formValue);
925 $this->validateFormField();
926
927 return false;
928 }
929
930 f12_debug_log('Insert operation completed', [
931 'result' => $result,
932 'insert_id' => $wpdb->insert_id,
933 ]);
934
935 if ($result > 0) {
936 $this->id = $wpdb->insert_id;
937 f12_debug_log('New record inserted, ID assigned', ['id' => $this->id]);
938
939 $hashResult = $this->createHash();
940 f12_debug_log('Hash created for new record', ['hashResult' => $hashResult]);
941
942 return $hashResult;
943 }
944
945 f12_debug_log('Failed to insert new record');
946 return false;
947 }
948
949 private function validateFormField()
950 {
951 global $wpdb;
952 // SQL-Anfrage, um die Felddefinitionen abzurufen
953 $table = $wpdb->prefix . 'f12_cf7_doubleoptin';
954
955 $columns = $wpdb->get_results("SHOW FIELDS FROM $table");
956
957 // Überprüfung der Feldtypen
958 foreach ($columns as $column) {
959 f12_debug_log('Field Info', [
960 'Field' => $column->Field,
961 'Type' => $column->Type,
962 'Null' => $column->Null,
963 'Default' => $column->Default
964 ]);
965 }
966 }
967
968 private function validateEncoding(string $data)
969 {
970 if (!mb_check_encoding($data, 'UTF-8')) {
971 f12_debug_log('Encoding Issue', ['form_data' => substr($data, 0, 500)]);
972 return false;
973 }
974 f12_debug_log('Encoding OK', []);
975 return true;
976 }
977
978 private function validateMaxAllowedPacket(string $data)
979 {
980 $maxAllowedPacketMB = $this->getMaxAllowedPacket();
981
982 $dataSize = strlen($data); // Size in bytes
983 $dataSizeMB = $dataSize / (1024 * 1024); // Convert bytes to MB
984
985 f12_debug_log('Data Size Check', [
986 'data_size_bytes' => $dataSize,
987 'data_size_mb' => $dataSizeMB,
988 ]);
989
990 if ($dataSize > $maxAllowedPacketMB) {
991 f12_debug_log('max_allowed_packet Too Small', [
992 'data_size_mb' => $dataSizeMB,
993 'max_allowed_packet_mb' => $maxAllowedPacketMB
994 ]);
995 return false;
996 } else {
997 f12_debug_log('max_allowed_packet OK', []);
998 return true;
999 }
1000 }
1001
1002 private function getMaxAllowedPacket()
1003 {
1004 global $wpdb;
1005
1006 $result = $wpdb->get_row("SHOW VARIABLES LIKE 'max_allowed_packet'", OBJECT);
1007
1008 /**
1009 * Prüfen, ob die Variable erfolgreich abgerufen wurde
1010 * Die zweite Spalte der Abfrage enthält den Wert (Value)
1011 */
1012 // Abfrage, um den aktuellen Wert von max_allowed_packet zu erhalten
1013 if ($result) {
1014 $maxAllowedPacket = $result->Value; // Wert aus der zweiten Spalte
1015 f12_debug_log('MySQL max_allowed_packet Value', [
1016 'max_allowed_packet_bytes' => $maxAllowedPacket,
1017 'max_allowed_packet_mb' => $maxAllowedPacket / (1024 * 1024) // In MB
1018 ]);
1019 } else {
1020 // Falls das Ergebnis leer ist (z. B. Fehler oder keine Berechtigung)
1021 f12_debug_log('Error fetching max_allowed_packet', [
1022 'error' => $wpdb->last_error
1023 ]);
1024 return 0;
1025 }
1026 return $maxAllowedPacket;
1027 }
1028
1029 /**
1030 * Creates a unique hash code and adds it to the current OptIn Object
1031 */
1032 private function createHash()
1033 {
1034 global $wpdb;
1035
1036 if (null == $wpdb) {
1037 return false;
1038 }
1039
1040 $table = $wpdb->prefix . 'f12_cf7_doubleoptin';
1041
1042 // add the hash to the element
1043
1044 $this->hash = base64_encode($this->get_createtime() . $this->get_id() . $this->get_cf_form_id());
1045
1046 return $wpdb->update($table, [
1047 'hash' => $this->hash,
1048 ], [
1049 'id' => $this->get_id()
1050 ]);
1051 }
1052
1053 private function is_base64_encoded($string)
1054 {
1055 // Prüfen, ob der String Base64-kompatible Zeichen enthält
1056 if (preg_match('/^[A-Za-z0-9+\/=]*$/', $string)) {
1057 // Prüfen, ob die Länge des Strings ein Vielfaches von 4 ist
1058 return strlen($string) % 4 === 0;
1059 }
1060 return false;
1061 }
1062
1063 /**
1064 * Return the Form
1065 *
1066 * @return string
1067 */
1068 public function get_form($encoded = false)
1069 {
1070 if (!$encoded) {
1071 if ($this->is_base64_encoded($this->form)) {
1072 return base64_decode($this->form);
1073 } else {
1074 return $this->form;
1075 }
1076 } else {
1077 if ($this->is_base64_encoded($this->form)) {
1078 return $this->form;
1079 } else {
1080 return base64_encode($this->form);
1081 }
1082 }
1083 }
1084
1085 /**
1086 * Returns the Name of the form if available
1087 *
1088 * @return string The name of the Form
1089 * @since 2.4.0
1090 */
1091 public function get_form_name()
1092 {
1093 $post = get_post($this->get_cf_form_id());
1094
1095 if (null === $post) {
1096 return __('Deleted', 'double-opt-in');
1097 }
1098
1099 return $post->post_title;
1100 }
1101
1102 /**
1103 * Returns the URL to the form depending on the Form Type.
1104 *
1105 * @return string The Backend URL to the Form, empty if the post is not found.
1106 * @since 2.4.0
1107 *
1108 */
1109 public function get_form_link()
1110 {
1111 if ($this->isTypeElementor()) {
1112 return get_edit_post_link($this->get_cf_form_id());
1113 } elseif ($this->isTypeAvada()) {
1114 return get_edit_post_link($this->get_cf_form_id());
1115 } elseif ($this->isTypeCF7()) {
1116 $post = get_post($this->get_cf_form_id());
1117
1118 if (!$post) {
1119 return '';
1120 }
1121
1122 return admin_url('admin.php?page=wpcf7&post=' . esc_attr($this->get_cf_form_id()) . '&action=edit');
1123 }
1124
1125 return '';
1126 }
1127
1128
1129 /**
1130 * Retrieves the form settings.
1131 *
1132 * If the form is created using Elementor, retrieves the settings using the `get_settings_by_elementor()`
1133 * method.
1134 *
1135 * @return array The form settings.
1136 * @since 2.4.0
1137 *
1138 */
1139 public function get_form_settings()
1140 {
1141 if ($this->isTypeElementor()) {
1142 return $this->get_settings_by_elementor();
1143 } else if ($this->isTypeCF7()) {
1144 return $this->get_settings_by_cf7();
1145 } else if ($this->isTypeAvada()) {
1146 return $this->get_settings_by_avada();
1147 }
1148
1149 return [];
1150 }
1151
1152 /**
1153 * Retrieves the settings of a specific element using avada.
1154 *
1155 * @return array
1156 * @since 2.4.0
1157 *
1158 * @see OptIn::maybe_normalize_settings() for details
1159 */
1160 private function get_settings_by_avada()
1161 {
1162
1163 $form_id = $this->get_cf_form_id();
1164
1165 $settings = CF7DoubleOptIn::getInstance()->getParameter($form_id);
1166
1167 return $this->maybe_normalize_settings($settings);
1168 }
1169
1170 /**
1171 * Retrieves the settings of a specific element using cf7.
1172 *
1173 * @return array
1174 * @since 2.4.0
1175 *
1176 * @see OptIn::maybe_normalize_settings() for details
1177 */
1178 private function get_settings_by_cf7()
1179 {
1180 $form_id = $this->get_cf_form_id();
1181
1182 $settings = get_post_meta($form_id, 'f12-cf7-doubleoptin', true);
1183
1184 if (null == $settings || !is_array($settings)) {
1185 return [];
1186 }
1187
1188 $settings = $this->maybe_normalize_settings($settings);
1189
1190 return $settings;
1191 }
1192
1193 /**
1194 * Retrieves the settings of a specific element using Elementor.
1195 *
1196 * @return array
1197 * @since 2.4.0
1198 *
1199 * @see OptIn::maybe_normalize_settings() for details
1200 */
1201 private function get_settings_by_elementor()
1202 {
1203 $page_id = $this->get_cf_form_id();
1204
1205 $post = get_post($page_id);
1206
1207 // skip if post not existing anymore
1208 if (null === $post) {
1209 return [];
1210 }
1211
1212 // skip if page is not build with elementor
1213 if (!\Elementor\Plugin::$instance->documents->get($page_id)->is_built_with_elementor()) {
1214 return [];
1215 }
1216
1217 // Load the page's data
1218 $document = \Elementor\Plugin::$instance->documents->get($page_id);
1219
1220 // Skip if document not exist
1221 if (!$document) {
1222 return [];
1223 }
1224
1225 // Loop through the elements
1226 $elements_data = $document->get_elements_data();
1227
1228 $content = maybe_unserialize($this->get_content());
1229
1230 // skip if form id not available
1231 if (!isset($content['form_id'])) {
1232 return [];
1233 }
1234
1235 $form_id = $content['form_id'];
1236
1237 $form_element = null;
1238
1239 // Find the Form Element
1240 foreach ($elements_data as $element) {
1241 if (isset($element['elements'])) {
1242 foreach ($element['elements'] as $el) {
1243 if ($form_id !== $el['id'] || 'form' !== $el['widgetType']) {
1244 continue;
1245 }
1246
1247 $form_element = $el;
1248 }
1249 }
1250
1251 // Check if this is the form widget
1252 if (isset($element['widgetType']) && isset($element['id']) && $element['widgetType'] === 'form' && $element['id'] === $form_id) {
1253 // Return the form settings
1254 $form_element = $element;
1255 }
1256 }
1257
1258 // skip if form element not found on the page anymore
1259 if ($form_element == null || !isset($form_element['settings'])) {
1260 return [];
1261 }
1262
1263 // Normalize Settings
1264 return $this->maybe_normalize_settings($form_element['settings']);
1265 }
1266
1267 /**
1268 * Normalizes the settings by converting the value of the settings
1269 *
1270 * @param array $settings The settings array to be normalized.
1271 * @formatter:off
1272 *
1273 * @return array {
1274 * The settings of the element if found or an empty array if nothing was found.
1275 * @type string $doi_email_to
1276 * @type string $doi_email_subject
1277 * @type string $doi_email_content
1278 * @type string $doi_email_from
1279 * @type string $doi_email_from_name
1280 * @type string $doi_email_template
1281 * @type string $doi_email_body
1282 * }
1283 *
1284 * @formatter:on
1285 */
1286 private function maybe_normalize_settings($settings)
1287 {
1288 if (isset($settings['sender'])) {
1289 $settings['doi_email_from'] = $settings['sender'];
1290 }
1291
1292 if (isset($settings['sender_name'])) {
1293 $settings['doi_email_from_name'] = $settings['sender_name'];
1294 }
1295
1296 if (isset($settings['subject'])) {
1297 $settings['doi_email_subject'] = $settings['subject'];
1298 }
1299
1300 if (isset($settings['recipient'])) {
1301 $settings['doi_email_to'] = $settings['recipient'];
1302 }
1303
1304 if (isset($settings['template'])) {
1305 $settings['doi_email_template'] = $settings['template'];
1306 }
1307
1308 if (isset($settings['body'])) {
1309 $settings['doi_email_body'] = $settings['body'];
1310 }
1311
1312 /**
1313 * Normalize the settings between the different form plugins
1314 *
1315 * @formatter:off
1316 *
1317 * @param array {
1318 * @type string $doi_email_to
1319 * @type string $doi_email_subject
1320 * @type string $doi_email_content
1321 * @type string $doi_email_from
1322 * @type string $doi_email_from_name
1323 * @type string $doi_email_template
1324 * @type string $doi_email_body
1325 * }
1326 *
1327 * @formatter:on
1328 *
1329 * @since 3.0.0
1330 */
1331 return apply_filters('f12_cf7_doubleoption_normalize_settings', $settings);
1332 }
1333
1334 /**
1335 * Set the Form as HTML
1336 *
1337 * @param string $form
1338 *
1339 * @return void
1340 */
1341 public function set_form($form)
1342 {
1343 $this->form = $form;
1344 }
1345
1346 /**
1347 * Return the Form
1348 *
1349 * @return string
1350 */
1351 public function get_mail_optin()
1352 {
1353 return $this->mail_optin;
1354 }
1355
1356 /**
1357 * Return the E-mail
1358 *
1359 * @return string
1360 */
1361 public function get_email()
1362 {
1363 return $this->email;
1364 }
1365
1366 /**
1367 * Store the email
1368 *
1369 * @param string $email
1370 *
1371 * @return void
1372 */
1373 public function set_email($email)
1374 {
1375 $this->email = $email;
1376 }
1377
1378 /**
1379 * Set the Form as HTML
1380 *
1381 * @param string $form
1382 *
1383 * @return void
1384 */
1385 public function set_mail_optin($mail_html)
1386 {
1387 $this->mail_optin = $mail_html;
1388 }
1389
1390 /**
1391 * Return the link to the detail view
1392 *
1393 * @return string
1394 */
1395 public function get_link_ui()
1396 {
1397 return admin_url('admin.php?page=f12-cf7-doubleoptin_optin_view&hash=' . $this->get_hash());
1398 }
1399
1400 /**
1401 * Return the link to delete
1402 *
1403 * @return string
1404 */
1405 public function get_link_delete()
1406 {
1407 return admin_url('admin.php?page=f12-cf7-doubleoptin&option=delete&hash=' . $this->get_hash());
1408 }
1409
1410 /**
1411 * Return the link to the export
1412 *
1413 * @return string
1414 */
1415 public function get_link_export()
1416 {
1417 return admin_url('admin.php?page=f12-cf7-doubleoptin&export=csv&id=' . $this->get_id());
1418 }
1419
1420 /**
1421 * Return the link to the export
1422 *
1423 * @return string
1424 */
1425 public function get_link_export_v2()
1426 {
1427 return admin_url('admin.php?page=f12-cf7-doubleoptin&export=csv_v2&id=' . $this->get_id());
1428 }
1429
1430 /**
1431 * Return the link to the optin
1432 *
1433 * @return string
1434 */
1435 public function get_link_optin($parameter = [])
1436 {
1437 if ($this->get_cf_form_id() == 0) {
1438 return get_home_url() . '?optin=' . $this->get_hash();
1439 }
1440
1441 $parameter = array_merge(CF7DoubleOptIn::getInstance()->getParameter($this->get_cf_form_id()), $parameter);
1442
1443 $page_id = $parameter['page'] ?? -1;
1444
1445 if ($page_id == -1 || !$page_id || $page_id == 0) {
1446 $link = get_home_url() . '?optin=' . $this->get_hash();
1447 } else {
1448
1449 $link = get_permalink($page_id);
1450
1451 if (strpos($link, "?") !== false) {
1452 $link .= '&optin=' . $this->get_hash();
1453 } else {
1454 $link .= '?optin=' . $this->get_hash();
1455 }
1456 }
1457
1458 return $link;
1459 }
1460
1461 /**
1462 * Return the link to the optout
1463 *
1464 * @return string
1465 */
1466 public function get_link_optout()
1467 {
1468 $settings = CF7DoubleOptIn::getInstance()->getSettings();
1469
1470 if (!isset($settings['optout_page']) || $settings['optout_page'] == 0) {
1471 return get_home_url() . '?optout=' . $this->get_hash();
1472 } else {
1473 $url = get_permalink($settings['optout_page']);
1474
1475 if (str_contains($url, '?')) {
1476 // If '?' exists in the URL, it means there are already parameters, so append with '&'
1477 $url .= '&optout=' . $this->get_hash();
1478 } else {
1479 // Else, there are no parameters yet, so append with '?'
1480 $url .= '?optout=' . $this->get_hash();
1481 }
1482
1483 return $url;
1484
1485 }
1486 }
1487 }
1488 }