Detect and handle symlinking of plugins in plugin_basename().

props rmccue, MikeSchinkel, jdgrimes.
see #16953.

Built from https://develop.svn.wordpress.org/trunk@27158


git-svn-id: http://core.svn.wordpress.org/trunk@27024 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Andrew Nacin 2014-02-10 23:00:15 +00:00
parent c8665c5973
commit 5f0981788d
6 changed files with 62 additions and 10 deletions

View File

@ -537,7 +537,8 @@ function activate_plugin( $plugin, $redirect = '', $network_wide = false, $silen
if ( !empty($redirect) ) if ( !empty($redirect) )
wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect)); // we'll override this later if the plugin can be included without fatal error wp_redirect(add_query_arg('_error_nonce', wp_create_nonce('plugin-activation-error_' . $plugin), $redirect)); // we'll override this later if the plugin can be included without fatal error
ob_start(); ob_start();
include_once(WP_PLUGIN_DIR . '/' . $plugin); wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
include_once( WP_PLUGIN_DIR . '/' . $plugin );
if ( ! $silent ) { if ( ! $silent ) {
/** /**
@ -921,6 +922,7 @@ function uninstall_plugin($plugin) {
unset($uninstallable_plugins); unset($uninstallable_plugins);
define('WP_UNINSTALL_PLUGIN', $file); define('WP_UNINSTALL_PLUGIN', $file);
wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . dirname( $file ) );
include WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php'; include WP_PLUGIN_DIR . '/' . dirname($file) . '/uninstall.php';
return true; return true;
@ -932,6 +934,7 @@ function uninstall_plugin($plugin) {
update_option('uninstall_plugins', $uninstallable_plugins); update_option('uninstall_plugins', $uninstallable_plugins);
unset($uninstallable_plugins); unset($uninstallable_plugins);
wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $file );
include WP_PLUGIN_DIR . '/' . $file; include WP_PLUGIN_DIR . '/' . $file;
add_action( 'uninstall_' . $file, $callable ); add_action( 'uninstall_' . $file, $callable );

View File

@ -143,6 +143,7 @@ if ( $action ) {
@ini_set('display_errors', true); //Ensure that Fatal errors are displayed. @ini_set('display_errors', true); //Ensure that Fatal errors are displayed.
// Go back to "sandbox" scope so we get the same errors as before // Go back to "sandbox" scope so we get the same errors as before
function plugin_sandbox_scrape( $plugin ) { function plugin_sandbox_scrape( $plugin ) {
wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
include( WP_PLUGIN_DIR . '/' . $plugin ); include( WP_PLUGIN_DIR . '/' . $plugin );
} }
plugin_sandbox_scrape( $plugin ); plugin_sandbox_scrape( $plugin );

View File

@ -84,7 +84,8 @@ if ( isset($_GET['action']) ) {
error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR ); error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
@ini_set('display_errors', true); //Ensure that Fatal errors are displayed. @ini_set('display_errors', true); //Ensure that Fatal errors are displayed.
include(WP_PLUGIN_DIR . '/' . $plugin); wp_register_plugin_realpath( WP_PLUGIN_DIR . '/' . $plugin );
include( WP_PLUGIN_DIR . '/' . $plugin );
} }
iframe_footer(); iframe_footer();
} elseif ( 'install-plugin' == $action ) { } elseif ( 'install-plugin' == $action ) {

View File

@ -1433,6 +1433,23 @@ function path_join( $base, $path ) {
return rtrim($base, '/') . '/' . ltrim($path, '/'); return rtrim($base, '/') . '/' . ltrim($path, '/');
} }
/**
* Normalize a filesystem path.
*
* Replaces backslashes with forward slashes for Windows systems,
* and ensures no duplicate slashes exist.
*
* @since 3.9.0
*
* @param string $path Path to normalize.
* @return string Normalized path.
*/
function wp_normalize_path( $path ) {
$path = str_replace( '\\', '/', $path );
$path = preg_replace( '|/+|','/', $path );
return $path;
}
/** /**
* Determines a writable directory for temporary files. * Determines a writable directory for temporary files.
* Function's preference is the return value of <code>sys_get_temp_dir()</code>, * Function's preference is the return value of <code>sys_get_temp_dir()</code>,

View File

@ -592,18 +592,42 @@ function remove_all_actions($tag, $priority = false) {
* @return string The name of a plugin. * @return string The name of a plugin.
* @uses WP_PLUGIN_DIR * @uses WP_PLUGIN_DIR
*/ */
function plugin_basename($file) { function plugin_basename( $file ) {
$file = str_replace('\\','/',$file); // sanitize for Win32 installs global $wp_plugin_paths;
$file = preg_replace('|/+|','/', $file); // remove any duplicate slash
$plugin_dir = str_replace('\\','/',WP_PLUGIN_DIR); // sanitize for Win32 installs foreach ( $wp_plugin_paths as $dir => $realdir ) {
$plugin_dir = preg_replace('|/+|','/', $plugin_dir); // remove any duplicate slash if ( strpos( $file, $realdir ) === 0 ) {
$mu_plugin_dir = str_replace('\\','/',WPMU_PLUGIN_DIR); // sanitize for Win32 installs $file = $dir . substr( $file, strlen( $realdir ) );
$mu_plugin_dir = preg_replace('|/+|','/', $mu_plugin_dir); // remove any duplicate slash }
}
$file = wp_normalize_path( $file );
$plugin_dir = wp_normalize_path( WP_PLUGIN_DIR );
$mu_plugin_dir = wp_normalize_path( WPMU_PLUGIN_DIR );
$file = preg_replace('#^' . preg_quote($plugin_dir, '#') . '/|^' . preg_quote($mu_plugin_dir, '#') . '/#','',$file); // get relative path from plugins dir $file = preg_replace('#^' . preg_quote($plugin_dir, '#') . '/|^' . preg_quote($mu_plugin_dir, '#') . '/#','',$file); // get relative path from plugins dir
$file = trim($file, '/'); $file = trim($file, '/');
return $file; return $file;
} }
/**
* Register a plugin's real path.
*
* This is used in {@see plugin_basename()} to resolve symlinked paths.
*
* @param string $file Known path to the file.
*/
function wp_register_plugin_realpath( $file ) {
global $wp_plugin_paths;
$plugin_path = wp_normalize_path( dirname( $file ) );
$plugin_realpath = wp_normalize_path( dirname( realpath( $file ) ) );
if ( $plugin_path !== $plugin_realpath ) {
$wp_plugin_paths[ $plugin_path ] = $plugin_realpath;
}
}
/** /**
* Gets the filesystem directory path (with trailing slash) for the plugin __FILE__ passed in * Gets the filesystem directory path (with trailing slash) for the plugin __FILE__ passed in
* @package WordPress * @package WordPress

View File

@ -164,8 +164,11 @@ if ( is_multisite() ) {
// Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in. // Define must-use plugin directory constants, which may be overridden in the sunrise.php drop-in.
wp_plugin_directory_constants(); wp_plugin_directory_constants();
$GLOBALS['wp_plugin_paths'] = array();
// Load must-use plugins. // Load must-use plugins.
foreach ( wp_get_mu_plugins() as $mu_plugin ) { foreach ( wp_get_mu_plugins() as $mu_plugin ) {
wp_register_plugin_realpath( $mu_plugin );
include_once( $mu_plugin ); include_once( $mu_plugin );
} }
unset( $mu_plugin ); unset( $mu_plugin );
@ -173,6 +176,7 @@ unset( $mu_plugin );
// Load network activated plugins. // Load network activated plugins.
if ( is_multisite() ) { if ( is_multisite() ) {
foreach( wp_get_active_network_plugins() as $network_plugin ) { foreach( wp_get_active_network_plugins() as $network_plugin ) {
wp_register_plugin_realpath( $network_plugin );
include_once( $network_plugin ); include_once( $network_plugin );
} }
unset( $network_plugin ); unset( $network_plugin );
@ -206,8 +210,10 @@ create_initial_post_types();
register_theme_directory( get_theme_root() ); register_theme_directory( get_theme_root() );
// Load active plugins. // Load active plugins.
foreach ( wp_get_active_and_valid_plugins() as $plugin ) foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
wp_register_plugin_realpath( $plugin );
include_once( $plugin ); include_once( $plugin );
}
unset( $plugin ); unset( $plugin );
// Load pluggable functions. // Load pluggable functions.