WordPress.org

Make WordPress Core

Ticket #31616: 31616.1.diff

File 31616.1.diff, 16.3 KB (added by jipmoors, 7 years ago)

Fixed formatting and docs. Applied the functionality improvements.

  • src/wp-admin/includes/file.php

     
    910910
    911911        $context = trailingslashit( $context );
    912912
    913         if ( ! $method ) {
     913        static $results = array();
    914914
    915                 $temp_file_name = $context . 'temp-write-test-' . time();
    916                 $temp_handle = @fopen($temp_file_name, 'w');
    917                 if ( $temp_handle ) {
     915        // saving hash for static cache; file reads/writes are to be avoided when possible
     916        $hash = md5(serialize($args) . $context . $allow_relaxed_file_ownership);
     917        if ( ! isset($results[$hash])) {
    918918
    919                         // Attempt to determine the file owner of the WordPress files, and that of newly created files
    920                         $wp_file_owner = $temp_file_owner = false;
    921                         if ( function_exists('fileowner') ) {
    922                                 $wp_file_owner = @fileowner( __FILE__ );
    923                                 $temp_file_owner = @fileowner( $temp_file_name );
    924                         }
     919                if ( ! $method ) {
    925920
    926                         if ( $wp_file_owner !== false && $wp_file_owner === $temp_file_owner ) {
    927                                 // WordPress is creating files as the same owner as the WordPress files,
    928                                 // this means it's safe to modify & create new files via PHP.
    929                                 $method = 'direct';
    930                                 $GLOBALS['_wp_filesystem_direct_method'] = 'file_owner';
    931                         } elseif ( $allow_relaxed_file_ownership ) {
    932                                 // The $context directory is writable, and $allow_relaxed_file_ownership is set, this means we can modify files
    933                                 // safely in this directory. This mode doesn't create new files, only alter existing ones.
    934                                 $method = 'direct';
    935                                 $GLOBALS['_wp_filesystem_direct_method'] = 'relaxed_ownership';
     921                        $temp_file_name = $context . 'temp-write-test-' . time();
     922                        $temp_handle    = @fopen( $temp_file_name, 'w' );
     923                        if ( $temp_handle ) {
     924
     925                                // Attempt to determine the file owner of the WordPress files, and that of newly created files
     926                                $wp_file_owner = $temp_file_owner = false;
     927                                if ( function_exists( 'fileowner' ) ) {
     928                                        $wp_file_owner   = @fileowner( __FILE__ );
     929                                        $temp_file_owner = @fileowner( $temp_file_name );
     930                                }
     931
     932                                if ( $wp_file_owner !== false && $wp_file_owner === $temp_file_owner ) {
     933                                        // WordPress is creating files as the same owner as the WordPress files,
     934                                        // this means it's safe to modify & create new files via PHP.
     935                                        $method                                  = 'direct';
     936                                        $GLOBALS['_wp_filesystem_direct_method'] = 'file_owner';
     937                                } elseif ( $allow_relaxed_file_ownership ) {
     938                                        // The $context directory is writable, and $allow_relaxed_file_ownership is set, this means we can modify files
     939                                        // safely in this directory. This mode doesn't create new files, only alter existing ones.
     940                                        $method                                  = 'direct';
     941                                        $GLOBALS['_wp_filesystem_direct_method'] = 'relaxed_ownership';
     942                                }
     943
     944                                @fclose( $temp_handle );
     945                                @unlink( $temp_file_name );
    936946                        }
    937 
    938                         @fclose($temp_handle);
    939                         @unlink($temp_file_name);
    940947                }
    941         }
    942948
    943         if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') && function_exists('stream_get_contents') ) $method = 'ssh2';
    944         if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext';
    945         if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
     949                if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') && function_exists('stream_get_contents') ) $method = 'ssh2';
     950                if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext';
     951                if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
    946952
    947         /**
    948          * Filter the filesystem method to use.
    949          *
    950          * @since 2.6.0
    951          *
    952          * @param string $method  Filesystem method to return.
    953          * @param array  $args    An array of connection details for the method.
    954          * @param string $context Full path to the directory that is tested for being writable.
    955          * @param bool   $allow_relaxed_file_ownership Whether to allow Group/World writable.
    956          */
    957         return apply_filters( 'filesystem_method', $method, $args, $context, $allow_relaxed_file_ownership );
     953                /**
     954                 * Filter the filesystem method to use.
     955                 *
     956                 * @since 2.6.0
     957                 *
     958                 * @param string $method  Filesystem method to return.
     959                 * @param array  $args    An array of connection details for the method.
     960                 * @param string $context Full path to the directory that is tested for being writable.
     961                 * @param bool   $allow_relaxed_file_ownership Whether to allow Group/World writable.
     962                 */
     963                $results[$hash] = apply_filters( 'filesystem_method', $method, $args, $context, $allow_relaxed_file_ownership );
     964        }
     965
     966        return $results[$hash];
    958967}
    959968
    960969/**
     970 * Get the filesystem credentials needed to connect to the site
     971 *
     972 * @param string  $form_post    the URL to post the form to
     973 * @param string  $type         the chosen Filesystem method in use
     974 * @param boolean $error        if the current request has failed to connect
     975 * @param string  $context      The directory which is needed access to,
     976 *                              The write-test will be performed on this
     977 *                              directory by get_filesystem_method()
     978 * @param array   $extra_fields Extra POST fields which should be checked for to be included in the post.
     979 * @param bool    $allow_relaxed_file_ownership Whether to allow Group/World writable.
     980 * @return mixed Credentials that are found, not guaranteed to contain all information
     981 */
     982function get_filesystem_credentials($form_post, $type = '', $error = false, $context = false, $extra_fields = null, $allow_relaxed_file_ownership = false) {
     983
     984        /** This filter is documented in wp-includes/file.php */
     985        $credentials = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields, $allow_relaxed_file_ownership );
     986        if ( '' !== $credentials ) {
     987                return $credentials;
     988        }
     989
     990        if ( empty($type) ) {
     991                $type = get_filesystem_method( array(), $context, $allow_relaxed_file_ownership );
     992        }
     993
     994        if ( 'direct' == $type ) {
     995                return true;
     996        }
     997
     998        $credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));
     999
     1000        // If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
     1001        $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? wp_unslash( $_POST['hostname'] ) : $credentials['hostname']);
     1002        $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? wp_unslash( $_POST['username'] ) : $credentials['username']);
     1003        $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? wp_unslash( $_POST['password'] ) : '');
     1004
     1005        // Check to see if we are setting the public/private keys for ssh
     1006        $credentials['public_key'] = defined('FTP_PUBKEY') ? FTP_PUBKEY : (!empty($_POST['public_key']) ? wp_unslash( $_POST['public_key'] ) : '');
     1007        $credentials['private_key'] = defined('FTP_PRIKEY') ? FTP_PRIKEY : (!empty($_POST['private_key']) ? wp_unslash( $_POST['private_key'] ) : '');
     1008
     1009        // Sanitize the hostname, Some people might pass in odd-data:
     1010        $credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off
     1011
     1012        if ( strpos($credentials['hostname'], ':') ) {
     1013                list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
     1014                if ( ! is_numeric($credentials['port']) )
     1015                        unset($credentials['port']);
     1016        } else {
     1017                unset($credentials['port']);
     1018        }
     1019
     1020        if ( ( defined( 'FTP_SSH' ) && FTP_SSH ) || ( defined( 'FS_METHOD' ) && 'ssh2' == FS_METHOD ) ) {
     1021                $credentials['connection_type'] = 'ssh';
     1022        } elseif ( ( defined( 'FTP_SSL' ) && FTP_SSL ) && 'ftpext' == $type ) { //Only the FTP Extension understands SSL
     1023                $credentials['connection_type'] = 'ftps';
     1024        } elseif ( ! empty( $_POST['connection_type'] ) ) {
     1025                $credentials['connection_type'] = wp_unslash( $_POST['connection_type'] );
     1026        } elseif ( ! isset( $credentials['connection_type'] ) ) { //All else fails (And it's not defaulted to something else saved), Default to FTP
     1027                $credentials['connection_type'] = 'ftp';
     1028        }
     1029
     1030        return $credentials;
     1031}
     1032
     1033/**
     1034 * @param array  $credentials   Credentials to check required parameters
     1035 * @param string $type          Type of connection to check credentials
     1036 *                              against (direct, ftps, ftp, ssh, etc.)
     1037 * @param string $context       The directory which is needed access to,
     1038 *                              the write-test will be performed on this
     1039 *                              directory by get_filesystem_method()
     1040 * @param bool   $allow_relaxed_file_ownership  Whether to allow Group/World writable.
     1041 *
     1042 * @return bool  True when all required parameters have been set for supplied type, False when anything is missing
     1043 */
     1044function usable_filesystem_credentials($credentials, $type = '', $context = null, $allow_relaxed_file_ownership = false) {
     1045        if ( empty($type) ) {
     1046                $type = get_filesystem_method( array(), $context, $allow_relaxed_file_ownership );
     1047        }
     1048
     1049        // Direct connection does not need any credentials
     1050        if ( 'direct' == $type ) {
     1051                return true;
     1052        }
     1053
     1054        // We need something to check against
     1055        if ( empty( $credentials ) ) {
     1056                return false;
     1057        }
     1058
     1059        // All the checks required an array for parameters; exit if we got something else
     1060        if ( ! is_array( $credentials ) ) {
     1061                return false;
     1062        }
     1063
     1064        // SSH needs public and private key
     1065        if ( 'ssh' == $credentials['connection_type'] ) {
     1066                return ( ! empty( $credentials['public_key'] ) && ! empty( $credentials['private_key'] ) );
     1067        }
     1068
     1069        // Other connection methods need hostname, password and username
     1070        return ( ! empty( $credentials['password'] ) && ! empty( $credentials['username'] ) && ! empty( $credentials['hostname'] ) );
     1071}
     1072
     1073/**
    9611074 * Displays a form to the user to request for their FTP/SSH details in order
    9621075 * to connect to the filesystem.
    9631076 *
     
    9821095 * @return boolean False on failure. True on success.
    9831096 */
    9841097function request_filesystem_credentials($form_post, $type = '', $error = false, $context = false, $extra_fields = null, $allow_relaxed_file_ownership = false ) {
    985 
    9861098        /**
    9871099         * Filter the filesystem credentials form output.
    9881100         *
     
    10011113         * @param bool $allow_relaxed_file_ownership Whether to allow Group/World writable.
    10021114         * @param array  $extra_fields Extra POST fields.
    10031115         */
    1004         $req_cred = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields, $allow_relaxed_file_ownership );
    1005         if ( '' !== $req_cred )
    1006                 return $req_cred;
     1116        $credentials = apply_filters( 'request_filesystem_credentials', '', $form_post, $type, $error, $context, $extra_fields, $allow_relaxed_file_ownership );
     1117        if ( '' !== $credentials ) {
     1118                return $credentials;
     1119        }
    10071120
    1008         if ( empty($type) ) {
     1121        if ( empty( $type ) ) {
    10091122                $type = get_filesystem_method( array(), $context, $allow_relaxed_file_ownership );
    10101123        }
    10111124
    1012         if ( 'direct' == $type )
     1125        if ( 'direct' == $type ) {
    10131126                return true;
     1127        }
    10141128
    1015         if ( is_null( $extra_fields ) )
    1016                 $extra_fields = array( 'version', 'locale' );
     1129        $credentials = get_filesystem_credentials( $form_post, $type, $error, $context, $extra_fields, $allow_relaxed_file_ownership );
    10171130
    1018         $credentials = get_option('ftp_credentials', array( 'hostname' => '', 'username' => ''));
     1131        if ( ! $error && usable_filesystem_credentials( $credentials, $type ) ) {
    10191132
    1020         // If defined, set it to that, Else, If POST'd, set it to that, If not, Set it to whatever it previously was(saved details in option)
    1021         $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? wp_unslash( $_POST['hostname'] ) : $credentials['hostname']);
    1022         $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? wp_unslash( $_POST['username'] ) : $credentials['username']);
    1023         $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? wp_unslash( $_POST['password'] ) : '');
    1024 
    1025         // Check to see if we are setting the public/private keys for ssh
    1026         $credentials['public_key'] = defined('FTP_PUBKEY') ? FTP_PUBKEY : (!empty($_POST['public_key']) ? wp_unslash( $_POST['public_key'] ) : '');
    1027         $credentials['private_key'] = defined('FTP_PRIKEY') ? FTP_PRIKEY : (!empty($_POST['private_key']) ? wp_unslash( $_POST['private_key'] ) : '');
    1028 
    1029         // Sanitize the hostname, Some people might pass in odd-data:
    1030         $credentials['hostname'] = preg_replace('|\w+://|', '', $credentials['hostname']); //Strip any schemes off
    1031 
    1032         if ( strpos($credentials['hostname'], ':') ) {
    1033                 list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
    1034                 if ( ! is_numeric($credentials['port']) )
    1035                         unset($credentials['port']);
    1036         } else {
    1037                 unset($credentials['port']);
    1038         }
    1039 
    1040         if ( ( defined( 'FTP_SSH' ) && FTP_SSH ) || ( defined( 'FS_METHOD' ) && 'ssh2' == FS_METHOD ) ) {
    1041                 $credentials['connection_type'] = 'ssh';
    1042         } elseif ( ( defined( 'FTP_SSL' ) && FTP_SSL ) && 'ftpext' == $type ) { //Only the FTP Extension understands SSL
    1043                 $credentials['connection_type'] = 'ftps';
    1044         } elseif ( ! empty( $_POST['connection_type'] ) ) {
    1045                 $credentials['connection_type'] = wp_unslash( $_POST['connection_type'] );
    1046         } elseif ( ! isset( $credentials['connection_type'] ) ) { //All else fails (And it's not defaulted to something else saved), Default to FTP
    1047                 $credentials['connection_type'] = 'ftp';
    1048         }
    1049         if ( ! $error &&
    1050                         (
    1051                                 ( !empty($credentials['password']) && !empty($credentials['username']) && !empty($credentials['hostname']) ) ||
    1052                                 ( 'ssh' == $credentials['connection_type'] && !empty($credentials['public_key']) && !empty($credentials['private_key']) )
    1053                         ) ) {
    10541133                $stored_credentials = $credentials;
    1055                 if ( !empty($stored_credentials['port']) ) //save port as part of hostname to simplify above code.
     1134                if ( ! empty( $stored_credentials['port'] ) ) //save port as part of hostname to simplify retrievement code
     1135                {
    10561136                        $stored_credentials['hostname'] .= ':' . $stored_credentials['port'];
     1137                }
    10571138
    1058                 unset($stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key']);
     1139                unset( $stored_credentials['password'], $stored_credentials['port'], $stored_credentials['private_key'], $stored_credentials['public_key'] );
     1140
    10591141                if ( ! defined( 'WP_INSTALLING' ) ) {
    10601142                        update_option( 'ftp_credentials', $stored_credentials );
    10611143                }
     1144
    10621145                return $credentials;
    10631146        }
     1147
     1148        // Display the credentials form to the user
     1149        request_filesystem_credentials_form( $form_post, $credentials, $type, $error, $context, $extra_fields );
     1150
     1151        // Nothing usable has been found yet.
     1152        return false;
     1153}
     1154
     1155/**
     1156 * Write the form needed to input credentials needed to connect for the specified type
     1157 *
     1158 * @param string $form_post the URL to post the form to
     1159 * @param $credentials
     1160 * @param string $type the chosen Filesystem method in use
     1161 * @param boolean $error if the current request has failed to connect
     1162 * @param string $context The directory which is needed access to, The write-test will be performed on this directory by get_filesystem_method()
     1163 * @param array $extra_fields Extra POST fields which should be checked for to be included in the post.
     1164 * @param bool $allow_relaxed_file_ownership Whether to allow Group/World writable.
     1165 */
     1166function request_filesystem_credentials_form($form_post, $credentials, $type = '', $error = false, $context = null, $extra_fields = null, $allow_relaxed_file_ownership = false) {
     1167        if ( empty( $type ) ) {
     1168                $type = get_filesystem_method( array(), $context, $allow_relaxed_file_ownership );
     1169        }
     1170
     1171        if ( ! is_array($credentials)) {
     1172                $credentials = array();
     1173        }
     1174
    10641175        $hostname = isset( $credentials['hostname'] ) ? $credentials['hostname'] : '';
    10651176        $username = isset( $credentials['username'] ) ? $credentials['username'] : '';
    10661177        $public_key = isset( $credentials['public_key'] ) ? $credentials['public_key'] : '';
     
    10681179        $port = isset( $credentials['port'] ) ? $credentials['port'] : '';
    10691180        $connection_type = isset( $credentials['connection_type'] ) ? $credentials['connection_type'] : '';
    10701181
     1182        if ( is_null( $extra_fields ) )
     1183                $extra_fields = array( 'version', 'locale' );
     1184
    10711185        if ( $error ) {
    10721186                $error_string = __('<strong>ERROR:</strong> There was an error connecting to the server, Please verify the settings are correct.');
    10731187                if ( is_wp_error($error) )
     
    11901304</div>
    11911305</form>
    11921306<?php
    1193         return false;
     1307
    11941308}