ServeController.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. <?php
  2. /**
  3. * @link https://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license https://www.yiiframework.com/license/
  6. */
  7. namespace yii\console\controllers;
  8. use Yii;
  9. use yii\console\Controller;
  10. use yii\helpers\Console;
  11. /**
  12. * Runs PHP built-in web server.
  13. *
  14. * In order to access server from remote machines use 0.0.0.0:8000. That is especially useful when running server in
  15. * a virtual machine.
  16. *
  17. * @author Alexander Makarov <sam@rmcreative.ru>
  18. * @since 2.0.7
  19. */
  20. class ServeController extends Controller
  21. {
  22. const EXIT_CODE_NO_DOCUMENT_ROOT = 2;
  23. const EXIT_CODE_NO_ROUTING_FILE = 3;
  24. const EXIT_CODE_ADDRESS_TAKEN_BY_ANOTHER_SERVER = 4;
  25. const EXIT_CODE_ADDRESS_TAKEN_BY_ANOTHER_PROCESS = 5;
  26. /**
  27. * @var int port to serve on.
  28. */
  29. public $port = 8080;
  30. /**
  31. * @var string path or [path alias](guide:concept-aliases) to directory to serve
  32. */
  33. public $docroot = '@app/web';
  34. /**
  35. * @var string path or [path alias](guide:concept-aliases) to router script.
  36. * See https://www.php.net/manual/en/features.commandline.webserver.php
  37. */
  38. public $router;
  39. /**
  40. * Runs PHP built-in web server.
  41. *
  42. * @param string $address address to serve on. Either "host" or "host:port".
  43. *
  44. * @return int
  45. */
  46. public function actionIndex($address = 'localhost')
  47. {
  48. $documentRoot = Yii::getAlias($this->docroot);
  49. $router = $this->router !== null ? Yii::getAlias($this->router) : null;
  50. if (strpos($address, ':') === false) {
  51. $address = $address . ':' . $this->port;
  52. }
  53. if (!is_dir($documentRoot)) {
  54. $this->stdout("Document root \"$documentRoot\" does not exist.\n", Console::FG_RED);
  55. return self::EXIT_CODE_NO_DOCUMENT_ROOT;
  56. }
  57. if ($this->isAddressTaken($address)) {
  58. $this->stdout("http://$address is taken by another process.\n", Console::FG_RED);
  59. return self::EXIT_CODE_ADDRESS_TAKEN_BY_ANOTHER_PROCESS;
  60. }
  61. if ($this->router !== null && !file_exists($router)) {
  62. $this->stdout("Routing file \"$router\" does not exist.\n", Console::FG_RED);
  63. return self::EXIT_CODE_NO_ROUTING_FILE;
  64. }
  65. $this->stdout("Server started on http://{$address}/\n");
  66. $this->stdout("Document root is \"{$documentRoot}\"\n");
  67. if ($this->router) {
  68. $this->stdout("Routing file is \"$router\"\n");
  69. }
  70. $this->stdout("Quit the server with CTRL-C or COMMAND-C.\n");
  71. $command = '"' . PHP_BINARY . '"' . " -S {$address} -t \"{$documentRoot}\"";
  72. if ($this->router !== null && $router !== '') {
  73. $command .= " -r \"{$router}\"";
  74. }
  75. $this->runCommand($command);
  76. }
  77. /**
  78. * {@inheritdoc}
  79. */
  80. public function options($actionID)
  81. {
  82. return array_merge(parent::options($actionID), [
  83. 'docroot',
  84. 'router',
  85. 'port',
  86. ]);
  87. }
  88. /**
  89. * {@inheritdoc}
  90. * @since 2.0.8
  91. */
  92. public function optionAliases()
  93. {
  94. return array_merge(parent::optionAliases(), [
  95. 't' => 'docroot',
  96. 'p' => 'port',
  97. 'r' => 'router',
  98. ]);
  99. }
  100. /**
  101. * @param string $address server address
  102. * @return bool if address is already in use
  103. */
  104. protected function isAddressTaken($address)
  105. {
  106. list($hostname, $port) = explode(':', $address);
  107. $fp = @fsockopen($hostname, $port, $errno, $errstr, 3);
  108. if ($fp === false) {
  109. return false;
  110. }
  111. fclose($fp);
  112. return true;
  113. }
  114. protected function runCommand($command)
  115. {
  116. passthru($command);
  117. }
  118. }