en | ru

WSPHP

WSPHP is small and fast server written in C++ providing developers with a tool to create bi-directional applications between clients and servers over Websockets.

Developers may continue using PHP as usual. No special knowledge is required.

Hello, world

Here are simple steps to create your first Websockets application in PHP

test1.js
ws = new WebSocket( "ws://127.0.0.1:30403" );
/* You may mask IP address and port using Nginx */

ws.onopen = onWebsocketConnected;
ws.onmessage = onWebsocketReceived;

function onWebsocketConnected(e)
{
ws.send("my_name_is=John");
}

function onWebsocketReceived(e)
{
alert(e.data);
}
app1.php
if(isset($_GET['my_name_is']))
{
echo "<WSContent>\n";
echo "<WSReply>Hello, " . $_GET['my_name_is'] . "</WSReply>";
echo "</WSContent>\n";
}

In java script we send query string my_name_is=John to server.
Server wraps its responce with special tags <WSReply>.
Once received, browser will show the alert window with greeting "Hello, John".

You expected complex source code with heavy classes included? Sorry for dissapointing...

The basics

After WSPHP is executed, it opens TCP port and begins listening for incoming connections.
We recommend to use Nginx or some other proxy server between WSPHP and the Internet. This would allow to mask WSPHP listening port, and provide first-level caching.
When websocket request is received, WSPHP calls the only PHP file: app.php and passes there some additional data.
Note, your regular PHP scripts should be working as usual (other.php on a picture).
We will talk about cron.php a little bit later.

All input data can be accessed in PHP via $_GET (or $_REQUEST) variable as usual.
PHP script runs as soon as Websocket frame is received by server.
After PHP script executed, it outputs simple XML to stdout.
As usual, PHP script dies after execution. As usual, you can use sessions to store the data.
Websocket connection remains open, and the data can be received from remote client or sent to remote client when needed.

Cron job

If you ever need to send some data to client, Cron Job is the tool for you.
Cron.php is executed periodically, and you may specify how often to run it.
Within cron.php you may send any data to any client.

cron2.php
echo "<WSContent>\n";
echo "<WSSend to='all'>Current time is:" . date('r') . "</WSSend>";
echo "<WSSend to='W0123456S'>Today is " . date('z') . "th day of the year.</WSSend>";
echo "</WSContent>\n";

In this example we send current time to all clients. In addition, we send day of the year to client with session id W0123456S.

Sessions

Unique string is assigned to every websocket connection. This string is stored in $_SERVER['WSPHP_SESSION'] variable. Standard PHP sessions work as usual. You only need to setup session ID with this tiny trick:

app3.php
session_id( $_SERVER['WSPHP_SESSION'] );
session_start();

/* Use $_SESSION variable as usual. */

Note. This trick works within cron.php as well.

Server variables

The following variables are set before PHP script is executed:

VariableTypeDescription
WSPHP_SESSIONstringCurrent session name
WSPHP_IPstringIP address of the client
WSPHP_ALIVEintegerConnection live time in seconds
WSPHP_LAST_OPintegerTime in seconds since last data received from client.
WSPHP_HOSTstring"Host" variable (extracted from HTTP headers)
WSPHP_ORIGINstring"Origin" variable (extracted from HTTP headers)
WSPHP_CRONintegerSet to 1 for every cron job. Undefined otherwise.
WSPHP_FIRST_CALLintegerSet to 1 for first PHP call since WSPHP execution. Undefined otherwise.

Notes:
IP address is extracted from the following sources: X-Forwarded-For header, X-Real-IP header, TCP connection information, which ever comes first.
WSPHP_FIRST_CALL is set for both application and cron script.

XML format

WSPHP server understands the following XML format.

XML
<WSContent>
<WSReply>A string to be send to requesting client</WSReply>
<WSSend to="list of clients">A string to be send to specified clients</WSSend>
<WSClose>Client list</WSClose>
</WSContent>
WSReplyThe text between these tags is sent to the requesting client as is. This tag should not appear in cron job,as there is no requesting client there. Use WSSend instead.
WSSendThe text between these tags is sent to list of clients. The list must be comma separated, and must consist of client sessions. In order to send something to all clients, use "All" keyword. Multiple WSSend tags may appear in XML.
WSCloseDisconnect specified clients from server. The list must be comma separated, and must consist of client sessions. You may use "All" keyword to disconnect all clients. Multiple WSClose tags may appear in XML.

Events

connected: sent to PHP once client is connected to server.
disconnected: sent to PHP once client is disconnected from server.
Variable $_SERVER['WSPHP_SESSION'] contains connected/disconnected client session.

app4.php
if( isset( $_GET['client_notification'] ) )
{
if( $_GET['client_notification'] == 'connected' )
{
// Store session ID in database.
// Send some greeting string, etc.
}

if( $_GET['client_notification'] == 'disconnected' )
{
// Remove session ID from database.
// Obviously, it does not make sense to send something to
// client, becase it is disconnected.
}
}

Note, the client_notification can be renamed in config file. See notification_param option.

Administrator commands

Let's assume, we have the following strings in configuration file:
control_name=wsphp_control
control_password=wsphp

Authentication.
Request: wsphp_control=authenticate&password=wsphp&output_format=json|xml|html.
There can be two possible replies (in case if output_format=json):
{"wsphp_control":{"Success":"Authenticated","request":"authenticate"}}
{"wsphp_control":{"Error":"Authentication error","request":"authenticate"}}
The following requests will be executed by server only after successfull authentication..

List of all connected clients.
Request: wsphp_control=get_endpoints.
Sample server output:
{ "wsphp_control": {"endpoint_list":[ ["SESS1111", "WS", "1.2.3.4", "10", "10", "host.com", "/origin"], [...], ... ],
"endpoint_list_fields": ["session", "type", "ip", "alive", "last_op", "host", "origin"],
"endpoint_this": "SESS012345678", "request": "get_endpoints" } }

Where endpoint_this is an ID of the client which made request.

Send message.
Request: wsphp_control=send_to&endpoint=SESSIONID&message=Hello,+world!
There can be two possible replies (in case if output_format=json):
{"wsphp_control":{"Success":"Message was delivered","request":"send_to"}}
{"wsphp_control":{"Error":"Endpoint not found","request":"send_to"}}

Disconnect client and server.
Request: wsphp_control=disconnect&endpoint=SESSIONID.
There can be two possible replies (in case if output_format=json):
{"wsphp_control":{"Success":"Endpoint disconnected","request":"disconnect"}}
{"wsphp_control":{"Error":"Endpoint not found","request":"disconnect"}}

Server state information.
Request: wsphp_control=get_info.
Server reply (in case if output_format=json):
{ "wsphp_control": { "connections": {"active":100, "dropped":0, "accepted":1500, "fastcgi":2600}, "server": { "version": "1.1", "build":123, "listen":{"ip":"127.0.0.1","port":30403}, "uptime":132456}, "request": "get_info" } }

You can see sample control panel source code here.

Config options

The following options are available for setup via config file:

OptionDescription
verboseLogging level. Possible values: 1,2,3. 1 - a lot of information, 3 - show only errors. Default is 2.
listen_portTCP port to listen for incoming websocket connections. Default is 30403.
fastcgi_serverFast CGI server name and port number
dicsonnect_timeoutPeriod of client inactivity that leads to disconnection (in seconds).
cron_pathPath to PHP script to be tun as a cron job.
cron_timeoutTimeout in seconds between cron job executions.
app_pathPath to PHP script to be run on every client request.
notification_paramClient notification parameter name.
control_nameAdministrator parameter name.
control_passwordAdministrator password.

For advanced users: plain text protocol

Do you develop client software on your own (not using browser and websockets)?
With other software, similar to ours, you have to develop websocket handhake, encode/decode websocket frames, etc.

With WSPHP the software development becomes a piece of cake. See:

Client —> Server
GET /uri HTTP/1.1
Host: yourwebsite.com
Content-Type: CRLF

Client connects to server and sends the above strings. This is standard HTTP request header. You may add here X-Forwarded-For header, X-Real-IP, or any other headers you need.
Pay attention to content type string. It must be CRLF.

Server —> Client
HTTP/1.1 200 OK
Content-Type: CRLF

Server sends standard HTTP reply. The connection is established now.

Send request strings to server as usual text with [CR+LF] (or even only [LF]) characters at the end.
PHP script will be executed right away with query parameters received from client. It should run the way described above. From PHP you will not see the difference working with websocket or plain text protocol.

The $_SERVER['SERVER_PROTOCOL'] variable is set to WS for websocket, and CRLF for plain text protocol.

Notice for Windows users

As PHP does not provide tools for autimatic launch of php-cgi.exe file, we have added special option to config file:
windows_autorun="C:/Program Files/PHP/php-cgi.exe" -b 127.0.0.1:9010
It will autimatically launch php-cgi in hidden window each time WSPHP is executed.
Even more, when php-cgi stops, this option will automatically re-launch it.

Example of nginx host setup

Nginx config
server
{ listen 80;
server_name example.com www.example.com;
root /var/web/example;

#error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;

location ~ \.php$
{ try_files $uri =404;
fastcgi_pass 127.0.0.1:9999;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

location /
{ index index.php index.html;
try_files $uri $uri/ /index.php?$args;
}

location /websocket
{ proxy_pass http://127.0.0.1:30403; ## WSPHP listening port
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
}

Now you may connect to WSPHP server with the following javascript code:
var ws = new WebSocket( "ws://example.com/websocket" )

You may also setup Nginx to use SSL and connect to websocket as
var ws = new WebSocket( "wss://example.com/websocket" )

Download

wsphp2.20.291-linux-amd64.tar.gz
wsphp2.20.291-windows-amd64.zip
wsphp2.20.291-windows-i386.zip

Install and Run

Extract files to any folder. Linux users make sure you chmod'ed the executable. Execute:

Running WSPHP
/path/to/wsphp /path/to/wsphp.cfg

Make sure you specified correct path to config file.
You may add WSPHP to system crontab. Only one instance will run:

Crontab
* * * * * /path/to/wsphp /path/to/wsphp.cfg

That it is. Feel free to email us if you still have any questions.

Source code

Chat
Control panel

Contact us

Please provide us as many details as possible if you faced some techincal issues.
wsphp.net@gmail.com