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

516 lines 14.7 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'] ) ? $_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 = strtolower( pathinfo( $_FILES['frm_import_file']['name'], PATHINFO_EXTENSION ) );
198 if ( 'xml' !== $file_type && isset( $export_format[ $file_type ] ) ) {
199 // allow other file types to be imported
200 do_action( 'frm_before_import_' . $file_type );
201
202 return;
203 }
204 unset( $file_type );
205
206 if ( ! function_exists( 'libxml_disable_entity_loader' ) ) {
207 $errors[] = __( 'XML import is not enabled on your server with the libxml_disable_entity_loader function.', 'formidable' );
208 self::form( $errors );
209
210 return;
211 }
212
213 $set_err = libxml_use_internal_errors( true );
214 $loader = libxml_disable_entity_loader( true );
215
216 $result = FrmXMLHelper::import_xml( $file );
217 FrmXMLHelper::parse_message( $result, $message, $errors );
218
219 unset( $file );
220
221 libxml_use_internal_errors( $set_err );
222 libxml_disable_entity_loader( $loader );
223
224 self::form( $errors, $message );
225 }
226
227 public static function export_xml() {
228 $error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'export-xml', 'export-xml-nonce' );
229 if ( ! empty( $error ) ) {
230 wp_die( esc_html( $error ) );
231 }
232
233 $ids = FrmAppHelper::get_post_param( 'frm_export_forms', array() );
234 $type = FrmAppHelper::get_post_param( 'type', array() );
235 $format = FrmAppHelper::get_post_param( 'format', 'xml', 'sanitize_title' );
236
237 if ( ! headers_sent() && ! $type ) {
238 wp_redirect( esc_url_raw( admin_url( 'admin.php?page=formidable-import' ) ) );
239 die();
240 }
241
242 if ( 'xml' === $format ) {
243 self::generate_xml( $type, compact( 'ids' ) );
244 } elseif ( 'csv' === $format ) {
245 self::generate_csv( compact( 'ids' ) );
246 } else {
247 do_action( 'frm_export_format_' . $format, compact( 'ids' ) );
248 }
249
250 wp_die();
251 }
252
253 public static function generate_xml( $type, $args = array() ) {
254 global $wpdb;
255
256 self::prepare_types_array( $type );
257
258 $tables = array(
259 'items' => $wpdb->prefix . 'frm_items',
260 'forms' => $wpdb->prefix . 'frm_forms',
261 'posts' => $wpdb->posts,
262 'styles' => $wpdb->posts,
263 'actions' => $wpdb->posts,
264 );
265
266 $defaults = array(
267 'ids' => false,
268 );
269 $args = wp_parse_args( $args, $defaults );
270
271 // Make sure ids are numeric.
272 if ( is_array( $args['ids'] ) && ! empty( $args['ids'] ) ) {
273 $args['ids'] = array_filter( $args['ids'], 'is_numeric' );
274 }
275
276 $records = array();
277
278 foreach ( $type as $tb_type ) {
279 $where = array();
280 $join = '';
281 $table = $tables[ $tb_type ];
282
283 $select = $table . '.id';
284 $query_vars = array();
285
286 switch ( $tb_type ) {
287 case 'forms':
288 //add forms
289 if ( $args['ids'] ) {
290 $where[] = array(
291 'or' => 1,
292 $table . '.id' => $args['ids'],
293 $table . '.parent_form_id' => $args['ids'],
294 );
295 } else {
296 $where[ $table . '.status !' ] = 'draft';
297 }
298 break;
299 case 'actions':
300 $select = $table . '.ID';
301 $where['post_type'] = FrmFormActionsController::$action_post_type;
302 if ( ! empty( $args['ids'] ) ) {
303 $where['menu_order'] = $args['ids'];
304 }
305 break;
306 case 'items':
307 // $join = "INNER JOIN {$wpdb->prefix}frm_item_metas im ON ($table.id = im.item_id)";
308 if ( $args['ids'] ) {
309 $where[ $table . '.form_id' ] = $args['ids'];
310 }
311 break;
312 case 'styles':
313 // Loop through all exported forms and get their selected style IDs.
314 $frm_style = new FrmStyle();
315 $default_style = $frm_style->get_default_style();
316 $form_ids = $args['ids'];
317 $style_ids = array();
318 foreach ( $form_ids as $form_id ) {
319 $form_data = FrmForm::getOne( $form_id );
320 // For forms that have not been updated while running 2.0, check if custom_style is set.
321 if ( isset( $form_data->options['custom_style'] ) ) {
322 if ( 1 === absint( $form_data->options['custom_style'] ) ) {
323 $style_ids[] = $default_style->ID;
324 } else {
325 $style_ids[] = $form_data->options['custom_style'];
326 }
327 }
328 unset( $form_id, $form_data );
329 }
330 $select = $table . '.ID';
331 $where['post_type'] = 'frm_styles';
332
333 // Only export selected styles.
334 if ( ! empty( $style_ids ) ) {
335 $where['ID'] = $style_ids;
336 }
337 break;
338 default:
339 $select = $table . '.ID';
340 $join = ' INNER JOIN ' . $wpdb->postmeta . ' pm ON (pm.post_id=' . $table . '.ID)';
341 $where['pm.meta_key'] = 'frm_form_id';
342
343 if ( empty( $args['ids'] ) ) {
344 $where['pm.meta_value >'] = 1;
345 } else {
346 $where['pm.meta_value'] = $args['ids'];
347 }
348 }
349
350 $records[ $tb_type ] = FrmDb::get_col( $table . $join, $where, $select );
351 unset( $tb_type );
352 }
353
354 $filename = self::get_file_name( $args, $type, $records );
355
356 header( 'Content-Description: File Transfer' );
357 header( 'Content-Disposition: attachment; filename=' . $filename );
358 header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
359
360 echo '<?xml version="1.0" encoding="' . esc_attr( get_bloginfo( 'charset' ) ) . "\" ?>\n";
361 include( FrmAppHelper::plugin_path() . '/classes/views/xml/xml.php' );
362 }
363
364 private static function prepare_types_array( &$type ) {
365 $type = (array) $type;
366 if ( ! in_array( 'forms', $type ) && ( in_array( 'items', $type ) || in_array( 'posts', $type ) ) ) {
367 // make sure the form is included if there are entries
368 $type[] = 'forms';
369 }
370
371 if ( in_array( 'forms', $type ) ) {
372 // include actions with forms
373 $type[] = 'actions';
374 }
375 }
376
377 /**
378 * Use a generic file name if multiple items are exported.
379 * Use the nme of the form if only one form is exported.
380 *
381 * @since 3.06
382 *
383 * @return string
384 */
385 private static function get_file_name( $args, $type, $records ) {
386 $has_one_form = isset( $records['forms'] ) && ! empty( $records['forms'] ) && count( $args['ids'] ) === 1;
387 if ( $has_one_form ) {
388 // one form is being exported
389 $selected_form_id = reset( $args['ids'] );
390 $filename = 'form-' . $selected_form_id . '.xml';
391
392 foreach ( $records['forms'] as $form_id ) {
393 $filename = 'form-' . $form_id . '.xml';
394 if ( $selected_form_id === $form_id ) {
395 $form = FrmForm::getOne( $form_id );
396 $filename = sanitize_title( $form->name ) . '-form.xml';
397 break;
398 }
399 }
400 } else {
401 $sitename = sanitize_key( get_bloginfo( 'name' ) );
402
403 if ( ! empty( $sitename ) ) {
404 $sitename .= '.';
405 }
406 $filename = $sitename . 'formidable.' . date( 'Y-m-d' ) . '.xml';
407 }
408
409 return $filename;
410 }
411
412 public static function generate_csv( $atts ) {
413 $form_ids = $atts['ids'];
414 if ( empty( $form_ids ) ) {
415 wp_die( esc_html__( 'Please select a form', 'formidable' ) );
416 }
417 self::csv( reset( $form_ids ) );
418 }
419
420 /**
421 * Export to CSV
422 *
423 * @since 2.0.19
424 */
425 public static function csv( $form_id = false, $search = '', $fid = '' ) {
426 FrmAppHelper::permission_check( 'frm_view_entries' );
427
428 if ( ! $form_id ) {
429 $form_id = FrmAppHelper::get_param( 'form', '', 'get', 'sanitize_text_field' );
430 $search = FrmAppHelper::get_param( ( isset( $_REQUEST['s'] ) ? 's' : 'search' ), '', 'get', 'sanitize_text_field' );
431 $fid = FrmAppHelper::get_param( 'fid', '', 'get', 'sanitize_text_field' );
432 }
433
434 set_time_limit( 0 ); //Remove time limit to execute this function
435 $mem_limit = str_replace( 'M', '', ini_get( 'memory_limit' ) );
436 if ( (int) $mem_limit < 256 ) {
437 wp_raise_memory_limit();
438 }
439
440 global $wpdb;
441
442 $form = FrmForm::getOne( $form_id );
443 $form_id = $form->id;
444
445 $form_cols = self::get_fields_for_csv_export( $form_id, $form );
446
447 $item_id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'sanitize_text_field' );
448 if ( ! empty( $item_id ) ) {
449 $item_id = explode( ',', $item_id );
450 }
451
452 $query = array(
453 'form_id' => $form_id,
454 );
455
456 if ( $item_id ) {
457 $query['id'] = $item_id;
458 }
459
460 /**
461 * Allows the query to be changed for fetching the entry ids to include in the export
462 *
463 * $query is the array of options to be filtered. It includes form_id, and maybe id (array of entry ids),
464 * and the search query. This should return an array, but it can be handled as a string as well.
465 */
466 $query = apply_filters( 'frm_csv_where', $query, compact( 'form_id', 'search', 'fid', 'item_id' ) );
467
468 $entry_ids = FrmDb::get_col( $wpdb->prefix . 'frm_items it', $query );
469 unset( $query );
470
471 if ( empty( $entry_ids ) ) {
472 esc_html_e( 'There are no entries for that form.', 'formidable' );
473 } else {
474 FrmCSVExportHelper::generate_csv( compact( 'form', 'entry_ids', 'form_cols' ) );
475 }
476
477 wp_die();
478 }
479
480 /**
481 * Get the fields that should be included in the CSV export
482 *
483 * @since 2.0.19
484 *
485 * @param int $form_id
486 * @param object $form
487 *
488 * @return array $csv_fields
489 */
490 private static function get_fields_for_csv_export( $form_id, $form ) {
491 $csv_fields = FrmField::get_all_for_form( $form_id, '', 'include', 'include' );
492 $no_export_fields = FrmField::no_save_fields();
493 foreach ( $csv_fields as $k => $f ) {
494 if ( in_array( $f->type, $no_export_fields ) ) {
495 unset( $csv_fields[ $k ] );
496 }
497 }
498
499 return $csv_fields;
500 }
501
502 public static function allow_mime( $mimes ) {
503 if ( ! isset( $mimes['csv'] ) ) {
504 // allow csv files
505 $mimes['csv'] = 'text/csv';
506 }
507
508 if ( ! isset( $mimes['xml'] ) ) {
509 // allow xml
510 $mimes['xml'] = 'text/xml';
511 }
512
513 return $mimes;
514 }
515 }
516