<?php

namespace WP_CLI\Hammer\Sanitizers\Options;
use WP_CLI;

/**
 * Sanitize sensitive data from the `wp_options` table.
 *
 * Note that some rows -- like `nonce_key` -- will be automatically regenerated by Core during each execution.
 * That's ok, though, because they'll get new values each time, which don't match the values in the production
 * database.
 */
function sanitizer() {
	global $wpdb;

	$safe_options = get_safe_option_names();
	$exact_names  = "'" . implode( "','", $safe_options['exact_names'] ) . "'";

	// Skip transients so that they can be deleted with `delete_transient()` instead of `delete_option()`.
	$like_clauses = array( "option_name NOT LIKE '%transient%' " );

	foreach ( $safe_options['partial_names'] as $partial_names ) {
		$like_clauses[] = "option_name NOT LIKE '$partial_names' ";
	}

	if ( ! empty( $like_clauses ) ) {
		$like_clauses = ' AND ' . implode( ' AND ', $like_clauses );
	}

	/*
	 * This is intentionally not escaped/prepared, to allow the use of wildcards in the input.
	 * It is still safe, though, since the input only comes from trusted sources.
	 */
	$options_to_delete = $wpdb->get_results( "
		SELECT option_name
		FROM `{$wpdb->prefix}options`
		WHERE
			`option_name` NOT IN ( $exact_names )
			$like_clauses
	" );
	$options_to_delete = wp_list_pluck( $options_to_delete, 'option_name' );

	foreach ( $options_to_delete as $option ) {
		WP_CLI::line( "Deleting option `{$option}`." );
		delete_option( $option );
	}

	WP_CLI::line( "Deleting all transients." );
	WP_CLI::runcommand( 'transient delete --all' );
}

/**
 * Get a list of options that are safe to remain in local development environments.
 *
 * This uses a safelist instead of a blocklist, because we can't predict what plugins -- or future
 * versions of Core -- will store in the `wp_options` table. A blocklist would inevitably result
 * in sensitive data being left in the database.
 *
 * @return array
 */
function get_safe_option_names() {
	$safelist = array(
		'exact_names' => array(
			'active_plugins', 'active_sitewide_plugins', 'admin_email', 'allowedthemes', 'avatar_default', 'avatar_rating',
			'blacklist_keys', 'blog_charset', 'blog_public', 'blogdescription', 'blogname', 'can_compress_scripts',
			'category_base', 'category_children', 'close_comments_days_old', 'close_comments_for_old_posts',
			'comment_max_links', 'comment_moderation', 'comment_order', 'comment_registration', 'comment_whitelist',
			'comments_notify', 'comments_per_page', 'cron', 'current_theme', 'dashboard_widget_options', 'date_format',
			'db_version', 'default_category', 'default_comment_status', 'default_comments_page', 'default_email_category',
			'default_link_category', 'default_ping_status', 'default_pingback_flag', 'default_post_format', 'default_role',
			'embed_size_h', 'embed_size_w', 'finished_splitting_shared_terms', 'fresh_site', 'gmt_offset', 'hack_file', 'home',
			'html_type', 'image_default_align', 'image_default_link_type', 'image_default_size', 'initial_db_version',
			'large_size_h', 'large_size_w', 'link_manager_enabled', 'links_updated_date_format', 'medium_large_size_h',
			'medium_large_size_w', 'medium_size_h', 'medium_size_w', 'moderation_keys', 'moderation_notify', 'nav_menu_options',
			'new_admin_email', 'page_comments', 'page_for_posts', 'page_on_front', 'permalink_structure', 'ping_sites',
			'post_count', 'posts_per_page', 'posts_per_rss', 'recently_activated', 'recently_edited', 'require_name_email',
			'rewrite_rules', 'rss_use_excerpt', 'show_avatars', 'show_comments_cookies_opt_in', 'show_on_front',
			'sidebars_widgets', 'site_icon', 'siteurl', 'start_of_week', 'sticky_posts', 'stylesheet', 'stylesheet_root',
			'tag_base', 'template', 'template_root', 'theme_switched', 'thread_comments', 'thread_comments_depth',
			'thumbnail_crop', 'thumbnail_size_h', 'thumbnail_size_w', 'time_format', 'timezone_string', 'uninstall_plugins',
			'upload_path', 'upload_url_path', 'uploads_use_yearmonth_folders', 'use_balanceTags', 'use_smilies', 'use_trackback',
			'users_can_register', 'wp_page_for_privacy_policy', 'wp_user_roles', 'WPLANG',
		),

		'partial_names' => array( 'widget_%', 'theme_mods_%' ),
	);

	/**
	 * Filter the list of safe option names.
	 *
	 * Entries in the `exact_names` array should be the exact option name. Entries in the `partial_names` array
	 * should contain partial option names and MySQL wildcards (i.e., `_` and `%` ), just like you would if you
	 * were adding `LIKE` clause to a SQL statement.
	 *
	 * @param array $safelist The list of safe names.
	 */
	return apply_filters( 'wp_hammer_safe_option_names', $safelist );
}

add_action( 'wp_hammer_run_sanitize_options', __NAMESPACE__ . '\sanitizer' );
