PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.05.02
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.05.02
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / controllers / FrmXMLController.php

FrmXMLController.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 4.05.02, at classes/controllers/FrmXMLController.php

517 lines 14.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class FrmXMLController {
4
5 public static function menu() {
6 add_submenu_page( 'formidable', 'Formidable | ' . __( 'Import/Export', 'formidable' ), __( 'Import/Export', 'formidable' ), 'frm_edit_forms', 'formidable-import', 'FrmXMLController::route' );
7 }
8
9 public static function add_default_templates() {
10 if ( ! function_exists( 'libxml_disable_entity_loader' ) ) {
11 // XML import is not enabled on your server
12 return;
13 }
14
15 $set_err = libxml_use_internal_errors( true );
16 $loader = libxml_disable_entity_loader( true );
17
18 $files = apply_filters( 'frm_default_templates_files', array() );
19
20 foreach ( (array) $files as $file ) {
21 FrmXMLHelper::import_xml( $file );
22 unset( $file );
23 }
24
25 unset( $files );
26
27 libxml_use_internal_errors( $set_err );
28 libxml_disable_entity_loader( $loader );
29 }
30
31 /**
32 * Use the template link to install the XML template
33 *
34 * @since 3.06
35 */
36 public static function install_template() {
37 FrmAppHelper::permission_check( 'frm_create_forms' );
38 check_ajax_referer( 'frm_ajax', 'nonce' );
39
40 $url = FrmAppHelper::get_param( 'xml', '', 'post', 'esc_url_raw' );
41
42 $response = wp_remote_get( $url );
43 $body = wp_remote_retrieve_body( $response );
44 $xml = simplexml_load_string( $body );
45
46 if ( ! $xml ) {
47 $response = array(
48 'message' => __( 'There was an error reading the form template', 'formidable' ),
49 );
50 echo wp_json_encode( $response );
51 wp_die();
52 }
53
54 self::set_new_form_name( $xml );
55
56 $imported = FrmXMLHelper::import_xml_now( $xml );
57 if ( isset( $imported['form_status'] ) && ! empty( $imported['form_status'] ) ) {
58 // Get the last form id in case there are child forms.
59 end( $imported['form_status'] );
60 $form_id = key( $imported['form_status'] );
61 $response = array(
62 'id' => $form_id,
63 'redirect' => FrmForm::get_edit_link( $form_id ),
64 'success' => 1,
65 );
66 } else {
67 $response = array(
68 'message' => __( 'There was an error importing form', 'formidable' ),
69 );
70 }
71
72 echo wp_json_encode( $response );
73 wp_die();
74 }
75
76 /**
77 * Change the name of the last form that is not a child.
78 * This will allow for lookup fields and embedded forms
79 * since we redirect to the last form.
80 *
81 * @since 3.06
82 *
83 * @param object $xml The values included in the XML.
84 */
85 private static function set_new_form_name( &$xml ) {
86 if ( ! isset( $xml->form ) ) {
87 return;
88 }
89
90 // Get the main form ID.
91 $set_name = 0;
92 foreach ( $xml->form as $form ) {
93 if ( ! isset( $form->parent_form_id ) || empty( $form->parent_form_id ) ) {
94 $set_name = $form->id;
95 }
96 }
97
98 foreach ( $xml->form as $form ) {
99 // Maybe set the form name if this isn't a child form.
100 if ( $set_name == $form->id ) {
101 $form->name = FrmAppHelper::get_param( 'name', '', 'post', 'sanitize_text_field' );
102 $form->description = FrmAppHelper::get_param( 'desc', '', 'post', 'sanitize_textarea_field' );
103 }
104
105 // Use a unique key to prevent editing existing form.
106 $name = sanitize_title( $form->name );
107 $form->form_key = FrmAppHelper::get_unique_key( $name, 'frm_forms', 'form_key' );
108 }
109 }
110
111 public static function route() {
112 $action = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action';
113 $action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
114 FrmAppHelper::include_svg();
115
116 if ( 'import_xml' === $action ) {
117 return self::import_xml();
118 } elseif ( 'export_xml' === $action ) {
119 return self::export_xml();
120 } elseif ( apply_filters( 'frm_xml_route', true, $action ) ) {
121 return self::form();
122 }
123 }
124
125 public static function form( $errors = array(), $message = '' ) {
126 $where = array(
127 'status' => array( null, '', 'published' ),
128 );
129 $forms = FrmForm::getAll( $where, 'name' );
130
131 $export_types = array(
132 'forms' => __( 'Forms', 'formidable' ),
133 'items' => __( 'Entries', 'formidable' ),
134 );
135 $export_types = apply_filters( 'frm_xml_export_types', $export_types );
136
137 $export_format = array(
138 'xml' => array(
139 'name' => 'XML',
140 'support' => 'forms',
141 'count' => 'multiple',
142 ),
143 'csv' => array(
144 'name' => 'CSV',
145 'support' => 'items',
146 'count' => 'single',
147 ),
148 );
149 $export_format = apply_filters( 'frm_export_formats', $export_format );
150
151 include( FrmAppHelper::plugin_path() . '/classes/views/xml/import_form.php' );
152 }
153
154 public static function import_xml() {
155 $errors = array();
156 $message = '';
157
158 $permission_error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'import-xml', 'import-xml-nonce' );
159 if ( false !== $permission_error ) {
160 $errors[] = $permission_error;
161 self::form( $errors );
162
163 return;
164 }
165
166 $has_file = isset( $_FILES ) && isset( $_FILES['frm_import_file'] ) && ! empty( $_FILES['frm_import_file']['name'] ) && ! empty( $_FILES['frm_import_file']['size'] ) && (int) $_FILES['frm_import_file']['size'] > 0;
167 if ( ! $has_file ) {
168 $errors[] = __( 'Oops, you didn\'t select a file.', 'formidable' );
169 self::form( $errors );
170
171 return;
172 }
173
174 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
175 $file = isset( $_FILES['frm_import_file']['tmp_name'] ) ? sanitize_option( 'upload_path', $_FILES['frm_import_file']['tmp_name'] ) : '';
176
177 if ( ! is_uploaded_file( $file ) ) {
178 unset( $file );
179 $errors[] = __( 'The file does not exist, please try again.', 'formidable' );
180 self::form( $errors );
181
182 return;
183 }
184
185 //add_filter('upload_mimes', 'FrmXMLController::allow_mime');
186
187 $export_format = array(
188 'xml' => array(
189 'name' => 'XML',
190 'support' => 'forms',
191 'count' => 'multiple',
192 ),
193 );
194 $export_format = apply_filters( 'frm_export_formats', $export_format );
195
196 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
197 $file_type = sanitize_option( 'upload_path', $_FILES['frm_import_file']['name'] );
198 $file_type = strtolower( pathinfo( $file_type, PATHINFO_EXTENSION ) );
199 if ( 'xml' !== $file_type && isset( $export_format[ $file_type ] ) ) {
200 // allow other file types to be imported
201 do_action( 'frm_before_import_' . $file_type );
202
203 return;
204 }
205 unset( $file_type );
206
207 if ( ! function_exists( 'libxml_disable_entity_loader' ) ) {
208 $errors[] = __( 'XML import is not enabled on your server with the libxml_disable_entity_loader function.', 'formidable' );
209 self::form( $errors );
210
211 return;
212 }
213
214 $set_err = libxml_use_internal_errors( true );
215 $loader = libxml_disable_entity_loader( true );
216
217 $result = FrmXMLHelper::import_xml( $file );
218 FrmXMLHelper::parse_message( $result, $message, $errors );
219
220 unset( $file );
221
222 libxml_use_internal_errors( $set_err );
223 libxml_disable_entity_loader( $loader );
224
225 self::form( $errors, $message );
226 }
227
228 public static function export_xml() {
229 $error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'export-xml', 'export-xml-nonce' );
230 if ( ! empty( $error ) ) {
231 wp_die( esc_html( $error ) );
232 }
233
234 $ids = FrmAppHelper::get_post_param( 'frm_export_forms', array(), 'sanitize_text_field' );
235 $type = FrmAppHelper::get_post_param( 'type', array(), 'sanitize_text_field' );
236 $format = FrmAppHelper::get_post_param( 'format', 'xml', 'sanitize_title' );
237
238 if ( ! headers_sent() && ! $type ) {
239 wp_redirect( esc_url_raw( admin_url( 'admin.php?page=formidable-import' ) ) );
240 die();
241 }
242
243 if ( 'xml' === $format ) {
244 self::generate_xml( $type, compact( 'ids' ) );
245 } elseif ( 'csv' === $format ) {
246 self::generate_csv( compact( 'ids' ) );
247 } else {
248 do_action( 'frm_export_format_' . $format, compact( 'ids' ) );
249 }
250
251 wp_die();
252 }
253
254 public static function generate_xml( $type, $args = array() ) {
255 global $wpdb;
256
257 self::prepare_types_array( $type );
258
259 $tables = array(
260 'items' => $wpdb->prefix . 'frm_items',
261 'forms' => $wpdb->prefix . 'frm_forms',
262 'posts' => $wpdb->posts,
263 'styles' => $wpdb->posts,
264 'actions' => $wpdb->posts,
265 );
266
267 $defaults = array(
268 'ids' => false,
269 );
270 $args = wp_parse_args( $args, $defaults );
271
272 // Make sure ids are numeric.
273 if ( is_array( $args['ids'] ) && ! empty( $args['ids'] ) ) {
274 $args['ids'] = array_filter( $args['ids'], 'is_numeric' );
275 }
276
277 $records = array();
278
279 foreach ( $type as $tb_type ) {
280 $where = array();
281 $join = '';
282 $table = $tables[ $tb_type ];
283
284 $select = $table . '.id';
285 $query_vars = array();
286
287 switch ( $tb_type ) {
288 case 'forms':
289 //add forms
290 if ( $args['ids'] ) {
291 $where[] = array(
292 'or' => 1,
293 $table . '.id' => $args['ids'],
294 $table . '.parent_form_id' => $args['ids'],
295 );
296 } else {
297 $where[ $table . '.status !' ] = 'draft';
298 }
299 break;
300 case 'actions':
301 $select = $table . '.ID';
302 $where['post_type'] = FrmFormActionsController::$action_post_type;
303 if ( ! empty( $args['ids'] ) ) {
304 $where['menu_order'] = $args['ids'];
305 }
306 break;
307 case 'items':
308 // $join = "INNER JOIN {$wpdb->prefix}frm_item_metas im ON ($table.id = im.item_id)";
309 if ( $args['ids'] ) {
310 $where[ $table . '.form_id' ] = $args['ids'];
311 }
312 break;
313 case 'styles':
314 // Loop through all exported forms and get their selected style IDs.
315 $frm_style = new FrmStyle();
316 $default_style = $frm_style->get_default_style();
317 $form_ids = $args['ids'];
318 $style_ids = array();
319 foreach ( $form_ids as $form_id ) {
320 $form_data = FrmForm::getOne( $form_id );
321 // For forms that have not been updated while running 2.0, check if custom_style is set.
322 if ( isset( $form_data->options['custom_style'] ) ) {
323 if ( 1 === absint( $form_data->options['custom_style'] ) ) {
324 $style_ids[] = $default_style->ID;
325 } else {
326 $style_ids[] = $form_data->options['custom_style'];
327 }
328 }
329 unset( $form_id, $form_data );
330 }
331 $select = $table . '.ID';
332 $where['post_type'] = 'frm_styles';
333
334 // Only export selected styles.
335 if ( ! empty( $style_ids ) ) {
336 $where['ID'] = $style_ids;
337 }
338 break;
339 default:
340 $select = $table . '.ID';
341 $join = ' INNER JOIN ' . $wpdb->postmeta . ' pm ON (pm.post_id=' . $table . '.ID)';
342 $where['pm.meta_key'] = 'frm_form_id';
343
344 if ( empty( $args['ids'] ) ) {
345 $where['pm.meta_value >'] = 1;
346 } else {
347 $where['pm.meta_value'] = $args['ids'];
348 }
349 }
350
351 $records[ $tb_type ] = FrmDb::get_col( $table . $join, $where, $select );
352 unset( $tb_type );
353 }
354
355 $filename = self::get_file_name( $args, $type, $records );
356
357 header( 'Content-Description: File Transfer' );
358 header( 'Content-Disposition: attachment; filename=' . $filename );
359 header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
360
361 echo '<?xml version="1.0" encoding="' . esc_attr( get_bloginfo( 'charset' ) ) . "\" ?>\n";
362 include( FrmAppHelper::plugin_path() . '/classes/views/xml/xml.php' );
363 }
364
365 private static function prepare_types_array( &$type ) {
366 $type = (array) $type;
367 if ( ! in_array( 'forms', $type ) && ( in_array( 'items', $type ) || in_array( 'posts', $type ) ) ) {
368 // make sure the form is included if there are entries
369 $type[] = 'forms';
370 }
371
372 if ( in_array( 'forms', $type ) ) {
373 // include actions with forms
374 $type[] = 'actions';
375 }
376 }
377
378 /**
379 * Use a generic file name if multiple items are exported.
380 * Use the nme of the form if only one form is exported.
381 *
382 * @since 3.06
383 *
384 * @return string
385 */
386 private static function get_file_name( $args, $type, $records ) {
387 $has_one_form = isset( $records['forms'] ) && ! empty( $records['forms'] ) && count( $args['ids'] ) === 1;
388 if ( $has_one_form ) {
389 // one form is being exported
390 $selected_form_id = reset( $args['ids'] );
391 $filename = 'form-' . $selected_form_id . '.xml';
392
393 foreach ( $records['forms'] as $form_id ) {
394 $filename = 'form-' . $form_id . '.xml';
395 if ( $selected_form_id === $form_id ) {
396 $form = FrmForm::getOne( $form_id );
397 $filename = sanitize_title( $form->name ) . '-form.xml';
398 break;
399 }
400 }
401 } else {
402 $sitename = sanitize_key( get_bloginfo( 'name' ) );
403
404 if ( ! empty( $sitename ) ) {
405 $sitename .= '.';
406 }
407 $filename = $sitename . 'formidable.' . gmdate( 'Y-m-d' ) . '.xml';
408 }
409
410 return $filename;
411 }
412
413 public static function generate_csv( $atts ) {
414 $form_ids = $atts['ids'];
415 if ( empty( $form_ids ) ) {
416 wp_die( esc_html__( 'Please select a form', 'formidable' ) );
417 }
418 self::csv( reset( $form_ids ) );
419 }
420
421 /**
422 * Export to CSV
423 *
424 * @since 2.0.19
425 */
426 public static function csv( $form_id = false, $search = '', $fid = '' ) {
427 FrmAppHelper::permission_check( 'frm_view_entries' );
428
429 if ( ! $form_id ) {
430 $form_id = FrmAppHelper::get_param( 'form', '', 'get', 'sanitize_text_field' );
431 $search = FrmAppHelper::get_param( ( isset( $_REQUEST['s'] ) ? 's' : 'search' ), '', 'get', 'sanitize_text_field' );
432 $fid = FrmAppHelper::get_param( 'fid', '', 'get', 'sanitize_text_field' );
433 }
434
435 set_time_limit( 0 ); //Remove time limit to execute this function
436 $mem_limit = str_replace( 'M', '', ini_get( 'memory_limit' ) );
437 if ( (int) $mem_limit < 256 ) {
438 wp_raise_memory_limit();
439 }
440
441 global $wpdb;
442
443 $form = FrmForm::getOne( $form_id );
444 $form_id = $form->id;
445
446 $form_cols = self::get_fields_for_csv_export( $form_id, $form );
447
448 $item_id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'sanitize_text_field' );
449 if ( ! empty( $item_id ) ) {
450 $item_id = explode( ',', $item_id );
451 }
452
453 $query = array(
454 'form_id' => $form_id,
455 );
456
457 if ( $item_id ) {
458 $query['id'] = $item_id;
459 }
460
461 /**
462 * Allows the query to be changed for fetching the entry ids to include in the export
463 *
464 * $query is the array of options to be filtered. It includes form_id, and maybe id (array of entry ids),
465 * and the search query. This should return an array, but it can be handled as a string as well.
466 */
467 $query = apply_filters( 'frm_csv_where', $query, compact( 'form_id', 'search', 'fid', 'item_id' ) );
468
469 $entry_ids = FrmDb::get_col( $wpdb->prefix . 'frm_items it', $query );
470 unset( $query );
471
472 if ( empty( $entry_ids ) ) {
473 esc_html_e( 'There are no entries for that form.', 'formidable' );
474 } else {
475 FrmCSVExportHelper::generate_csv( compact( 'form', 'entry_ids', 'form_cols' ) );
476 }
477
478 wp_die();
479 }
480
481 /**
482 * Get the fields that should be included in the CSV export
483 *
484 * @since 2.0.19
485 *
486 * @param int $form_id
487 * @param object $form
488 *
489 * @return array $csv_fields
490 */
491 private static function get_fields_for_csv_export( $form_id, $form ) {
492 $csv_fields = FrmField::get_all_for_form( $form_id, '', 'include', 'include' );
493 $no_export_fields = FrmField::no_save_fields();
494 foreach ( $csv_fields as $k => $f ) {
495 if ( in_array( $f->type, $no_export_fields ) ) {
496 unset( $csv_fields[ $k ] );
497 }
498 }
499
500 return $csv_fields;
501 }
502
503 public static function allow_mime( $mimes ) {
504 if ( ! isset( $mimes['csv'] ) ) {
505 // allow csv files
506 $mimes['csv'] = 'text/csv';
507 }
508
509 if ( ! isset( $mimes['xml'] ) ) {
510 // allow xml
511 $mimes['xml'] = 'text/xml';
512 }
513
514 return $mimes;
515 }
516 }
517