I am trying to fire up the Ratchet's chat-server.php file which is needed to fire up the socket server from a php file so that whenever a client visits the page the server is started but its not happening. This chat-server.php file needs to be run from the terminal but I am trying to run it from the main page on user visit.
FILE STRUCTURE
./index.php
./config.php
./vendor/(all vendor files)
./src/MyApp/Chat.php
./js/app.js
./inc/connect.php <--Database connection file
./inc/send-message.php
./inc/startServer.php
./inc/bg.php
./inc/serverStatus.txt
./css/index.css
./css/reset.css
./bin/chat-server.php
config.php
<?php
include_once ("./inc/startServer.php");
?>
chat-server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;
if(isset($startNow)){
require dirname(__DIR__) . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Chat()
)
),
8080
);
$server->run();
}
?>
bg.php
<?php
$startNow = 1;
include_once ("../bin/chat-server.php");
?>
startServer.php
<?php
$statusFile = dirname(__FILE__).'/serverStatus.txt';
$status = file_get_contents($statusFile);
if($status == "0"){
function execInBackground($cmd) {
if(substr(php_uname(), 0, 7) == "WINDOWS") {
pclose(popen('start /B ' . $cmd, 'r'));
file_put_contents($statusFile, 1);
}
else {
exec($cmd . ' > /dev/null &');
file_put_contents($statusFile, 1);
}
}
execInBackground("php " . dirname(__FILE__) . "/bg.php");
}
?>
serverStatus.txt
Its default value has been set to 0
NOTE: Updated the code accordingly but doesn't work still now.
Plus I don't have any idea about restarting the server incase of any failure or how to shutdown the server when all clients leave.
When you including files using relative paths you must remember that they are relative to the current running file, not just to current file.
In your case. When you accessing index.php
and including in it config.php
and from then startServer.php
it's all ok, because you are including ./inc/startServer.php
which is right, relative to index.php
.
But than you are including ../inc/serverStatus.txt
, which is not right, because you are still running index.php
and that relative path resolves to /../inc/serverStatus.txt
in other words you are trying to access a file that is one level higher than your DOCUMENT_ROOT
. So you will never get into your if
statement.
You can use a __FILE__
constant which is always resolves to the absolute path of the current file. So you can change your $statusFile
to
$statusFile = dirname(__FILE__) . '/serverStatus.txt';
Next thing is regards your exec()
and popen(pclose())
commands. If you want to execute some command that is not in your PATH
environment variable, than you must specify an absolute path to your file. Because you don't know from which folder it will be started. It may be started from Apache
home dir or maybe started from your user's home dir. It depends on the setup of your PHP
is it sapi
module or is it fcgi
. Anyway, you need to change your execInBackground()
to
execInBackground("php " . dirname(__FILE__) . "/bg.php");
And add some spaces in your commands, like this:
pclose(popen('start /B ' . $cmd, 'r'));
exec($cmd . ' > /dev/null &');
this way you will not have some strange errors that might occur.
In your bg.php you need to change current working directory, like this:
<?php
$startNow = 1;
chdir(dirname(__FILE__));
include_once ("../bin/chat-server.php");
?>
This way, PHP
will find chat-server.php
no matter from what folder you will run it.
BTW, how did you planning to stop your server? =)
UPDATE: Also you have a variable scope issue in your function execInBackground()
. Your function relies on the variable $statusFile
, but this variable defined in the global scope and is not visible inside the function. To make it visible, you must include statement global $statusFile;
in your function before accessing $statusFile
. Like this:
function execInBackground($cmd) {
global $statusFile;
if (false !== stripos(PHP_OS, 'win')) {
pclose(popen('start /B ' . $cmd, 'r'));
file_put_contents($statusFile, 1);
} else {
exec($cmd . ' > /dev/null &');
file_put_contents($statusFile, 1);
}
}
and I've changed the way you are checking the OS, because your approach contained an error.
UPDATE2:
After a bunch of tests, I figured out that when php-script running in the background (under Windows) it can't use "echo()" to write to STDOUT. When it happens, php-script will silently die, with no errors. So change all echo()
's to some log-function.
Change listening port to some other, that is free for sure, like 50000. Because, 8080 is often may be already taken by some web server or other service.
And remember! You can start your chat server only if you have your own server (like VPS/VDS or dedicated server), on the public hosting no one will allow you to open some port for incoming connections for security reasons. On the public servers there are often disabled functions like exec()
, popen()
and similar for the same reasons.