1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Bundle\WebServerBundle;
13
14/**
15 * @author Fabien Potencier <fabien@symfony.com>
16 */
17class WebServerConfig
18{
19    private $hostname;
20    private $port;
21    private $documentRoot;
22    private $env;
23    private $router;
24
25    public function __construct($documentRoot, $env, $address = null, $router = null)
26    {
27        if (!is_dir($documentRoot)) {
28            throw new \InvalidArgumentException(sprintf('The document root directory "%s" does not exist.', $documentRoot));
29        }
30
31        if (null === $file = $this->findFrontController($documentRoot, $env)) {
32            throw new \InvalidArgumentException(sprintf('Unable to find the front controller under "%s" (none of these files exist: "%s").', $documentRoot, implode('", "', $this->getFrontControllerFileNames($env))));
33        }
34
35        $_ENV['APP_FRONT_CONTROLLER'] = $file;
36
37        $this->documentRoot = $documentRoot;
38        $this->env = $env;
39
40        if (null !== $router) {
41            $absoluteRouterPath = realpath($router);
42
43            if (false === $absoluteRouterPath) {
44                throw new \InvalidArgumentException(sprintf('Router script "%s" does not exist.', $router));
45            }
46
47            $this->router = $absoluteRouterPath;
48        } else {
49            $this->router = __DIR__.'/Resources/router.php';
50        }
51
52        if (null === $address) {
53            $this->hostname = '127.0.0.1';
54            $this->port = $this->findBestPort();
55        } elseif (false !== $pos = strrpos($address, ':')) {
56            $this->hostname = substr($address, 0, $pos);
57            if ('*' === $this->hostname) {
58                $this->hostname = '0.0.0.0';
59            }
60            $this->port = substr($address, $pos + 1);
61        } elseif (ctype_digit($address)) {
62            $this->hostname = '127.0.0.1';
63            $this->port = $address;
64        } else {
65            $this->hostname = $address;
66            $this->port = $this->findBestPort();
67        }
68
69        if (!ctype_digit($this->port)) {
70            throw new \InvalidArgumentException(sprintf('Port "%s" is not valid.', $this->port));
71        }
72    }
73
74    public function getDocumentRoot()
75    {
76        return $this->documentRoot;
77    }
78
79    public function getEnv()
80    {
81        return $this->env;
82    }
83
84    public function getRouter()
85    {
86        return $this->router;
87    }
88
89    public function getHostname()
90    {
91        return $this->hostname;
92    }
93
94    public function getPort()
95    {
96        return $this->port;
97    }
98
99    public function getAddress()
100    {
101        return $this->hostname.':'.$this->port;
102    }
103
104    /**
105     * @param string $documentRoot
106     * @param string $env
107     *
108     * @return string|null
109     */
110    private function findFrontController($documentRoot, $env)
111    {
112        $fileNames = $this->getFrontControllerFileNames($env);
113
114        foreach ($fileNames as $fileName) {
115            if (file_exists($documentRoot.'/'.$fileName)) {
116                return $fileName;
117            }
118        }
119
120        return null;
121    }
122
123    /**
124     * @param string $env
125     *
126     * @return array
127     */
128    private function getFrontControllerFileNames($env)
129    {
130        return ['app_'.$env.'.php', 'app.php', 'index_'.$env.'.php', 'index.php'];
131    }
132
133    /**
134     * @return int
135     */
136    private function findBestPort()
137    {
138        $port = 8000;
139        while (false !== $fp = @fsockopen($this->hostname, $port, $errno, $errstr, 1)) {
140            fclose($fp);
141            if ($port++ >= 8100) {
142                throw new \RuntimeException('Unable to find a port available to run the web server.');
143            }
144        }
145
146        return $port;
147    }
148}
149