PluginProbe
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment / 3.1.14
FireBox – WooCommerce Popup Builder, Exit Intent Popup, Email Optin & Cart Abandonment v3.1.14
3.1.14 3.1.13 3.1.12 3.1.11 3.1.10 3.1.9 3.1.8 3.1.7 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 All 123 releases
← All changes | Inc/Core/Controllers/BoxImport.php +112 -45 1.0.9 → 3.1.14 View file →
@@ -1,12 +1,12 @@
1 1 <?php
2 2 /**
3 3 * @package FireBox
4 - * @version 1.0.9 Free
4 + * @version 3.1.14 Free
5 5 *
6 6 * @author FirePlugins <[email protected]>
7 7 * @link https://www.fireplugins.com
8 - * @copyright Copyright © 2021 FirePlugins All Rights Reserved
8 + * @copyright Copyright © 2026 FirePlugins All Rights Reserved
9 9 * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
10 10 */
11 11
12 12 namespace FireBox\Core\Controllers;
@@ -49,14 +49,37 @@
49 49 * @return void
50 50 */
51 51 public function processBoxesImport($input)
52 52 {
53 - $file = $this->getUploadedFile();
53 + // run a quick security check
54 + if (!check_admin_referer('fpf_form_nonce_firebox_import', 'fpf_form_nonce_firebox_import'))
55 + {
56 + return; // get out if we didn't click the Activate button
57 + }
54 58
59 + /**
60 + * Importing creates campaigns from a file the user supplies, so it needs an
61 + * explicit capability check of its own. Today options.php also enforces
62 + * manage_options for this option group, but this method must not depend on
63 + * how it happens to be reached.
64 + */
65 + if (!current_user_can('edit_fireboxes'))
66 + {
67 + \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_CANNOT_VERIFY_REQUEST'));
68 + return;
69 + }
70 +
71 + if (!isset($_FILES['file']))
72 + {
73 + return;
74 + }
75 +
76 + $file = $_FILES['file'];
77 +
55 78 // ensure a file was given
56 79 if (!is_array($file) || !isset($file['name']) || empty($file['name']))
57 80 {
58 - add_settings_error( self::settings_name, 'settings_updated', fpframework()->_('FPF_PLEASE_SELECT_A_FILE_TO_UPLOAD'), 'error');
81 + \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_PLEASE_SELECT_A_FILE_TO_UPLOAD'));
59 82 return;
60 83 }
61 84
62 85 $ext = explode('.', $file['name']);
@@ -63,9 +86,9 @@
63 86
64 87 // ensure given file plugin was given
65 88 if (!in_array($ext[count($ext) - 1], ['fbox']))
66 89 {
67 - add_settings_error( self::settings_name, 'settings_updated', fpframework()->_('FPF_PLEASE_CHOOSE_A_VALID_FILE'), 'error');
90 + \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_PLEASE_CHOOSE_A_VALID_FILE'));
68 91 return;
69 92 }
70 93
71 94 $publish_all = isset($input['publish_all']) ? $input['publish_all'] : 0;
@@ -70,20 +93,24 @@
70 93
71 94 $publish_all = isset($input['publish_all']) ? $input['publish_all'] : 0;
72 95
73 96 // read file contents
74 - $data = $this->getUploadedFileContents($file['tmp_name']);
97 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
98 + $data = file_get_contents($file['tmp_name']);
75 99
76 100 // if empty data file then abort
77 101 if (empty($data))
78 102 {
79 - add_settings_error( self::settings_name, 'settings_updated', fpframework()->_('FPF_FILE_EMPTY'), 'error');
103 + \FPFramework\Libs\AdminNotice::displayError(fpframework()->_('FPF_FILE_EMPTY'));
80 104 return;
81 105 }
82 106
83 - if (!$items = json_decode($data, true))
107 + $items = json_decode($data, true);
108 +
109 + // Scalar JSON (e.g. "123") is valid JSON but not an export payload
110 + if (!$items || !is_array($items))
84 111 {
85 - add_settings_error( self::settings_name, 'settings_updated', firebox()->_('FB_POPUP_IMPORT_CONTENTS_ERROR'), 'error');
112 + \FPFramework\Libs\AdminNotice::displayError(firebox()->_('FB_CAMPAIGN_IMPORT_CONTENTS_ERROR'));
86 113 return;
87 114 }
88 115
89 116 if (is_null($items))
@@ -90,43 +117,25 @@
90 117 {
91 118 $items = [];
92 119 }
93 120
121 + if (!$items)
122 + {
123 + return;
124 + }
125 +
94 126 // import all boxes
95 127 if (!$new_box_id = $this->importBoxes($items, $publish_all))
96 128 {
97 - add_settings_error( self::settings_name, 'settings_updated', firebox()->_('FB_POPUP_IMPORT_CONTENTS_ERROR'), 'error');
129 + \FPFramework\Libs\AdminNotice::displayError(firebox()->_('FB_CAMPAIGN_IMPORT_CONTENTS_ERROR'));
98 130 return;
99 131 }
100 132
101 - add_settings_error( self::settings_name, 'settings_updated', fpframework()->_('FPF_ITEMS_SAVED'), 'success');
133 + \FPFramework\Libs\AdminNotice::displaySuccess(fpframework()->_('FPF_ITEMS_SAVED'));
102 134 return $new_box_id;
103 135 }
104 136
105 137 /**
106 - * Returns the uploaded file
107 - *
108 - * @return mixed
109 - */
110 - protected function getUploadedFile()
111 - {
112 - $file = isset($_FILES['file']) ? $_FILES['file'] : '';
113 - return $file;
114 - }
115 -
116 - /**
117 - * Returns the contents of the file
118 - *
119 - * @param string $tmp_name
120 - *
121 - * @return string
122 - */
123 - protected function getUploadedFileContents($tmp_name)
124 - {
125 - return file_get_contents($tmp_name);
126 - }
127 -
128 - /**
129 138 * Imports boxes data
130 139 *
131 140 * @param array $items
132 141 * @param int $publish_all
@@ -138,14 +147,16 @@
138 147 $success = true;
139 148
140 149 foreach ($items as $item)
141 150 {
142 - if (!isset($item['meta']))
151 + // The .fbox contents are user-supplied; validate the shape before
152 + // using it or a hand-edited file fatals instead of erroring.
153 + if (!is_array($item) || !isset($item['meta']))
143 154 {
144 155 $success = false;
145 156 break;
146 157 }
147 -
158 +
148 159 // get meta
149 160 $meta = $item['meta'];
150 161
151 162 // remote meta from item
@@ -150,21 +161,58 @@
150 161
151 162 // remote meta from item
152 163 unset($item['meta']);
153 164
154 - if (!isset($item['box']))
165 + // Campaign settings are free-form, but they are always a map — never a scalar.
166 + if (!is_array($meta) && !is_object($meta))
155 167 {
156 168 $success = false;
157 169 break;
158 170 }
159 171
172 + if (!isset($item['box']) || !is_array($item['box']))
173 + {
174 + $success = false;
175 + break;
176 + }
177 +
160 178 $box = $item['box'];
161 179
162 - // remove ID
163 - $box['ID'] = '';
180 + /**
181 + * The .fbox file carries a full wp_posts row, and every key in it used to be
182 + * written straight to the database. Keep only the columns that actually
183 + * describe a campaign; everything else (post_type, post_author, guid,
184 + * post_parent, ...) is either forced below or dropped.
185 + */
186 + $box = array_intersect_key($box, array_flip([
187 + 'post_title',
188 + 'post_content',
189 + 'post_excerpt',
190 + 'post_name',
191 + 'menu_order'
192 + ]));
164 193
194 + if (!isset($box['post_content']) || !is_string($box['post_content']))
195 + {
196 + $box['post_content'] = '';
197 + }
198 +
199 + $box['post_title'] = isset($box['post_title']) && is_string($box['post_title'])
200 + ? sanitize_text_field($box['post_title'])
201 + : '';
202 +
203 + $box['post_excerpt'] = isset($box['post_excerpt']) && is_string($box['post_excerpt'])
204 + ? sanitize_textarea_field($box['post_excerpt'])
205 + : '';
206 +
207 + $box['post_name'] = isset($box['post_name']) && is_string($box['post_name'])
208 + ? sanitize_title($box['post_name'])
209 + : '';
210 +
211 + $box['menu_order'] = isset($box['menu_order']) ? (int) $box['menu_order'] : 0;
212 +
165 213 $factory = new \FPFramework\Base\Factory();
166 -
214 +
167 215 $tz = wp_timezone();
168 216 $date_without_tz = $factory->getDate();
169 217 $date_with_tz = $factory->getDate()->setTimezone($tz);
170 218
@@ -170,23 +218,41 @@
170 218
171 219 $box['post_date'] = $date_with_tz->format('Y-m-d H:i:s');
172 220 $box['post_date_gmt'] = $date_without_tz->format('Y-m-d H:i:s');
173 221
222 + // These are ours to decide, never the file's.
223 + $box['post_type'] = 'firebox';
224 + $box['post_author'] = get_current_user_id();
225 +
226 + \FireBox\Core\Helpers\Form\Form::ensureUniqueFormIDs($box['post_content']);
227 +
174 228 // set publish status
175 229 if (in_array($publish_all, [0, 1]))
176 230 {
177 231 $box['post_status'] = ($publish_all == 0) ? 'draft' : 'publish';
178 232 }
179 -
180 - // insert new box
181 - if (!$new_box_id = firebox()->tables->box->insert((object) $box))
233 + else
182 234 {
235 + $box['post_status'] = 'draft';
236 + }
237 +
238 + /**
239 + * Insert through wp_insert_post() rather than the raw table layer so that
240 + * kses, slug uniqueness and the usual save_post hooks all apply.
241 + */
242 + $new_box_id = wp_insert_post(wp_slash($box), true);
243 +
244 + if (is_wp_error($new_box_id) || !$new_box_id)
245 + {
183 246 $success = false;
184 247 break;
185 248 }
186 249
187 250 // add meta options for new box
188 - update_post_meta($new_box_id, 'fpframework_meta_settings', wp_slash($meta));
251 + // TODO: In the future, use "firebox_meta". This is a temporary fix for backwards compatibility.
252 + $checkMeta = (array) $meta;
253 + $meta_key = isset($checkMeta['width']) ? 'firebox_meta' : 'fpframework_meta_settings';
254 + update_post_meta($new_box_id, $meta_key, wp_slash($meta));
189 255 $success = $new_box_id;
190 256 }
191 257
192 258 return $success;
@@ -204,7 +270,8 @@
204 270 'section_name' => self::settings_name,
205 271 'class' => 'settings-ui-inner-fields',
206 272 'button_label' => 'FPF_IMPORT'
207 273 ]);
208 - $form->render();
274 +
275 + echo $form->render(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
209 276 }
210 277 }