ServerRunCommand.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Bundle\FrameworkBundle\Command;
  11. use Symfony\Component\Console\Input\InputArgument;
  12. use Symfony\Component\Console\Input\InputInterface;
  13. use Symfony\Component\Console\Input\InputOption;
  14. use Symfony\Component\Console\Output\OutputInterface;
  15. use Symfony\Component\Console\Style\SymfonyStyle;
  16. use Symfony\Component\Process\PhpExecutableFinder;
  17. use Symfony\Component\Process\ProcessBuilder;
  18. /**
  19. * Runs Symfony application using PHP built-in web server.
  20. *
  21. * @author Michał Pipa <michal.pipa.xsolve@gmail.com>
  22. */
  23. class ServerRunCommand extends ServerCommand
  24. {
  25. /**
  26. * {@inheritdoc}
  27. */
  28. protected function configure()
  29. {
  30. $this
  31. ->setDefinition(array(
  32. new InputArgument('address', InputArgument::OPTIONAL, 'Address:port', '127.0.0.1'),
  33. new InputOption('port', 'p', InputOption::VALUE_REQUIRED, 'Address port number', '8000'),
  34. new InputOption('docroot', 'd', InputOption::VALUE_REQUIRED, 'Document root', null),
  35. new InputOption('router', 'r', InputOption::VALUE_REQUIRED, 'Path to custom router script'),
  36. ))
  37. ->setName('server:run')
  38. ->setDescription('Runs PHP built-in web server')
  39. ->setHelp(<<<'EOF'
  40. The <info>%command.name%</info> runs PHP built-in web server:
  41. <info>%command.full_name%</info>
  42. To change default bind address and port use the <info>address</info> argument:
  43. <info>%command.full_name% 127.0.0.1:8080</info>
  44. To change default docroot directory use the <info>--docroot</info> option:
  45. <info>%command.full_name% --docroot=htdocs/</info>
  46. If you have custom docroot directory layout, you can specify your own
  47. router script using <info>--router</info> option:
  48. <info>%command.full_name% --router=app/config/router.php</info>
  49. Specifing a router script is required when the used environment is not "dev",
  50. "prod", or "test".
  51. See also: http://www.php.net/manual/en/features.commandline.webserver.php
  52. EOF
  53. )
  54. ;
  55. }
  56. /**
  57. * {@inheritdoc}
  58. */
  59. protected function execute(InputInterface $input, OutputInterface $output)
  60. {
  61. $io = new SymfonyStyle($input, $output);
  62. $documentRoot = $input->getOption('docroot');
  63. if (null === $documentRoot) {
  64. $documentRoot = $this->getContainer()->getParameter('kernel.root_dir').'/../web';
  65. }
  66. if (!is_dir($documentRoot)) {
  67. $io->error(sprintf('The given document root directory "%s" does not exist', $documentRoot));
  68. return 1;
  69. }
  70. $env = $this->getContainer()->getParameter('kernel.environment');
  71. $address = $input->getArgument('address');
  72. if (false === strpos($address, ':')) {
  73. $address .= ':'.$input->getOption('port');
  74. }
  75. if ($this->isOtherServerProcessRunning($address)) {
  76. $io->error(sprintf('A process is already listening on http://%s.', $address));
  77. return 1;
  78. }
  79. if ('prod' === $env) {
  80. $io->error('Running PHP built-in server in production environment is NOT recommended!');
  81. }
  82. $io->success(sprintf('Server running on http://%s', $address));
  83. $io->comment('Quit the server with CONTROL-C.');
  84. if (null === $builder = $this->createPhpProcessBuilder($io, $address, $input->getOption('router'), $env)) {
  85. return 1;
  86. }
  87. $builder->setWorkingDirectory($documentRoot);
  88. $builder->setTimeout(null);
  89. $process = $builder->getProcess();
  90. if (OutputInterface::VERBOSITY_VERBOSE > $output->getVerbosity()) {
  91. $process->disableOutput();
  92. }
  93. $this
  94. ->getHelper('process')
  95. ->run($output, $process, null, null, OutputInterface::VERBOSITY_VERBOSE);
  96. if (!$process->isSuccessful()) {
  97. $errorMessages = array('Built-in server terminated unexpectedly.');
  98. if ($process->isOutputDisabled()) {
  99. $errorMessages[] = 'Run the command again with -v option for more details.';
  100. }
  101. $io->error($errorMessages);
  102. }
  103. return $process->getExitCode();
  104. }
  105. private function createPhpProcessBuilder(SymfonyStyle $io, $address, $router, $env)
  106. {
  107. $router = $router ?: $this
  108. ->getContainer()
  109. ->get('kernel')
  110. ->locateResource(sprintf('@FrameworkBundle/Resources/config/router_%s.php', $env))
  111. ;
  112. if (!file_exists($router)) {
  113. $io->error(sprintf('The given router script "%s" does not exist.', $router));
  114. return;
  115. }
  116. $router = realpath($router);
  117. $finder = new PhpExecutableFinder();
  118. if (false === $binary = $finder->find()) {
  119. $io->error('Unable to find PHP binary to run server.');
  120. return;
  121. }
  122. return new ProcessBuilder(array($binary, '-S', $address, $router));
  123. }
  124. }