Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .distignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
.travis.yml
behat.yml
circle.yml
phpcs.xml.dist
phpunit.xml.dist
bin/
features/
utils/
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
.DS_Store
.phpcs.xml
wp-cli.local.yml
node_modules/
vendor/
*.zip
*.tar.gz
composer.lock
phpunit.xml
phpcs.xml
*.log
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"wp-cli/wp-cli": "^2"
},
"require-dev": {
"wp-cli/wp-cli-tests": "^2.0.7"
"wp-cli/wp-cli-tests": "^2.1"
},
"config": {
"process-timeout": 7200,
Expand Down
58 changes: 58 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0"?>
<ruleset name="WP-CLI-server">
<description>Custom ruleset for WP-CLI server-command</description>

<!--
#############################################################################
COMMAND LINE ARGUMENTS
For help understanding this file: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml
For help using PHPCS: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage
#############################################################################
-->

<!-- What to scan. -->
<file>.</file>

<!-- Show progress. -->
<arg value="p"/>

<!-- Strip the filepaths down to the relevant bit. -->
<arg name="basepath" value="./"/>

<!-- Check up to 8 files simultaneously. -->
<arg name="parallel" value="8"/>

<!--
#############################################################################
USE THE WP_CLI_CS RULESET
#############################################################################
-->

<rule ref="WP_CLI_CS"/>

<!--
#############################################################################
PROJECT SPECIFIC CONFIGURATION FOR SNIFFS
#############################################################################
-->

<!-- For help understanding the `testVersion` configuration setting:
https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions -->
<config name="testVersion" value="5.4-"/>

<!-- Verify that everything in the global namespace is either namespaced or prefixed.
See: https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Customizable-sniff-properties#naming-conventions-prefix-everything-in-the-global-namespace -->
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
<properties>
<property name="prefixes" type="array">
<element value="WP_CLI\Router"/><!-- Namespaces. -->
<element value="wpcli_server"/><!-- Global variables and such. -->
</property>
</properties>
</rule>

<!-- Exclude existing classes from the prefix rule as it would break BC to prefix them now. -->
<rule ref="WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound">
<exclude-pattern>*/src/Server_Command\.php$</exclude-pattern>
</rule>
</ruleset>
102 changes: 62 additions & 40 deletions router.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@
*
* We duplicate it because WordPress is not loaded yet.
*/
function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) {
function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
global $wp_filter, $merged_filters;

$idx = _wp_filter_build_unique_id($tag, $function_to_add, $priority);
$wp_filter[$tag][$priority][$idx] = array('function' => $function_to_add, 'accepted_args' => $accepted_args);
$idx = _wp_filter_build_unique_id( $tag, $function_to_add, $priority );

// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$wp_filter[ $tag ][ $priority ][ $idx ] = array(
'function' => $function_to_add,
'accepted_args' => $accepted_args,
);
unset( $merged_filters[ $tag ] );
return true;
}
Expand All @@ -22,30 +27,35 @@ function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1)
*
* We duplicate it because WordPress is not loaded yet.
*/
function _wp_filter_build_unique_id($tag, $function, $priority) {
function _wp_filter_build_unique_id( $tag, $function, $priority ) {
global $wp_filter;
static $filter_id_count = 0;

if ( is_string($function) )
if ( is_string( $function ) ) {
return $function;
}

if ( is_object($function) ) {
if ( is_object( $function ) ) {
// Closures are currently implemented as objects
$function = array( $function, '' );
} else {
$function = (array) $function;
}

if (is_object($function[0]) ) {
if ( is_object( $function[0] ) ) {
// Object Class Calling
if ( function_exists('spl_object_hash') ) {
return spl_object_hash($function[0]) . $function[1];
if ( function_exists( 'spl_object_hash' ) ) {
return spl_object_hash( $function[0] ) . $function[1];
} else {
$obj_idx = get_class($function[0]).$function[1];
if ( !isset($function[0]->wp_filter_id) ) {
if ( false === $priority )
$obj_idx = get_class( $function[0] ) . $function[1];
if ( ! isset( $function[0]->wp_filter_id ) ) {
if ( false === $priority ) {
return false;
$obj_idx .= isset($wp_filter[$tag][$priority]) ? count((array)$wp_filter[$tag][$priority]) : $filter_id_count;
}
$obj_idx .= isset( $wp_filter[ $tag ][ $priority ] )
? count( (array) $wp_filter[ $tag ][ $priority ] )
: $filter_id_count;

$function[0]->wp_filter_id = $filter_id_count;
++$filter_id_count;
} else {
Expand All @@ -54,60 +64,72 @@ function _wp_filter_build_unique_id($tag, $function, $priority) {

return $obj_idx;
}
} else if ( is_string($function[0]) ) {
} elseif ( is_string( $function[0] ) ) {
// Static Calling
return $function[0] . '::' . $function[1];
}
}

function _get_full_host( $url ) {
// phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url
$parsed_url = parse_url( $url );

$host = $parsed_url['host'];
if ( isset( $parsed_url['port'] ) && $parsed_url['port'] != 80 )
if ( isset( $parsed_url['port'] ) && 80 !== $parsed_url['port'] ) {
$host .= ':' . $parsed_url['port'];
}

return $host;
}

// We need to trick WordPress into using the URL set by `wp server`, especially on multisite.
add_filter( 'option_home', function ( $url ) {
$GLOBALS['_wp_cli_original_url'] = $url;

return 'http://' . $_SERVER['HTTP_HOST'];
}, 20 );

add_filter( 'option_siteurl', function ( $url ) {
if ( !isset( $GLOBALS['_wp_cli_original_url'] ) )
get_option('home'); // trigger the option_home filter
add_filter(
'option_home',
function ( $url ) {
$GLOBALS['wpcli_server_original_url'] = $url;

return 'http://' . $_SERVER['HTTP_HOST'];
},
20
);

add_filter(
'option_siteurl',
function ( $url ) {
if ( ! isset( $GLOBALS['wpcli_server_original_url'] ) ) {
get_option( 'home' ); // trigger the option_home filter
}

$home_url_host = _get_full_host( $GLOBALS['_wp_cli_original_url'] );
$site_url_host = _get_full_host( $url );
$home_url_host = _get_full_host( $GLOBALS['wpcli_server_original_url'] );
$site_url_host = _get_full_host( $url );

if ( $site_url_host == $home_url_host ) {
$url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url );
}
if ( $site_url_host === $home_url_host ) {
$url = str_replace( $site_url_host, $_SERVER['HTTP_HOST'], $url );
}

return $url;
}, 20 );
return $url;
},
20
);

$_SERVER['SERVER_ADDR'] = gethostbyname( $_SERVER['SERVER_NAME'] );
$root = $_SERVER['DOCUMENT_ROOT'];
$path = '/'. ltrim( parse_url( urldecode( $_SERVER['REQUEST_URI'] ) )['path'], '/' );
$wpcli_server_root = $_SERVER['DOCUMENT_ROOT'];
// phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url
$wpcli_server_path = '/' . ltrim( parse_url( urldecode( $_SERVER['REQUEST_URI'] ) )['path'], '/' );

if ( file_exists( $root.$path ) ) {
if ( is_dir( $root.$path ) && substr( $path, -1 ) !== '/' ) {
header( "Location: $path/" );
if ( file_exists( $wpcli_server_root . $wpcli_server_path ) ) {
if ( is_dir( $wpcli_server_root . $wpcli_server_path ) && substr( $wpcli_server_path, -1 ) !== '/' ) {
header( "Location: $wpcli_server_path/" );
exit;
}

if ( strpos( $path, '.php' ) !== false ) {
chdir( dirname( $root.$path ) );
require_once $root.$path;
if ( strpos( $wpcli_server_path, '.php' ) !== false ) {
chdir( dirname( $wpcli_server_root . $wpcli_server_path ) );
require_once $wpcli_server_root . $wpcli_server_path;
} else {
return false;
}
} else {
chdir( $root );
chdir( $wpcli_server_root );
require_once 'index.php';
}
26 changes: 15 additions & 11 deletions server-command.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@
return;
}

$autoload = dirname( __FILE__ ) . '/vendor/autoload.php';
if ( file_exists( $autoload ) ) {
require_once $autoload;
$wpcli_server_autoloader = dirname( __FILE__ ) . '/vendor/autoload.php';
if ( file_exists( $wpcli_server_autoloader ) ) {
require_once $wpcli_server_autoloader;
}

WP_CLI::add_command( 'server', 'Server_Command', array(
'before_invoke' => function() {
$min_version = '5.4';
if ( version_compare( PHP_VERSION, $min_version, '<' ) ) {
WP_CLI::error( "The `wp server` command requires PHP {$min_version} or newer." );
}
}
) );
WP_CLI::add_command(
'server',
'Server_Command',
array(
'before_invoke' => function() {
$min_version = '5.4';
if ( version_compare( PHP_VERSION, $min_version, '<' ) ) {
WP_CLI::error( "The `wp server` command requires PHP {$min_version} or newer." );
}
},
)
);
31 changes: 17 additions & 14 deletions src/Server_Command.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?php

use WP_CLI\Utils;

class Server_Command extends WP_CLI_Command {

/**
Expand Down Expand Up @@ -57,49 +59,50 @@ class Server_Command extends WP_CLI_Command {
*
* @when before_wp_load
*/
function __invoke( $_, $assoc_args ) {
$defaults = array(
'host' => 'localhost',
'port' => 8080,
public function __invoke( $_, $assoc_args ) {
$defaults = array(
'host' => 'localhost',
'port' => 8080,
'docroot' => ! is_null( WP_CLI::get_runner()->config['path'] ) ? WP_CLI::get_runner()->config['path'] : false,
'config' => get_cfg_var( 'cfg_file_path' )
'config' => get_cfg_var( 'cfg_file_path' ),
);
$assoc_args = array_merge( $defaults, $assoc_args );

$docroot = $assoc_args['docroot'];

if ( !$docroot ) {
if ( ! $docroot ) {
$config_path = WP_CLI::get_runner()->project_config_path;

if ( !$config_path ) {
if ( ! $config_path ) {
$docroot = ABSPATH;
} else {
$docroot = dirname( $config_path );
}
}

// Get the path to the router file
$command_root = WP_CLI\Utils\phar_safe_path( dirname( __DIR__ ) );
$router_path = $command_root . '/router.php';
$command_root = Utils\phar_safe_path( dirname( __DIR__ ) );
$router_path = $command_root . '/router.php';
if ( ! file_exists( $router_path ) ) {
WP_CLI::error( "Couldn't find router.php" );
}
$cmd = \WP_CLI\Utils\esc_cmd( '%s -S %s -t %s -c %s %s',
$cmd = Utils\esc_cmd(
'%s -S %s -t %s -c %s %s',
WP_CLI::get_php_binary(),
$assoc_args['host'] . ':' . $assoc_args['port'],
$docroot,
$assoc_args['config'],
\WP_CLI\Utils\extract_from_phar( $router_path )
Utils\extract_from_phar( $router_path )
);

$descriptors = array( STDIN, STDOUT, STDERR );

// https://bugs.php.net/bug.php?id=60181
$options = array();
if ( \WP_CLI\Utils\is_windows() ) {
$options["bypass_shell"] = TRUE;
if ( Utils\is_windows() ) {
$options['bypass_shell'] = true;
}

exit( proc_close( proc_open( $cmd, $descriptors, $pipes, NULL, NULL, $options ) ) );
exit( proc_close( proc_open( $cmd, $descriptors, $pipes, null, null, $options ) ) );
}
}