[PHP] Stateful RPC

d4f

Kaffee? Wo?
Ich brauchte heute eine php-benutzbare RCP-Loesung
(Remote Procedure Call, also das Benutzen von Funktionen oder Klassen auf einem entfernten Server als ob sie lokal vorliegen wuerden)

Voraussetzungen
  • Muss ein Standard sein (ich habe JSON RPC gewaehlt)
  • muss stateful sein (gespeicherte Variablen der Klasse muessen bei dem naechsten Funktionsaufruf noch vorhanden sein)
  • Muss ueber HTTP mit einem normalen Webserver und PHP funktion
  • Darf nicht vom Client modifizierbar sein (was das Zwischenspeichern auf Clientseite ausschliesst)

Naja ganz habe ich meine Voraussetzungen nicht erfuellen koennen, ich musste JSON-RPC ergaenzen um es "stateful" zu kriegen.
Durch Zeitdruck und Muedigkeit bedingt ist es hack'n code geraten, aber ich bin fuer Feedback und Kritik immer offen =)
Sofern aber ein Client nicht die notwendige Protokollergaenzung mitliefert um sich als stateful-kompatibel auszugeben faellt die Serverseite auf den Standard zurueck.

Benutzung:
Ich gehe von einer Klasse auf Serverseite aus. Funktionen ohne Klasse sind _nicht_ implementiert.

Serverseite:
PHP:
class meineklasse {
     private $MeinName = 'undefiniert';
     public function SpeicherName($name) {
          $this->MeinName = $name;
          return true;
     }
     public function SagHallo() {
          return "hallo ".$this->MeinName;
     }
}

include 'jsonRPCServer.php';
$json = new jsonRPCServer;
$json->handle('meineklasse') OR die("Not a JSON-RPC request!");

Clientseite:
PHP:
include 'jsonRPCClient.php';
$meineklasse = new jsonRPCClient('http://api.beispiel.tld/server.php',true); //true triggert stateful
echo "<br>".$meineklasse->SagHallo();
$meineklasse->SpeicherName('Max Mustermann');
echo "<br>".$meineklasse->SagHallo();


Ein paar Details zur Implementierung:
Basiert auf Ideen dieser Implementierung: http://jsonrpcphp.org/

Protokoll-Ergaenzung
-> Request:
  • <session> [bool] If defined and true, use stateful support
  • <sid> [int] If defined resume an existing session
  • <skey> [var] Security-Key corresponding to the session-id

Sicherheit
nur Funktionen die mit 'public' markiert sind koennen aufgerufen werden. Variablen, sowie protected- und private-Funktionen hingegen nicht.

Jeder Client kann anfragen stellen. Die Authentifizierung -sofern gewuenscht- muss durch die Klasse selbst erfolgen.

Eine Session bedarf zum Resume der Session-ID, dem Session-Key sowie der gleichen IP als die erste Anfrage.

Eine Session ist nur fuer ein paar Sekunden gueltig.

Eine Session ist [aktuell] nur waehrend der Skriptlaufzeit des Clients gueltig

Speicherung

Die serverseitige Klasse wird nach _jedem_ Aufruf mit serialize() in einen String verwandelt und in einer sqlite-Datenbank gespeichert was der Leistung abtraeglich ist. Der Einsatz von Alternativen wie memcachedb waere zumindest teilweise optimaler aber nicht allround-tauglich.

Lizenz
Code:
Copyright 2010 by Daniel Ruppert < daniel@kaffi.lu >
License: http://creativecommons.org/licenses/by-sa/3.0/

[License addition]
You are required to submit any extensions or modifications to the class to the original author's email address. (diff-patch'es preferred)
within 30 days of modification. Failure to do so revokes you the license for lifetime. I made it available, it's only fair you make it available too

Ich bitte um Feedback, Anregungen und Kritik :)
 

Attachments

Last edited by a moderator:
(Remote Procedure Call, also das Benutzen von Funktionen oder Klassen auf einem entfernten Server als ob sie lokal vorliegen wuerden)

Schlag mich, wenn ich jetzt falsch liege, aber:
Was hat ein RPC genau mit Klassen zu tun? Für Klassen (also Methodenaufrufe in Objekten) ist doch RMI zuständig?

Ansonsten schöner Artikel, muss ich mir mal näher zu gemüte führen.
 
Sieht soweit ganz gut was mich nur erheblich stört ist das du da scheinbar keine Namens Konventionen einhälst.
Klassen groß, Methoden klein anfangen dann jedes weitere Wort groß usw. Wenn ich das jetzt implementieren würde würd ich mich ja dumm und dusselig suchen :p
 
nur erheblich stört ist das du da scheinbar keine Namens Konventionen einhäls

Naja mit den Coding-Styles hab ich es nicht soooo ;)
Ich versuch mir grade Yii und deren Coding-Stil auf zu zwingen, mal schauen ob das was wird =)

In der Regel versuche ich aber mich zumindest an meine eigenen Regeln zu halten ^^

- Methoden: Anfangsbuchstabe von jedem Wort gross, Verb als letztes
function MeineFunktion()
function Einlesen()
function DatenEinlesen()

- Variablen klein


Wenn du willst kannst du aber gern ein schnelles Search/Replace der Funktionsnamen auf eine 'offizielle' Konvention machen :)
Selbstbrauerei schmeckt zwar aber Massenproduktion ist doch besser =)

Allerdings brauchst du zur Einbindung die internen Methoden und Variablen nicht zu kennen, nur auf Serverseite die handle(), waehrend es auf Clientseitr keine einzige ist. (__call() wird ja automatisiert aufgerufen)
Ich bau mir demnaechst eine ausfuehrlichere Protokollbeschreibung, ich werde sie dann hier anhaengen :)


Was hat ein RPC genau mit Klassen zu tun? Für Klassen (also Methodenaufrufe in Objekten) ist doch RMI zuständig?
Najaaaaa *hust* Sagen wir so: ich hab nen Cocktail gemacht.
Meine Serverseite nimmt zwar als Eingabe eine Klasse und der Client stellt eine Klasse zur Verfuegung, aber die Schnittstelle ist RPC und die Methoden werden nicht OOP sondern funktional aufgerufen.
jeder RPC-Client in jeder Sprache kann somit die Klasse benutzen - selbst wenn er das Konzept von Objekten gar nicht kennt.
Der Grund ist dass RPC extrem einfach zu implementieren ist und auch cross-language ohne Schwierigkeiten oder Einschraenkungen funktioniert.

Nachteil ist halt dass Variablen nicht clientseitig zur Verfuegung steht was sich aber durch folgende Konstruktion relativ einfach umgehen laesst:
PHP:
class myclass {
     public $publicdata;
     public function GetVar($name) {
          if(isset($this->publicdata[$name[)) return $this->publicdata[$name];
          else return null;
     }
     public function SetVar($name,$value) {
            $this->publicdata[$name] = $value;
     }
}
Vorteil: die Variablen koennen ebenfalls durch eine Authentifizierung abgesichert werden.
 
Last edited by a moderator:
- Methoden: Anfangsbuchstabe von jedem Wort gross, Verb als letztes
function MeineFunktion()
function Einlesen()
function DatenEinlesen()

- Variablen klein

[klugscheiss]
PHP:
class MeineKlasse {
 private $eigenschaft;
 function meineMethode();
}
[/klugscheiss]

So kenn ich es ;)
 
Ok, werde ich fuer die naechste Version ein zu halten versuchen ^^
Trial&Error-Learning hat Nachteile; solche "unwichtige" Sachen wie clean-code und COnventions lernt man nicht :P

Wens interessiert: ich bastle eine neue Version welche unter anderem folgende Funktionen hat
- stateful
- memcachedb/sqlite/mysql als Datenspeicher
- Variablen abrufbar (ausser Ressourcen, Objekte nur eingeschraenkt)
- "native" Funktionalitaet zur Authentifizierung von Clients
- "delayed"-Funktionalitaet fuer unkritische Calls (um Ressourcen zu sparen)
- PHP-PROC over HTTP/HTTPS/TCP/TLS
- verschachtelte Objekte steuerbar (bsp: $Klasse1->Subklasse1->Subklasse2->funktion($klasse1->$klasse2->zeigWert($klasse1->wert))
- OOP-Funktionalitaet ohne OOP-Client benutzbar

Mir ist kein besserer Name eingefallen als PHP-PetRock (PHP-PROC fuer PHP-based prodecure-style remote object-oriented calls)
=> http://github.com/d4fseeker/php-petrock
(Wer die Pet Rocks nicht kennt: http://en.wikipedia.org/wiki/Pet_Rock )
Die Version wird auf meinem privaten Git-Server entwickelt und nach Fertigstellung jedes Releases auf Github gepusht

Any suggestions? ;)
 
Last edited by a moderator:
Back
Top