ServeController.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://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 to router script.
  36. * See https://secure.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. if (strpos($address, ':') === false) {
  50. $address = $address . ':' . $this->port;
  51. }
  52. if (!is_dir($documentRoot)) {
  53. $this->stdout("Document root \"$documentRoot\" does not exist.\n", Console::FG_RED);
  54. return self::EXIT_CODE_NO_DOCUMENT_ROOT;
  55. }
  56. if ($this->isAddressTaken($address)) {
  57. $this->stdout("http://$address is taken by another process.\n", Console::FG_RED);
  58. return self::EXIT_CODE_ADDRESS_TAKEN_BY_ANOTHER_PROCESS;
  59. }
  60. if ($this->router !== null && !file_exists($this->router)) {
  61. $this->stdout("Routing file \"$this->router\" does not exist.\n", Console::FG_RED);
  62. return self::EXIT_CODE_NO_ROUTING_FILE;
  63. }
  64. $this->stdout("Server started on http://{$address}/\n");
  65. $this->stdout("Document root is \"{$documentRoot}\"\n");
  66. if ($this->router) {
  67. $this->stdout("Routing file is \"$this->router\"\n");
  68. }
  69. $this->stdout("Quit the server with CTRL-C or COMMAND-C.\n");
  70. passthru('"' . PHP_BINARY . '"' . " -S {$address} -t \"{$documentRoot}\" $this->router");
  71. }
  72. /**
  73. * {@inheritdoc}
  74. */
  75. public function options($actionID)
  76. {
  77. return array_merge(parent::options($actionID), [
  78. 'docroot',
  79. 'router',
  80. 'port',
  81. ]);
  82. }
  83. /**
  84. * {@inheritdoc}
  85. * @since 2.0.8
  86. */
  87. public function optionAliases()
  88. {
  89. return array_merge(parent::optionAliases(), [
  90. 't' => 'docroot',
  91. 'p' => 'port',
  92. 'r' => 'router',
  93. ]);
  94. }
  95. /**
  96. * @param string $address server address
  97. * @return bool if address is already in use
  98. */
  99. protected function isAddressTaken($address)
  100. {
  101. list($hostname, $port) = explode(':', $address);
  102. $fp = @fsockopen($hostname, $port, $errno, $errstr, 3);
  103. if ($fp === false) {
  104. return false;
  105. }
  106. fclose($fp);
  107. return true;
  108. }
  109. }