HEX
Server: nginx
System: Linux pool195-106-36.bur.atomicsites.net 6.12.57+deb12-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.57-1~bpo12+1 (2025-11-17) x86_64
User: (0)
PHP: 8.3.32
Disabled: pcntl_fork
Upload Files
File: /wordpress/plugins/wp-cloud-client/1.1.0/src/Handler/NetworkInstallHandler.php
<?php

declare(strict_types=1);

namespace VPlugins\WPCloudClient\Handler;

use VPlugins\WPCloudClient\Support\Logger;

/**
 * Installs a WordPress multisite network.
 *
 * WP_ALLOW_MULTISITE must already be defined and true in wp-config.php
 * before this action is called. After a successful response, the caller
 * is responsible for writing the remaining multisite constants
 * (MULTISITE, SUBDOMAIN_INSTALL, DOMAIN_CURRENT_SITE, etc.) to wp-config.php.
 *
 * See: https://github.com/vendasta/wsp-bootstrapper/blob/master/src/add-ons/api/wsp-network-install.php
 * Mirrored contract: email + optional domain/site_name in → installed bool + domain out.
 */
final class NetworkInstallHandler extends AbstractHandler {

	/**
	 * Class constructor.
	 *
	 * @param Logger $logger Logger instance.
	 */
	public function __construct( private readonly Logger $logger ) {}

	/**
	 * Return the action name.
	 *
	 * @return string Action name.
	 */
	public function action(): string {
		return 'network_install';
	}

	/**
	 * Install the WordPress multisite network.
	 *
	 * Requires WP_ALLOW_MULTISITE to be defined and true in wp-config.php.
	 *
	 * @param array{email: string, domain?: string, site_name?: string} $params Action parameters.
	 * @return array{installed: bool, domain: string, message?: string} Install result.
	 *
	 * @throws \InvalidArgumentException If email is missing or invalid, or domain resolves to empty.
	 * @throws \RuntimeException         If WP_ALLOW_MULTISITE is off, a network is already installed
	 *                                   on a different domain, admin user cannot be created,
	 *                                   or populate_network() fails.
	 */
	public function execute( array $params ): array {
		$this->requireParams( $params, 'email' );

		if ( ! \defined( 'WP_ALLOW_MULTISITE' ) || ! \WP_ALLOW_MULTISITE ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
			throw new \RuntimeException( 'Multisite is not enabled. Set WP_ALLOW_MULTISITE to true in wp-config.php.' );
		}

		if ( ! \function_exists( 'install_network' ) ) {
			require_once \ABSPATH . 'wp-admin/includes/network.php';
		}
		if ( ! \function_exists( 'dbDelta' ) ) {
			require_once \ABSPATH . 'wp-admin/includes/upgrade.php';
		}

		$email = \sanitize_email( $params['email'] );
		if ( '' === $email ) {
			throw new \InvalidArgumentException( 'A valid admin email is required.' );
		}

		$domain = isset( $params['domain'] )
			? \sanitize_text_field( (string) $params['domain'] )
			: (string) \wp_parse_url( (string) \get_option( 'siteurl' ), PHP_URL_HOST );

		if ( '' === $domain ) {
			throw new \InvalidArgumentException( 'A valid domain is required.' );
		}

		$siteName  = \sanitize_text_field( $params['site_name'] ?? \get_bloginfo( 'name' ) );
		$normalize = static fn ( string $d ): string => \strtolower( \rtrim( $d, '.' ) );

		// Populate global multisite table references before calling network_domain_check().
		global $wpdb;
		foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) {
			$wpdb->$table = $prefixed_table;
		}

		$existingDomain = \network_domain_check();

		if ( $existingDomain ) {
			if ( $normalize( $existingDomain ) === $normalize( $domain ) ) {
				$this->logger->info( 'NetworkInstall: network already installed, skipping', [ 'domain' => $existingDomain ] );
				return [
					'installed' => false,
					'message'   => 'Network already installed with this domain.',
					'domain'    => $existingDomain,
				];
			}
			throw new \RuntimeException(
				\sprintf( 'A network is already installed with domain: %s', $existingDomain )
			);
		}

		$this->ensureAdminUser( $email );

		$this->logger->info(
			'NetworkInstall: installing network',
			[
				'domain' => $domain,
				'email'  => $email,
			]
		);

		\install_network();

		$result = \populate_network( 1, $domain, $email, $siteName, '/', false );

		if ( \is_wp_error( $result ) ) {
			$this->logger->error(
				'NetworkInstall: populate_network failed',
				[
					'domain' => $domain,
					'code'   => $result->get_error_code(),
					'error'  => $result->get_error_message(),
				]
			);
			throw new \RuntimeException(
				\sprintf( '[%s] %s', $result->get_error_code(), $result->get_error_message() )
			);
		}

		$installedDomain = (string) \network_domain_check();
		$this->logger->info( 'NetworkInstall: network installed', [ 'domain' => $installedDomain ] );

		return [
			'installed' => true,
			'domain'    => $installedDomain,
		];
	}

	/**
	 * Ensure a WordPress admin user exists for the given email.
	 *
	 * Throws if the user already exists but is not an administrator, to prevent
	 * silent privilege promotion of unrelated accounts.
	 * The generated password is intentionally discarded — access is via OneClickLogin.
	 *
	 * @param string $email Admin email address.
	 * @return void
	 *
	 * @throws \RuntimeException If the user is not an admin, or user creation fails.
	 */
	private function ensureAdminUser( string $email ): void {
		$user = \get_user_by( 'email', $email );

		if ( $user ) {
			if ( ! \in_array( 'administrator', (array) $user->roles, true ) ) {
				$this->logger->warning(
					'NetworkInstall: refusing to promote existing non-admin user',
					[
						'email' => $email,
						'roles' => (array) $user->roles,
					]
				);
				throw new \RuntimeException(
					\sprintf( 'User %s already exists and is not an administrator; refusing to promote.', $email )
				);
			}
			return;
		}

		$login  = \sanitize_user( (string) \strstr( $email, '@', true ) );
		$userId = \wpmu_create_user( $login, \wp_generate_password(), $email );

		if ( false === $userId || \is_wp_error( $userId ) ) {
			$message = \is_wp_error( $userId ) ? $userId->get_error_message() : 'wpmu_create_user returned false';
			$this->logger->error(
				'NetworkInstall: failed to create admin user',
				[
					'email' => $email,
					'error' => $message,
				]
			);
			throw new \RuntimeException(
				\sprintf( 'Failed to create admin user for %s: %s', $email, $message )
			);
		}
	}
}