I am trying to build a PHP class that can municate 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 = ".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.
I am trying to build a PHP class that can municate 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 = ".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.
Share Improve this question edited Nov 13, 2017 at 16:59 Digital Human asked Nov 13, 2017 at 16:50 Digital HumanDigital Human 1,6471 gold badge19 silver badges27 bronze badges 8- The first quote isn't sent to stdin, those are mand line parameters. If you see it in your php code then something is wrong. As for the python example, the meaningful part is send_message and read_thread_func. The protocol is simple and described in the documentation: 4 bytes length, JSON-ified message. – woxxom Commented Nov 13, 2017 at 17:50
- Sounds plausible indeed. Gonna check and reply soon. – Digital Human Commented Nov 14, 2017 at 7:07
-
@wOxxOm chrome doesn't seem to pipe stdin correctly. I use a windows .bat file, like the example Python app.
echo %* | php -f "%~dp0/native_host.php"
– Digital Human Commented Nov 14, 2017 at 8:22 -
echo %*
prints your mand line into stdin, which is hardly what you want. The documentation's bat file doesn't do that. – woxxom Commented Nov 14, 2017 at 9:16 -
I tried only with
php -f "%~dp0/native_host.php"
but that doesn't work either.......kind stuck here – Digital Human Commented Nov 14, 2017 at 13:15
1 Answer
Reset to default 11 +25Native Messaging use structured data (length-formatted) to read and write. in browser (JavaScript), that structure has been handled by browser. If you want to municate 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;
}