I am trying to build a PHP class that can communicate with a Chrome Extention through Native Messaging.
I can connect to my code, but at initiation Chrome sends
chrome-extension://lkjcciocnocjjgpacggbaikjehbfedbl/ --parent-window=1837060
To my PHP console app (The Host). What do I reply to make the connection working?
Below my PHP code. Yes its dirty because its a POC project and I am very new to Chrome Extensions especially with the current updates.
function out($data = ""){
$fp = fopen("php://stdout", "w");
if($fp){
$response = array("text" => "Ok");
$message = json_encode($response);
fwrite($fp, $message);
fflush($fp);
slog("[OUTPUT] " . json_encode($response));
fclose($fp);
exit(0);
}else{
slog("Can't open output stream.");
exit(1);
}
}
function err($data){
$fp = fopen("php://stderr", "w");
if($fp){
fwrite($fp, $data);
fflush($fp);
fclose($fp);
}
return;
}
function in(){
$data = "";
$fp = fopen("php://stdin", "r");
if($fp){
$data = fgets($fp);
fclose($fp);
}else{
slog("Can't open input stream.");
exit(1);
}
slog("[INPUT]" . $data);
return $data;
}
function slog($data){
if($data != ""){
file_put_contents("./log.txt", date("r").": {$data}\r\n", FILE_APPEND);
}
}
slog("Entering");
while(true){
if(($l = in()) !== ""){
out($l);
}else{
exit(0);
}
}
exit(0);
My background.js code. (the extention)
var port = null;
var hostName = "com.google.chrome.poc-extension";
function appendMessage(text) {
document.getElementById('response').innerHTML += "<p>" + text + "</p>";
}
function updateUiState() {
if (port) {
document.getElementById('connect-button').style.display = 'none';
}else{
document.getElementById('connect-button').style.display = 'block';
}
}
function sendNativeMessage() {
port = chrome.runtime.connectNative(hostName);
port.onMessage.addListener(onNativeMessage);
message = {"text": document.getElementById('input-text').value};
port.postMessage(message);
appendMessage("Sent message: <b>" + JSON.stringify(message) + "</b>");
}
function onNativeMessage(message) {
alert(message);
appendMessage("Received message: <b>" + JSON.stringify(message) + "</b>");
}
function onDisconnected() {
appendMessage("Failed to connect: " + chrome.runtime.lastError.message);
console.log(chrome.runtime.lastError);
port = null;
updateUiState();
}
function connect() {
appendMessage("Connecting to native messaging host <b>" + hostName + "</b>")
port = chrome.runtime.connectNative(hostName);
port.onMessage.addListener(onNativeMessage);
port.onDisconnect.addListener(onDisconnected);
updateUiState();
}
document.addEventListener('DOMContentLoaded', function (){
document.getElementById('connect-button').addEventListener('click', connect);
document.getElementById('send-message-button').addEventListener('click', sendNativeMessage);
updateUiState();
});
There is this Python example app but I don't really get what it does exactly. Besides that it also uses the Tkinter plugin which I don't want. I want a clean, plain and simpel extension.
Native Messaging use structured data (length-formatted) to read and write. in browser (JavaScript), that structure has been handled by browser. If you want to communicate with Native Messaging, so you need to follow that structure.
Read refference here
Each message is serialized using JSON, UTF-8 encoded and is preceded
with 32-bit message length in native byte order.
So you need to send your message as: len(message) + [your message]
len(message) must be packed following the protocol.
Example function to send output:
function out($data = ""){
$fp = fopen("php://stdout", "w");
if($fp){
$response = array("text" => "Ok");
$message = json_encode($response);
//Send the length of data
fwrite($fp, pack('L', strlen($message)));
fwrite($fp, $message);
fflush($fp);
slog("[OUTPUT] " . json_encode($response));
fclose($fp);
exit(0);
}else{
slog("Can't open output stream.");
exit(1);
}
}
Read Input:
function in(){
$data = "";
$fp = fopen("php://stdin", "r");
if($fp){
//Read first 4 bytes as unsigned integer
$len = current( unpack('L', fread($fp, 4) ) );
$data = fread($fp, $len);
fclose($fp);
}else{
slog("Can't open input stream.");
exit(1);
}
slog("[INPUT]" . $data);
return $data;
}
Related
Uncaught SyntaxError: JSON.parse: unexpected character at line 1 column 2 of the JSON data site:stackoverflow.com error is showing in firefox debug console.
I have a form in my website and on submit button this functions calls
$("#contact-form").on("submit",function(e)
{
var sendData = $(this).serialize();
e.preventDefault();
if ( checkSubmitInputs(this) )
{
$.ajax({
type: "POST",
url: "js/ajaxsubmit.php",
data: sendData,
success: function(data)
{
$("#loading-img").css("display","none");
// $(".response_msg").text(data);
// document.getElementById('contact-form').style.display = 'none'
// document.getElementById('success').style.display = 'block'
data = JSON.parse(data);
if(data.status){
document.getElementById('contact-form').style.display = 'none';
$("#error").text('');
$("#success").text(data.msg);
document.getElementById('success').style.display = 'block';
document.getElementById('scicon-c').style.display = 'block';
document.getElementById('error').style.display = 'none';
$("#contact-form").find("input[type=text], input[type=email], textarea").val("");
}
else {
document.getElementById('contact-form').style.display = '';
$("#success").text('');
$("#error").text(data.msg);
document.getElementById('error').style.display = 'block'
document.getElementById('success').style.display = 'none'
document.getElementById('scicon-c').style.display = 'none'
}
}
});
} else{
document.getElementsByClassName('error').style.display = 'block'
}
})
This line data = JSON.parse(data); shows above error as soon as i add include_once('mail.php'); in my ajaxsubmit.php file and without including it works perfectly.
Mail.php I am receiving mail too
<?php
error_reporting(-1);
ini_set('display_errors', 'On');
set_error_handler("var_dump");
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require_once("vendor/autoload.php");
$mail = new PHPMailer(true);
//Enable SMTP debugging.
$mail->SMTPDebug = 3;
//Set PHPMailer to use SMTP.
$mail->isSMTP();
//Set SMTP host name
$mail->Host = "email-smtp.us-west-1.amazonaws.com";
//Set this to true if SMTP host requires authentication to send email
$mail->SMTPAuth = true;
//Provide username and password
$mail->Username = "ID";
$mail->Password = "Pass";
//Set TCP port to connect to
$mail->Port = 587;
$mail->setFrom('demo#example', 'demo#example');
error_reporting(E_ALL); // Error/Exception engine, always use E_ALL
ini_set('ignore_repeated_errors', TRUE); // always use TRUE
ini_set('display_errors', true); // Error/Exception display, use FALSE only in production environment or real server. Use TRUE in development environment
ini_set('log_errors', TRUE); // Error/Exception file logging engine.
ini_set('error_log', 'zeeErrors.log'); // Logging file path
function sendEmailToUser($con, $emailMsg, $Subject)
{
global $mail;
$msg = "";
$subject = $Subject;
$tempArray = explode(',', $emailMsg);
$name = $tempArray[0];
$mobile = $tempArray[1];
$email = $tempArray[2];
$mail->Subject = "Test.";
$to = $email;
$htmlTemplate = file_get_contents('ration.html', true);
$mail->addAddress($to, $name); //Add a recipient
//$mail->addAddress('ellen#example.com'); //Name is optional
//$mail->addCC('cc#example.com');
//$mail->addBCC('varun7952#gmail.com');
$mail->isHTML(true);
$mail->Body = $msg;
//$mail->AltBody = "This is the plain text version of the email content";
try {
$mail->send();
echo "Message has been sent successfully";
return true;
} catch (Exception $e) {
echo "Mailer Error: " . $mail->ErrorInfo;
return false;
}
}
?>
AjaxSubmit.php
<?php
include_once('mail.php');
$response = array();
if((isset($_POST['name'])&& $_POST['name'] !='') && (isset($_POST['email'])&& $_POST['email'] !='') && (isset($_POST['phone'])&& $_POST['phone'] !=''))
{
//whether ip is from share internet
$ia = '';
if (!empty($_SERVER['HTTP_CLIENT_IP']))
{
$ia = $_SERVER['HTTP_CLIENT_IP'];
}
//whether ip is from proxy
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
{
$ia = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
//whether ip is from remote address
else
{
$ia = $_SERVER['REMOTE_ADDR'];
}
/*Get user ip address details with geoplugin.net*/
$geopluginURL='http://www.geoplugin.net/php.gp?ip='.$ia;
$addrDetailsArr = unserialize(file_get_contents($geopluginURL));
/*Get City name by return array*/
$city = $addrDetailsArr['geoplugin_city'];
/*Get Country name by return array*/
$country = $addrDetailsArr['geoplugin_countryName'];
$region = $addrDetailsArr['geoplugin_regionName'];
if(!$city){
$city='Not Define';
}
if(!$country){
$country='Not Define';
}
if(!$region){
$region='Not Define';
}
//file_put_contents('zee1.log', print_r($addrDetailsArr, TRUE));
$yourName = $conn->real_escape_string($_POST['name']);
$yourEmail = $conn->real_escape_string($_POST['email']);
$yourPhone = $conn->real_escape_string($_POST['phone']);
$city = $conn->real_escape_string($city);
$country = $conn->real_escape_string($country);
$region = $conn->real_escape_string($region);
$checkSql = "SELECT name, email, contact from reg where email='".$yourEmail."' OR contact='".$yourPhone."'";
$resultCheck = $conn->query($checkSql);
if($resultCheck->num_rows > 0) {
$response['status'] = false;
$response['msg'] = "You have registered already with ".$yourEmail." OR ".$yourPhone."";;
}else {
$userLocation = $city.' '.$region.' '.$country;
$sql="INSERT INTO reg (name, email, contact,IP_Address,City) VALUES ('".$yourName."','".$yourEmail."', '".$yourPhone."','".$ia."','".$userLocation."')";
if(!$result = $conn->query($sql)){
$response['status'] = false;
$response['msg'] = 'There was an error running the query [' . $conn->error . ']';
}
else
{
$response['status'] = true;
$response['msg'] = "Thank you $yourName. Welcome in SAAS Application. We will connect with you soon. :)";
$msg = $yourName.','.$yourPhone.','.$yourEmail.','.$userLocation;
if(sendEmailToUser($conn,$msg,'Reg')){
//Email Sent
}
}
}
}
else
{
$response['status'] = false;
$response['msg'] = 'Please fill Name and Email';
}
echo json_encode($response);
?>
As i said everything is working if i don't add require in ajaxsubmit file. I am not good in php or JS so after reading so many answers i still can't figure out why i am not able to parse json at my form.
This is JSON Returned by AJAXsubmit
{
"status": true,
"msg": "Thank you Demo. Welcome in SAAS Application. We will connect with you soon. :)"
}
Your problem is that mail.php has this code in it:
try {
$mail->send();
echo "Message has been sent successfully";
return true;
} catch (Exception $e) {
echo "Mailer Error: " . $mail->ErrorInfo;
return false;
}
which, regardless of the result, causes text to be echo'ed. As a result, your json response will look something like:
Message has been sent successfully
{
... normal json response
}
which will not parse successfully.
I have a "contact us" form and everything is working but my error callback in the ajax runs instead of the success. I ajax is called, the PHP file runs, and I get an email to my localhost (using Mercury).
So why is my success callback not running? I have no idea how to find out what is causing the error especially since everything works.
The only thing I suspect is the file folders. The current structure is this. My html file and php file are in the root directory. The JS file is in a folder.
Here is a screenshot of the network tab in chrome debugger after I press submit
http://i.imgur.com/HfRYjj0.png
My Ajax:
$(document).ready(function(e) {
$("#main-contact-form").on('submit', (function(e) {
e.preventDefault();
$('#sendingemail').fadeIn();
$.ajax({
url : "../sendemail.php",
type : "POST",
data : new FormData(this),
contentType : false,
cache : false,
processData : false,
success : function(data) {
$('#sendingemail').fadeOut();
$('#emailsent').fadeIn();
},
error : function() {
alert("Error");
}
});
}));
});
My PHP:
<?php
// ini_set('display_errors', 'On');
// error_reporting(E_ALL);
header('Content-type: application/json');
// WE SHOULD ASSUME THAT THE EMAIL WAS NOT SENT AT FIRST UNTIL WE KNOW MORE.
// WE ALSO ADD AN ATTACHMENT KEY TO OUR STATUS ARRAY TO INDICATE THE STATUS OF OUR ATTACHMENT:
/*$status = array(
'type'=>'Error',
'message'=>'Couldn\'t send the Email at this Time. Something went wrong',
'attachement'=>'Couldn\'t attach the uploaded File to the Email.'
);*/
//Added to deal with Files
require_once ('PHPMailer/class.phpmailer.php');
if (isset($_FILES['uploaded_file'])) {
//require_once('/PHPMailer/class.smtp.php');
//Get the uploaded file information
$name_of_uploaded_file = basename($_FILES['uploaded_file']['name']);
//get the file extension of the file
$type_of_uploaded_file = substr($name_of_uploaded_file, strrpos($name_of_uploaded_file, '.') + 1);
$size_of_uploaded_file = $_FILES["uploaded_file"]["size"] / 1024;
//size in KBs
//Settings
$max_allowed_file_size = 10240;
// size in KB
$allowed_extensions = array("jpg", "jpeg", "gif", "bmp", "png");
//Validations
if ($size_of_uploaded_file > $max_allowed_file_size) {
$errors .= "\n Size of file should be less than $max_allowed_file_size (~10MB). The file you attempted to upload is too large. To reduce the size, open the file in an image editor and change the Image Size and resave the file.";
}
//------ Validate the file extension -----
$allowed_ext = false;
for ($i = 0; $i < sizeof($allowed_extensions); $i++) {
if (strcasecmp($allowed_extensions[$i], $type_of_uploaded_file) == 0) {
$allowed_ext = true;
}
}
if (!$allowed_ext) {
$errors .= "\n The uploaded file is not supported file type. " . " Only the following file types are supported: " . implode(',', $allowed_extensions);
}
//copy the temp. uploaded file to uploads folder - make sure the folder exists on the server and has 777 as its permission
$upload_folder = "temp/";
$path_of_uploaded_file = $upload_folder . $name_of_uploaded_file;
$tmp_path = $_FILES["uploaded_file"]["tmp_name"];
if (is_uploaded_file($tmp_path)) {
if (!copy($tmp_path, $path_of_uploaded_file)) {
$errors .= '\n error while copying the uploaded file';
}
}
}
//--end
$name = #trim(stripslashes($_POST['name']));
$clientemail = #trim(stripslashes($_POST['email']));
$subject = #trim(stripslashes($_POST['subject']));
$message = #trim(stripslashes($_POST['message']));
$body = 'Name: ' . $name . "\n\n" . 'Email: ' . $clientemail . "\n\n" . 'Subject: ' . $subject . "\n\n" . 'Message: ' . $message;
$email = new PHPMailer();
$email -> From = $clientemail;
$email -> FromName = $name;
$email -> Subject = $subject;
$email -> Body = $body;
$email -> AddAddress('root#localhost.com');
//Send to this email
// EXPLICITLY TELL PHP-MAILER HOW TO SEND THE EMAIL... IN THIS CASE USING PHP BUILT IT MAIL FUNCTION
$email -> isMail();
// THE AddAttachment METHOD RETURNS A BOOLEAN FLAG: TRUE WHEN ATTACHMENT WAS SUCCESSFUL & FALSE OTHERWISE:
// KNOWING THIS, WE MAY JUST USE IT WITHIN A CONDITIONAL BLOCK SUCH THAT
// WHEN IT IS TRUE, WE UPDATE OUR STATUS ARRAY...
if (isset($_FILES['uploaded_file'])) {
if ($email -> AddAttachment($path_of_uploaded_file, $name_of_uploaded_file)) {
//$status[] = 'The Uploaded File was successfully attached to the Email.';
}
}
// NOW, TRY TO SEND THE EMAIL ANYWAY:
try {
$success = $email -> send();
//$status['type'] = 'success';
$status[] = 'Thank you for contacting us. We will reply as soon as possible.';
} catch(Exception $e) {
//$status['type'] ='Error';
$status[] = 'Couldn\'t send the Email at this Time. Something went wrong';
}
// SIMPLY, RETURN THE JSON DATA...
die(json_encode($status));
I am developing a smart tv app that plays live streams. App itself works fine, when i provide a valid xml playlist to it.
But when i use php to generate xml file (wich also generates fine), it doesnt work.
I get an error:
TypeError: 'null' is not an object (evaluating 'this.XHRObj.responseXML.documentElement')
Here is my php file that generates videoList.xml, it works 100%.
In short words, this script checks if MAC address in database, and if it is, then it writes videoList.xml with walid live streaming links.
SamsungAPI.php
<?php
$MAC = $_GET['MAC'];
require_once('../config.php');
//Remove brackets form array
$_INFO = preg_replace('/[{}]/', '', $_INFO);
$mysqli = new mysqli($_INFO['host'], $_INFO['db_user'], $_INFO['db_pass'], $_INFO['db_name']);
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
$sql="SELECT * FROM users WHERE admin_notes = '$MAC' ";
$rs=$mysqli->query($sql);
$rows=mysqli_num_rows($rs);
if ($rows == 1) {
//MAC FOUND
$row = mysqli_fetch_array($rs);
$username = $row['username'];
$password = $row['password'];
$file = "videoList.xml";
$txt_file = file_get_contents('http://' . $_SERVER['HTTP_HOST'] . '/get.php?type=starlivev3&username=' . $username . '&password=' . $password . '&output=hls');
$rows = explode("\n", $txt_file);
if(empty($rows[count($rows)-1])) {
unset($rows[count($rows)-1]);
$rows=array_map('trim',$rows);
}
$handle = fopen($file, "w+") or die('Could not open file');
fwrite($handle, "<?xml version=\"1.0\"?>"."\n");
fwrite($handle, "<rss version=\"2.0\">"."\n");
fwrite($handle, "<channel>"."\n");
foreach($rows as $row => $data)
{
//get row data
$row_data = explode(',', $data);
//replace _ with spaces
$row_data[0] = str_replace('_', ' ', $row_data[0]);
//generate playlist content
fwrite($handle, "<item>"."\n");
fwrite($handle, "<title>{$row_data[0]}</title>"."\n");
fwrite($handle, "<link>{$row_data[1]}</link>"."\n");
fwrite($handle, "<description> Reserved for EPG </description>"."\n");
fwrite($handle, "</item>"."\n");
}
fwrite($handle, "</channel>"."\n");
fwrite($handle, "</rss>");
fclose($handle);
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file));
readfile($file);
exit;
} else {
//MAC NOT FOUND
echo "MAC NOT FOUND";
}
mysqli_close($mysqli); // Closing Connection
?>
Then in samsung smart tv videoplayer app, i have xml parser like this:
Server.js
var Server =
{
/* Callback function to be set by client */
dataReceivedCallback : null,
XHRObj : null,
url : "http://myvalidhost.com/samsungAPI.php?MAC=02000027000b"
}
Server.init = function()
{
var success = true;
if (this.XHRObj)
{
this.XHRObj.destroy(); // Save memory
this.XHRObj = null;
}
return success;
}
Server.fetchVideoList = function()
{
if (this.XHRObj == null)
{
this.XHRObj = new XMLHttpRequest();
}
if (this.XHRObj)
{
this.XHRObj.onreadystatechange = function()
{
if (Server.XHRObj.readyState == 4)
{
Server.createVideoList();
}
}
this.XHRObj.open("GET", this.url, true);
this.XHRObj.send(null);
}
else
{
alert("Failed to create XHR");
}
}
Server.createVideoList = function()
{
if (this.XHRObj.status != 200)
{
Display.status("XML Server Error " + this.XHRObj.status);
}
else
{
var xmlElement = this.XHRObj.responseXML.documentElement;
if (!xmlElement)
{
alert("Failed to get valid XML");
}
else
{
// Parse RSS
// Get all "item" elements
var items = xmlElement.getElementsByTagName("item");
var videoNames = [ ];
var videoURLs = [ ];
var videoDescriptions = [ ];
for (var index = 0; index < items.length; index++)
{
var titleElement = items[index].getElementsByTagName("title")[0];
var descriptionElement = items[index].getElementsByTagName("description")[0];
var linkElement = items[index].getElementsByTagName("link")[0];
if (titleElement && descriptionElement && linkElement)
{
videoNames[index] = titleElement.firstChild.data;
if(linkElement.firstChild.data.substring(0,4) !="http"){
alert("asdasdasd "+linkElement.firstChild.data.substring(0,4));
var rootPath = window.location.href.substring(0, location.href.lastIndexOf("/")+1);
var Abs_path = unescape(rootPath).split("file://")[1]+linkElement.firstChild.data;
videoURLs[index] = Abs_path;
}
else{
videoURLs[index] = linkElement.firstChild.data;
}
videoDescriptions[index] = descriptionElement.firstChild.data;
}
}
Data.setVideoNames(videoNames);
Data.setVideoURLs(videoURLs);
Data.setVideoDescriptions(videoDescriptions);
if (this.dataReceivedCallback)
{
this.dataReceivedCallback(); /* Notify all data is received and stored */
}
}
}
}
Does anyone have any idea why doesnt it accept my generated xml file?
Regards
M
I figured it out, in php headers content type was wrong.
Changed
header('Content-Type: application/octet-stream');
to
header('Content-Type: application/xml');
Now it works perfect!
I am new in websockets technology. I was trying to create a websockets php server and connect to the server with a javascript client. I am using xampp 1.8.3.
I made this simple PHP server:
<?php
error_reporting(E_ALL);
set_time_limit(0);
$address = "127.0.0.1";
$port = 1777;
$maxConnections = 10;
if(!($sock = socket_create(AF_INET, SOCK_STREAM, 0))){
$errorCode = socket_last_error();
$errorMsg = socket_strerror($errorCode);
die("socket_create() failed -> {$errorCode}:{$errorMsg}\n");
}
echo "Server created.\n";
if(!(socket_bind($sock, $address, $port))){
$errorCode = socket_last_error();
$errorMsg = socket_strerror($errorCode);
die("socket_bind() failed -> {$errorCode}:{$errorMsg}\n");
}
echo "Server opened on {$address}:{$port}\n";
if(!(socket_listen($sock, $maxConnections))){
$errorCode = socket_last_error();
$errorMsg = socket_strerror($errorCode);
die("socket_listen() failed -> {$errorCode}:{$errorMsg}\n");
}
echo "Waiting for connections...\n";
$client = socket_accept($sock);
if(socket_getpeername($client, $address, $port)){
echo "The client {$address}:{$port} is online.\n";
}
$msg = socket_read($client, 1024000);
if(!(socket_write($client, $msg, strlen($msg)))){
$errorCode = socket_last_error();
$errorMsg = socket_strerror($errorCode);
die("socket_write() failed -> {$errorCode}:{$errorMsg}\n");
}
echo "Message sent\n";
socket_close($client);
socket_close($sock);
?>
I ran this php file with xampp shell using the following expression:
php htdocs/server.php
and I got this message on shell:
php htdocs/server.php
Server created.
Server opened on 127.0.0.1:1777
Waiting for connections...
Then I opened my client.html on chrome (my supports websockets).
My client.html code is:
<html>
<head>
<meta charset="UTF-8" />
<title>Websockets web-server connection</title>
</head>
<body>
<p>Websockets connection. Status: <span id="status"></span></p>
<script type="text/javascript">
var webSockets = new WebSocket("ws://127.0.0.1:1777/");
webSockets.onopen = function(){
document.getElementById("status").innerHTML="connected";
webSockets.send("ping");
}
</script>
</body>
</html>
And I received this message on javascript console log:
WebSocket connection to 'ws://127.0.0.1:1777/' failed: client.html:9
And my shell had this messages:
php htdocs/server.php
Server created.
Server opened on 127.0.0.1:1777
Waiting for connections...
The client 127.0.0.1:64446 is online
Message sent
However I didn't receive any message on client, I do not even get a connected status.
What is happening? Where is my error?
Thank you.
WebSockets are not raw TCP sockets. They require a rather complex HTTP-like handshake to establish a connection, and require data transferred over them to be encoded and framed in a very particular way. The protocol is defined in RFC 6455.
Unless you are feeling incredibly masochistic, you don't want to try to implement this yourself. Use a library like Ratchet to implement WebSockets in PHP.
I had the same problem bro but no need of using Ratchet or other libraries you can write your own simple code . The handshake process,and the masking-unmasking of messages is rather difficult so i copied the code for those
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/\r\n".
"Sec-WebSocket-Accept:$secAccept\r\n\r\n";
socket_write($client_conn,$upgrade,strlen($upgrade));
return $upgrade;
}
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;
}
Instead of socket_accept user socket_read to get the http header containing request from webpage that it wants to upgrade its http conn to websocket then use the handshake function above to write an accept header message .then your connection will be established .but still on the client side you have to add events like these
if("WebSocket" in window){
var a = "ws://"+serverip+":9000";
var ws = new WebSocket(a);
var error = null;
ws.onopen = function(){
open();
}
ws.onerror = function(err){
errorhandler(err);
}
ws.onmessage = function(e){
messagehandler(e);
}
ws.onclose = function(){
close();
}
}
function open(){
document.getElementById('logs').innerHTML+='<p>WebSocket Connection OPened</p>';
}
function errorhandler(err){
document.getElementById('logs').innerHTML+='<p>WebSocket Connection Error occured  '+err.data+'</p>';
}
function messagehandler(a){
document.getElementById('logs').innerHTML+="<p>"+a.data+"</p>";
}
function close(){
document.getElementById('logs').innerHTML+='<p>WebSocket Connection Closed</p>';
ws = null;
}
I am writing a project that is in 2 parts.
So far I have a front end View.php (HTML5,CSS3,JQuery) and this will query the server.php
The server PHP opens a TCP socket to a server and listens in and can make commands by writing to the socket.
The normal procedure now goes like this
View.php -> Calls using rest API to server.php
Server.php -> Connects to TCP -> Reads from TCP -> Json_encodes & print -> close TCP socket connection.
What I want to achieve is a script Server.php that once started. It constantly listens in to a server, until it gets a shutdown command. I want to keep a fsocket connection open. Any thoughts?
The answer is using non blocking programming. In PHP we have specific function for non blocking I/O. For sockets you should use socket_set_nonblock function on a socket resource.
$port = 8081;
$address = '127.0.0.1';
if (($sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
echo "socket_create() failed: reason: " . socket_strerror(socket_last_error()) . "\n";
exit();
}
if (socket_bind($sock, $address, $port) === false) {
echo "socket_bind() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
exit();
}
if (socket_listen($sock, 5) === false) {
echo "socket_listen() failed: reason: " . socket_strerror(socket_last_error($sock)) . "\n";
}
socket_set_nonblock($sock);
echo "listening for new connection".PHP_EOL;
$conneted_clients = [];
do {
$clientsock = socket_accept($sock);
if($clientsock !== false){
socket_set_nonblock($clientsock);
$conneted_clients[] = $clientsock;
socket_getpeername($clientsock,$address);
echo "New Connection from: ".$address.PHP_EOL;
$msg = PHP_EOL."Welcome to the PHP Test Server. " . PHP_EOL.
"To quit, type 'quit'. To shut down the server type 'shutdown'." . PHP_EOL;
socket_write($clientsock, $msg, strlen($msg));
}
$status = check_clients($conneted_clients);
if(!$status) break;
usleep(500000);
} while (true);
function check_clients($clients)
{
foreach($clients as $key => $con)
{
if(get_resource_type($con) !== "Socket")
{
socket_getpeername($clientsock,$address);
echo $address." has diconnected.".PHP_EOL;
unset($clients[$key]);
continue;
}
if (false === $buff = socket_read($con, 2048)) {
continue;
}
$buff = trim($buff);
if ($buff == 'quit') {
socket_close($con);
unset($clients[$key]);
continue;
}
if (trim($buff) == 'shutdown') {
socket_close($con);
echo "shutdown initiated".PHP_EOL;
return FALSE;
}
if($buff != false || $buff != null)
{
$talkback = "PHP: You said '$buff'.".PHP_EOL;
socket_write($con, $talkback, strlen($talkback));
echo "$buff".PHP_EOL;
}
}
return TRUE;
}
echo "Closing Server";
socket_close($sock);