Skip to content

Commit

Permalink
Upgrades mime type options from regex to keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
sybrew committed Apr 3, 2024
1 parent e4b2523 commit ef1b719
Show file tree
Hide file tree
Showing 11 changed files with 391 additions and 220 deletions.
13 changes: 8 additions & 5 deletions inc/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@

\defined( 'Pro_Mime_Types\VERSION' ) or die;

use function \Pro_Mime_Types\is_network_mode;
use const \Pro_Mime_Types\{
ALLOWED_MIME_TYPES_OPTIONS_NAME,
PLUGIN_DIR_PATH,
};

use const \Pro_Mime_Types\ALLOWED_MIME_TYPES_OPTIONS_NAME;
use function \Pro_Mime_Types\is_network_mode;

/**
* Pro Mime Types plugin
Expand Down Expand Up @@ -178,7 +181,7 @@ function () {
* @access private
*/
function _display_admin_page() {
include \Pro_Mime_Types\PLUGIN_DIR_PATH . 'views/admin.php';
include PLUGIN_DIR_PATH . 'views/admin.php';
}

/**
Expand All @@ -193,10 +196,10 @@ function _display_admin_page() {
function _output_tab_content( $current_tab ) {
switch ( $current_tab ) {
case '':
include \Pro_Mime_Types\PLUGIN_DIR_PATH . 'views/tab-options.php';
include PLUGIN_DIR_PATH . 'views/tab-options.php';
break;
case 'allowed-types':
include \Pro_Mime_Types\PLUGIN_DIR_PATH . 'views/tab-allowed-types.php';
include PLUGIN_DIR_PATH . 'views/tab-allowed-types.php';
}
}

Expand Down
33 changes: 6 additions & 27 deletions inc/init.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,10 @@ function _register_mime_types( $mime_types ) {
* @hook upload_mimes 10
* @since 2.0.0
*
* @param array $t Mime types keyed by the file extension regex corresponding to those types.
* @return array The MIME types.
* @return array MIME types keyed by the file extension regex corresponding to those types.
*/
function _register_allowed_upload_mimes( $t = [] ) {

// Reset.
$t = [];

// This creates [ 'jpg|jpeg|jpe' => 'image/jpeg' ], aka [ extension_regex => mime ];
$mimes = array_column( SUPPORTED_MIME_TYPES, 1, 0 );

foreach (
explode(
',',
get_allowed_mime_types_settings()
)
as $extension_regex
) {
if ( isset( $mimes[ $extension_regex ] ) )
$t[ $extension_regex ] = $mimes[ $extension_regex ];
}

return $t;
function _register_allowed_upload_mimes() {
return \Pro_Mime_Types\get_allowed_mime_types();
}

/**
Expand Down Expand Up @@ -378,7 +359,7 @@ function _allow_real_filetype_and_ext( $wp_check_filetype_and_ext, $file, $filen
$ext = false;
$type = false;

$allowed = \get_allowed_mime_types();
$allowed = \Pro_Mime_Types\get_allowed_mime_types();

if ( \str_starts_with( $real_mime, 'text/' ) ) {
// Get all mime types of type text and code; these are assumed plaintext by PHP ($real_mime).
Expand All @@ -390,8 +371,8 @@ function _allow_real_filetype_and_ext( $wp_check_filetype_and_ext, $file, $filen
array_intersect(
// This creates [ 'jpg|jpeg|jpe' => 'image' ], aka [ extension_regex => type ];
array_column( SUPPORTED_MIME_TYPES, 4, 0 ),
[ 'text', 'code' ]
)
[ 'text', 'code' ],
),
);

foreach ( $text_and_code_mimes as $extension_regex => $mime_type )
Expand All @@ -414,8 +395,6 @@ function _allow_real_filetype_and_ext( $wp_check_filetype_and_ext, $file, $filen
'heic|heif' => 'image/heic',
];
}
// Candidates, '$ext', 'realmime'
// 'class', 'application/java'

if ( isset( $assumed_extension_and_mimes ) ) {
// Redo basic extension validation and MIME mapping.
Expand Down
182 changes: 148 additions & 34 deletions inc/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@

\defined( 'Pro_Mime_Types\VERSION' ) or die;

use function \Pro_Mime_Types\is_network_mode;

use const \Pro_Mime_Types\{
MIME_DANGER_LEVEL,
ALLOWED_MIME_TYPES_OPTIONS_NAME,
DB_VERSION,
DB_VERSION_OPTION_NAME,
MIME_DANGER_LEVEL,
SUPPORTED_MIME_TYPES,
};

use function \Pro_Mime_Types\{
get_allowed_mime_types_settings,
get_db_version,
is_network_mode,
};

/**
* Pro Mime Types plugin
* Copyright (C) 2023 - 2024 Sybre Waaijer, CyberWire B.V. (https://cyberwire.nl/)
Expand All @@ -39,12 +45,10 @@
*
* @since 2.0.0
* @access private
* @global WPDB $wpdb
*
* @return bool True when done, false when locked.
*/
function _register_or_upgrade_settings() {
global $wpdb;

$timeout = 5 * \MINUTE_IN_SECONDS; // Same as WP Core, function update_core().

Expand All @@ -60,15 +64,101 @@ function _register_or_upgrade_settings() {
if ( 0 !== $ini_max_execution_time )
set_time_limit( max( $ini_max_execution_time, $timeout ) );

// Delete options; $success may in an unpredicted event return false otherwise.
\delete_option( ALLOWED_MIME_TYPES_OPTIONS_NAME );
\delete_site_option( ALLOWED_MIME_TYPES_OPTIONS_NAME );
// Get unaltered settings.
$settings = is_network_mode()
? \get_site_option( ALLOWED_MIME_TYPES_OPTIONS_NAME )
: \get_option( ALLOWED_MIME_TYPES_OPTIONS_NAME );

$success = false !== $settings
? _upgrade_settings()
: _register_or_migrate_settings(); // Register or migrate from < 2.0

_release_upgrade_lock();

/**
* Clear the cache to prevent a get_option() from retrieving a stale database version to the cache.
* Not all caching plugins recognize 'flush', so delete the options cache too, just to be safe.
*
* @see WordPress's `.../update-core.php`
*/
\wp_cache_flush();
\wp_cache_delete( 'alloptions', 'options' );

return $success;
}

/**
* Upgrades the settings.
*
* @since 2.1.0
* @access private
*
* @return bool True when done, false on failure.
*/
function _upgrade_settings() {

/**
* Clear the cache to prevent an update_option() from saving a stale database version to the cache.
* Not all caching plugins recognize 'flush', so delete the options cache too, just to be safe.
*
* @see WordPress's `.../update-core.php`
*/
\wp_cache_flush();
\wp_cache_delete( 'alloptions', 'options' );

$current_version = get_db_version();

switch ( true ) {
case $current_version < 2100:
// Convert from 2.0 to 2.1+; gets automaticlly from either network mode or single site.
$supported_types = _update_extension_regexes_to_mime_type_options( get_allowed_mime_types_settings( true ) );

// Migrate
$success = is_network_mode()
? \update_site_option( ALLOWED_MIME_TYPES_OPTIONS_NAME, $supported_types )
: \update_option( ALLOWED_MIME_TYPES_OPTIONS_NAME, $supported_types );

if ( ! $success ) break;
// Pass through

case true:
$success = is_network_mode()
? \update_site_option( DB_VERSION_OPTION_NAME, DB_VERSION )
: \update_option( DB_VERSION_OPTION_NAME, DB_VERSION );
}

return $success ?? false;
}

/**
* Registers or migrates the settings from Pro Mime Types 2.0 and earlier.
*
* @since 2.1.0
* @access private
* @global WPDB $wpdb
*
* @return bool True when done, false on failure.
*/
function _register_or_migrate_settings() {
global $wpdb;

// Delete options; $success may, in an unpredicted event, return false otherwise.
is_network_mode()
? \delete_site_option( ALLOWED_MIME_TYPES_OPTIONS_NAME )
: \delete_option( ALLOWED_MIME_TYPES_OPTIONS_NAME );

/**
* Clear the cache to prevent an update_option() from saving a stale database version to the cache.
* Not all caching plugins recognize 'flush', so delete the options cache too, just to be safe.
*
* @see WordPress's `.../update-core.php`
*/
\wp_cache_flush();
\wp_cache_delete( 'alloptions', 'options' );

$supported_extensions = [];

// We used to separate storage based on site mode, rather than plugin activation mode.
if ( \is_multisite() ) {
$old_results = $wpdb->get_results(
$wpdb->prepare(
Expand Down Expand Up @@ -106,12 +196,20 @@ function _register_or_upgrade_settings() {
}

if ( ! $old_results ) {
// phpcs:ignore, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- unpack list.
foreach ( SUPPORTED_MIME_TYPES as [ $extension_regex, $mime, $danger ] )
if ( MIME_DANGER_LEVEL['safe'] === $danger )
$supported_extensions[] = $extension_regex;
// Register.
$supported_types = [];

// Extract to reduce array access opcodes in loop.
$safe = MIME_DANGER_LEVEL['safe'];

// SUPPORTED_MIME_TYPES: extension_regex, mime, danger, comment, type
foreach ( SUPPORTED_MIME_TYPES as $option => [ , , $danger ] )
if ( $safe === $danger )
$supported_types[] = $option;

$supported_types = implode( ',', $supported_types );
} else {
// Migrate from old extension regex to new extension regex.
// Migrate from < 2.0
foreach (
[
'jpg|jpeg|jpe' => 'jpg|jpeg|jpe|jif|jfif',
Expand All @@ -126,18 +224,22 @@ function _register_or_upgrade_settings() {
$supported_extensions[] = $new;
}
}
}

// SWF and FLV are long gone. Let's stop recognizing it.
$supported_extensions = array_diff( $supported_extensions, [ 'swf', 'flv' ] );
// SWF and FLV are long gone. Let's stop recognizing it.
$supported_extensions = array_diff( $supported_extensions, [ 'swf', 'flv' ] );

// Convert extensions to 2.1+
$supported_types = _update_extension_regexes_to_mime_type_options( $supported_extensions );
}

// Migrate;
$success = is_network_mode()
? \update_site_option( ALLOWED_MIME_TYPES_OPTIONS_NAME, implode( ',', $supported_extensions ) )
: \update_option( ALLOWED_MIME_TYPES_OPTIONS_NAME, implode( ',', $supported_extensions ) );
? \update_site_option( ALLOWED_MIME_TYPES_OPTIONS_NAME, $supported_types )
: \update_option( ALLOWED_MIME_TYPES_OPTIONS_NAME, $supported_types );

// Try again later. Don't warn user -- the plugin will simply be unavailable.
if ( ! $success ) return false;
if ( ! $success )
return false;

// Delete old options, if any.
if ( ! empty( $old_results ) ) {
Expand All @@ -155,17 +257,6 @@ function _register_or_upgrade_settings() {
);
}

_release_upgrade_lock();

/**
* Clear the cache to prevent a get_option() from retrieving a stale database version to the cache.
* Not all caching plugins recognize 'flush', so delete the options cache too, just to be safe.
*
* @see WordPress's `.../update-core.php`
*/
\wp_cache_flush();
\wp_cache_delete( 'alloptions', 'options' );

return true;
}

Expand All @@ -190,15 +281,15 @@ function _set_upgrade_lock( $release_timeout ) {
$wpdb->prepare(
"INSERT IGNORE INTO `$wpdb->sitemeta` ( `meta_key`, `meta_value` ) VALUES (%s, %s) /* LOCK */",
UPGRADE_LOCK_OPTION_NAME,
time()
time(),
)
);
} else {
$lock_result = $wpdb->query(
$wpdb->prepare(
"INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */",
UPGRADE_LOCK_OPTION_NAME,
time()
time(),
)
);
}
Expand Down Expand Up @@ -232,9 +323,32 @@ function _set_upgrade_lock( $release_timeout ) {
*
* When the upgrader halts, timeouts, or crashes for any reason, this will run.
*
* @since 4.0.0
* @since 4.1.0 Now uses a controllable option instead of a transient.
* @since 2.0.0
*/
function _release_upgrade_lock() {
\delete_site_option( UPGRADE_LOCK_OPTION_NAME );
}

/**
* Updates file extension regexes to mime type option names
* (2.0 to 2.1 ALLOWED_MIME_TYPES_OPTIONS_NAME option value).
*
* @since 2.1.0
* @param string[] $extension_regexes File extension regexes.
* @return string[] Mime type option names.
*/
function _update_extension_regexes_to_mime_type_options( $extension_regexes ) {

$supported_types = [];

// This extracts SUPPORTED_MIME_TYPES to becomes [ 'avif' => 'avif|avifs', 'bpm' => 'bmp', ... ]
$options = array_combine(
array_keys( SUPPORTED_MIME_TYPES ),
array_column( SUPPORTED_MIME_TYPES, 0 ),
);

foreach ( $extension_regexes as $regex )
$supported_types[] = array_search( $regex, $options, true ) ?: '';

return implode( ',', array_filter( $supported_types, 'strlen' ) );
}
8 changes: 8 additions & 0 deletions lib/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

/**
* Suppress nags.
*/
#update-nag,
.update-nag {
display: none;
}

/**
* Most of the styles below are repurposed from WordPress's Privacy and Health pages.
*
Expand Down
Loading

0 comments on commit ef1b719

Please sign in to comment.