class Test {
public function mul ($param1, $param2) {
return $param1 * $param2;
}
}
* This source code was highlighted with Source Code Highlighter .
We want to have the same exact class with exactly the same functionality in our client-side JavaScript and write something like:var test = new Test();
var result = test.foo(1,2);
* This source code was highlighted with Source Code Highlighter .
For this, in the current version, I need to create a file (let's call it for decency aip / Test.php) with the following contents:include '../base/IRPCProxy.inc' ;
class Test extends IRPCProxy {
public function mul ($param1, $param2) {
return $param1 * $param2;
}
}
IRPCProxy::populate( new Test());
* This source code was highlighted with Source Code Highlighter .
And we will create test JavaScript in another file (without further ado we call it test.html) of such a plan:var test = new rpc.ServiceProxy( 'api/Test.php' , { asynchronous: false });
var result = test.mul (19, 7);
* This source code was highlighted with Source Code Highlighter .
As you can see, nothing has changed much either in terms of PHP or in terms of JavaScripta. You just need to inherit the class we need in PHP from IRPCProxy and “in a special way” initialize the test variable in JavaScript. Naturally, the JavaScript code is not complete, but in the end, the use of such remote objects looks like this in the code./**
* RPC user implementation
* @author alexander.voronin@gmail.com
*/
class TestUser extends IRPCUser {
/**
* @see IRPCUser::authorize()
*/
public function authorize ( $login, $password ) {
if ( $login == "test" ) {
$ this ->login = $login;
$ this ->role = "admin" ;
return true ;
} else {
IRPCProxy::logText( "Authorization failed for user '$login' - invalid login" );
return false ;
}
}
};
* This source code was highlighted with Source Code Highlighter .
Next we need a session. In order not to confuse data with other projects, our session will be initialized with a special prefix “test” (file impl / TestSession.inc):require_once '../base/IRPCSession.inc' ;
/**
* RPC session implementation
* @author alexander.voronin@gmail.com
*/
class TestSession extends IRPCSession {
/**
* Reload CTOR and create own session namespace
*/
function __construct () {
parent::__construct( "test" );
}
};
* This source code was highlighted with Source Code Highlighter .
And finally, the proxy implementation itself should “know” that we are using not our standard users and sessions, but our own (impl / RPCTestProxy.inc file):// base
require_once '../base/IRPCProxy.inc' ;
// implementations
require_once 'TestSession.inc' ;
require_once 'TestUser.inc' ;
/**
* RPC proxy implementation
* @author alexander.voronin@gmail.com
*/
class TestProxy extends IRPCProxy {
/**
* @see IRPCProxy::createSession()
* @return TestSession
*/
public function createSession() {
return new TestSession();
}
/**
* @see IRPCProxy::createUser()
* @return TestUser
*/
public function createUser() {
return new TestUser();
}
}
* This source code was highlighted with Source Code Highlighter .
Now we are ready to assign permissions to roles in our RPC code in PHP. From the point of view of the current implementation, this is done once at the request, and the resulting code is cached in the session data. The key to the cached code is complex and consists of the session prefix and user role, so that if the user changes his role during the work, the missing code will be generated automatically. It should be noted that if the code already exists, you can only reset the cache by destroying the session or affect the cached code "directly", which, of course, is better not to do so that the code remains clear and readable. So, we distribute the rights (api / Test.php file):<?php
include '../impl/RPCTestProxy.inc' ;
class Test extends RPCTestProxy {
function haveAccess ( $method ) {
switch ( $ this ->getUser()->getRole()) {
case "anonymous" :
switch ( $method ) {
case "mul" :
case "getRole" :
case "sessionLogin" :
return true ;
default :
return false ;
}
case "admin" :
return true ;
default :
return false ;
}
}
public function mul ($param1, $param2) {
return $param1 * $param2;
}
public function getRole () {
return $ this ->getUser()->getRole();
}
public function sessionLogin ($login) {
if ( $ this ->authorize($login, "" )) {
return true ;
} else {
return false ;
}
}
public function sessionLogout () {
$ this ->logout();
}
public function forAdmins () {
return "hello admin" ;
}
}
IRPCProxy::populate( new Test());
?>
* This source code was highlighted with Source Code Highlighter .
As can be seen from the code, we simply define access to the class methods by their name and based on the current role of the user. We also added the sessionLogin method, which allows us to log in without a password and sessionLogout, which obviously ends our session. You should not worry about what is happening inside - everything just works there and, after successful authorization, the role will change for the user, as we agreed above. This is all we need for further work. Now we extend our JavaScript test to show how it all works:// simple log
function log ( msg ) {
document .write( 'LOG: ' + msg + '\n' );
}
var start = new Date();
// RPC init
var test = new rpc.ServiceProxy( 'api/Test.php' , { asynchronous: false });
log( 'Test calls: ' + test.system.listMethods());
log( 'Role: ' + test.getRole());
var result = test.mul (19, 7);
log ( 'Test result: ' + result );
// try to login with invalid credentials
if ( !test.sessionLogin ( 'vasya' )) {
log ( 'Login failed!' );
} else {
log ( 'Login success!' );
}
// check role after login
log( 'Role: ' + test.getRole());
// now try to login with valid credentials
if ( !test.sessionLogin ( 'test' )) {
log ( 'Login failed!' );
} else {
log ( 'Login success!' );
}
// check role after login
log( 'Role: ' + test.getRole());
// must reinit RPC to get access to new methods
test = new rpc.ServiceProxy( 'api/Test.php' , { asynchronous: false });
log( 'Test calls: ' + test.system.listMethods());
log( 'Admin test: ' + test.forAdmins());
// logout now
log ( 'Logout now...' );
test.sessionLogout();
// check role after login
log( 'Role: ' + test.getRole());
// check timing
var stop = new Date();
var testTime = stop.getTime() - start.getTime ();
log ( 'Test time: ' + testTime + 'ms' );
* This source code was highlighted with Source Code Highlighter .
As can be seen from the code, during its execution, the user changes his role twice. In this case, after authorization, you need to re-create an RPC object in order to update its list of methods. After logout, the session with all data is destroyed and the user role is changed to anonymous. Here is a typical result of the execution of such code in the browser:LOG: Test calls: mul,getRole,sessionLogin,system.setJSONDateFormat,system.setDBResultIndexType
LOG: Role: anonymous
LOG: Test result: 133
LOG: Login failed!
LOG: Role: anonymous
LOG: Login success!
LOG: Role: admin
LOG: Test calls: mul,getRole,sessionLogin,sessionLogout,forAdmins,system.setJSONDateFormat,system.setDBResultIndexType
LOG: Admin test: hello admin
LOG: Logout now...
LOG: Role: anonymous
LOG: Test time: 212ms
Source: https://habr.com/ru/post/110727/
All Articles