@@ -363,23 +363,30 @@ 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+ // Construct destination path.
367+ $ dest_path = trailingslashit ( WP_PLUGIN_DIR ) . $ dest_filename ;
368+
369+ // Check if plugin is already installed before downloading.
370+ if ( file_exists ( $ dest_path ) && ! Utils \get_flag_value ( $ assoc_args , 'force ' ) ) {
371+ return new WP_Error ( 'already_installed ' , 'Plugin already installed. ' );
372+ }
373+
366374 // Ensure plugin directory exists.
367375 if ( ! is_dir ( WP_PLUGIN_DIR ) ) {
368376 wp_mkdir_p ( WP_PLUGIN_DIR );
369377 }
370378
371- // Validate the destination stays within the plugin directory.
372- $ dest_path = trailingslashit ( WP_PLUGIN_DIR ) . $ dest_filename ;
373- $ real_dest = realpath ( WP_PLUGIN_DIR );
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 ) {
379+ // Validate the destination stays within the plugin directory (prevent directory traversal).
380+ // Since single-file plugins are installed directly in WP_PLUGIN_DIR, we just need to ensure
381+ // the destination resolves to a file within WP_PLUGIN_DIR.
382+ $ real_plugin_dir = realpath ( WP_PLUGIN_DIR );
383+ if ( false === $ real_plugin_dir ) {
378384 return new WP_Error ( 'invalid_path ' , 'Cannot validate plugin directory path. ' );
379385 }
380386
381- // Ensure destination is within plugin directory (prevent directory traversal).
382- if ( 0 !== strpos ( $ real_path , $ real_dest ) ) {
387+ // Verify the constructed path is within the plugin directory.
388+ $ expected_path = trailingslashit ( $ real_plugin_dir ) . $ dest_filename ;
389+ if ( realpath ( dirname ( $ dest_path ) ) !== $ real_plugin_dir ) {
383390 return new WP_Error ( 'invalid_path ' , 'The destination path is outside the plugin directory. ' );
384391 }
385392
@@ -404,13 +411,6 @@ protected function install_from_php_file( $url, $assoc_args ) {
404411
405412 $ plugin_name = $ plugin_data ['Name ' ];
406413
407- // Check if plugin is already installed.
408- if ( file_exists ( $ dest_path ) && ! Utils \get_flag_value ( $ assoc_args , 'force ' ) ) {
409- // Clean up temp file.
410- unlink ( $ temp_file );
411- return new WP_Error ( 'already_installed ' , 'Plugin already installed. ' );
412- }
413-
414414 // Display plugin info.
415415 $ version = ! empty ( $ plugin_data ['Version ' ] ) ? $ plugin_data ['Version ' ] : '' ;
416416 WP_CLI ::log ( sprintf ( 'Installing %s%s ' , $ plugin_name , $ version ? " ( $ version) " : '' ) );
0 commit comments