Question

Im creating "communication" with websockets. (thanks: http://www.sanwebe.com/2013/05/chat-using-websocket-php-socket), the communication works very well, but Im trying to save some date when it goes through the "websocket server"(?)

I have created the socket ws_server.php

    <?php
require_once('filegenerator.php');
$filegenerator = new FileGenerator();

$host = '127.0.0.1'; //host
$port = '9000'; //port
$null = NULL; //null var

//Create TCP/IP sream socket
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//reuseable port
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);

//bind socket to specified host
socket_bind($socket, 0, $port);

//listen to port
socket_listen($socket);

//create & add listning socket to the list
$clients = array($socket);

//start endless loop, so that our script doesn't stop
while (true) {
    //manage multipal connections
    $changed = $clients;
    //returns the socket resources in $changed array
    socket_select($changed, $null, $null, 0, 10);

    //check for new socket
    if (in_array($socket, $changed)) {
        $socket_new = socket_accept($socket); //accpet new socket
        $clients[] = $socket_new; //add socket to client array

        $header = socket_read($socket_new, 1024); //read data sent by the socket
        perform_handshaking($header, $socket_new, $host, $port); //perform websocket handshake

        socket_getpeername($socket_new, $ip); //get ip address of connected socket
        $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' connected'))); //prepare json data
        send_message($response); //notify all users about new connection

        //make room for new socket
        $found_socket = array_search($socket, $changed);
        unset($changed[$found_socket]);
    }

    //loop through all connected sockets
    foreach ($changed as $changed_socket) { 

        //check for any incomming data
        while(socket_recv($changed_socket, $buf, 1024, 0) >= 1)
        {
            $received_text = unmask($buf); //unmask data
            $tst_msg = json_decode($received_text); //json decode 

            if ($tst_msg->type == 'order') {

                filegen( 'String for testing',$filegenerator );

                $items_to_kitchen = $tst_msg->order->items;

                foreach ($items_to_kitchen as $key => $value) {
                    $msg_to_kitchen[$key] = $value;
                }
                $response_text = mask(json_encode(array('order'=>$msg_to_kitchen)));

            } elseif ($tst_msg->type == 'kitchen') {
                $response_text = mask(json_encode(array('type'=>$tst_msg->type,'kitchenstate'=>$tst_msg)));

            }

            send_message($response_text); //send data
            break 2; //exist this loop
        }

        $buf = @socket_read($changed_socket, 1024, PHP_NORMAL_READ);
        if ($buf === false) { // check disconnected client
            // remove client for $clients array
            $found_socket = array_search($changed_socket, $clients);
            socket_getpeername($changed_socket, $ip);
            unset($clients[$found_socket]);

            //notify all users about disconnected connection
            $response = mask(json_encode(array('type'=>'system', 'message'=>$ip.' disconnected')));
            send_message($response);
        }
    }
}
// close the listening socket
socket_close($sock);

function send_message($msg)
{
    global $clients;
    foreach($clients as $changed_socket)
    {
        @socket_write($changed_socket,$msg,strlen($msg));
    }
    return true;
}


//Unmask incoming framed message
function unmask($text) {
    $length = ord($text[1]) & 127;
    if($length == 126) {
        $masks = substr($text, 4, 4);
        $data = substr($text, 8);
    }
    elseif($length == 127) {
        $masks = substr($text, 10, 4);
        $data = substr($text, 14);
    }
    else {
        $masks = substr($text, 2, 4);
        $data = substr($text, 6);
    }
    $text = "";
    for ($i = 0; $i < strlen($data); ++$i) {
        $text .= $data[$i] ^ $masks[$i%4];
    }
    return $text;
}

//Encode message for transfer to client.
function mask($text)
{
    $b1 = 0x80 | (0x1 & 0x0f);
    $length = strlen($text);

    if($length <= 125)
        $header = pack('CC', $b1, $length);
    elseif($length > 125 && $length < 65536)
        $header = pack('CCn', $b1, 126, $length);
    elseif($length >= 65536)
        $header = pack('CCNN', $b1, 127, $length);
    return $header.$text;
}

//handshake new client.
function perform_handshaking($receved_header,$client_conn, $host, $port)
{
    $headers = array();
    $lines = preg_split("/\r\n/", $receved_header);
    foreach($lines as $line)
    {
        $line = chop($line);
        if(preg_match('/\A(\S+): (.*)\z/', $line, $matches))
        {
            $headers[$matches[1]] = $matches[2];
        }
    }

    $secKey = $headers['Sec-WebSocket-Key'];
    $secAccept = base64_encode(pack('H*', sha1($secKey . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')));
    //hand shaking header
    $upgrade  = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" .
    "Upgrade: websocket\r\n" .
    "Connection: Upgrade\r\n" .
    "WebSocket-Origin: $host\r\n" .
    "WebSocket-Location: ws://$host:$port/xxx/includes/ws_server.php\r\n".
    "Sec-WebSocket-Accept:$secAccept\r\n\r\n";
    socket_write($client_conn,$upgrade,strlen($upgrade));
}

The client sends the data with $tst_msg->type == 'order' .. then I wants to create json file to save it. The class of file generation is in filegenerator.php

<?php

class FileGenerator{
private $_filename;
private $_data;

public function write($str_filename,$str_data){
    $this->_filename = $str_filename;
    $this->_data = $str_data;

    $this->_checkPermission();

    $this->_checkData();

    $handle = fopen($str_filename,'w');

    fwrite($handle, $str_data."\r\n");
    fclose($handle);
}

public function test(){
    echo "This string outputs in console";
    // php -q ws_server.php
}

public function read($str_filename){
    $this->_filename = $str_filename;
    echo $this->_filename;
    $this->_checkExists();
    $handle = fopen($str_filename, 'r');
    return file_get_contents($str_filename);
}

private function _checkPermission(){
    if ( !is_writable($this->_filename)) {
        die('Change your CHMOD permissions to:'.$this->_filename);
    }
}

private function _checkData(){
    if (strlen($this->_data) < 1) {
        die('You must have more than one character for data');
    }
}

private function _checkExists(){
    if (!file_exists($this->_filename)) {
        die('The File does not exis');
    }
}
}

function filegen( $str,$filegenerator ){
$filegenerator->test();
$filegenerator->write('test.json',$str);
}

?>

When I call the function filegen() at line 58 in ws_server.php ,

filegen( 'String for testing',$filegenerator );

at the permission check the program die(). But

  1. The file is writable, full access (for testing purposes)
  2. It exists
  3. Interesting thin, when I create another file for testing the FileGenerator class it works perfectly, but doesnt from ws_server.php file
  4. Im using xampp on windows The console run: php -q D:\xampp\htdocs\xxx\includes\ws_server.php

I tried simply put

$handle = fopen($str_filename,'w');
fwrite($handle, $str_data."\r\n");
fclose($handle);

but same issue occurs. Interesting thing, that I can get $handle #id if I echo, and echoing fwrite() can return the the number of characters, but the file doesnt change!

Can somebody help me, describe me what am I doing wrong! Thank you

Was it helpful?

Solution

I think it's a path problem or a file ownership problem.

  1. Try $filegenerator->write(__DIR__ . '/test.json, $str) to make sure it tries to write test.json in the directory the file is in.
  2. Check who the file owner on the filesystem is. Webservers often have their own user (www-data for example), which might conflict with your own logged in user. You might have to chown the file.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top