123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- <?php
- /**
- * @package Grav\Console\Cli
- *
- * @copyright Copyright (c) 2015 - 2023 Trilby Media, LLC. All rights reserved.
- * @license MIT License; see LICENSE file for details.
- */
- namespace Grav\Console\Cli;
- use Grav\Common\Utils;
- use Grav\Console\GravCommand;
- use Symfony\Component\Console\Input\InputOption;
- use Symfony\Component\Process\PhpExecutableFinder;
- use Symfony\Component\Process\Process;
- /**
- * Class ServerCommand
- * @package Grav\Console\Cli
- */
- class ServerCommand extends GravCommand
- {
- const SYMFONY_SERVER = 'Symfony Server';
- const PHP_SERVER = 'Built-in PHP Server';
- /** @var string */
- protected $ip;
- /** @var int */
- protected $port;
- /**
- * @return void
- */
- protected function configure(): void
- {
- $this
- ->setName('server')
- ->addOption('port', 'p', InputOption::VALUE_OPTIONAL, 'Preferred HTTP port rather than auto-find (default is 8000-9000')
- ->addOption('symfony', null, InputOption::VALUE_NONE, 'Force using Symfony server')
- ->addOption('php', null, InputOption::VALUE_NONE, 'Force using built-in PHP server')
- ->setDescription("Runs built-in web-server, Symfony first, then tries PHP's")
- ->setHelp("Runs built-in web-server, Symfony first, then tries PHP's");
- }
- /**
- * @return int
- */
- protected function serve(): int
- {
- $input = $this->getInput();
- $io = $this->getIO();
- $io->title('Grav Web Server');
- // Ensure CLI colors are on
- ini_set('cli_server.color', 'on');
- // Options
- $force_symfony = $input->getOption('symfony');
- $force_php = $input->getOption('php');
- // Find PHP
- $executableFinder = new PhpExecutableFinder();
- $php = $executableFinder->find(false);
- $this->ip = '127.0.0.1';
- $this->port = (int)($input->getOption('port') ?? 8000);
- // Get an open port
- while (!$this->portAvailable($this->ip, $this->port)) {
- $this->port++;
- }
- // Setup the commands
- $symfony_cmd = ['symfony', 'server:start', '--ansi', '--port=' . $this->port];
- $php_cmd = [$php, '-S', $this->ip.':'.$this->port, 'system/router.php'];
- $commands = [
- self::SYMFONY_SERVER => $symfony_cmd,
- self::PHP_SERVER => $php_cmd
- ];
- if ($force_symfony) {
- unset($commands[self::PHP_SERVER]);
- } elseif ($force_php) {
- unset($commands[self::SYMFONY_SERVER]);
- }
- $error = 0;
- foreach ($commands as $name => $command) {
- $process = $this->runProcess($name, $command);
- if (!$process) {
- $io->note('Starting ' . $name . '...');
- }
- // Should only get here if there's an error running
- if (!$process->isRunning() && (($name === self::SYMFONY_SERVER && $force_symfony) || ($name === self::PHP_SERVER))) {
- $error = 1;
- $io->error('Could not start ' . $name);
- }
- }
- return $error;
- }
- /**
- * @param string $name
- * @param array $cmd
- * @return Process
- */
- protected function runProcess(string $name, array $cmd): Process
- {
- $io = $this->getIO();
- $process = new Process($cmd);
- $process->setTimeout(0);
- $process->start();
- if ($name === self::SYMFONY_SERVER && Utils::contains($process->getErrorOutput(), 'symfony: not found')) {
- $io->error('The symfony binary could not be found, please install the CLI tools: https://symfony.com/download');
- $io->warning('Falling back to PHP web server...');
- }
- if ($name === self::PHP_SERVER) {
- $io->success('Built-in PHP web server listening on http://' . $this->ip . ':' . $this->port . ' (PHP v' . PHP_VERSION . ')');
- }
- $process->wait(function ($type, $buffer) {
- $this->getIO()->write($buffer);
- });
- return $process;
- }
- /**
- * Simple function test the port
- *
- * @param string $ip
- * @param int $port
- * @return bool
- */
- protected function portAvailable(string $ip, int $port): bool
- {
- $fp = @fsockopen($ip, $port, $errno, $errstr, 0.1);
- if (!$fp) {
- return true;
- }
- fclose($fp);
- return false;
- }
- }
|