View source
<?php
namespace Drupal\Core\Command;
use Drupal\Core\Database\ConnectionNotDefinedException;
use Drupal\Core\DrupalKernel;
use Drupal\Core\DrupalKernelInterface;
use Drupal\Core\Site\Settings;
use Drupal\user\Entity\User;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Process\PhpExecutableFinder;
use Symfony\Component\Process\PhpProcess;
use Symfony\Component\Process\Process;
class ServerCommand extends Command {
protected $classLoader;
public function __construct($class_loader) {
parent::__construct('server');
$this->classLoader = $class_loader;
}
protected function configure() {
$this
->setDescription('Starts up a webserver for a site.')
->addOption('host', NULL, InputOption::VALUE_OPTIONAL, 'Provide a host for the server to run on.', '127.0.0.1')
->addOption('port', NULL, InputOption::VALUE_OPTIONAL, 'Provide a port for the server to run on. Will be determined automatically if none supplied.')
->addOption('suppress-login', 's', InputOption::VALUE_NONE, 'Disable opening a login URL in a browser.')
->addUsage('--host localhost --port 8080')
->addUsage('--host my-site.com --port 80');
}
protected function execute(InputInterface $input, OutputInterface $output) {
$io = new SymfonyStyle($input, $output);
$host = $input
->getOption('host');
$port = $input
->getOption('port');
if (!$port) {
$port = $this
->findAvailablePort($host);
}
if (!$port) {
$io
->getErrorStyle()
->error('Unable to automatically determine a port. Use the --port to hardcode an available port.');
}
try {
$kernel = $this
->boot();
} catch (ConnectionNotDefinedException $e) {
$io
->getErrorStyle()
->error("No installation found. Use the 'install' command.");
return 1;
}
return $this
->start($host, $port, $kernel, $input, $io);
}
protected function boot() {
$kernel = new DrupalKernel('prod', $this->classLoader, FALSE);
$kernel::bootEnvironment();
$kernel
->setSitePath($this
->getSitePath());
Settings::initialize($kernel
->getAppRoot(), $kernel
->getSitePath(), $this->classLoader);
$kernel
->boot();
$kernel
->getContainer()
->get('request_stack')
->push(Request::createFromGlobals());
return $kernel;
}
protected function findAvailablePort($host) {
$port = 8888;
while ($port >= 8888 && $port <= 9999) {
$connection = @fsockopen($host, $port);
if (is_resource($connection)) {
fclose($connection);
}
else {
return $port;
}
$port++;
}
return FALSE;
}
protected function openBrowser($url, SymfonyStyle $io) {
$is_windows = defined('PHP_WINDOWS_VERSION_BUILD');
if ($is_windows) {
$cmd = 'start "web" "' . $url . '""';
}
else {
$url = escapeshellarg($url);
}
$is_linux = Process::fromShellCommandline('which xdg-open')
->run();
$is_osx = Process::fromShellCommandline('which open')
->run();
if ($is_linux === 0) {
$cmd = 'xdg-open ' . $url;
}
elseif ($is_osx === 0) {
$cmd = 'open ' . $url;
}
if (empty($cmd)) {
$io
->getErrorStyle()
->error('No suitable browser opening command found, open yourself: ' . $url);
return;
}
if ($io
->isVerbose()) {
$io
->writeln("<info>Browser command:</info> {$cmd}");
}
$cmd = str_replace('"', '\\"', $cmd);
$php = "<?php sleep(2); passthru(\"{$cmd}\"); ?>";
$process = new PhpProcess($php);
$process
->start();
}
protected function getOneTimeLoginUrl() {
$user = User::load(1);
\Drupal::moduleHandler()
->load('user');
return user_pass_reset_url($user);
}
protected function start($host, $port, DrupalKernelInterface $kernel, InputInterface $input, SymfonyStyle $io) {
$finder = new PhpExecutableFinder();
$binary = $finder
->find();
if ($binary === FALSE) {
throw new \RuntimeException('Unable to find the PHP binary.');
}
$io
->writeln("<info>Drupal development server started:</info> <http://{$host}:{$port}>");
$io
->writeln('<info>This server is not meant for production use.</info>');
$one_time_login = "http://{$host}:{$port}{$this->getOneTimeLoginUrl()}/login";
$io
->writeln("<info>One time login url:</info> <{$one_time_login}>");
$io
->writeln('Press Ctrl-C to quit the Drupal development server.');
if (!$input
->getOption('suppress-login')) {
if ($this
->openBrowser("{$one_time_login}?destination=" . urlencode("/"), $io) === 1) {
$io
->error('Error while opening up a one time login URL');
}
}
$process = new Process([
$binary,
'-S',
$host . ':' . $port,
'.ht.router.php',
], $kernel
->getAppRoot(), [], NULL, NULL);
if ($io
->isVerbose()) {
$io
->writeln("<info>Server command:</info> {$process->getCommandLine()}");
}
$descriptors = [];
$descriptors[0] = STDIN;
$descriptors[1] = [
'pipe',
'w',
];
$descriptors[2] = [
'pipe',
'w',
];
$server = proc_open($process
->getCommandLine(), $descriptors, $pipes, $kernel
->getAppRoot());
if (is_resource($server)) {
if ($io
->isVerbose()) {
$io
->writeln('');
}
$server_status = proc_get_status($server);
while ($server_status['running']) {
if ($io
->isVerbose()) {
fpassthru($pipes[2]);
}
sleep(1);
$server_status = proc_get_status($server);
}
}
return proc_close($server);
}
protected function getSitePath() {
return getenv('DRUPAL_DEV_SITE_PATH') ?: 'sites/default';
}
}