self::REQ, 'browser' => true, 'dns' => false]) { global $base_url; // Determine active configuration. $uri = $this->uri($uri, $options); if (!$uri) { return false; } // Remove any leading slashes from the path, since that is what url() expects. $path = ltrim($uri['path'], '/'); // $uri['addr'] is a special field set by runserver_uri() $hostname = $uri['host']; $addr = $uri['addr']; drush_set_context('DRUSH_URI', 'http://' . $hostname . ':' . $uri['port']); // We delete any registered files here, since they are not caught by Ctrl-C. _drush_delete_registered_files(); // We set the effective base_url, since we have now detected the current site, // and need to ensure generated URLs point to our runserver host. // We also pass in the effective base_url to our auto_prepend_script via the // CGI environment. This allows Drupal to generate working URLs to this http // server, whilst finding the correct multisite from the HTTP_HOST header. $base_url = 'http://' . $addr . ':' . $uri['port']; $env['RUNSERVER_BASE_URL'] = $base_url; $link = Url::fromUserInput('/' . $path, ['absolute' => true])->toString(); $this->logger()->notice(dt('HTTP server listening on !addr, port !port (see http://!hostname:!port/!path), serving site !site', ['!addr' => $addr, '!hostname' => $hostname, '!port' => $uri['port'], '!path' => $path, '!site' => drush_get_context('DRUSH_DRUPAL_SITE', 'default')])); // Start php built-in server. if (!empty($path)) { // Start a browser if desired. Include a 2 second delay to allow the server to come up. $this->startBrowser($link, 2); } // Start the server using 'php -S'. $extra = ' "' . DRUSH_BASE_PATH . '/misc/d8-rs-router.php"'; $root = Drush::bootstrapManager()->getRoot(); drush_shell_exec_interactive('cd %s && %s -S ' . $addr . ':' . $uri['port']. $extra, $root, Drush::config()->get('php', 'php')); } /** * Determine the URI to use for this server. */ public function uri($uri, $options) { $drush_default = [ 'host' => '127.0.0.1', 'port' => '8888', 'path' => '', ]; $user_default = $this->parseUri($options['default-server']); $site_default = $this->parseUri($uri); $uri = $this->parseUri($uri); if (is_array($uri)) { // Populate defaults. $uri = $uri + $user_default + $site_default + $drush_default; if (ltrim($uri['path'], '/') == '-') { // Allow a path of a single hyphen to clear a default path. $uri['path'] = ''; } // Determine and set the new URI. $uri['addr'] = $uri['host']; if ($options['dns']) { if (ip2long($uri['host'])) { $uri['host'] = gethostbyaddr($uri['host']); } else { $uri['addr'] = gethostbyname($uri['host']); } } } return $uri; } /** * Parse a URI or partial URI (including just a port, host IP or path). * * @param string $uri * String that can contain partial URI. * * @return array * URI array as returned by parse_url. */ public function parseUri($uri) { if (empty($uri)) { return []; } if ($uri[0] == ':') { // ':port/path' shorthand, insert a placeholder hostname to allow parsing. $uri = 'placeholder-hostname' . $uri; } // FILTER_VALIDATE_IP expects '[' and ']' to be removed from IPv6 addresses. // We check for colon from the right, since IPv6 addresses contain colons. $to_path = trim(substr($uri, 0, strpos($uri, '/')), '[]'); $to_port = trim(substr($uri, 0, strrpos($uri, ':')), '[]'); if (filter_var(trim($uri, '[]'), FILTER_VALIDATE_IP) || filter_var($to_path, FILTER_VALIDATE_IP) || filter_var($to_port, FILTER_VALIDATE_IP)) { // 'IP', 'IP/path' or 'IP:port' shorthand, insert a schema to allow parsing. $uri = 'http://' . $uri; } $uri = parse_url($uri); if (empty($uri)) { throw new \Exception(dt('Invalid argument - should be in the "host:port/path" format, numeric (port only) or non-numeric (path only).')); } if (count($uri) == 1 && isset($uri['path'])) { if (is_numeric($uri['path'])) { // Port only shorthand. $uri['port'] = $uri['path']; unset($uri['path']); } } if (isset($uri['host']) && $uri['host'] == 'placeholder-hostname') { unset($uri['host']); } return $uri; } }