Skip to content

Conversation

@hellofromtonya
Copy link
Contributor

@hellofromtonya hellofromtonya commented Nov 23, 2020

Trac ticket: https://core.trac.wordpress.org/ticket/51423

Function: wp_privacy_generate_personal_data_export_file()

Problems

When/if the '_export_data_grouped' post meta exists but is not an array, a PHP Warning (< 8)/Error (8+) is thrown for array_merge argument 2 type mismatch.

See in action https://3v4l.org/9gLZ8

PHP Warning/Error

  • PHP 8+:
PHP Fatal error:  Uncaught TypeError: array_merge(): Argument #2 must be of type array, string given in .../public/wp-admin/includes/privacy-tools.php:397
  • PHP 5.6 to 5.7.x:
PHP Warning:  array_merge(): Expected parameter 2 to be an array, string given in .../public/wp-admin/includes/privacy-tools.php on line 397
  • and PHP 7.2 to 7.4.x:
PHP Warning:  count(): Parameter must be an array or an object that implements Countable in .../public/wp-admin/includes/privacy-tools.php on line 399

Current Behavior

Case: '_export_data_grouped' post meta is not an array

$groups = array_merge( array( 'about' => $about_group ), $groups );
// $groups = null

$groups_count = count( $groups );
// $groups_count = 0

$groups_json = wp_json_encode( $groups );
// $groups_json = 'null'

With these values, the following happens:

  • The export file is created
  • But the groups TOC or groups content

The resultant zip file looks like this:

  • export.json file:
{"Personal Data Export for [email protected]":null}
  • index.html file:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
<style type='text/css'>body { color: black; font-family: Arial, sans-serif; font-size: 11pt; margin: 15px auto; width: 860px; }table { background: #f0f0f0; border: 1px solid #ddd; margin-bottom: 20px; width: 100%; }th { padding: 5px; text-align: left; width: 20%; }td { padding: 5px; }tr:nth-child(odd) { background-color: #fafafa; }.return-to-top { text-align: right; }</style><title>Personal Data Export for [email protected]</title></head>
<body>
<h1 id="top">Personal Data Export</h1></body>
</html>

Fix

Check if the post meta is an array.

  • If yes, continue with the array_merge and count
  • Else:
    • invoke _doing_it_wrong (to alert the developer where the problem exists while eliminating the warning/error)
    • set the variables to retain the current behavior and file generations

See it in action https://3v4l.org/P3VAM.

See

This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

…$arr1 of function array_merge expects array, array|bool given."
@hellofromtonya hellofromtonya force-pushed the fix/php8.0/51423-wp-admin/includes/privacy-tools.php branch from b16f03b to 00e73a0 Compare November 29, 2020 17:03
@hellofromtonya hellofromtonya force-pushed the fix/php8.0/51423-wp-admin/includes/privacy-tools.php branch from fae0f61 to 5baeff0 Compare March 18, 2021 21:09
@hellofromtonya
Copy link
Contributor Author

Testing BEFORE fixes

PHP 7.3.5

Results:

  • Export file downloaded ✅
  • 2 PHP Warnings

Screen Shot 2021-03-18 at 4 46 23 PM

Error log:

[18-Mar-2021 21:46:02 UTC] PHP Warning:  array_merge(): Expected parameter 2 to be an array, string given in .../public/wp-admin/includes/privacy-tools.php on line 397
[18-Mar-2021 21:46:02 UTC] PHP Stack trace:
[18-Mar-2021 21:46:02 UTC] PHP   1. {main}() .../public/wp-admin/admin-ajax.php:0
[18-Mar-2021 21:46:02 UTC] PHP   2. do_action() .../public/wp-admin/admin-ajax.php:187
[18-Mar-2021 21:46:02 UTC] PHP   3. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[18-Mar-2021 21:46:02 UTC] PHP   4. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[18-Mar-2021 21:46:02 UTC] PHP   5. wp_ajax_wp_privacy_export_personal_data() .../public/wp-includes/class-wp-hook.php:292
[18-Mar-2021 21:46:02 UTC] PHP   6. apply_filters() .../public/wp-admin/includes/ajax-actions.php:4911
[18-Mar-2021 21:46:02 UTC] PHP   7. WP_Hook->apply_filters() .../public/wp-includes/plugin.php:212
[18-Mar-2021 21:46:02 UTC] PHP   8. wp_privacy_process_personal_data_export_page() .../public/wp-includes/class-wp-hook.php:292
[18-Mar-2021 21:46:02 UTC] PHP   9. do_action() .../public/wp-admin/includes/privacy-tools.php:844
[18-Mar-2021 21:46:02 UTC] PHP  10. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[18-Mar-2021 21:46:02 UTC] PHP  11. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[18-Mar-2021 21:46:02 UTC] PHP  12. wp_privacy_generate_personal_data_export_file() .../public/wp-includes/class-wp-hook.php:292
[18-Mar-2021 21:46:02 UTC] PHP  13. array_merge() .../public/wp-admin/includes/privacy-tools.php:397
[18-Mar-2021 21:46:02 UTC] PHP Warning:  count(): Parameter must be an array or an object that implements Countable in .../public/wp-admin/includes/privacy-tools.php on line 399
[18-Mar-2021 21:46:02 UTC] PHP Stack trace:
[18-Mar-2021 21:46:02 UTC] PHP   1. {main}() .../public/wp-admin/admin-ajax.php:0
[18-Mar-2021 21:46:02 UTC] PHP   2. do_action() .../public/wp-admin/admin-ajax.php:187
[18-Mar-2021 21:46:02 UTC] PHP   3. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[18-Mar-2021 21:46:02 UTC] PHP   4. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[18-Mar-2021 21:46:02 UTC] PHP   5. wp_ajax_wp_privacy_export_personal_data() .../public/wp-includes/class-wp-hook.php:292
[18-Mar-2021 21:46:02 UTC] PHP   6. apply_filters() .../public/wp-admin/includes/ajax-actions.php:4911
[18-Mar-2021 21:46:02 UTC] PHP   7. WP_Hook->apply_filters() .../public/wp-includes/plugin.php:212
[18-Mar-2021 21:46:02 UTC] PHP   8. wp_privacy_process_personal_data_export_page() .../public/wp-includes/class-wp-hook.php:292
[18-Mar-2021 21:46:02 UTC] PHP   9. do_action() .../public/wp-admin/includes/privacy-tools.php:844
[18-Mar-2021 21:46:02 UTC] PHP  10. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[18-Mar-2021 21:46:02 UTC] PHP  11. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[18-Mar-2021 21:46:02 UTC] PHP  12. wp_privacy_generate_personal_data_export_file() .../public/wp-includes/class-wp-hook.php:292

PHP 8.0

Results:

  • Fatal error
  • Export failed

Screen Shot 2021-03-18 at 4 44 47 PM

Error log:

[18-Mar-2021 21:37:33 UTC] PHP Fatal error:  Uncaught TypeError: array_merge(): Argument #2 must be of type array, string given in .../public/wp-admin/includes/privacy-tools.php:397
Stack trace:
#0 .../public/wp-admin/includes/privacy-tools.php(397): array_merge(Array, 'invalid type')
#1 .../app/public/wp-includes/class-wp-hook.php(292): wp_privacy_generate_personal_data_export_file(21)
#2 .../public/wp-includes/class-wp-hook.php(316): WP_Hook->apply_filters(NULL, Array)
#3 .../public/wp-includes/plugin.php(484): WP_Hook->do_action(Array)
#4 .../public/wp-admin/includes/privacy-tools.php(844): do_action('wp_privacy_pers...', 21)
#5 .../public/wp-includes/class-wp-hook.php(292): wp_privacy_process_personal_data_export_page(Array, 3, '[email protected]...', 1, 21, false, 'wordpress-media')
#6 .../public/wp-includes/plugin.php(212): WP_Hook->apply_filters(Array, Array)
#7 .../public/wp-admin/includes/ajax-actions.php(4911): apply_filters('wp_privacy_pers...', Array, 3, '[email protected]...', 1, 21, false, 'wordpress-media')
#8 .../public/wp-includes/class-wp-hook.php(292): wp_ajax_wp_privacy_export_personal_data('')
#9 .../public/wp-includes/class-wp-hook.php(316): WP_Hook->apply_filters('', Array)
#10 .../public/wp-includes/plugin.php(484): WP_Hook->do_action(Array)
#11 .../public/wp-admin/admin-ajax.php(187): do_action('wp_ajax_wp-priv...')
#12 {main}
  thrown in .../public/wp-admin/includes/privacy-tools.php on line 397

How Tested

Used this code in a must-use to change the meta value to a string value:

<?php

add_action( 'wp_privacy_personal_data_export_file', function( $request_id ) {
	update_post_meta( $request_id, '_export_data_grouped', 'invalid type' );
} , 5 );

Tests to reproduce:

  1. Create a wp-content/mu-plugins/51423.php and add code above.
  2. Add a test user, e.g. username tester2 and password [email protected].
  3. Go to Tools > Export Personal Data.
  4. Create a request for the user.
  5. Attempt to download the export file.

hellofromtonya added 2 commits March 19, 2021 13:06
Why?

Type casting a non-array value creates an invalid
groups structure. In < PHP 8, the invalid structure is ignored.
In PHP 8, it causes a fatal error:

TypeError: Cannot access offset of type string on string

This commit fixes this problem. When a value exists in the
post meta but it's not an array, it uses the about group only,
skipping the type cast and array merge.
The timestamp in the about group can be off by 1 second
between the code and test. Why? It depends upon the
system clock of when each current_time() is called.

To avoid failed tests when this happens, this commit
extracts and uses the timestamp from the report's JSON.
@hellofromtonya
Copy link
Contributor Author

hellofromtonya commented Mar 22, 2021

Testing AFTER fixes

PHP 7.3.5

Results:

  • Export file downloaded ✅
  • No PHP Warnings
  • 1 PHP Notice

Screen Shot 2021-03-22 at 2 18 05 PM

Error log:

[22-Mar-2021 19:16:05 UTC] PHP Notice:  wp_privacy_generate_personal_data_export_file was called <strong>incorrectly</strong>. The <code>'_export_data_grouped'</code> post meta must be an array. Please see <a href="https://wordpress.org/support/article/debugging-in-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 5.8.0.) in .../public/wp-includes/functions.php on line 5313
[22-Mar-2021 19:16:05 UTC] PHP Stack trace:
[22-Mar-2021 19:16:05 UTC] PHP   1. {main}() .../public/wp-admin/admin-ajax.php:0
[22-Mar-2021 19:16:05 UTC] PHP   2. do_action() .../public/wp-admin/admin-ajax.php:187
[22-Mar-2021 19:16:05 UTC] PHP   3. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[22-Mar-2021 19:16:05 UTC] PHP   4. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[22-Mar-2021 19:16:05 UTC] PHP   5. wp_ajax_wp_privacy_export_personal_data() /Users/hellofromtonya/Local/wpcore/app/public/wp-includes/class-wp-hook.php:292
[22-Mar-2021 19:16:05 UTC] PHP   6. apply_filters() .../public/wp-admin/includes/ajax-actions.php:4911
[22-Mar-2021 19:16:05 UTC] PHP   7. WP_Hook->apply_filters() .../public/wp-includes/plugin.php:212
[22-Mar-2021 19:16:05 UTC] PHP   8. wp_privacy_process_personal_data_export_page() .../public/wp-includes/class-wp-hook.php:292
[22-Mar-2021 19:16:05 UTC] PHP   9. do_action() .../public/wp-admin/includes/privacy-tools.php:862
[22-Mar-2021 19:16:05 UTC] PHP  10. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[22-Mar-2021 19:16:05 UTC] PHP  11. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[22-Mar-2021 19:16:05 UTC] PHP  12. wp_privacy_generate_personal_data_export_file() .../public/wp-includes/class-wp-hook.php:292
[22-Mar-2021 19:16:05 UTC] PHP  13. _doing_it_wrong() .../public/wp-admin/includes/privacy-tools.php:411
[22-Mar-2021 19:16:05 UTC] PHP  14. trigger_error() .../public/wp-includes/functions.php:5313

In the downloaded zip file:

  • export.json:
{"Personal Data Export for [email protected]":null}
  • index.html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
<style type='text/css'>body { color: black; font-family: Arial, sans-serif; font-size: 11pt; margin: 15px auto; width: 860px; }table { background: #f0f0f0; border: 1px solid #ddd; margin-bottom: 20px; width: 100%; }th { padding: 5px; text-align: left; width: 20%; }td { padding: 5px; }tr:nth-child(odd) { background-color: #fafafa; }.return-to-top { text-align: right; }</style><title>Personal Data Export for [email protected]</title></head>
<body>
<h1 id="top">Personal Data Export</h1></body>
</html>

PHP 8.0

Results:

  • Export file downloaded ✅
  • No PHP Fatal error
  • 1 PHP Notice

Screen Shot 2021-03-22 at 2 23 30 PM

Error log:

[22-Mar-2021 19:23:22 UTC] PHP Notice:  wp_privacy_generate_personal_data_export_file was called <strong>incorrectly</strong>. The <code>'_export_data_grouped'</code> post meta must be an array. Please see <a href="https://wordpress.org/support/article/debugging-in-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 5.8.0.) in .../public/wp-includes/functions.php on line 5313
[22-Mar-2021 19:23:22 UTC] PHP Stack trace:
[22-Mar-2021 19:23:22 UTC] PHP   1. {main}().../public/wp-admin/admin-ajax.php:0
[22-Mar-2021 19:23:22 UTC] PHP   2. do_action() .../public/wp-admin/admin-ajax.php:187
[22-Mar-2021 19:23:22 UTC] PHP   3. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[22-Mar-2021 19:23:22 UTC] PHP   4. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[22-Mar-2021 19:23:22 UTC] PHP   5. wp_ajax_wp_privacy_export_personal_data() .../public/wp-includes/class-wp-hook.php:292
[22-Mar-2021 19:23:22 UTC] PHP   6. apply_filters() .../public/wp-admin/includes/ajax-actions.php:4911
[22-Mar-2021 19:23:22 UTC] PHP   7. WP_Hook->apply_filters() .../public/wp-includes/plugin.php:212
[22-Mar-2021 19:23:22 UTC] PHP   8. wp_privacy_process_personal_data_export_page() .../public/wp-includes/class-wp-hook.php:292
[22-Mar-2021 19:23:22 UTC] PHP   9. do_action() .../public/wp-admin/includes/privacy-tools.php:862
[22-Mar-2021 19:23:22 UTC] PHP  10. WP_Hook->do_action() .../public/wp-includes/plugin.php:484
[22-Mar-2021 19:23:22 UTC] PHP  11. WP_Hook->apply_filters() .../public/wp-includes/class-wp-hook.php:316
[22-Mar-2021 19:23:22 UTC] PHP  12. wp_privacy_generate_personal_data_export_file() .../public/wp-includes/class-wp-hook.php:292
[22-Mar-2021 19:23:22 UTC] PHP  13. _doing_it_wrong() .../public/wp-admin/includes/privacy-tools.php:411
[22-Mar-2021 19:23:22 UTC] PHP  14. trigger_error() .../public/wp-includes/functions.php:5313

In the downloaded zip file:

  • export.json:
{"Personal Data Export for [email protected]":null}
  • index.html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
<style type='text/css'>body { color: black; font-family: Arial, sans-serif; font-size: 11pt; margin: 15px auto; width: 860px; }table { background: #f0f0f0; border: 1px solid #ddd; margin-bottom: 20px; width: 100%; }th { padding: 5px; text-align: left; width: 20%; }td { padding: 5px; }tr:nth-child(odd) { background-color: #fafafa; }.return-to-top { text-align: right; }</style><title>Personal Data Export for [email protected]</title></head>
<body>
<h1 id="top">Personal Data Export</h1></body>
</html>

@hellofromtonya
Copy link
Contributor Author

@jrfnl This PR is ready for a final review. Since we last did a pair programming session on it, I discovered our solution caused a breaking change. Why? When the post meta does not exist or it's value is not an array, no about group content is generated in the downloaded zip file.

Why? See the updated notes in the description of this PR which includes 3v4l links to show it in action.

What's different since you and I last worked on it?

  • See here 2483915
  • Updated the tests
  • And consolidated a couple of individual ones, pulling the test data into the data provider, i.e. for consistency

Copy link
Member

@jrfnl jrfnl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - discussed multiple times and does what we concluded should be done.
Tests also had significant improvements, so all together a great step forward.

@hellofromtonya
Copy link
Contributor Author

Merged via changeset https://core.trac.wordpress.org/changeset/50613.

@hellofromtonya hellofromtonya deleted the fix/php8.0/51423-wp-admin/includes/privacy-tools.php branch April 6, 2021 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants