Background Updates: Introduce support to take advantage of Group Writable (or World Writable) to Core Background updates.

This is only enabled when new files will not be installed during the update (as indicated by the WordPress.org API), and does not apply to Plugin/Theme/Translation Background Updates.

Additionally, the code to determine if the 'direct' filesystem transport should be used has been tweaked for wider support (where getmyuid() was unavailalbe) which fixes #10424

See #10205, #30245

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


git-svn-id: http://core.svn.wordpress.org/trunk@30381 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Dion Hulse 2014-11-19 05:40:23 +00:00
parent d95b5196cc
commit 9b9289e0a3
5 changed files with 93 additions and 36 deletions

View File

@ -40,12 +40,18 @@ class WP_Upgrader_Skin {
$this->result = $result;
}
public function request_filesystem_credentials($error = false) {
public function request_filesystem_credentials( $error = false, $context = false, $allow_relaxed_file_ownership = false ) {
$url = $this->options['url'];
$context = $this->options['context'];
if ( !empty($this->options['nonce']) )
if ( ! $context ) {
$context = $this->options['context'];
}
if ( !empty($this->options['nonce']) ) {
$url = wp_nonce_url($url, $this->options['nonce']);
return request_filesystem_credentials($url, '', $error, $context); //Possible to bring inline, Leaving as is for now.
}
$extra_fields = array();
return request_filesystem_credentials( $url, '', $error, $context, $extra_fields, $allow_relaxed_file_ownership );
}
public function header() {
@ -699,13 +705,14 @@ class Language_Pack_Upgrader_Skin extends WP_Upgrader_Skin {
class Automatic_Upgrader_Skin extends WP_Upgrader_Skin {
protected $messages = array();
public function request_filesystem_credentials( $error = false, $context = '' ) {
if ( $context )
public function request_filesystem_credentials( $error = false, $context = '', $allow_relaxed_file_ownership = false ) {
if ( $context ) {
$this->options['context'] = $context;
}
// TODO: fix up request_filesystem_credentials(), or split it, to allow us to request a no-output version
// This will output a credentials form in event of failure, We don't want that, so just hide with a buffer
ob_start();
$result = parent::request_filesystem_credentials( $error );
$result = parent::request_filesystem_credentials( $error, $context, $allow_relaxed_file_ownership );
ob_end_clean();
return $result;
}

View File

@ -61,17 +61,19 @@ class WP_Upgrader {
$this->strings['maintenance_end'] = __('Disabling Maintenance mode…');
}
public function fs_connect( $directories = array() ) {
public function fs_connect( $directories = array(), $allow_relaxed_file_ownership = false ) {
global $wp_filesystem;
if ( false === ($credentials = $this->skin->request_filesystem_credentials()) )
if ( false === ( $credentials = $this->skin->request_filesystem_credentials( false, $directories[0], $allow_relaxed_file_ownership ) ) ) {
return false;
}
if ( ! WP_Filesystem($credentials) ) {
if ( ! WP_Filesystem( $credentials, $directories[0], $allow_relaxed_file_ownership ) ) {
$error = true;
if ( is_object($wp_filesystem) && $wp_filesystem->errors->get_error_code() )
$error = $wp_filesystem->errors;
$this->skin->request_filesystem_credentials($error); //Failed to connect, Error and request again
// Failed to connect, Error and request again
$this->skin->request_filesystem_credentials( $error, $directories[0], $allow_relaxed_file_ownership );
return false;
}
@ -1456,6 +1458,7 @@ class Core_Upgrader extends WP_Upgrader {
'pre_check_md5' => true,
'attempt_rollback' => false,
'do_rollback' => false,
'allow_relaxed_file_ownership' => false,
);
$parsed_args = wp_parse_args( $args, $defaults );
@ -1466,7 +1469,7 @@ class Core_Upgrader extends WP_Upgrader {
if ( !isset( $current->response ) || $current->response == 'latest' )
return new WP_Error('up_to_date', $this->strings['up_to_date']);
$res = $this->fs_connect( array(ABSPATH, WP_CONTENT_DIR) );
$res = $this->fs_connect( array( ABSPATH, WP_CONTENT_DIR ), $parsed_args['allow_relaxed_file_ownership'] );
if ( ! $res || is_wp_error( $res ) ) {
return $res;
}
@ -1911,8 +1914,14 @@ class WP_Automatic_Updater {
if ( $this->is_disabled() )
return false;
// Only relax the filesystem checks when the update doesn't include new files
$allow_relaxed_file_ownership = false;
if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) {
$allow_relaxed_file_ownership = true;
}
// If we can't do an auto core update, we may still be able to email the user.
if ( ! $skin->request_filesystem_credentials( false, $context ) || $this->is_vcs_checkout( $context ) ) {
if ( ! $skin->request_filesystem_credentials( false, $context, $allow_relaxed_file_ownership ) || $this->is_vcs_checkout( $context ) ) {
if ( 'core' == $type )
$this->send_core_update_notification_email( $item );
return false;
@ -2072,6 +2081,11 @@ class WP_Automatic_Updater {
break;
}
$allow_relaxed_file_ownership = false;
if ( 'core' == $type && isset( $item->new_files ) && ! $item->new_files ) {
$allow_relaxed_file_ownership = true;
}
// Boom, This sites about to get a whole new splash of paint!
$upgrade_result = $upgrader->upgrade( $upgrader_item, array(
'clear_update_cache' => false,
@ -2079,6 +2093,9 @@ class WP_Automatic_Updater {
'pre_check_md5' => false,
// Only available for core updates.
'attempt_rollback' => true,
// Allow relaxed file ownership in some scenarios
'allow_relaxed_file_ownership' => $allow_relaxed_file_ownership,
) );
// If the filesystem is unavailable, false is returned.

View File

@ -809,14 +809,15 @@ function copy_dir($from, $to, $skip_list = array() ) {
*
* @param array $args (optional) Connection args, These are passed directly to the WP_Filesystem_*() classes.
* @param string $context (optional) Context for get_filesystem_method(), See function declaration for more information.
* @param bool $allow_relaxed_file_ownership Whether to allow Group/World writable.
* @return null|boolean false on failure, true on success
*/
function WP_Filesystem( $args = false, $context = false ) {
function WP_Filesystem( $args = false, $context = false, $allow_relaxed_file_ownership = false ) {
global $wp_filesystem;
require_once(ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php');
$method = get_filesystem_method($args, $context);
$method = get_filesystem_method( $args, $context, $allow_relaxed_file_ownership );
if ( ! $method )
return false;
@ -879,25 +880,46 @@ function WP_Filesystem( $args = false, $context = false ) {
*
* @param array $args Connection details.
* @param string $context Full path to the directory that is tested for being writable.
* @param bool $allow_relaxed_file_ownership Whether to allow Group/World writable.
* @return string The transport to use, see description for valid return values.
*/
function get_filesystem_method($args = array(), $context = false) {
function get_filesystem_method( $args = array(), $context = false, $allow_relaxed_file_ownership = false ) {
$method = defined('FS_METHOD') ? FS_METHOD : false; // Please ensure that this is either 'direct', 'ssh2', 'ftpext' or 'ftpsockets'
if ( ! $method && function_exists('getmyuid') && function_exists('fileowner') ){
if ( !$context )
$context = WP_CONTENT_DIR;
if ( ! $context ) {
$context = WP_CONTENT_DIR;
}
// If the directory doesn't exist (wp-content/languages) then use the parent directory as we'll create it.
if ( WP_LANG_DIR == $context && ! is_dir( $context ) )
$context = dirname( $context );
// If the directory doesn't exist (wp-content/languages) then use the parent directory as we'll create it.
if ( WP_LANG_DIR == $context && ! is_dir( $context ) ) {
$context = dirname( $context );
}
$context = trailingslashit( $context );
if ( ! $method ) {
$context = trailingslashit($context);
$temp_file_name = $context . 'temp-write-test-' . time();
$temp_handle = @fopen($temp_file_name, 'w');
if ( $temp_handle ) {
if ( getmyuid() == @fileowner($temp_file_name) )
// Attempt to determine the file owner of the WordPress files, and that of newly created files
$wp_file_owner = $temp_file_owner = false;
if ( function_exists('fileowner') ) {
$wp_file_owner = @fileowner( __FILE__ );
$temp_file_owner = @fileowner( $temp_file_name );
}
if ( $wp_file_owner !== false && $wp_file_owner === $temp_file_owner ) {
// WordPress is creating files as the same owner as the WordPress files,
// this means it's safe to modify & create new files via PHP.
$method = 'direct';
} else if ( $allow_relaxed_file_ownership ) {
// The $context directory is writable, and $allow_relaxed_file_ownership is set, this means we can modify files
// safely in this directory. This mode doesn't create new files, only alter existing ones.
$method = 'direct';
}
@fclose($temp_handle);
@unlink($temp_file_name);
}
@ -912,10 +934,12 @@ function get_filesystem_method($args = array(), $context = false) {
*
* @since 2.6.0
*
* @param string $method Filesystem method to return.
* @param array $args An array of connection details for the method.
* @param string $method Filesystem method to return.
* @param array $args An array of connection details for the method.
* @param string $context Full path to the directory that is tested for being writable.
* @param bool $allow_relaxed_file_ownership Whether to allow Group/World writable.
*/
return apply_filters( 'filesystem_method', $method, $args );
return apply_filters( 'filesystem_method', $method, $args, $context, $allow_relaxed_file_ownership );
}
/**
@ -933,9 +957,10 @@ function get_filesystem_method($args = array(), $context = false) {
* @param boolean $error if the current request has failed to connect
* @param string $context The directory which is needed access to, The write-test will be performed on this directory by get_filesystem_method()
* @param string $extra_fields Extra POST fields which should be checked for to be included in the post.
* @param bool $allow_relaxed_file_ownership Whether to allow Group/World writable.
* @return boolean False on failure. True on success.
*/
function request_filesystem_credentials($form_post, $type = '', $error = false, $context = false, $extra_fields = null) {
function request_filesystem_credentials($form_post, $type = '', $error = false, $context = false, $extra_fields = null, $allow_relaxed_file_ownership = false ) {
/**
* Filter the filesystem credentials form output.
@ -952,14 +977,16 @@ function request_filesystem_credentials($form_post, $type = '', $error = false,
* Default false.
* @param string $context Full path to the directory that is tested for
* being writable.
* @param bool $allow_relaxed_file_ownership Whether to allow Group/World writable.
* @param array $extra_fields Extra POST fields.
*/
$req_cred = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields );
$req_cred = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields, $allow_relaxed_file_ownership );
if ( '' !== $req_cred )
return $req_cred;
if ( empty($type) )
$type = get_filesystem_method(array(), $context);
if ( empty($type) ) {
$type = get_filesystem_method( array(), $context, $allow_relaxed_file_ownership );
}
if ( 'direct' == $type )
return true;

View File

@ -381,19 +381,23 @@ function do_core_upgrade( $reinstall = false ) {
if ( !$update )
return;
// Allow relaxed file ownership writes for User-initiated upgrades when the API specifies
// that it's safe to do so. This only happens when there are no new files to create.
$allow_relaxed_file_ownership = ! $reinstall && isset( $update->new_files ) && ! $update->new_files;
?>
<div class="wrap">
<h2><?php _e('Update WordPress'); ?></h2>
<?php
if ( false === ( $credentials = request_filesystem_credentials( $url, '', false, ABSPATH ) ) ) {
if ( false === ( $credentials = request_filesystem_credentials( $url, '', false, ABSPATH, array(), $allow_relaxed_file_ownership ) ) ) {
echo '</div>';
return;
}
if ( ! WP_Filesystem( $credentials, ABSPATH ) ) {
if ( ! WP_Filesystem( $credentials, ABSPATH, $allow_relaxed_file_ownership ) ) {
// Failed to connect, Error and request again
request_filesystem_credentials( $url, '', true, ABSPATH );
request_filesystem_credentials( $url, '', true, ABSPATH, array(), $allow_relaxed_file_ownership );
echo '</div>';
return;
}
@ -411,7 +415,9 @@ function do_core_upgrade( $reinstall = false ) {
add_filter( 'update_feedback', 'show_message' );
$upgrader = new Core_Upgrader();
$result = $upgrader->upgrade( $update );
$result = $upgrader->upgrade( $update, array(
'allow_relaxed_file_ownership' => $allow_relaxed_file_ownership
) );
if ( is_wp_error($result) ) {
show_message($result);

View File

@ -142,7 +142,7 @@ function wp_version_check( $extra_stats = array(), $force_check = false ) {
$offer[ $offer_key ] = esc_html( $value );
}
$offer = (object) array_intersect_key( $offer, array_fill_keys( array( 'response', 'download', 'locale',
'packages', 'current', 'version', 'php_version', 'mysql_version', 'new_bundled', 'partial_version', 'notify_email', 'support_email' ), '' ) );
'packages', 'current', 'version', 'php_version', 'mysql_version', 'new_bundled', 'partial_version', 'notify_email', 'support_email', 'new_files' ), '' ) );
}
$updates = new stdClass();