I'm new to GTK Broadway and I succeeded creating an instance of gedit running under it. I can access the interface using any browser and http://localhost:8080 but I can't open two different tabs on the same address. When I try to connect from another tab, the previous disconnects.
What I wish to do is to create a server running a GTK application on one side and serving this application for multiple users, they will be able to visualize the GUI and what's happening but only one user will be able to interact (I'm working on it).
Edit: I thought about a workaround where the server loads the page with the Websockets and the HTML5 Canvas then acts like a proxy and serves the same content to the clients, the proxy would then handle the incoming input from the clients (and manage the parallel connections). Is it technically possible?
Thanks in advance.
I found this on waybackmachine:
Transparent Proxy for Broadway ( Gtk3 / HTML5 backend )
Fortunately the source code could be recovered on waybackmachine:
#!/usr/bin/perl
#
# Peteris Krumins (peter#catonmat.net)
# http://www.catonmat.net -- good coders code, great reuse
#
# A simple TCP proxy that implements IP-based access control
# Currently the ports are hard-coded, and it proxies
# 0.0.0.0:1080 to localhost:55555.
#
# Written for the article "Turn any Linux computer into SOCKS5
# proxy in one command," which can be read here:
#
# http://www.catonmat.net/blog/linux-socks5-proxy
#
##############################################################
#
# Modified by Dan Kasak ( d.j.kasak.dk#gmail.com )
# http://tesla.duckdns.org
#
# Added some hacks for proxying based on the value in a cookie,
# as a proof-of-concept transparent proxy for Gtk+ / broadway
use warnings;
use strict;
use Data::Dumper;
use IO::Socket;
use IO::Select;
my $ioset = IO::Select->new;
my %socket_map;
my $debug = 0;
sub new_server {
my ($host, $port) = #_;
my $server = IO::Socket::INET->new(
LocalAddr => $host,
LocalPort => $port,
ReuseAddr => 1,
Listen => 100
) || die "Unable to listen on $host:$port: $!";
}
sub close_connection {
my $client = shift;
my $client_ip = client_ip($client);
my $remote = $socket_map{$client};
foreach my $socket ( $client , $remote ) {
if ( ref $socket eq 'ConnectionFuture' ) {
$socket->disconnect;
} else {
$ioset->remove( $socket );
}
}
delete $socket_map{$client};
delete $socket_map{$remote};
$client->close;
$remote->close;
print "Connection from $client_ip closed.\n" if $debug;
}
sub client_ip {
my $client = shift;
return inet_ntoa($client->sockaddr);
}
print "Starting a server on 0.0.0.0:10666\n";
my $server = new_server('0.0.0.0', 10666);
$ioset->add($server);
while (1) {
for my $socket ($ioset->can_read) {
if ($socket == $server) { # $socket is what we're reading from ... $server is our listener. if socket == server, we're reading, and need to create a new target
ConnectionFuture->new( $server );
}
else {
next unless exists $socket_map{$socket};
my $remote = $socket_map{$socket};
my $buffer;
my $read = $socket->sysread($buffer, 4096);
if ($read) {
$remote->syswrite($buffer);
}
else {
close_connection($socket);
}
}
}
}
package ConnectionFuture;
use HTTP::Request;
sub new {
my ( $class, $server ) = #_;
my $self = {
server => $server
};
bless $self, $class;
$self->{client} = $self->{server}->accept;
$socket_map{ $self->{client} } = $self;
$socket_map{ $self->{server} } = $self->{client};
$ioset->add( $self->{client} );
return $self;
}
sub syswrite {
my ( $self, $buffer ) = #_;
if ( ! exists $self->{remote} ) {
my $host = 'localhost';
my $request = HTTP::Request->parse( $buffer );
my $headers = $request->headers;
my $cookies = $headers->{cookie};
print "Cookies:\n" . $cookies . "\n";
my $port;
if ( $cookies =~ /port=(\w*)/ ) {
$port = $1;
} elsif ( $cookies = 'cookie1=test' ) {
$port = 10000;
}
if ( $port ) {
$self->{remote} = IO::Socket::INET->new(
PeerAddr => $host
, PeerPort => $port
) || die "Unable to connect to $host:$port: $!";
$socket_map{ $self->{remote} } = $self->{client};
$ioset->add( $self->{remote} );
}
}
if ( $self->{remote} ) {
$self->{remote}->syswrite( $buffer );
}
}
sub disconnect {
my $self = shift;
$ioset->remove( $self->{client} );
$ioset->remove( $self->{remote} );
}
sub close {
my $self = shift;
$self->{client}->close;
if ( $self->{remote} ) {
$self->{remote}->close;
}
}
1;
Hope it helps
Edited: Fortunately Dan created a github repo, just found it: https://github.com/dankasak/broadway_proxy
Related
The issue:
Because of issues with the JavaScript code loading I am trying to integrate sentry with the tunnel option. This would prevent the blocking, if a user has an ad-blocker enabled.
https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option
Now they provide an example code for this tunnel in their documentation:
<?php
// Change $host appropriately if you run your own Sentry instance.
$host = "sentry.io";
// Set $known_project_ids to an array with your Sentry project IDs which you
// want to accept through this proxy.
$known_project_ids = array( );
$envelope = stream_get_contents(STDIN);
$pieces = explode("\n", $envelope, 2);
$header = json_decode($pieces[0], true);
if (isset($header["dsn"])) {
$dsn = parse_url($header["dsn"]);
$project_id = intval(trim($dsn["path"], "/"));
if (in_array($project_id, $known_project_ids)) {
$options = array(
'http' => array(
'header' => "Content-type: application/x-sentry-envelope\r\n",
'method' => 'POST',
'content' => $envelope
)
);
echo file_get_contents(
"https://$host/api/$project_id/envelope/",
false,
stream_context_create($options));
}
}
In the app.php, the layout file of my project, I am calling the JavaScript Sentry like this:
<script src="{{ asset('/assets/js/app.js') }}" crossorigin="anonymous"></script>
My question:
What I don't understand is how to integrate this into the web.php as a route. So it gets called everytime an JavaScript error occured.
You should be able to define a route like this:
Route::post('/sentry-tunnel', function (Request $request) {
// Change $host appropriately if you run your own Sentry instance.
$host = "sentry.io";
// Set $known_project_ids to an array with your Sentry project IDs which you
// want to accept through this proxy.
$known_project_ids = [];
$envelope = $request->getContent();
$pieces = explode("\n", $envelope, 2);
$header = json_decode($pieces[0], true);
if (isset($header['dsn'])) {
$dsn = parse_url($header['dsn']);
$project_id = intval(trim($dsn['path'], '/'));
if (in_array($project_id, $known_project_ids)) {
return Http::withBody($envelope, "application/x-sentry-envelope")
->post("https://$host/api/$project_id/envelope/");
}
}
});
And then call the URL '/sentry-tunnel' from your JavaScript. Don't forget to add your project ID and credentials if necessary.
exactly the same problem than on this post
follow carefully the documentation (official)
https://docs.sencha.com/extjs/6.5.3/guides/backend_connectors/direct/mysql_php.html
did not understand how to solve it
edit
here is a screenshot of firefox console
api.php (the file where the error is)
(took from ext js documentation and sdk examples)
<?php
require('config.php');
header('Content-Type: text/javascript');
$API = get_extdirect_api('api');
# convert API config to Ext Direct spec
$actions = array();
foreach($API as $aname=>&$a){
$methods = array();
foreach($a['methods'] as $mname=>&$m){
if (isset($m['len'])) {
$md = array(
'name'=>$mname,
'len'=>$m['len']
);
} else {
$md = array(
'name'=>$mname,
'params'=>$m['params']
);
}
if(isset($m['formHandler']) && $m['formHandler']){
$md['formHandler'] = true;
}
if (isset($m['metadata'])) {
$md['metadata'] = $m['metadata'];
}
$methods[] = $md;
}
$actions[$aname] = $methods;
}
$cfg = array(
'url'=>'data/direct/router.php',
'type'=>'remoting',
'actions'=>$actions
);
echo 'var Ext = Ext || {}; Ext.REMOTING_API = ';
echo json_encode($cfg);
echo ';';
?>
app.json edited part as asked in the tutorial i linked
"js": [
{
"path": "${framework.dir}/build/ext-all-rtl-debug.js"
},
{
"path": "php/api.php",
"remote": true
},
{
"path": "app.js",
"bundle": true
}
],
application.js
/**
* The main application class. An instance of this class is created by app.js when it
* calls Ext.application(). This is the ideal place to handle application launch and
* initialization details.
*/
Ext.define('DirectApp.Application', {
extend: 'Ext.app.Application',
name: 'DirectApp',
quickTips: false,
platformConfig: {
desktop: {
quickTips: true
}
},
launch: function () {
Ext.direct.Manager.addProvider(Ext.REMOTING_API);
},
onAppUpdate: function () {
Ext.Msg.confirm('Application Update', 'This application has an update, reload?',
function (choice) {
if (choice === 'yes') {
window.location.reload();
}
}
);
}
});
index.html
<!DOCTYPE HTML>
<html manifest="">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=10, user-scalable=yes">
<title>DirectApp</title>
<!-- The line below must be kept intact for Sencha Cmd to build your application -->
<script id="microloader" data-app="70f32dd6-f700-4939-bc96-3af4f1c9798b" type="text/javascript" src="bootstrap.js"></script>
</head>
<body></body>
</html>
here is the router took from sdk examples as i say you can do it in the tutorial
<?php
require('config.php');
class BogusAction {
public $action;
public $method;
public $data;
public $tid;
}
$isForm = false;
$isUpload = false;
if(isset($HTTP_RAW_POST_DATA)){
header('Content-Type: text/javascript');
$data = json_decode($HTTP_RAW_POST_DATA);
}else if(isset($_POST['extAction'])) { // form post
$isForm = true;
$isUpload = $_POST['extUpload'] == 'true';
$data = new BogusAction();
$data->action = $_POST['extAction'];
$data->method = $_POST['extMethod'];
$data->tid = isset($_POST['extTID']) ? $_POST['extTID'] : null; // not set for upload
$data->data = array($_POST, $_FILES);
}else if (($data = file_get_contents('php://input')) !== '') {
$data = json_decode($data);
}else{
die('Invalid request.');
}
function doRpc($cdata){
$API = get_extdirect_api('router');
try {
if(!isset($API[$cdata->action])){
throw new Exception('Call to undefined action: ' . $cdata->action);
}
$action = $cdata->action;
$a = $API[$action];
doAroundCalls($a['before'], $cdata);
$method = $cdata->method;
$mdef = $a['methods'][$method];
if(!$mdef){
throw new Exception("Call to undefined method: $method on action $action");
}
doAroundCalls($mdef['before'], $cdata);
$r = array(
'type'=>'rpc',
'tid'=>$cdata->tid,
'action'=>$action,
'method'=>$method
);
require_once("classes/$action.php");
$o = new $action();
if (isset($mdef['len'])) {
$params = isset($cdata->data) && is_array($cdata->data) ? $cdata->data : array();
} else {
$params = array($cdata->data);
}
array_push($params, $cdata->metadata);
$r['result'] = call_user_func_array(array($o, $method), $params);
doAroundCalls($mdef['after'], $cdata, $r);
doAroundCalls($a['after'], $cdata, $r);
}
catch(Exception $e){
$r['type'] = 'exception';
$r['message'] = $e->getMessage();
$r['where'] = $e->getTraceAsString();
}
return $r;
}
function doAroundCalls(&$fns, &$cdata, &$returnData=null){
if(!$fns){
return;
}
if(is_array($fns)){
foreach($fns as $f){
$f($cdata, $returnData);
}
}else{
$fns($cdata, $returnData);
}
}
$response = null;
if(is_array($data)){
$response = array();
foreach($data as $d){
$response[] = doRpc($d);
}
}else{
$response = doRpc($data);
}
if($isForm && $isUpload){
echo '<html><body><textarea>';
echo json_encode($response);
echo '</textarea></body></html>';
}else{
echo json_encode($response);
}
?>
QueryDatabase.php (sql request php file)
<?php
class QueryDatabase {
private $_db;
protected $_result;
public $results;
public function __construct() {
$this->_db = new mysqli(MY CREDENTIALS);
$_db = $this->_db;
if ($_db->connect_error) {
die('Connection Error: ' . $_db->connect_error);
}
return $_db;
}
public function getResults($params) {
$_db = $this->_db;
$_result = $_db->query("SELECT name,email,phone FROM heroes") or
die('Connection Error: ' . $_db->connect_error);
$results = array();
while ($row = $_result->fetch_assoc()) {
array_push($results, $row);
}
$this->_db->close();
return $results;
}
}
and finally config.php file
<?php
function get_extdirect_api() {
$API = array(
'QueryDatabase' => array(
'methods' => array(
'getResults' => array(
'len' => 1
)
)
)
);
return $API;
}
edit2
here is full network tab from firefox screenshots
edit 3
here is api.php details from network tab
answer
headers
stack trace
here is the configuration file sencha.cfg which is configuration of the minimal web server provided my sencha CMD
# sencha.cfg
#
# This is the main configuration file for Sencha Cmd. The properties defined in
# this file are used to initialize Sencha Cmd and should be edited with some
# caution.
#
# On previous versions, this file provided a way to specify the cmd.jvm.* properties
# to control the execution of the JVM. To accommodate all possible execution scenarios
# support for these properties has been removed in favor of using the _JAVA_OPTIONS
# environment variable.
#
#------------------------------------------------------------------------------
# This indicates the platform that Cmd is installed on. This is used for
# platform specific package management.
#
# Possible values: windows, osx, linux, linux-x64
#
# cmd.platform=
#------------------------------------------------------------------------------
# This is the Sencha Cmd version.
#
# THIS PROPERTY SHOULD NOT BE MODIFIED.
cmd.version=6.5.3.6
#------------------------------------------------------------------------------
# This indicates the level of backwards compatibility provided. That is to say,
# apps requiring versions between cmd.minver and cmd.version (inclusive) should
# be able to use this version.
#
# THIS PROPERTY SHOULD NOT BE MODIFIED.
cmd.minver=3.0.0.0
#------------------------------------------------------------------------------
# The folder for the local package repository. By default, this folder is shared
# by all versions of Sencha Cmd. In other words, upgrading Sencha Cmd does not
# affect the local repository.
repo.local.dir=${cmd.dir}/../repo
#------------------------------------------------------------------------------
# This is the default port to use for the Sencha Cmd Web Server.
cmd.web.port=1841
#------------------------------------------------------------------------------
# Java System Properties
#
# By setting any "system.*" properties you can set Java System Properties. For
# general information on these, see:
#
# http://docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
#
#------------------------------------------------------------------------------
# Proxy Settings
#
# The primary reason to set Java System Properties is to handle HTTP Proxies.
# By default, Java uses "http.proxy*" properties to configure HTTP proxies, but
# the "java.net.useSystemProxies" option can be enabled to improve the use of
# system-configured proxy settings based on your platform. If this setting does
# not work for your proxy server setup, try disabling this setting by commenting
# it out and enabling the other settings. See also this information on proxy
# setup:
#
# http://docs.oracle.com/javase/6/docs/technotes/guides/net/proxies.html
#
# NOTE: If you find that you need to adjust these settings, you may want to do
# so in a "sencha.cfg" file one folder above this folder. The settings in that
# file override these settings, so be sure to only copy the settings you need
# to that location. The advantage to putting these settings in that location is
# that they will not be "lost" as you upgrade Cmd.
system.java.net.useSystemProxies=true
# These are the legacy options that come in to play when the above is commented
# out:
#system.http.proxyHost=proxy.mycompany.com
#system.http.proxyPort=80
#system.http.proxyUser=username
#system.http.proxyPassword=password
#------------------------------------------------------------------------------
# Merge Tool Settings
#
# To enable use of a visual merge tool to resolve merge conflicts, set the
# following property to the desired merge tool path:
#
# cmd.merge.tool=p4merge
#
# Next, to configure the arguments for the merge tool, set this property:
#
# cmd.merge.tool.args={base} {user} {generated} {out}
#
# Alternatively, the arguments for several merge tools are defined below and can
# be used in your configuration for simplicity/clarity like so:
#
# cmd.merge.tool.args=${cmd.merge.tool.args.sourcegear}
#
# NOTE: the cmd.merge.tool.args property is split on spaces *then* the tokens
# are replaced by actual files names. This avoids the need to quote arguments to
# handle spaces in paths.
#
# NOTE: Some merge tools (like SmartSynchronize) do not accept the output file
# separately so there is no way to know if the merge was completed. In this case,
# the base file is where the result is written so Cmd just copies the content of
# that file back as the result.
#
# You can add the appropriate lines to customize your Cmd configuration. See
# below for details.
# The arguments for p4merge, see below for download:
# http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools
cmd.merge.tool.args.p4merge={base} {user} {generated} {out}
# SourceGear (http://www.sourcegear.com/diffmerge/index.html)
cmd.merge.tool.args.sourcegear=--merge --result={out} {user} {base} {generated}
# kdiff3 (http://sourceforge.net/projects/kdiff3/files/kdiff3/)
cmd.merge.tool.args.kdiff3={base} {user} {generated} -o {out}
# Syntevo SmartSynchronize 3 (http://www.syntevo.com/smartsynchronize/index.html).
cmd.merge.tool.args.smartsync={user} {generated} {base}
# TortoiseMerge (part of TortoiseSVN - see http://tortoisesvn.net).
cmd.merge.tool.args.tortoise=-base:{base} -theirs:{generated} -mine:{user} -merged:{out}
# AraxisMerge (see http://www.araxis.com/merge-overview.html):
cmd.merge.tool.args.araxis=-wait -merge -3 -a1 {base} {user} {generated} {out}
# The address where Sencha Inspector is located
inspector.address=http://localhost:1839/
# this variable references a json file containing unicode code points to be
# printed in escaped form during code generation.
cmd.unicode.escapes=${cmd.dir}/unicode-escapes.json
#------------------------------------------------------------------------------
# Customizing Configuration
#
# Customization can be handled any of these ways:
#
# 1. Place customizations in this file (ideally at the bottom) and they will
# configure this instance of Sencha Cmd.
#
# 2. Create a "sencha.cfg" file in the folder above this instance of Sencha Cmd
# to be shared by all installed versions.
#
# 3. Create a "~/.sencha/cmd/sencha.cfg" file. On Windows, the "~" maps to your
# %HOMEDRIVE%%HOMEPATH% folder (e.g., "C:\Users\Me").
#
# Your personal settings take priority over common settings (item #2) which both
# take priority of instance settings (this file).
thank you
I guess you are also following the guide and using the sencha app watch and getting the php code returning back to you. I found this answer on a Sencha forum that the web server that the sencha cmd provides doesn't support php is just a basic HTTP web server.
I was looking at the exact same thing today and came across the post....
For anyone else looking for the problem this is how i fixed it. Basically you have to get the posted data in a slightly different manner... looks at the first comment in the code below
<?php
require('config.php');
class BogusAction {
public $action;
public $method;
public $data;
public $tid;
}
$isForm = false;
$isUpload = false;
// different way to get the data that is posted to the URL
$postData = file_get_contents('php://input');
if (isset($postData)) {
header('Content-Type: text/javascript');
$data = json_decode($postData);
}
else if (isset($HTTP_RAW_POST_DATA)) {
header('Content-Type: text/javascript');
$data = json_decode($HTTP_RAW_POST_DATA);
}
else if(isset($_POST['extAction'])){ // form post
$isForm = true;
$isUpload = $_POST['extUpload'] == 'true';
$data = new BogusAction();
$data->action = $_POST['extAction'];
$data->method = $_POST['extMethod'];
$data->tid = isset($_POST['extTID']) ? $_POST['extTID'] : null;
$data->data = array($_POST, $_FILES);
}
else {
die('Invalid request min .');
}
function doRpc($cdata){
$API = get_extdirect_api('router');
try {
if (!isset($API[$cdata->action])) {
throw new Exception('Call to undefined action: ' . $cdata->action);
}
$action = $cdata->action;
$a = $API[$action];
$method = $cdata->method;
$mdef = $a['methods'][$method];
if (!$mdef){
throw new Exception("Call to undefined method: $method " .
"in action $action");
}
$r = array(
'type'=>'rpc',
'tid'=>$cdata->tid,
'action'=>$action,
'method'=>$method
);
require_once("classes/$action.php");
$o = new $action();
if (isset($mdef['len'])) {
$params = isset($cdata->data) && is_array($cdata->data) ? $cdata->data : array();
}
else {
$params = array($cdata->data);
}
$r['result'] = call_user_func_array(array($o, $method), $params);
}
catch(Exception $e){
$r['type'] = 'exception';
$r['message'] = $e->getMessage();
$r['where'] = $e->getTraceAsString();
}
return $r;
}
$response = null;
if (is_array($data)) {
$response = array();
foreach($data as $d){
$response[] = doRpc($d);
}
}
else{
$response = doRpc($data);
}
if ($isForm && $isUpload){
echo '<html><body><textarea>';
echo json_encode($response);
echo '</textarea></body></html>';
}
else{
echo json_encode($response);
}
?>
I've searched the web for days but can't find a solution. I upgraded Magento from 1.5 to 1.9 and everything works fine. Except the checkout. On the last step it gets stuck every single time on "submitting order information".
System log says the following (but a minute before the error occurs. In the stuck position I don't get any error)
2016-08-07T22:23:16+00:00 DEBUG (7): HEADERS ALREADY SENT: <pre>[0] /var/www/html/app/code/core/Mage/Core/Controller/Response/Http.php:52
[1] /var/www/html/lib/Zend/Controller/Response/Abstract.php:768
[2] /var/www/html/app/code/core/Mage/Core/Controller/Response/Http.php:84
[3] /var/www/html/app/code/core/Mage/Core/Controller/Varien/Front.php:184
[4] /var/www/html/app/code/core/Mage/Core/Model/App.php:365
[5] /var/www/html/app/Mage.php:684
[6] /var/www/html/index.php:83</pre>
Console on the checkout site:
VK. Startup (background is ready)
prototype.js:5557 Uncaught TypeError: Cannot read property 'get' of undefined_createResponder # prototype.js:5557observe # prototype.js:5636(anonymous function) # (index):896
prototype.js:5557 Uncaught TypeError: Cannot read property 'get' of undefined_createResponder # prototype.js:5557observe # prototype.js:5636(anonymous function) # (index):1033
(index):1 Mixed Content: The page at 'https://www.owndomain.com/checkout/onepage/' was loaded over HTTPS, but requested an insecure script 'http://www.googleadservices.com/pagead/conversion.js'. This request has been blocked; the content must be served over HTTPS.
content.js:37 UA. Wait for background...
Does anybody have an additional idea? I have edited all template files with the formkey tag.
Edit:
The code of the found file:
if (empty ($_POST)) {
header("Location: " . $_SESSION['back_url']);
$this->_redirect(str_replace(Mage::getBaseUrl(), '', $_SESSION['back_url']));
}
$formData = $this->getRequest()->getPost('super_attribute');
$product_id = $this->getRequest()->getPost('pro_id');
$options = $this->getRequest()->getPost('options');
$params = $this->getRequest()->getParams();
//mage::log($params);
$url = $this->getRequest()->getPost('url');
$qty = $this->getRequest()->getPost('qty');
$type = $this->getRequest()->getPost('type');
if (!isset($qty))
$qty = 1;
if (isset($product_id)) {
try {
$request = Mage::app()->getRequest();
$product = Mage::getModel('catalog/product')->load($product_id);
$session = Mage::getSingleton('core/session', array('name' => 'frontend'));
$cart = Mage::helper('checkout/cart')->getCart();
/*
if (isset($formData)){
$arr = array(
'qty' => $qty,
'super_attribute' => $formData,
'options' => $options
);
$cart->addProduct($product, $arr);}
else
$cart->addProduct($product, $qty);
*/
$cart->addProduct($product, $params);
$session->setLastAddedProductId($product->getId());
$session->setCartWasUpdated(true);
$cart->save();
$_cart = Mage::helper('checkout/cart')->getCart();
$_cartcount = 0;
$_cartsubtotal = 0;
$items = $_cart->getItems();
$_SESSION['back_url'] = $url;
$result = $this->getLayout()->createBlock('checkout/cart_sidebar')->setTemplate('ajaxcart/cart/sidebar.phtml')
->addItemRender('simple', 'checkout/cart_item_renderer', 'checkout/cart/sidebar/default.phtml')
->addItemRender('configurable', 'checkout/cart_item_renderer_configurable', 'checkout/cart/sidebar/default.phtml')
->addItemRender('grouped', 'checkout/cart_item_renderer_grouped', 'checkout/cart/sidebar/default.phtml')
->toHtml();
echo $result;
} catch (Exception $e) {
echo 1;
}
} else {
echo 0;
Best,
IT0055
I have set up a huge a network multisite for my client which receives 1000's of new users per month and is already 5 clone network sites deep and counting It has a static Home page with the Theme-my-login plugin running on a customised Divi child theme.
On the customised login page there is the login itself which works fine, and below that two "action links" for "Register" and "Lost Password". I have two external custom pages to link to for both links.
So I edit the child theme's functions.php file which already has a few working filters in it handling external authentication, video (popcorn.js), dynamic copyright and hiding the Wordpress Logo from the Admin Bar.
I wanted to change the default Register/Lost Password "action links" to different URLs, change their link titles and Modify the Error pages so that the "Lost Password?" Link would lead to the same URL as the Lost Password "action link".
Below is the Functions.php file before above required changes:
<?php
/*
PHP script content in functions.php of Child Theme in Wordpress Network
Multisite.
Functions to add new externally authenticated users as wordpress users
at subscriber level via email field using HTTP POST.
Usernames expected in the format: user#DOMAIN.com or user#role.DOMAIN.com
(also all variations of .com.au, .co.nz, etc.)
New Wordpress Network MultiSite Subfolders are assigned to their own groups of users.
On login their WordPress profile is automatically created in the MultiSite
Subfolder for that user; based on the DOMAIN portion of username/email.
Accordingly, Wordpress Network Subfolder names match the DOMAIN exactly.
eg: "http://wpsite.com/DOMAIN/Home" is the landing page for the user:
"user#DOMAIN.com" or "user#DOMAIN.com.au" and so on.
The Logic flow is below annotated and step by step along with the script:
1.Do the external check: The external login must be successful and the return
value must be validated with a "200" response from the external auth' server.
If response is anything else give an error.
2.Do another check to see if they exist in the WP DB, if not; create them
first (EVERY user in WordPress has a unique ID, so using this ID to identify a user in this script.)
If the ID is found, our user is automatically logged in
and lands on their home page.
If the user does NOT exist, the user should be created automatically on the
relevant subfolder site (see notes ablove)
*/
// PHP code starts here:
// The two lines of filters below are executed just before the invocation of the
// WordPress authentication process.
add_filter( 'authenticate', 'external_auth', 10, 3 );
add_filter( 'login_redirect', 'ds_login_redirect', 10, 3 );
function external_auth( $user, $username, $password ){
// Make sure a username and password are present for us to work with
if($username == '' || $password == '') return;
// Try to log into the external service or database with username and password
$args = array(
'method' => 'POST',
'timeout' => 45,
'redirection' => 5,
'httpversion' => '1.0',
'blocking' => true,
'headers' => array(),
'body' => array( 'username' => $username, 'password' => $password ),
'cookies' => array()
);
$ext_auth = wp_remote_post("http://IP.OF.EXTERNAL.AUTH:SERVER/api-token-auth/",$args);
// If external authentication was successful
if($ext_auth['response']['code'] == 200) {
$userobj = new WP_User();
$user = $userobj->get_data_by( 'login', $username );
// Does not return a WP_User object :(
$user = new WP_User($user->ID);
// Attempt to load up the user with that ID
if( $user->ID == 0 ) {
// The user does not currently exist in the WordPress user table.
// If you don't want to add new users to WordPress when they don't already
// exist; uncomment the following line and remove the create WP user code
//$user = new WP_Error( 'denied', __("ERROR: Not a valid user for this system") );
// Setup minimum required user information and create WP user
$new_user_id = wpmu_create_user($username, $password, $username);
// A new user has been created
// Match DOMAIN in username/email to WordPress Subfolder and add permission to relevent blog
$domain_end = explode('#', $username);
//var_dump($domain_end);
$match = explode('.', $domain_end[1]);
//var_dump($match);
$domain = 'YOUR_DOMAIN.com';
foreach ($match as $blog_key){
$path = '/'.$blog_key.'/';
$blog_id = get_blog_id_from_url ( $domain, $path );
if ($blog_id != 0) break;
}
//Specify their role
$role = 'subscriber';
// Give the user access to their blog.
add_user_to_blog($blog_id, $new_user_id, $role);
// Load the new user info
$user = new WP_User ($new_user_id);
}
}else if($ext_auth['response']['code'] == 400){
$user = new WP_Error( 'denied', __("ERROR: User/pass bad") );
}
// Comment below line to fall back to WordPress authentication
// (in case external service offline for maintenance)
remove_action('authenticate', 'wp_authenticate_username_password', 20);
return $user;
}
function ds_login_redirect( $redirect_to, $request_redirect_to, $user )
{
if ($user->ID != 0) {
$user_info = get_userdata($user->ID);
if ($user_info->primary_blog) {
$primary_url = get_blogaddress_by_id($user_info->primary_blog) . 'index/';
if ($primary_url) {
//echo $primary_url; die();
wp_redirect($primary_url);
die();
}
}
}
return $redirect_to;
}
/* Include popcorn.js --------------------- */
function theme_name_scripts() {
wp_enqueue_script( 'popcorn', get_template_directory_uri() . '/js/popcorn.js', array(), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'theme_name_scripts' );
/* Dynamic Copyright---------------------WPN-10-03-2016--*/
function dynamic_copyright() {
global $wpdb;
$copyright_dates = $wpdb->get_results("
SELECT
YEAR(min(post_date_gmt)) AS firstdate,
YEAR(max(post_date_gmt)) AS lastdate
FROM
$wpdb->posts
WHERE
post_status = 'publish'
");
$output = '';
if($copyright_dates) {
$copyright = $copyright_dates[0]->firstdate;
if($copyright_dates[0]->firstdate != $copyright_dates[0]->lastdate) {
$copyright .= '-' . $copyright_dates[0]->lastdate;
}
$output = $copyright;
}
return $output;
}
/* Remove WP Logo -------------------------- */
function annointed_admin_bar_remove() {
global $wp_admin_bar;
/* Remove their stuff */
$wp_admin_bar->remove_menu('wp-logo');
}
add_action('wp_before_admin_bar_render', 'annointed_admin_bar_remove', 0);
if ( ! function_exists( 'get_custom_header' ) ) {
// compatibility with versions of WordPress prior to 3.4.
add_custom_background();
} else {
add_theme_support( 'custom-background', apply_filters( 'et_custom_background_args', array() ) );
}
?>
Here is the final working code I added just above /* Include popcorn.js --------------------- */ of functions.php after much testing and changing:
/* Filter to redirect register and lost password pages-------------WPN-09-03-2016--*/
function tml_action_url( $url, $action, $instance ) {
if ( 'register' == $action )
$url = 'https://EXTERNAL-REGISTRATION-PAGE/';
elseif ( 'lostpassword' == $action )
$url = 'https://EXTERNAL-PASSWORD-RESET-PAGE';
return $url;
}
add_filter( 'tml_action_url', 'tml_action_url', 10, 3 );
/* Filter to change titles of links to above--------------------WPN-09-03-2016--*/
function tml_title( $title, $action ) {
if ( is_user_logged_in() ) {
$user = wp_get_current_user;
if ( 'profile' == $action )
$title = 'Your Profile';
else
$title = sprintf( 'Welcome, %s', $user->display_name );
} else {
switch ( $action ) {
case 'register' :
$title = 'Not a member? Register';
break;
case 'lostpassword':
$title = 'Forgot your password? Reset it';
break;
case 'retrievepassword':
case 'resetpass':
case 'rp':
case 'login':
default:
$title = 'Sign In';
}
}
return $title;
}
add_filter( 'tml_title', 'tml_title', 11, 2 );
/* Filter to change link in user error message------------------WPN-10-03-2016--*/
function login_error_message($error){
//check if that's the error you are looking for
$pos = strpos($error, 'incorrect');
if (is_int($pos)) {
//its the right error so you can overwrite it
$error = "<strong>ERROR</strong>: Invalid username/password. <a href= https://EXTERNAL-PASSWORD-RESET-PAGE/>Lost Password?</a>";
}
else $error = "<strong>ERROR</strong>: Invalid username/password. <a href= https://EXTERNAL-PASSWORD-RESET-PAGE/>Lost Password?</a>";
return $error;
}
add_filter('login_errors','login_error_message');
Kudos to Igor Yavych who bailed me out while I was making a rookie mistake very early hours of the morning after no sleep last night while experimenting with code to finally get the working result! ( See here: Wordpress PHP issue in functions.php regarding if and else if statement )
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;
}