Completed
Push — master ( 458dfc...f12a94 )
by Stephanie
02:58
created

FrmXMLController::route()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
nc 8
nop 0
dl 0
loc 11
rs 9.6111
c 0
b 0
f 0
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( FrmAppHelper::plugin_path() . '/classes/views/xml/default-templates.xml' ) );
19
20
		foreach ( (array) $files as $file ) {
21
			FrmXMLHelper::import_xml( $file );
22
			unset( $file );
23
		}
24
		/*
25
		if(is_wp_error($result))
26
			$errors[] = $result->get_error_message();
27
		else if($result)
28
			$message = $result;
29
		*/
30
31
		unset( $files );
32
33
		libxml_use_internal_errors( $set_err );
34
		libxml_disable_entity_loader( $loader );
35
	}
36
37
38
	/**
39
	 * Use the template link to install the XML template
40
	 *
41
	 * @since 3.06
42
	 */
43
	public static function install_template() {
44
		FrmAppHelper::permission_check( 'frm_create_forms' );
45
		check_ajax_referer( 'frm_ajax', 'nonce' );
46
47
		$url = FrmAppHelper::get_param( 'xml', '', 'post', 'esc_url_raw' );
48
49
		$response = wp_remote_get( $url );
50
		$body     = wp_remote_retrieve_body( $response );
51
		$xml      = simplexml_load_string( $body );
52
53
		if ( ! $xml ) {
54
			$response = array(
55
				'message' => __( 'There was an error reading the form template', 'formidable' ),
56
			);
57
			echo wp_json_encode( $response );
58
			wp_die();
59
		}
60
61
		self::set_new_form_name( $xml );
62
63
		$imported = FrmXMLHelper::import_xml_now( $xml );
64
		if ( isset( $imported['form_status'] ) && ! empty( $imported['form_status'] ) ) {
65
			// Get the last form id in case there are child forms.
66
			end( $imported['form_status'] );
67
			$form_id = key( $imported['form_status'] );
68
			$response = array(
69
				'id'       => $form_id,
70
				'redirect' => admin_url( 'admin.php?page=formidable&frm_action=edit&id=' . absint( $form_id ) ),
71
				'success'  => 1,
72
			);
73
		} else {
74
			$response = array(
75
				'message' => __( 'There was an error importing form', 'formidable' ),
76
			);
77
		}
78
79
		echo wp_json_encode( $response );
80
		wp_die();
81
	}
82
83
	/**
84
	 * Change the name of the last form that is not a child.
85
	 * This will allow for lookup fields and embedded forms
86
	 * since we redirect to the last form.
87
	 *
88
	 * @since 3.06
89
	 * @param object $xml The values included in the XML.
90
	 */
91
	private static function set_new_form_name( &$xml ) {
92
		if ( ! isset( $xml->form ) ) {
93
			return;
94
		}
95
96
		// Get the main form ID.
97
		$set_name = 0;
98
		foreach ( $xml->form as $form ) {
99
			if ( ! isset( $form->parent_form_id ) || empty( $form->parent_form_id ) ) {
100
				$set_name = $form->id;
101
			}
102
		}
103
104
		foreach ( $xml->form as $form ) {
105
			// Use a unique key to prevent editing existing form.
106
			$form->form_key = FrmAppHelper::get_unique_key( $form->form_key, 'frm_forms', 'form_key' );
107
108
			// Maybe set the form name if this isn't a child form.
109
			if ( $set_name == $form->id ) {
110
				$form->name        = FrmAppHelper::get_param( 'name', '', 'post', 'sanitize_text_field' );
111
				$form->description = FrmAppHelper::get_param( 'desc', '', 'post', 'sanitize_textarea_field' );
112
			}
113
		}
114
	}
115
116
	public static function route() {
117
		$action = isset( $_REQUEST['frm_action'] ) ? 'frm_action' : 'action';
118
		$action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
119
		if ( 'import_xml' === $action ) {
120
			return self::import_xml();
121
		} elseif ( 'export_xml' === $action ) {
122
			return self::export_xml();
123
		} elseif ( apply_filters( 'frm_xml_route', true, $action ) ) {
124
			return self::form();
125
		}
126
	}
127
128
	public static function form( $errors = array(), $message = '' ) {
129
		$where = array(
130
			'status' => array( null, '', 'published' ),
131
		);
132
		$forms = FrmForm::getAll( $where, 'name' );
133
134
		$export_types = array(
135
			'forms' => __( 'Forms', 'formidable' ),
136
			'items' => __( 'Entries', 'formidable' ),
137
		);
138
		$export_types = apply_filters( 'frm_xml_export_types', $export_types );
139
140
		$export_format = array(
141
			'xml' => array(
142
				'name'    => 'XML',
143
				'support' => 'forms',
144
				'count'   => 'multiple',
145
			),
146
			'csv' => array(
147
				'name'    => 'CSV',
148
				'support' => 'items',
149
				'count'   => 'single',
150
			),
151
		);
152
		$export_format = apply_filters( 'frm_export_formats', $export_format );
153
154
		include( FrmAppHelper::plugin_path() . '/classes/views/xml/import_form.php' );
155
	}
156
157
	public static function import_xml() {
158
		$errors = array();
159
		$message = '';
160
161
		$permission_error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'import-xml', 'import-xml-nonce' );
162
		if ( false !== $permission_error ) {
163
			$errors[] = $permission_error;
164
			self::form( $errors );
165
			return;
166
		}
167
168
		if ( ! isset( $_FILES ) || ! isset( $_FILES['frm_import_file'] ) || empty( $_FILES['frm_import_file']['name'] ) || (int) $_FILES['frm_import_file']['size'] < 1 ) {
169
			$errors[] = __( 'Oops, you didn\'t select a file.', 'formidable' );
170
			self::form( $errors );
171
			return;
172
		}
173
174
		$file = $_FILES['frm_import_file']['tmp_name'];
175
176
		if ( ! is_uploaded_file( $file ) ) {
177
			unset( $file );
178
			$errors[] = __( 'The file does not exist, please try again.', 'formidable' );
179
			self::form( $errors );
180
			return;
181
		}
182
183
		//add_filter('upload_mimes', 'FrmXMLController::allow_mime');
184
185
		$export_format = array(
186
			'xml' => array(
187
				'name'    => 'XML',
188
				'support' => 'forms',
189
				'count'   => 'multiple',
190
			),
191
		);
192
		$export_format = apply_filters( 'frm_export_formats', $export_format );
193
194
		$file_type = strtolower( pathinfo( $_FILES['frm_import_file']['name'], PATHINFO_EXTENSION ) );
195
		if ( 'xml' !== $file_type && isset( $export_format[ $file_type ] ) ) {
196
			// allow other file types to be imported
197
			do_action( 'frm_before_import_' . $file_type );
198
			return;
199
		}
200
		unset( $file_type );
201
202
		if ( ! function_exists( 'libxml_disable_entity_loader' ) ) {
203
			$errors[] = __( 'XML import is not enabled on your server with the libxml_disable_entity_loader function.', 'formidable' );
204
			self::form( $errors );
205
			return;
206
		}
207
208
		$set_err = libxml_use_internal_errors( true );
209
		$loader = libxml_disable_entity_loader( true );
210
211
		$result = FrmXMLHelper::import_xml( $file );
212
		FrmXMLHelper::parse_message( $result, $message, $errors );
213
214
		unset( $file );
215
216
		libxml_use_internal_errors( $set_err );
217
		libxml_disable_entity_loader( $loader );
218
219
		self::form( $errors, $message );
220
	}
221
222
	public static function export_xml() {
223
		$error = FrmAppHelper::permission_nonce_error( 'frm_edit_forms', 'export-xml', 'export-xml-nonce' );
224
		if ( ! empty( $error ) ) {
225
			wp_die( esc_html( $error ) );
226
		}
227
228
		$ids = FrmAppHelper::get_post_param( 'frm_export_forms', array() );
229
		$type = FrmAppHelper::get_post_param( 'type', array() );
230
		$format = FrmAppHelper::get_post_param( 'format', 'xml', 'sanitize_title' );
231
232
		if ( ! headers_sent() && ! $type ) {
233
			wp_redirect( esc_url_raw( admin_url( 'admin.php?page=formidable-import' ) ) );
234
			die();
235
		}
236
237
		if ( 'xml' === $format ) {
238
			self::generate_xml( $type, compact( 'ids' ) );
239
		} elseif ( 'csv' === $format ) {
240
			self::generate_csv( compact( 'ids' ) );
241
		} else {
242
			do_action( 'frm_export_format_' . $format, compact( 'ids' ) );
243
		}
244
245
		wp_die();
246
	}
247
248
	public static function generate_xml( $type, $args = array() ) {
249
		global $wpdb;
250
251
		self::prepare_types_array( $type );
252
253
		$tables = array(
254
			'items'     => $wpdb->prefix . 'frm_items',
255
			'forms'     => $wpdb->prefix . 'frm_forms',
256
			'posts'     => $wpdb->posts,
257
			'styles'    => $wpdb->posts,
258
			'actions'   => $wpdb->posts,
259
		);
260
261
		$defaults = array(
262
			'ids' => false,
263
		);
264
		$args = wp_parse_args( $args, $defaults );
265
266
		// Make sure ids are numeric.
267
		if ( is_array( $args['ids'] ) && ! empty( $args['ids'] ) ) {
268
			$args['ids'] = array_filter( $args['ids'], 'is_numeric' );
269
		}
270
271
		$records = array();
272
273
		foreach ( $type as $tb_type ) {
274
			$where = array();
275
			$join = '';
276
			$table = $tables[ $tb_type ];
277
278
			$select = $table . '.id';
279
			$query_vars = array();
280
281
			switch ( $tb_type ) {
282
				case 'forms':
283
					//add forms
284
					if ( $args['ids'] ) {
285
						$where[] = array(
286
							'or'           => 1,
287
							$table . '.id' => $args['ids'],
288
							$table . '.parent_form_id' => $args['ids'],
289
						);
290
					} else {
291
						$where[ $table . '.status !' ] = 'draft';
292
					}
293
					break;
294
				case 'actions':
295
					$select = $table . '.ID';
296
					$where['post_type'] = FrmFormActionsController::$action_post_type;
297
					if ( ! empty( $args['ids'] ) ) {
298
						$where['menu_order'] = $args['ids'];
299
					}
300
					break;
301
				case 'items':
302
					//$join = "INNER JOIN {$wpdb->prefix}frm_item_metas im ON ($table.id = im.item_id)";
303
					if ( $args['ids'] ) {
304
						$where[ $table . '.form_id' ] = $args['ids'];
305
					}
306
					break;
307
				case 'styles':
308
					// Loop through all exported forms and get their selected style IDs
309
					$frm_style = new FrmStyle();
310
					$default_style = $frm_style->get_default_style();
311
					$form_ids = $args['ids'];
312
					$style_ids = array();
313
					foreach ( $form_ids as $form_id ) {
314
						$form_data = FrmForm::getOne( $form_id );
315
						// For forms that have not been updated while running 2.0, check if custom_style is set
316
						if ( isset( $form_data->options['custom_style'] ) ) {
317
							if ( 1 === absint( $form_data->options['custom_style'] ) ) {
318
								$style_ids[] = $default_style->ID;
319
							} else {
320
								$style_ids[] = $form_data->options['custom_style'];
321
							}
322
						}
323
						unset( $form_id, $form_data );
324
					}
325
					$select = $table . '.ID';
326
					$where['post_type'] = 'frm_styles';
327
328
					// Only export selected styles
329
					if ( ! empty( $style_ids ) ) {
330
						$where['ID'] = $style_ids;
331
					}
332
					break;
333
				default:
334
					$select = $table . '.ID';
335
					$join = ' INNER JOIN ' . $wpdb->postmeta . ' pm ON (pm.post_id=' . $table . '.ID)';
336
					$where['pm.meta_key'] = 'frm_form_id';
337
338
					if ( empty( $args['ids'] ) ) {
339
						$where['pm.meta_value >'] = 1;
340
					} else {
341
						$where['pm.meta_value'] = $args['ids'];
342
					}
343
			}
344
345
			$records[ $tb_type ] = FrmDb::get_col( $table . $join, $where, $select );
346
			unset( $tb_type );
347
		}
348
349
		$filename = self::get_file_name( $args, $type, $records );
350
351
		header( 'Content-Description: File Transfer' );
352
		header( 'Content-Disposition: attachment; filename=' . $filename );
353
		header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
354
355
		echo '<?xml version="1.0" encoding="' . esc_attr( get_bloginfo( 'charset' ) ) . "\" ?>\n";
356
		include( FrmAppHelper::plugin_path() . '/classes/views/xml/xml.php' );
357
	}
358
359
	private static function prepare_types_array( &$type ) {
360
		$type = (array) $type;
361
		if ( ! in_array( 'forms', $type ) && ( in_array( 'items', $type ) || in_array( 'posts', $type ) ) ) {
362
			// make sure the form is included if there are entries
363
			$type[] = 'forms';
364
		}
365
366
		if ( in_array( 'forms', $type ) ) {
367
			// include actions with forms
368
			$type[] = 'actions';
369
		}
370
	}
371
372
	/**
373
	 * Use a generic file name if multiple items are exported.
374
	 * Use the nme of the form if only one form is exported.
375
	 *
376
	 * @since 3.05.01
377
	 *
378
	 * @return string
379
	 */
380
	private static function get_file_name( $args, $type, $records ) {
381
		$has_one_form = isset( $records['forms'] ) && ! empty( $records['forms'] ) && count( $args['ids'] ) === 1;
382
		if ( $has_one_form ) {
383
			// one form is being exported
384
			$selected_form_id = reset( $args['ids'] );
385
			foreach ( $records['forms'] as $form_id ) {
386
				$filename = 'form-' . $form_id . '.xml';
387
				if ( $selected_form_id === $form_id ) {
388
					$form = FrmForm::getOne( $form_id );
389
					$filename = sanitize_title( $form->name ) . '-form.xml';
390
					break;
391
				}
392
			}
393
		} else {
394
			$sitename = sanitize_key( get_bloginfo( 'name' ) );
395
396
			if ( ! empty( $sitename ) ) {
397
				$sitename .= '.';
398
			}
399
			$filename = $sitename . 'formidable.' . date( 'Y-m-d' ) . '.xml';
400
		}
401
		return $filename;
0 ignored issues
show
Bug introduced by
The variable $filename does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
402
	}
403
404
	public static function generate_csv( $atts ) {
405
		$form_ids = $atts['ids'];
406
		if ( empty( $form_ids ) ) {
407
			wp_die( esc_html__( 'Please select a form', 'formidable' ) );
408
		}
409
		self::csv( reset( $form_ids ) );
410
	}
411
412
	/**
413
	 * Export to CSV
414
	 *
415
	 * @since 2.0.19
416
	 */
417
	public static function csv( $form_id = false, $search = '', $fid = '' ) {
418
		FrmAppHelper::permission_check( 'frm_view_entries' );
419
420
		if ( ! $form_id ) {
421
			$form_id = FrmAppHelper::get_param( 'form', '', 'get', 'sanitize_text_field' );
422
			$search = FrmAppHelper::get_param( ( isset( $_REQUEST['s'] ) ? 's' : 'search' ), '', 'get', 'sanitize_text_field' );
423
			$fid = FrmAppHelper::get_param( 'fid', '', 'get', 'sanitize_text_field' );
424
		}
425
426
		set_time_limit( 0 ); //Remove time limit to execute this function
427
		$mem_limit = str_replace( 'M', '', ini_get( 'memory_limit' ) );
428
		if ( (int) $mem_limit < 256 ) {
429
			ini_set( 'memory_limit', '256M' );
430
		}
431
432
		global $wpdb;
433
434
		$form = FrmForm::getOne( $form_id );
435
		$form_id = $form->id;
436
437
		$form_cols = self::get_fields_for_csv_export( $form_id, $form );
438
439
		$item_id = FrmAppHelper::get_param( 'item_id', 0, 'get', 'sanitize_text_field' );
440
		if ( ! empty( $item_id ) ) {
441
			$item_id = explode( ',', $item_id );
442
		}
443
444
		$query = array(
445
			'form_id' => $form_id,
446
		);
447
448
		if ( $item_id ) {
449
			$query['id'] = $item_id;
450
		}
451
452
		/**
453
		 * Allows the query to be changed for fetching the entry ids to include in the export
454
		 *
455
		 * $query is the array of options to be filtered. It includes form_id, and maybe id (array of entry ids),
456
		 * and the search query. This should return an array, but it can be handled as a string as well.
457
		 */
458
		$query = apply_filters( 'frm_csv_where', $query, compact( 'form_id', 'search', 'fid', 'item_id' ) );
459
460
		$entry_ids = FrmDb::get_col( $wpdb->prefix . 'frm_items it', $query );
461
		unset( $query );
462
463
		if ( empty( $entry_ids ) ) {
464
			esc_html_e( 'There are no entries for that form.', 'formidable' );
465
		} else {
466
			FrmCSVExportHelper::generate_csv( compact( 'form', 'entry_ids', 'form_cols' ) );
467
		}
468
469
		wp_die();
470
	}
471
472
	/**
473
	* Get the fields that should be included in the CSV export
474
	*
475
	* @since 2.0.19
476
	*
477
	* @param int $form_id
478
	* @param object $form
479
	* @return array $csv_fields
480
	*/
481
	private static function get_fields_for_csv_export( $form_id, $form ) {
482
		$csv_fields = FrmField::get_all_for_form( $form_id, '', 'include', 'include' );
483
		$no_export_fields = FrmField::no_save_fields();
484
		foreach ( $csv_fields as $k => $f ) {
485
			if ( in_array( $f->type, $no_export_fields ) ) {
486
				unset( $csv_fields[ $k ] );
487
			}
488
		}
489
490
		return $csv_fields;
491
	}
492
493
	public static function allow_mime( $mimes ) {
494
		if ( ! isset( $mimes['csv'] ) ) {
495
			// allow csv files
496
			$mimes['csv'] = 'text/csv';
497
		}
498
499
		if ( ! isset( $mimes['xml'] ) ) {
500
			// allow xml
501
			$mimes['xml'] = 'text/xml';
502
		}
503
504
		return $mimes;
505
	}
506
}
507