PHP、JavaScript、RPC、その他の恐ろしい言葉

私たちは皆ここに集まって、賢く、教育を受け、美しく、経験を積んでいます。 そして今日、私には、ほとんどすべての人が、このタイプのJavaScriptとPHPの間のRPCを使用しています。 誰かが松葉杖や小道具を開発することさえあります。 もちろん、私も例外ではありません。 確かに、私は最も抵抗の少ない道を歩みました。実際、この記事ではJavaScriptとPHPのXML \ JSON RPCの次の実装について説明します。

その背景から、ある種のデータ管理システムを開発する必要がありました。 当然、データはDBMSに保存されるため、Webで管理する必要があります。 私はフレームワークに夢中になりたくなかったので、PHPクイックコーディング、またはsmartyなどの既成の開発に基づいたレンダリングを使用したMVCの選択はあまりよくありませんでした。 しかし、ほぼ同時に、extJS(別名Sencha)やqooxdooなどのプロジェクトに注目しました。これらのプロジェクトにより、退屈なHTMLレイアウト、HTML / XML生成、XSLT変換、およびその他多くの「怖い」ことなく本格的なWebアプリケーションを作成できます»MVCおよびPHPのbydcode固有のもの。 したがって、次のアクションプランは成熟しています。
したがって、どのようなモデルであるかはわかりませんが、MVCではなく、すでに太っているクライアントです。 一般的に、何が起こったのか、最終的に私は本当に好きです。 インターフェースについては、選択はqooxooにかかっていました-それはGNUライセンスであり、私の意見では、そのコードはextJSのようにインターフェースの宣言的なJSONスタイルのプログラミングよりもOOPとFPに重点を置いています。 しかし、RPCには少し工夫がありました。

軽量で、独立した、理解しやすい、シンプルで、ハーフキックで動作するものを探していました。 このようなプロジェクトはcode.google.com/p/json-xml-rpcで見つかりましたこれは、PHPのサーバーとJavaScriptのクライアントを使用した、かなり柔軟でシンプルなRPCの実装で、XMLとJSONの両方で動作し、同期、非同期呼び出し。これは後で重要ではないことが判明しました。 次のステップは、RPC、およびロールとアクセス権の分配システムを拡張することでした。 これについて詳しく説明したいと思います。 だから。

そもそも、私はOOPスクールの支持者であり、一般に、オリジナルのC ++で記述します。その結果、そのようなPHPやJavaScript自体は、コードで許可または禁止することに関して時々怒り狂います。 それにもかかわらず、OOPで再利用されるコードを書くことは可能であるだけでなく、必要でもあると思います。 そして、何を書いてもかまいません。 そのため、このシステム用に一連のインターフェイスとその実装が開発されました。これは、セッション、承認、ユーザー、ロールなどの作業の側面を反映します。また、PHPクラスをJavaScriptに自動的に転送するだけでなく、メソッド呼び出しまでこれらのクラスにアクセス権を割り当てます。

まず、PHPとJavaScriptでタスクとコードを設定する観点から見た様子を示します。 単純なクラスがあるとしましょう:
class Test {
public function mul ($param1, $param2) {
return $param1 * $param2;
}
}


* This source code was highlighted with Source Code Highlighter .
クライアント側のJavaScriptでまったく同じ機能を持つまったく同じクラスを作成し、次のように記述します。
var test = new Test();
var result = test.foo(1,2);

* This source code was highlighted with Source Code Highlighter .
これを行うには、現在のバージョンでは、次の内容のファイルを作成する必要があります(良識のaip / Test.phpで呼び出しましょう):
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 .
そして、そのような計画の別のファイルにテストJavaScriptを作成してみましょう(これ以上テストを行わずにtest.htmlと呼びます)。
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 .
ご覧のとおり、PHPの観点からもJavaScriptaの観点からも大きな変化はありません。 PHPで必要なクラスをIRPCProxyから継承し、「特別な方法」でJavaScriptのテスト変数を初期化するだけです。 当然、JavaScriptコードは完全ではありませんが、最終的に、そのようなリモートオブジェクトの使用は、コードでの使用とまったく同じに見えます。

今すぐアクセス権。 RPCシステム自体は、セッションについても、ユーザーについても、当然のことながら、その役割についてもまったく知りません。 これらはすべて、私が開発したクラスとインターフェースによって、いつの間にか簡単に制御されます。 主なエンティティ:PHPをリクエストする場合、RPCのコードは毎回生成および解析されるのではなく、セッションのパラメーターに応じてキャッシュされることに注意してください。 さらに、現在の実装では、コードはセッションデータの形式でキャッシュされますが、おそらくそれらを個別のファイルに保存する方が収益性が高くなるか、このオプションをテストしていません。 そのため、結果として、完全なシステムを取得するには、ユーザーコードとセッションコードを実装する必要があります。 基本クラスは、実装の特定の明確化なしで非常にうまく機能するため、これは必要ありません。 つまり、上で書かれたコードは期待どおりに機能します。

ユーザーから始めましょう。 怠け者になり、その承認は正しいログインの確認とロールの変更(ファイルimpl / TestUser.inc)のみで構成されます。
/**
* 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 .
次に、セッションが必要です。 データを他のプロジェクトと混同しないように、セッションは特別な接頭辞「test」(ファイル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 .
最後に、プロキシの実装自体は、標準のユーザーとセッションではなく、独自の(impl / RPCTestProxy.incファイル)を使用していることを「認識」する必要があります。
// 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 .
これで、PHPのRPCコードでロールごとに権利を配布する準備が整いました。 現在の実装の観点から見ると、これは要求に応じて1回行われ、受信したコードはセッションデータにキャッシュされます。 キャッシュされたコードのキーは複雑で、セッションプレフィックスとユーザーロールで構成されているため、ユーザーが作業中にロールを変更すると、不足しているコードが自動的に生成されます。 コードが既に存在する場合、セッションを破棄するか、キャッシュされたコードを「直接」実行することによってのみキャッシュをリセットできます。もちろん、コードを明確で読みやすいものにしない方がよいことに注意してください。 そのため、権利(api / Test.phpファイル)を配布します。
<?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 .
コードからわかるように、クラスのメソッドへのアクセスは、その名前とユーザーの現在のロールに基づいて判断するだけです。 また、sessionLoginメソッドを追加しました。これにより、パスワードとsessionLogoutなしでログインできるようになり、明らかにセッションが終了します。 内部で何が起こっているか心配する必要はありません。すべてがそこで機能し、承認に成功すると、ユーザーは上記で合意したように役割を変更します。 これが、今後の作業に必要なすべてです。 JavaScriptテストを展開して、すべてがどのように機能するかを示します。
// 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 .
コードからわかるように、実行の過程で、ユーザーはロールを2回変更します。 承認後、メソッドのリストを更新するためにRPCオブジェクトを再作成する必要があります。 ログイン後、すべてのデータを含むセッションは破棄され、ユーザーロールは匿名に変更されます。 このようなコードをブラウザで実行した典型的な結果は次のとおりです。

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


その結果、HTMLレイアウトをまったく使用せずに動作するWebシステムを手に入れました。 データモデルのコードとその処理を純粋な非クラウドPHPで記述し、上記のRPCシステムを介してアクセスできるようにします。クライアントは、ウィンドウ、リベット、フリルを備えた通常のqooxdooアプリケーションです。 そのようなシステムの場合、MVC世紀は終わりを迎え、彼らが言うように神に感謝します!

結論として、パフォーマンスについていくつかお話したいと思います。 確かに-RPCは遅いです。 ただし、非同期RPC要求を使用すると、RPC呼び出し時にブラウザーがフリーズするのをなくすことができます。もちろん、コード自体の記述方法に注意する必要があります。 おそらく、ダースのRPC呼び出しを1つに結合するか、メソッドの結果として返されるものについて考える必要があります。

上記の例全体とRPCラッパーコードは、 depositfiles.com / files / xsnid5wg9からダウンロードできます。どこかで使用することを考えている場合は、作成者に問い合わせてください。 ありがとう

あなたに良い、美しく、安定したコード!

Source: https://habr.com/ru/post/J110727/


All Articles