wp/wp-admin/includes/privacy-tools.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
    11  *
    11  *
    12  * @since 4.9.6
    12  * @since 4.9.6
    13  * @access private
    13  * @access private
    14  *
    14  *
    15  * @param int $request_id Request ID.
    15  * @param int $request_id Request ID.
    16  * @return bool|WP_Error Returns true/false based on the success of sending the email, or a WP_Error object.
    16  * @return true|WP_Error Returns true if sending the email was successful, or a WP_Error object.
    17  */
    17  */
    18 function _wp_privacy_resend_request( $request_id ) {
    18 function _wp_privacy_resend_request( $request_id ) {
    19 	$request_id = absint( $request_id );
    19 	$request_id = absint( $request_id );
    20 	$request    = get_post( $request_id );
    20 	$request    = get_post( $request_id );
    21 
    21 
    22 	if ( ! $request || 'user_request' !== $request->post_type ) {
    22 	if ( ! $request || 'user_request' !== $request->post_type ) {
    23 		return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
    23 		return new WP_Error( 'privacy_request_error', __( 'Invalid personal data request.' ) );
    24 	}
    24 	}
    25 
    25 
    26 	$result = wp_send_user_request( $request_id );
    26 	$result = wp_send_user_request( $request_id );
    27 
    27 
    28 	if ( is_wp_error( $result ) ) {
    28 	if ( is_wp_error( $result ) ) {
    29 		return $result;
    29 		return $result;
    30 	} elseif ( ! $result ) {
    30 	} elseif ( ! $result ) {
    31 		return new WP_Error( 'privacy_request_error', __( 'Unable to initiate confirmation request.' ) );
    31 		return new WP_Error( 'privacy_request_error', __( 'Unable to initiate confirmation for personal data request.' ) );
    32 	}
    32 	}
    33 
    33 
    34 	return true;
    34 	return true;
    35 }
    35 }
    36 
    36 
    47 	// Get the request.
    47 	// Get the request.
    48 	$request_id = absint( $request_id );
    48 	$request_id = absint( $request_id );
    49 	$request    = wp_get_user_request( $request_id );
    49 	$request    = wp_get_user_request( $request_id );
    50 
    50 
    51 	if ( ! $request ) {
    51 	if ( ! $request ) {
    52 		return new WP_Error( 'privacy_request_error', __( 'Invalid request.' ) );
    52 		return new WP_Error( 'privacy_request_error', __( 'Invalid personal data request.' ) );
    53 	}
    53 	}
    54 
    54 
    55 	update_post_meta( $request_id, '_wp_user_request_completed_timestamp', time() );
    55 	update_post_meta( $request_id, '_wp_user_request_completed_timestamp', time() );
    56 
    56 
    57 	$result = wp_update_post(
    57 	$result = wp_update_post(
   102 
   102 
   103 				if ( ! isset( $_POST['type_of_action'], $_POST['username_or_email_for_privacy_request'] ) ) {
   103 				if ( ! isset( $_POST['type_of_action'], $_POST['username_or_email_for_privacy_request'] ) ) {
   104 					add_settings_error(
   104 					add_settings_error(
   105 						'action_type',
   105 						'action_type',
   106 						'action_type',
   106 						'action_type',
   107 						__( 'Invalid action.' ),
   107 						__( 'Invalid personal data action.' ),
   108 						'error'
   108 						'error'
   109 					);
   109 					);
   110 				}
   110 				}
   111 				$action_type               = sanitize_text_field( wp_unslash( $_POST['type_of_action'] ) );
   111 				$action_type               = sanitize_text_field( wp_unslash( $_POST['type_of_action'] ) );
   112 				$username_or_email_address = sanitize_text_field( wp_unslash( $_POST['username_or_email_for_privacy_request'] ) );
   112 				$username_or_email_address = sanitize_text_field( wp_unslash( $_POST['username_or_email_for_privacy_request'] ) );
   113 				$email_address             = '';
   113 				$email_address             = '';
       
   114 				$status                    = 'pending';
       
   115 
       
   116 				if ( ! isset( $_POST['send_confirmation_email'] ) ) {
       
   117 					$status = 'confirmed';
       
   118 				}
   114 
   119 
   115 				if ( ! in_array( $action_type, _wp_privacy_action_request_types(), true ) ) {
   120 				if ( ! in_array( $action_type, _wp_privacy_action_request_types(), true ) ) {
   116 					add_settings_error(
   121 					add_settings_error(
   117 						'action_type',
   122 						'action_type',
   118 						'action_type',
   123 						'action_type',
   119 						__( 'Invalid action.' ),
   124 						__( 'Invalid personal data action.' ),
   120 						'error'
   125 						'error'
   121 					);
   126 					);
   122 				}
   127 				}
   123 
   128 
   124 				if ( ! is_email( $username_or_email_address ) ) {
   129 				if ( ! is_email( $username_or_email_address ) ) {
   139 
   144 
   140 				if ( empty( $email_address ) ) {
   145 				if ( empty( $email_address ) ) {
   141 					break;
   146 					break;
   142 				}
   147 				}
   143 
   148 
   144 				$request_id = wp_create_user_request( $email_address, $action_type );
   149 				$request_id = wp_create_user_request( $email_address, $action_type, array(), $status );
       
   150 				$message    = '';
   145 
   151 
   146 				if ( is_wp_error( $request_id ) ) {
   152 				if ( is_wp_error( $request_id ) ) {
       
   153 					$message = $request_id->get_error_message();
       
   154 				} elseif ( ! $request_id ) {
       
   155 					$message = __( 'Unable to initiate confirmation request.' );
       
   156 				}
       
   157 
       
   158 				if ( $message ) {
   147 					add_settings_error(
   159 					add_settings_error(
   148 						'username_or_email_for_privacy_request',
   160 						'username_or_email_for_privacy_request',
   149 						'username_or_email_for_privacy_request',
   161 						'username_or_email_for_privacy_request',
   150 						$request_id->get_error_message(),
   162 						$message,
   151 						'error'
       
   152 					);
       
   153 					break;
       
   154 				} elseif ( ! $request_id ) {
       
   155 					add_settings_error(
       
   156 						'username_or_email_for_privacy_request',
       
   157 						'username_or_email_for_privacy_request',
       
   158 						__( 'Unable to initiate confirmation request.' ),
       
   159 						'error'
   163 						'error'
   160 					);
   164 					);
   161 					break;
   165 					break;
   162 				}
   166 				}
   163 
   167 
   164 				wp_send_user_request( $request_id );
   168 				if ( 'pending' === $status ) {
   165 
   169 					wp_send_user_request( $request_id );
   166 				add_settings_error(
   170 
   167 					'username_or_email_for_privacy_request',
   171 					$message = __( 'Confirmation request initiated successfully.' );
   168 					'username_or_email_for_privacy_request',
   172 				} elseif ( 'confirmed' === $status ) {
   169 					__( 'Confirmation request initiated successfully.' ),
   173 					$message = __( 'Request added successfully.' );
   170 					'success'
   174 				}
   171 				);
   175 
   172 				break;
   176 				if ( $message ) {
       
   177 					add_settings_error(
       
   178 						'username_or_email_for_privacy_request',
       
   179 						'username_or_email_for_privacy_request',
       
   180 						$message,
       
   181 						'success'
       
   182 					);
       
   183 					break;
       
   184 				}
   173 		}
   185 		}
   174 	}
   186 	}
   175 }
   187 }
   176 
   188 
   177 /**
   189 /**
   277 		$group_html .= '</table>';
   289 		$group_html .= '</table>';
   278 	}
   290 	}
   279 
   291 
   280 	if ( $groups_count > 1 ) {
   292 	if ( $groups_count > 1 ) {
   281 		$group_html .= '<div class="return-to-top">';
   293 		$group_html .= '<div class="return-to-top">';
   282 		$group_html .= '<a href="#top"><span aria-hidden="true">&uarr; </span> ' . esc_html__( 'Return to top' ) . '</a>';
   294 		$group_html .= '<a href="#top"><span aria-hidden="true">&uarr; </span> ' . esc_html__( 'Go to top' ) . '</a>';
   283 		$group_html .= '</div>';
   295 		$group_html .= '</div>';
   284 	}
   296 	}
   285 
   297 
   286 	$group_html .= '</div>';
   298 	$group_html .= '</div>';
   287 
   299 
   295  *
   307  *
   296  * @param int $request_id The export request ID.
   308  * @param int $request_id The export request ID.
   297  */
   309  */
   298 function wp_privacy_generate_personal_data_export_file( $request_id ) {
   310 function wp_privacy_generate_personal_data_export_file( $request_id ) {
   299 	if ( ! class_exists( 'ZipArchive' ) ) {
   311 	if ( ! class_exists( 'ZipArchive' ) ) {
   300 		wp_send_json_error( __( 'Unable to generate export file. ZipArchive not available.' ) );
   312 		wp_send_json_error( __( 'Unable to generate personal data export file. ZipArchive not available.' ) );
   301 	}
   313 	}
   302 
   314 
   303 	// Get the request.
   315 	// Get the request.
   304 	$request = wp_get_user_request( $request_id );
   316 	$request = wp_get_user_request( $request_id );
   305 
   317 
   306 	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
   318 	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
   307 		wp_send_json_error( __( 'Invalid request ID when generating export file.' ) );
   319 		wp_send_json_error( __( 'Invalid request ID when generating personal data export file.' ) );
   308 	}
   320 	}
   309 
   321 
   310 	$email_address = $request->email;
   322 	$email_address = $request->email;
   311 
   323 
   312 	if ( ! is_email( $email_address ) ) {
   324 	if ( ! is_email( $email_address ) ) {
   313 		wp_send_json_error( __( 'Invalid email address when generating export file.' ) );
   325 		wp_send_json_error( __( 'Invalid email address when generating personal data export file.' ) );
   314 	}
   326 	}
   315 
   327 
   316 	// Create the exports folder if needed.
   328 	// Create the exports folder if needed.
   317 	$exports_dir = wp_privacy_exports_dir();
   329 	$exports_dir = wp_privacy_exports_dir();
   318 	$exports_url = wp_privacy_exports_url();
   330 	$exports_url = wp_privacy_exports_url();
   319 
   331 
   320 	if ( ! wp_mkdir_p( $exports_dir ) ) {
   332 	if ( ! wp_mkdir_p( $exports_dir ) ) {
   321 		wp_send_json_error( __( 'Unable to create export folder.' ) );
   333 		wp_send_json_error( __( 'Unable to create personal data export folder.' ) );
   322 	}
   334 	}
   323 
   335 
   324 	// Protect export folder from browsing.
   336 	// Protect export folder from browsing.
   325 	$index_pathname = $exports_dir . 'index.html';
   337 	$index_pathname = $exports_dir . 'index.php';
   326 	if ( ! file_exists( $index_pathname ) ) {
   338 	if ( ! file_exists( $index_pathname ) ) {
   327 		$file = fopen( $index_pathname, 'w' );
   339 		$file = fopen( $index_pathname, 'w' );
   328 		if ( false === $file ) {
   340 		if ( false === $file ) {
   329 			wp_send_json_error( __( 'Unable to protect export folder from browsing.' ) );
   341 			wp_send_json_error( __( 'Unable to protect personal data export folder from browsing.' ) );
   330 		}
   342 		}
   331 		fwrite( $file, '<!-- Silence is golden. -->' );
   343 		fwrite( $file, "<?php\n// Silence is golden.\n" );
   332 		fclose( $file );
   344 		fclose( $file );
   333 	}
   345 	}
   334 
   346 
   335 	$obscura              = wp_generate_password( 32, false, false );
   347 	$obscura              = wp_generate_password( 32, false, false );
   336 	$file_basename        = 'wp-personal-data-file-' . $obscura;
   348 	$file_basename        = 'wp-personal-data-file-' . $obscura;
   347 	$title = sprintf(
   359 	$title = sprintf(
   348 		/* translators: %s: User's email address. */
   360 		/* translators: %s: User's email address. */
   349 		__( 'Personal Data Export for %s' ),
   361 		__( 'Personal Data Export for %s' ),
   350 		$email_address
   362 		$email_address
   351 	);
   363 	);
   352 
       
   353 	// And now, all the Groups.
       
   354 	$groups = get_post_meta( $request_id, '_export_data_grouped', true );
       
   355 
   364 
   356 	// First, build an "About" group on the fly for this report.
   365 	// First, build an "About" group on the fly for this report.
   357 	$about_group = array(
   366 	$about_group = array(
   358 		/* translators: Header for the About section in a personal data export. */
   367 		/* translators: Header for the About section in a personal data export. */
   359 		'group_label'       => _x( 'About', 'personal data group label' ),
   368 		'group_label'       => _x( 'About', 'personal data group label' ),
   379 				),
   388 				),
   380 			),
   389 			),
   381 		),
   390 		),
   382 	);
   391 	);
   383 
   392 
   384 	// Merge in the special about group.
   393 	// And now, all the Groups.
   385 	$groups = array_merge( array( 'about' => $about_group ), $groups );
   394 	$groups = get_post_meta( $request_id, '_export_data_grouped', true );
   386 
   395 	if ( is_array( $groups ) ) {
   387 	$groups_count = count( $groups );
   396 		// Merge in the special "About" group.
       
   397 		$groups       = array_merge( array( 'about' => $about_group ), $groups );
       
   398 		$groups_count = count( $groups );
       
   399 	} else {
       
   400 		if ( false !== $groups ) {
       
   401 			_doing_it_wrong(
       
   402 				__FUNCTION__,
       
   403 				/* translators: %s: Post meta key. */
       
   404 				sprintf( __( 'The %s post meta must be an array.' ), '<code>_export_data_grouped</code>' ),
       
   405 				'5.8.0'
       
   406 			);
       
   407 		}
       
   408 
       
   409 		$groups       = null;
       
   410 		$groups_count = 0;
       
   411 	}
   388 
   412 
   389 	// Convert the groups to JSON format.
   413 	// Convert the groups to JSON format.
   390 	$groups_json = wp_json_encode( $groups );
   414 	$groups_json = wp_json_encode( $groups );
   391 
   415 
       
   416 	if ( false === $groups_json ) {
       
   417 		$error_message = sprintf(
       
   418 			/* translators: %s: Error message. */
       
   419 			__( 'Unable to encode the personal data for export. Error: %s' ),
       
   420 			json_last_error_msg()
       
   421 		);
       
   422 
       
   423 		wp_send_json_error( $error_message );
       
   424 	}
       
   425 
   392 	/*
   426 	/*
   393 	 * Handle the JSON export.
   427 	 * Handle the JSON export.
   394 	 */
   428 	 */
   395 	$file = fopen( $json_report_pathname, 'w' );
   429 	$file = fopen( $json_report_pathname, 'w' );
   396 
   430 
   397 	if ( false === $file ) {
   431 	if ( false === $file ) {
   398 		wp_send_json_error( __( 'Unable to open export file (JSON report) for writing.' ) );
   432 		wp_send_json_error( __( 'Unable to open personal data export file (JSON report) for writing.' ) );
   399 	}
   433 	}
   400 
   434 
   401 	fwrite( $file, '{' );
   435 	fwrite( $file, '{' );
   402 	fwrite( $file, '"' . $title . '":' );
   436 	fwrite( $file, '"' . $title . '":' );
   403 	fwrite( $file, $groups_json );
   437 	fwrite( $file, $groups_json );
   408 	 * Handle the HTML export.
   442 	 * Handle the HTML export.
   409 	 */
   443 	 */
   410 	$file = fopen( $html_report_pathname, 'w' );
   444 	$file = fopen( $html_report_pathname, 'w' );
   411 
   445 
   412 	if ( false === $file ) {
   446 	if ( false === $file ) {
   413 		wp_send_json_error( __( 'Unable to open export file (HTML report) for writing.' ) );
   447 		wp_send_json_error( __( 'Unable to open personal data export (HTML report) for writing.' ) );
   414 	}
   448 	}
   415 
   449 
   416 	fwrite( $file, "<!DOCTYPE html>\n" );
   450 	fwrite( $file, "<!DOCTYPE html>\n" );
   417 	fwrite( $file, "<html>\n" );
   451 	fwrite( $file, "<html>\n" );
   418 	fwrite( $file, "<head>\n" );
   452 	fwrite( $file, "<head>\n" );
   502 	}
   536 	}
   503 
   537 
   504 	$zip = new ZipArchive;
   538 	$zip = new ZipArchive;
   505 	if ( true === $zip->open( $archive_pathname, ZipArchive::CREATE ) ) {
   539 	if ( true === $zip->open( $archive_pathname, ZipArchive::CREATE ) ) {
   506 		if ( ! $zip->addFile( $json_report_pathname, 'export.json' ) ) {
   540 		if ( ! $zip->addFile( $json_report_pathname, 'export.json' ) ) {
   507 			$error = __( 'Unable to add data to JSON file.' );
   541 			$error = __( 'Unable to archive the personal data export file (JSON format).' );
   508 		}
   542 		}
   509 
   543 
   510 		if ( ! $zip->addFile( $html_report_pathname, 'index.html' ) ) {
   544 		if ( ! $zip->addFile( $html_report_pathname, 'index.html' ) ) {
   511 			$error = __( 'Unable to add data to HTML file.' );
   545 			$error = __( 'Unable to archive the personal data export file (HTML format).' );
   512 		}
   546 		}
   513 
   547 
   514 		$zip->close();
   548 		$zip->close();
   515 
   549 
   516 		if ( ! $error ) {
   550 		if ( ! $error ) {
   527 			 * @param string $json_report_pathname The full path to the JSON personal data report on the filesystem.
   561 			 * @param string $json_report_pathname The full path to the JSON personal data report on the filesystem.
   528 			 */
   562 			 */
   529 			do_action( 'wp_privacy_personal_data_export_file_created', $archive_pathname, $archive_url, $html_report_pathname, $request_id, $json_report_pathname );
   563 			do_action( 'wp_privacy_personal_data_export_file_created', $archive_pathname, $archive_url, $html_report_pathname, $request_id, $json_report_pathname );
   530 		}
   564 		}
   531 	} else {
   565 	} else {
   532 		$error = __( 'Unable to open export file (archive) for writing.' );
   566 		$error = __( 'Unable to open personal data export file (archive) for writing.' );
   533 	}
   567 	}
   534 
   568 
   535 	// Remove the JSON file.
   569 	// Remove the JSON file.
   536 	unlink( $json_report_pathname );
   570 	unlink( $json_report_pathname );
   537 
   571 
   626 	 */
   660 	 */
   627 	$subject = apply_filters( 'wp_privacy_personal_data_email_subject', $subject, $site_name, $email_data );
   661 	$subject = apply_filters( 'wp_privacy_personal_data_email_subject', $subject, $site_name, $email_data );
   628 
   662 
   629 	/* translators: Do not translate EXPIRATION, LINK, SITENAME, SITEURL: those are placeholders. */
   663 	/* translators: Do not translate EXPIRATION, LINK, SITENAME, SITEURL: those are placeholders. */
   630 	$email_text = __(
   664 	$email_text = __(
   631 		'Howdy,
   665 // phpcs:ignore Generic.WhiteSpace.ScopeIndent.Incorrect, PEAR.Functions.FunctionCallSignature.Indent
       
   666 'Howdy,
   632 
   667 
   633 Your request for an export of personal data has been completed. You may
   668 Your request for an export of personal data has been completed. You may
   634 download your personal data by clicking on the link below. For privacy
   669 download your personal data by clicking on the link below. For privacy
   635 and security, we will automatically delete the file on ###EXPIRATION###,
   670 and security, we will automatically delete the file on ###EXPIRATION###,
   636 so please download it before then.
   671 so please download it before then.
   756 
   791 
   757 	// Get the request.
   792 	// Get the request.
   758 	$request = wp_get_user_request( $request_id );
   793 	$request = wp_get_user_request( $request_id );
   759 
   794 
   760 	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
   795 	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
   761 		wp_send_json_error( __( 'Invalid request ID when merging exporter data.' ) );
   796 		wp_send_json_error( __( 'Invalid request ID when merging personal data to export.' ) );
   762 	}
   797 	}
   763 
   798 
   764 	$export_data = array();
   799 	$export_data = array();
   765 
   800 
   766 	// First exporter, first page? Reset the report data accumulation array.
   801 	// First exporter, first page? Reset the report data accumulation array.
   767 	if ( 1 === $exporter_index && 1 === $page ) {
   802 	if ( 1 === $exporter_index && 1 === $page ) {
   768 		update_post_meta( $request_id, '_export_data_raw', $export_data );
   803 		update_post_meta( $request_id, '_export_data_raw', $export_data );
   769 	} else {
   804 	} else {
   770 		$export_data = get_post_meta( $request_id, '_export_data_raw', true );
   805 		$accumulated_data = get_post_meta( $request_id, '_export_data_raw', true );
       
   806 
       
   807 		if ( $accumulated_data ) {
       
   808 			$export_data = $accumulated_data;
       
   809 		}
   771 	}
   810 	}
   772 
   811 
   773 	// Now, merge the data from the exporter response into the data we have accumulated already.
   812 	// Now, merge the data from the exporter response into the data we have accumulated already.
   774 	$export_data = array_merge( $export_data, $response['data'] );
   813 	$export_data = array_merge( $export_data, $response['data'] );
   775 	update_post_meta( $request_id, '_export_data_raw', $export_data );
   814 	update_post_meta( $request_id, '_export_data_raw', $export_data );
   903 
   942 
   904 	// Get the request.
   943 	// Get the request.
   905 	$request = wp_get_user_request( $request_id );
   944 	$request = wp_get_user_request( $request_id );
   906 
   945 
   907 	if ( ! $request || 'remove_personal_data' !== $request->action_name ) {
   946 	if ( ! $request || 'remove_personal_data' !== $request->action_name ) {
   908 		wp_send_json_error( __( 'Invalid request ID when processing eraser data.' ) );
   947 		wp_send_json_error( __( 'Invalid request ID when processing personal data to erase.' ) );
   909 	}
   948 	}
   910 
   949 
   911 	/** This filter is documented in wp-admin/includes/ajax-actions.php */
   950 	/** This filter is documented in wp-admin/includes/ajax-actions.php */
   912 	$erasers        = apply_filters( 'wp_privacy_personal_data_erasers', array() );
   951 	$erasers        = apply_filters( 'wp_privacy_personal_data_erasers', array() );
   913 	$is_last_eraser = count( $erasers ) === $eraser_index;
   952 	$is_last_eraser = count( $erasers ) === $eraser_index;