Decoding data from a WebSocket frame in PHP involves understanding the WebSocket protocol's framing structure and applying bitwise operations to extract the payload. Here's a breakdown of the process:
1. Reading the Frame Bytes:

   Receive the raw bytes of the WebSocket frame from the client.

2. Extracting Control Bits and Opcode:

   The first byte of the frame contains the FIN bit (most significant bit) and the OpCode (last four bits).
   Use bitwise operations to extract these:

Code

   $fin = ($firstByte >> 7) & 0x01; // Get the FIN bit
   $opcode = $firstByte & 0x0F; // Get the OpCode

3. Extracting Mask Bit and Payload Length:

   The second byte contains the MASK bit (most significant bit) and the initial Payload Length (last seven bits).
   Extract these:

Code

   $mask = ($secondByte >> 7) & 0x01; // Get the MASK bit
   $payloadLength = $secondByte & 0x7F; // Get the initial payload length

4. Determining Actual Payload Length:

   If $payloadLength is 126, the actual length is in the next two bytes (unsigned 16-bit integer).
   If $payloadLength is 127, the actual length is in the next eight bytes (unsigned 64-bit integer, with the most significant bit being 0).
   Otherwise, $payloadLength is the actual length.

5. Extracting Masking Key (if MASK bit is set):

   If the MASK bit is 1, the next four bytes after the length bytes constitute the 4-byte Masking Key.

6. Decoding the Payload:

   The payload follows the masking key (or length bytes if no masking).
   If the MASK bit is 1, you need to unmask the payload by applying an XOR operation with the Masking Key.
   Iterate through each byte of the payload and XOR it with the corresponding byte from the Masking Key (using modulo 4 to cycle through the key bytes).

Example (Simplified for a basic text frame without extended length):
Code

function decodeWebSocketFrame($data) {
   $firstByte = ord($data[0]);
   $secondByte = ord($data[1]);

   $fin = ($firstByte >> 7) & 0x01;
   $opcode = $firstByte & 0x0F;

   $mask = ($secondByte >> 7) & 0x01;
   $payloadLength = $secondByte & 0x7F;

   $offset = 2; // Start after the first two bytes

   // Handle extended payload length (simplified for brevity)
   if ($payloadLength == 126) {
       $payloadLength = (ord($data[$offset]) << 8) | ord($data[$offset + 1]);
       $offset += 2;
   } elseif ($payloadLength == 127) {
       // Handle 64-bit length (more complex, requires reading 8 bytes)
       // For simplicity, this example assumes shorter payloads
       return false;
   }

   $maskingKey = '';
   if ($mask) {
       $maskingKey = substr($data, $offset, 4);
       $offset += 4;
   }

   $payload = substr($data, $offset);
   $decodedPayload = '';

   if ($mask) {
       for ($i = 0; $i < $payloadLength; $i++) {
           $decodedPayload .= chr(ord($payload[$i]) ^ ord($maskingKey[$i % 4]));
       }
   } else {
       $decodedPayload = $payload;
   }

   return [
       'fin' => $fin,
       'opcode' => $opcode,
       'payload' => $decodedPayload,
   ];
}

// Example usage:
// $receivedData = "your_raw_websocket_frame_bytes";
// $decoded = decodeWebSocketFrame($receivedData);
// if ($decoded) {
//     echo "Decoded Payload: " . $decoded['payload'] . "\n";
// }