PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 4.04.05
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v4.04.05
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.04.05, at classes/controllers/FrmXMLController.php

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