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
64 changes: 64 additions & 0 deletions features/site-create.feature
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,67 @@ Feature: Create a new site on a WP multisite
| blog_id | url |
| 1 | https://example.com/ |
| 2 | http://testsite.example.com/ |

Scenario: Error when invalid slug containing special characters is provided
Given a WP multisite install

When I try `wp site create --slug='x$(touch /tmp/wpcli_poc)'`
Then STDERR should be:
"""
Error: Slug may only contain letters, numbers, and dashes.
"""
And the return code should be 1
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Scenario: Error when invalid domain format is provided in site-url
Given a WP multisite install

When I try `wp site create --site-url='http://invalid$domain.com/site'`
Then STDERR should be:
"""
Error: Invalid domain format in --site-url.
"""
And the return code should be 1

Scenario: Error when malformed domain with double dots is provided in site-url
Given a WP multisite install

When I try `wp site create --site-url='http://example..com/site'`
Then STDERR should be:
"""
Error: Invalid domain format in --site-url.
"""
And the return code should be 1

Scenario: Error when invalid path format is provided in site-url
Given a WP multisite install

When I try `wp site create --site-url='http://example.com/invalid_path'`
Then STDERR should be:
"""
Error: Invalid path format in --site-url.
"""
And the return code should be 1

Scenario: Error when duplicate slashes are provided in site-url path
Given a WP multisite install

When I try `wp site create --site-url='http://example.com//foo'`
Then STDERR should be:
"""
Error: Invalid path format in --site-url.
"""
And the return code should be 1

Scenario: Error when unsupported components are provided in site-url
Given a WP multisite install

When I try `wp site create --site-url='http://example.com:8080/site'`
Then STDERR should be:
"""
Error: Invalid URL format. User credentials, ports, query parameters, and fragments are not supported in --site-url.
"""
And the return code should be 1




11 changes: 11 additions & 0 deletions features/site-generate.feature
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,14 @@ Feature: Generate new WordPress sites
"""
And STDOUT should be empty
And the return code should be 1

Scenario: Error when invalid slug containing special characters is provided
Given a WP multisite install

When I try `wp site generate --slug='x$(touch /tmp/wpcli_poc)'`
Then STDERR should be:
"""
Error: Slug may only contain letters, numbers, and dashes.
"""
And the return code should be 1

45 changes: 38 additions & 7 deletions src/Site_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ public function create( $args, $assoc_args ) {

if ( $has_site_url ) {
$parsed_url = wp_parse_url( $assoc_args['site-url'] );
if ( ! isset( $parsed_url['host'] ) ) {
if ( ! is_array( $parsed_url ) || ! isset( $parsed_url['host'] ) || ! is_string( $parsed_url['host'] ) ) {
WP_CLI::error( 'Invalid URL format. Please provide a valid URL (e.g., http://site.example.com).' );
}

Expand All @@ -588,9 +588,33 @@ public function create( $args, $assoc_args ) {
WP_CLI::error( 'Invalid URL scheme. Only http and https schemes are supported.' );
}

// Reject unsupported URL components (user, pass, port, query, fragment)
$unsupported = array_intersect_key( $parsed_url, array_flip( [ 'user', 'pass', 'port', 'query', 'fragment' ] ) );
if ( ! empty( $unsupported ) ) {
WP_CLI::error( 'Invalid URL format. User credentials, ports, query parameters, and fragments are not supported in --site-url.' );
}

// Sanitize domain and path
$raw_path = isset( $parsed_url['path'] ) && is_string( $parsed_url['path'] ) ? $parsed_url['path'] : '/';
$custom_domain = sanitize_text_field( $parsed_url['host'] );
$custom_path = isset( $parsed_url['path'] ) ? sanitize_text_field( '/' . ltrim( $parsed_url['path'], '/' ) ) : '/';
$custom_path = sanitize_text_field( '/' . ltrim( $raw_path, '/' ) );

$domain_parts = explode( '.', $custom_domain );
$valid_domain = true;
foreach ( $domain_parts as $part ) {
if ( '' === $part || ! preg_match( '/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/', $part ) ) {
$valid_domain = false;
break;
}
}

if ( ! $valid_domain ) {
WP_CLI::error( 'Invalid domain format in --site-url.' );
}

if ( ! preg_match( '|^[a-zA-Z0-9/-]+$|', $custom_path ) || false !== strpos( $raw_path, '//' ) ) {
WP_CLI::error( 'Invalid path format in --site-url.' );
}

// Ensure path ends with /
if ( '/' !== substr( $custom_path, -1 ) ) {
Expand All @@ -613,7 +637,12 @@ public function create( $args, $assoc_args ) {
$base = strtolower( $base );
} else {
// For subdirectory installs, derive slug from the last part of the path.
$path_parts = array_filter( explode( '/', trim( $custom_path, '/' ) ) );
$path_parts = array_filter(
explode( '/', trim( $custom_path, '/' ) ),
function ( $part ) {
return '' !== $part;
}
);
$base = (string) array_pop( $path_parts );

// If base is empty (root path), require explicit slug.
Expand Down Expand Up @@ -651,9 +680,10 @@ public function create( $args, $assoc_args ) {
$public = ! Utils\get_flag_value( $assoc_args, 'private' );

// Sanitize
if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) {
$base = strtolower( $base );
if ( ! preg_match( '|^([a-zA-Z0-9-])+$|D', $base ) ) {
WP_CLI::error( 'Slug may only contain letters, numbers, and dashes.' );
}
$base = strtolower( $base );

// If not a subdomain install, make sure the domain isn't a reserved word
if ( ! is_subdomain_install() ) {
Expand Down Expand Up @@ -792,9 +822,10 @@ public function generate( $args, $assoc_args ) {

// Base.
$base = $assoc_args['slug'];
if ( preg_match( '|^([a-zA-Z0-9-])+$|', $base ) ) {
$base = strtolower( $base );
if ( ! preg_match( '|^([a-zA-Z0-9-])+$|D', $base ) ) {
WP_CLI::error( 'Slug may only contain letters, numbers, and dashes.' );
}
$base = strtolower( $base );

$is_subdomain_install = is_subdomain_install();
// If not a subdomain install, make sure the domain isn't a reserved word
Expand Down
Loading