PluginProbe
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar / 3.2.13
NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar v3.2.13
3.3.1 3.3.0 3.2.14 3.2.13 3.2.12 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 trunk 0.2.5.5 0.2.5.6 0.2.5.7 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 All 156 releases
notificationx / includes / Admin / Entries.php

Entries.php in NotificationX – FOMO, Live Sales Notification, WooCommerce Sales Popup, GDPR, Social Proof, Announcement Banner & Floating Notification Bar 3.2.13, at includes/Admin/Entries.php

168 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Extension Factory
5 *
6 * @package NotificationX\Extensions
7 */
8
9 namespace NotificationX\Admin;
10
11 use NotificationX\Core\Database;
12 use NotificationX\Core\Helper;
13 use NotificationX\GetInstance;
14
15 /**
16 * @method static Entries get_instance($args = null)
17 */
18 class Entries {
19 /**
20 * Instance of Entries
21 *
22 * @var Entries
23 */
24 use GetInstance;
25
26 protected $wpdb;
27 protected $count = [];
28 public $format = [
29 'entry_id' => '%d',
30 'nx_id' => '%d',
31 'source' => '%s',
32 'entry_key' => '%s',
33 'data' => '%s',
34 'created_at' => '%s',
35 'updated_at' => '%s',
36 ];
37
38 /**
39 * Initially Invoked when initialized.
40 * @hook init
41 */
42 public function __construct() {
43 global $wpdb;
44 $this->wpdb = $wpdb;
45 }
46
47 public function count($source, $col = 'source'){
48 if(empty($this->count)){
49 $this->count = Database::get_instance()->get_source_count(Database::$table_entries, $col, [$col => $source]);
50 }
51 if(!empty($this->count[$source])){
52 return $this->count[$source];
53 }
54 elseif(!empty($source)){
55 return 0;
56 }
57 return $this->count;
58 }
59
60
61 /**
62 * Recursively sanitize the user-controlled `data` payload of an entry
63 * before it is stored. Entry data frequently originates from low-trust,
64 * even unauthenticated sources — public form submissions (Gravity Forms,
65 * CF7, FluentForm, WPForms, Ninja Forms, WeForms, Formidable, …) and the
66 * Zapier / IFTTT REST ingest — and is later rendered on the frontend. The
67 * JS renderer only escapes string-typed values, so an array-wrapped value
68 * (e.g. `name => ['<img src=x onerror=alert(1)>']`) is coerced back to its
69 * raw string and injected via `dangerouslySetInnerHTML` — a stored XSS
70 * (Patchstack, NotificationX Pro <= 3.1.3). insert_entry()/insert_entries()
71 * are the single storage chokepoint every extension (Free and Pro) funnels
72 * through, so sanitizing every string leaf here closes that class of issue
73 * regardless of ingest path. Non-string scalars (ints, bools, timestamps)
74 * are left untouched so downstream typing is preserved; only strings can
75 * carry markup.
76 *
77 * @param mixed $data
78 * @return mixed
79 */
80 public function sanitize_entry_data($data) {
81 if (is_array($data)) {
82 array_walk_recursive($data, function (&$val) {
83 if (is_string($val)) {
84 $val = sanitize_text_field($val);
85 }
86 });
87 } elseif (is_string($data)) {
88 $data = sanitize_text_field($data);
89 }
90 return $data;
91 }
92
93 public function insert_entry($entry) {
94 if(empty($entry['data'])){
95 return false;
96 }
97 $entry['data'] = $this->sanitize_entry_data($entry['data']);
98 $timestamp = !empty($entry['data']['timestamp']) ? $entry['data']['timestamp'] : time();
99 if(empty($entry['created_at'])){
100 $entry['created_at'] = Helper::mysql_time($timestamp);
101 }
102 if(empty($entry['updated_at'])){
103 $entry['updated_at'] = Helper::mysql_time($timestamp);
104 }
105 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
106 $entry = apply_filters('nx_insert_entry', $entry);
107 $result = Database::get_instance()->insert_post(Database::$table_entries, $entry, $this->format);
108 if ( $result ) {
109 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
110 do_action( 'nx_after_entry_inserted', $entry );
111 }
112 return $result;
113 }
114
115 public function insert_entries($entries) {
116 foreach ($entries as $key => $entry) {
117 if(empty($entry['data'])){
118 unset($entries[$key]);
119 continue;
120 }
121 $entry['data'] = $this->sanitize_entry_data($entry['data']);
122 $timestamp = !empty($entry['data']['timestamp']) ? $entry['data']['timestamp'] : time();
123 if(empty($entry['created_at'])){
124 $entry['created_at'] = Helper::mysql_time($timestamp);
125 }
126 if(empty($entry['updated_at'])){
127 $entry['updated_at'] = Helper::mysql_time($timestamp);
128 }
129 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
130 $entries[$key] = apply_filters('nx_insert_entry', $entry);
131 }
132 return Database::get_instance()->insert_posts(Database::$table_entries, $entries, $this->format);
133 }
134
135 public function get_entries($where__or_nx_id = [], $select = "*", $join_table = '', $group_by_col = '', $data_in_entry = false) {
136 if (is_int($where__or_nx_id)) {
137 $where__or_nx_id = ['nx_id' => $where__or_nx_id];
138 }
139 $entries = Database::get_instance()->get_posts(Database::$table_entries, $select, $where__or_nx_id, $join_table, $group_by_col, '', 'ORDER BY `created_at` DESC');
140 if ($data_in_entry) {
141 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
142 $entries = apply_filters('nx_get_entries', $entries);
143 return $entries;
144 }
145 foreach ($entries as $key => $value) {
146 if (!empty($value['data'])) {
147 $value = array_merge($value['data'], $value);
148 unset($value['data']);
149 }
150 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
151 $entries[$key] = apply_filters('nx_get_entry', $value);
152 }
153 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Reviewed for the NotificationX codebase: acceptable in this context.
154 $entries = apply_filters('nx_get_entries', $entries);
155 return $entries;
156 }
157
158 public function delete_entries($where__or_nx_id, $limit = 0) {
159 if (!is_array($where__or_nx_id)) {
160 $where__or_nx_id = ['nx_id' => $where__or_nx_id];
161 }
162 $results = Database::get_instance()->delete_posts(Database::$table_entries, $where__or_nx_id, $limit);
163 // @todo add action.
164 return $results;
165 }
166
167 }
168