| | 4329 | |
| | 4330 | function wp_ajax_wp_privacy_export_personal_data() { |
| | 4331 | check_ajax_referer( 'wp-privacy-export-personal-data', 'security' ); |
| | 4332 | |
| | 4333 | if ( ! current_user_can( 'manage_options' ) ) { |
| | 4334 | wp_send_json_error( 'access denied' ); |
| | 4335 | } |
| | 4336 | |
| | 4337 | $email_address = sanitize_text_field( $_POST['email'] ); |
| | 4338 | $exporter_index = (int) sanitize_text_field( $_POST['exporter'] ); |
| | 4339 | $page = (int) sanitize_text_field( $_POST['page'] ); |
| | 4340 | |
| | 4341 | /** |
| | 4342 | * Filters the array of exporter callbacks. |
| | 4343 | * |
| | 4344 | * @since 4.9.5. |
| | 4345 | * |
| | 4346 | * @param array $args { |
| | 4347 | * An array of callable exporters of personal data. Default empty array. |
| | 4348 | * [ |
| | 4349 | * callback string Callable exporter that accepts an email address and |
| | 4350 | * a zero-based page and returns an array of name value |
| | 4351 | * pairs of personal data |
| | 4352 | * exporter_friendly_name string Translated user facing friendly name for the exporter |
| | 4353 | * ] |
| | 4354 | * } |
| | 4355 | */ |
| | 4356 | $exporters = apply_filters( 'wp_privacy_personal_data_exporters', array() ); |
| | 4357 | |
| | 4358 | if ( ! is_array( $exporters ) ) { |
| | 4359 | wp_send_json_error( 'an exporter has improperly used the registration filter' ); |
| | 4360 | } |
| | 4361 | |
| | 4362 | // Do we have any registered exporters? |
| | 4363 | if ( 0 < count( $exporters ) ) { |
| | 4364 | if ( $exporter_index < 0 ) { |
| | 4365 | wp_send_json_error( 'exporter index cannot be negative' ); |
| | 4366 | } |
| | 4367 | |
| | 4368 | if ( $exporter_index > count( $exporters ) - 1 ) { |
| | 4369 | wp_send_json_error( 'exporter index out of range' ); |
| | 4370 | } |
| | 4371 | |
| | 4372 | if ( $page < 0 ) { |
| | 4373 | wp_send_json_error( 'page index cannot be negative' ); |
| | 4374 | } |
| | 4375 | |
| | 4376 | // Surprisingly, email addresses can contain mutli-byte characters now |
| | 4377 | $email_address = trim( mb_strtolower( $email_address ) ); |
| | 4378 | |
| | 4379 | if ( ! is_email( $email_address ) ) { |
| | 4380 | wp_send_json_error( 'a valid email address must be given' ); |
| | 4381 | } |
| | 4382 | |
| | 4383 | $exporter = $exporters[ $exporter_index ]; |
| | 4384 | if ( ! is_array( $exporter ) ) { |
| | 4385 | wp_send_json_error( "expected an array describing the exporter at index $exporter_index" ); |
| | 4386 | } |
| | 4387 | if ( ! array_key_exists( 'callback', $exporter ) ) { |
| | 4388 | wp_send_json_error( "exporter array at index $exporter_index does not include a callback" ); |
| | 4389 | } |
| | 4390 | if ( ! is_callable( $exporter['callback'] ) ) { |
| | 4391 | wp_send_json_error( "exporter callback at index $exporter_index is not a valid callback" ); |
| | 4392 | } |
| | 4393 | if ( ! array_key_exists( 'exporter_friendly_name', $exporter ) ) { |
| | 4394 | wp_send_json_error( "exporter array at index $exporter_index does not include a friendly name" ); |
| | 4395 | } |
| | 4396 | |
| | 4397 | $callback = $exporters[ $exporter_index ]['callback']; |
| | 4398 | $exporter_friendly_name = $exporters[ $exporter_index ]['exporter_friendly_name']; |
| | 4399 | |
| | 4400 | $response = call_user_func( $callback, $email_address, $page ); |
| | 4401 | if ( is_wp_error( $response ) ) { |
| | 4402 | wp_send_json_error( $response ); |
| | 4403 | } |
| | 4404 | |
| | 4405 | if ( ! is_array( $response ) ) { |
| | 4406 | wp_send_json_error( "expected response as an array from exporter: $exporter_friendly_name" ); |
| | 4407 | } |
| | 4408 | if ( ! array_key_exists( 'data', $response ) ) { |
| | 4409 | wp_send_json_error( "expected data in response array from exporter: $exporter_friendly_name" ); |
| | 4410 | } |
| | 4411 | if ( ! is_array( $response['data'] ) ) { |
| | 4412 | wp_send_json_error( "expected data array in response array from exporter: $exporter_friendly_name" ); |
| | 4413 | } |
| | 4414 | if ( ! array_key_exists( 'done', $response ) ) { |
| | 4415 | wp_send_json_error( "expected done (boolean) in response array from exporter: $exporter_friendly_name" ); |
| | 4416 | } |
| | 4417 | } else { |
| | 4418 | // No exporters, so we're done |
| | 4419 | $response = array( |
| | 4420 | 'data' => array(), |
| | 4421 | 'done' => true, |
| | 4422 | ); |
| | 4423 | } |
| | 4424 | |
| | 4425 | /** |
| | 4426 | * Filters a page of personal data exporter data. Used to build the export report. |
| | 4427 | * |
| | 4428 | * Allows the export response to be consumed by destinations in addition to Ajax. |
| | 4429 | * |
| | 4430 | * @since 4.9.5 |
| | 4431 | * |
| | 4432 | * @param array $response The personal data for the given exporter and page. |
| | 4433 | * @param int $exporter_index The index of the exporter that provided this data. |
| | 4434 | * @param string $email_address The email address associated with this personal data. |
| | 4435 | * @param int $page The zero-based page for this response. |
| | 4436 | */ |
| | 4437 | $response = apply_filters( 'wp_privacy_personal_data_export_page', $response, $exporter_index, $email_address, $page ); |
| | 4438 | if ( is_wp_error( $response ) ) { |
| | 4439 | wp_send_json_error( $response ); |
| | 4440 | } |
| | 4441 | |
| | 4442 | wp_send_json_success( $response ); |
| | 4443 | } |