wp_privacy_generate_personal_data_export_file( int $request_id )

Generate the personal data export file.


Description Description


Parameters Parameters

$request_id

(int) (Required) The export request ID.


Top ↑

Source Source

File: wp-admin/includes/file.php

function wp_privacy_generate_personal_data_export_file( $request_id ) {
	if ( ! class_exists( 'ZipArchive' ) ) {
		wp_send_json_error( __( 'Unable to generate export file. ZipArchive not available.' ) );
	}

	// Get the request data.
	$request = wp_get_user_request_data( $request_id );

	if ( ! $request || 'export_personal_data' !== $request->action_name ) {
		wp_send_json_error( __( 'Invalid request ID when generating export file.' ) );
	}

	$email_address = $request->email;

	if ( ! is_email( $email_address ) ) {
		wp_send_json_error( __( 'Invalid email address when generating export file.' ) );
	}

	// Create the exports folder if needed.
	$exports_dir = wp_privacy_exports_dir();
	$exports_url = wp_privacy_exports_url();

	if ( ! wp_mkdir_p( $exports_dir ) ) {
		wp_send_json_error( __( 'Unable to create export folder.' ) );
	}

	// Protect export folder from browsing.
	$index_pathname = $exports_dir . 'index.html';
	if ( ! file_exists( $index_pathname ) ) {
		$file = fopen( $index_pathname, 'w' );
		if ( false === $file ) {
			wp_send_json_error( __( 'Unable to protect export folder from browsing.' ) );
		}
		fwrite( $file, '<!-- Silence is golden. -->' );
		fclose( $file );
	}

	$stripped_email       = str_replace( '@', '-at-', $email_address );
	$stripped_email       = sanitize_title( $stripped_email ); // slugify the email address
	$obscura              = wp_generate_password( 32, false, false );
	$file_basename        = 'wp-personal-data-file-' . $stripped_email . '-' . $obscura;
	$html_report_filename = $file_basename . '.html';
	$html_report_pathname = wp_normalize_path( $exports_dir . $html_report_filename );
	$file                 = fopen( $html_report_pathname, 'w' );
	if ( false === $file ) {
		wp_send_json_error( __( 'Unable to open export file (HTML report) for writing.' ) );
	}

	$title = sprintf(
		/* translators: %s: user's e-mail address */
		__( 'Personal Data Export for %s' ),
		$email_address
	);

	// Open HTML.
	fwrite( $file, "<!DOCTYPE html>\n" );
	fwrite( $file, "<html>\n" );

	// Head.
	fwrite( $file, "<head>\n" );
	fwrite( $file, "<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />\n" );
	fwrite( $file, "<style type='text/css'>" );
	fwrite( $file, 'body { color: black; font-family: Arial, sans-serif; font-size: 11pt; margin: 15px auto; width: 860px; }' );
	fwrite( $file, 'table { background: #f0f0f0; border: 1px solid #ddd; margin-bottom: 20px; width: 100%; }' );
	fwrite( $file, 'th { padding: 5px; text-align: left; width: 20%; }' );
	fwrite( $file, 'td { padding: 5px; }' );
	fwrite( $file, 'tr:nth-child(odd) { background-color: #fafafa; }' );
	fwrite( $file, '</style>' );
	fwrite( $file, '<title>' );
	fwrite( $file, esc_html( $title ) );
	fwrite( $file, '</title>' );
	fwrite( $file, "</head>\n" );

	// Body.
	fwrite( $file, "<body>\n" );

	// Heading.
	fwrite( $file, '<h1>' . esc_html__( 'Personal Data Export' ) . '</h1>' );

	// And now, all the Groups.
	$groups = get_post_meta( $request_id, '_export_data_grouped', true );

	// First, build an "About" group on the fly for this report.
	$about_group = array(
		/* translators: Header for the About section in a personal data export. */
		'group_label' => _x( 'About', 'personal data group label' ),
		'items'       => array(
			'about-1' => array(
				array(
					'name'  => _x( 'Report generated for', 'email address' ),
					'value' => $email_address,
				),
				array(
					'name'  => _x( 'For site', 'website name' ),
					'value' => get_bloginfo( 'name' ),
				),
				array(
					'name'  => _x( 'At URL', 'website URL' ),
					'value' => get_bloginfo( 'url' ),
				),
				array(
					'name'  => _x( 'On', 'date/time' ),
					'value' => current_time( 'mysql' ),
				),
			),
		),
	);

	// Merge in the special about group.
	$groups = array_merge( array( 'about' => $about_group ), $groups );

	// Now, iterate over every group in $groups and have the formatter render it in HTML.
	foreach ( (array) $groups as $group_id => $group_data ) {
		fwrite( $file, wp_privacy_generate_personal_data_export_group_html( $group_data ) );
	}

	fwrite( $file, "</body>\n" );

	// Close HTML.
	fwrite( $file, "</html>\n" );
	fclose( $file );

	/*
	 * Now, generate the ZIP.
	 *
	 * If an archive has already been generated, then remove it and reuse the
	 * filename, to avoid breaking any URLs that may have been previously sent
	 * via email.
	 */
	$error            = false;
	$archive_url      = get_post_meta( $request_id, '_export_file_url', true );
	$archive_pathname = get_post_meta( $request_id, '_export_file_path', true );

	if ( empty( $archive_pathname ) || empty( $archive_url ) ) {
		$archive_filename = $file_basename . '.zip';
		$archive_pathname = $exports_dir . $archive_filename;
		$archive_url      = $exports_url . $archive_filename;

		update_post_meta( $request_id, '_export_file_url', $archive_url );
		update_post_meta( $request_id, '_export_file_path', wp_normalize_path( $archive_pathname ) );
	}

	if ( ! empty( $archive_pathname ) && file_exists( $archive_pathname ) ) {
		wp_delete_file( $archive_pathname );
	}

	$zip = new ZipArchive;
	if ( true === $zip->open( $archive_pathname, ZipArchive::CREATE ) ) {
		if ( ! $zip->addFile( $html_report_pathname, 'index.html' ) ) {
			$error = __( 'Unable to add data to export file.' );
		}

		$zip->close();

		if ( ! $error ) {
			/**
			 * Fires right after all personal data has been written to the export file.
			 *
			 * @since 4.9.6
			 *
			 * @param string $archive_pathname     The full path to the export file on the filesystem.
			 * @param string $archive_url          The URL of the archive file.
			 * @param string $html_report_pathname The full path to the personal data report on the filesystem.
			 * @param int    $request_id           The export request ID.
			 */
			do_action( 'wp_privacy_personal_data_export_file_created', $archive_pathname, $archive_url, $html_report_pathname, $request_id );
		}
	} else {
		$error = __( 'Unable to open export file (archive) for writing.' );
	}

	// And remove the HTML file.
	unlink( $html_report_pathname );

	if ( $error ) {
		wp_send_json_error( $error );
	}
}

Top ↑

Changelog Changelog

Changelog
Version Description
4.9.6 Introduced.


Top ↑

User Contributed Notes User Contributed Notes

You must log in before being able to contribute a note or feedback.