1: <?php
2:
3: namespace Alpha\Util\Http;
4:
5: use Alpha\Exception\AlphaException;
6:
7: /**
8: * A utility class controlling the build-in HTTP server in PHP.
9: *
10: * @since 1.2.2
11: *
12: * @author John Collins <dev@alphaframework.org>
13: * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
14: * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
15: * All rights reserved.
16: *
17: * <pre>
18: * Redistribution and use in source and binary forms, with or
19: * without modification, are permitted provided that the
20: * following conditions are met:
21: *
22: * * Redistributions of source code must retain the above
23: * copyright notice, this list of conditions and the
24: * following disclaimer.
25: * * Redistributions in binary form must reproduce the above
26: * copyright notice, this list of conditions and the
27: * following disclaimer in the documentation and/or other
28: * materials provided with the distribution.
29: * * Neither the name of the Alpha Framework nor the names
30: * of its contributors may be used to endorse or promote
31: * products derived from this software without specific
32: * prior written permission.
33: *
34: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
35: * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
36: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
37: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
39: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
46: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47: * </pre>
48: */
49: class PHPServerUtils
50: {
51: /**
52: * Starts a new HTTP server at the hostname and port provided, and returns the process ID (PID) of
53: * the service if it was started successfully.
54: *
55: * @param string $host The hostname or IP address
56: * @param int $port The port number to use
57: * @param string $docRoot The file path to directory containing the documents we want to serve
58: *
59: * @return int The PID of the new server
60: *
61: * @throws AlphaException
62: */
63: public static function start($host, $port, $docRoot)
64: {
65: // we are on Windows
66: if (mb_strtoupper(mb_substr(PHP_OS, 0, 3)) === 'WIN') {
67: // Command that starts the built-in web server
68: $command = sprintf(
69: 'php -S %s:%d -t %s',
70: $host,
71: $port,
72: $docRoot
73: );
74:
75: $descriptorspec = array(
76: 0 => array('pipe', 'r'),
77: 1 => array('pipe', 'w'),
78: );
79:
80: // Execute the command and store the process ID of the parent
81: $prog = proc_open($command, $descriptorspec, $pipes, '.', null);
82: $ppid = proc_get_status($prog)['pid'];
83:
84: // this gets us the process ID of the child (i.e. the server we just started)
85: $output = array_filter(explode(' ', shell_exec("wmic process get parentprocessid,processid | find \"$ppid\"")));
86: array_pop($output);
87: $pid = end($output);
88: } else { // we are on Linux
89: // Command that starts the built-in web server
90: $command = sprintf(
91: 'php -S %s:%d -t %s >/dev/null 2>&1 & echo $!',
92: $host,
93: $port,
94: $docRoot
95: );
96:
97: // Execute the command and store the process ID
98: $output = array();
99: exec($command, $output);
100: $pid = (int) $output[0];
101: }
102:
103: if (!isset($pid)) {
104: throw new AlphaException("Could not start the build-in PHP server [$host:$port] using the doc root [$docRoot]");
105: } else {
106: return $pid;
107: }
108: }
109:
110: /**
111: * Stops the server running locally under the process ID (PID) provided.
112: *
113: * @param int $PID The PID of the running server we want to stop
114: */
115: public static function stop($PID)
116: {
117: // we are on Windows
118: if (mb_strtoupper(mb_substr(PHP_OS, 0, 3)) === 'WIN') {
119: exec("taskkill /F /pid $PID");
120: } else { // we are on Linux
121: exec("kill -9 $PID");
122: }
123: }
124:
125: /**
126: * Checks to see if there is a server running locally under the process ID (PID) provided.
127: *
128: * @param int $PID The PID of the running server we want to check
129: *
130: * @return bool True if there is a server process running under the PID, false otherwise
131: */
132: public static function status($PID)
133: {
134: $output = array();
135: // we are on Windows
136: if (mb_strtoupper(mb_substr(PHP_OS, 0, 3)) === 'WIN') {
137: exec("tasklist /fi \"PID eq $PID\"", $output);
138:
139: if (isset($output[0]) && $output[0] == 'INFO: No tasks are running which match the specified criteria.') {
140: return false;
141: } else {
142: return true;
143: }
144: } else { // we are on Linux
145: exec("ps -ef | grep $PID | grep -v grep", $output);
146:
147: if (count($output) == 0) {
148: return false;
149: } else {
150: return true;
151: }
152: }
153: }
154: }
155: