@@ -363,15 +363,24 @@ protected function install_from_php_file( $url, $assoc_args ) {
363363 return new WP_Error ( 'invalid_filename ' , 'The sanitized filename does not have a .php extension. ' );
364364 }
365365
366+ // Ensure plugin directory exists.
367+ if ( ! is_dir ( WP_PLUGIN_DIR ) ) {
368+ wp_mkdir_p ( WP_PLUGIN_DIR );
369+ }
370+
366371 // Validate the destination stays within the plugin directory.
367372 $ dest_path = trailingslashit ( WP_PLUGIN_DIR ) . $ dest_filename ;
368373 $ real_dest = realpath ( WP_PLUGIN_DIR );
369- if ( false !== $ real_dest ) {
370- // Ensure destination is within plugin directory (prevent directory traversal).
371- $ dest_dir = dirname ( $ dest_path );
372- if ( 0 !== strpos ( $ dest_dir , $ real_dest ) ) {
373- return new WP_Error ( 'invalid_path ' , 'The destination path is outside the plugin directory. ' );
374- }
374+ $ real_path = realpath ( dirname ( $ dest_path ) );
375+
376+ // Ensure plugin directory and destination parent directory are valid.
377+ if ( false === $ real_dest || false === $ real_path ) {
378+ return new WP_Error ( 'invalid_path ' , 'Cannot validate plugin directory path. ' );
379+ }
380+
381+ // Ensure destination is within plugin directory (prevent directory traversal).
382+ if ( 0 !== strpos ( $ real_path , $ real_dest ) ) {
383+ return new WP_Error ( 'invalid_path ' , 'The destination path is outside the plugin directory. ' );
375384 }
376385
377386 // Display info message before downloading.
@@ -384,11 +393,16 @@ protected function install_from_php_file( $url, $assoc_args ) {
384393 return new WP_Error ( 'download_failed ' , sprintf ( 'Could not download PHP file from %s: %s ' , esc_url ( $ url ), $ temp_file ->get_error_message () ) );
385394 }
386395
387- // Read the plugin headers from the downloaded file.
396+ // Verify the downloaded file is a valid PHP file with plugin headers .
388397 $ plugin_data = get_plugin_data ( $ temp_file , false , false );
389398
390- // If no plugin name is found, use the filename.
391- $ plugin_name = ! empty ( $ plugin_data ['Name ' ] ) ? $ plugin_data ['Name ' ] : '' ;
399+ // Verify this is actually a plugin file with at least a plugin name.
400+ if ( empty ( $ plugin_data ['Name ' ] ) ) {
401+ unlink ( $ temp_file );
402+ return new WP_Error ( 'invalid_plugin ' , 'The downloaded file does not appear to be a valid WordPress plugin. ' );
403+ }
404+
405+ $ plugin_name = $ plugin_data ['Name ' ];
392406
393407 // Check if plugin is already installed.
394408 if ( file_exists ( $ dest_path ) && ! Utils \get_flag_value ( $ assoc_args , 'force ' ) ) {
@@ -398,10 +412,8 @@ protected function install_from_php_file( $url, $assoc_args ) {
398412 }
399413
400414 // Display plugin info.
401- if ( ! empty ( $ plugin_name ) ) {
402- $ version = ! empty ( $ plugin_data ['Version ' ] ) ? $ plugin_data ['Version ' ] : '' ;
403- WP_CLI ::log ( sprintf ( 'Installing %s%s ' , $ plugin_name , $ version ? " ( $ version) " : '' ) );
404- }
415+ $ version = ! empty ( $ plugin_data ['Version ' ] ) ? $ plugin_data ['Version ' ] : '' ;
416+ WP_CLI ::log ( sprintf ( 'Installing %s%s ' , $ plugin_name , $ version ? " ( $ version) " : '' ) );
405417
406418 // Move the file to the plugins directory.
407419 $ result = copy ( $ temp_file , $ dest_path );
0 commit comments