diff --git a/web.d.php b/web.d.php new file mode 100644 index 0000000..9ddffd0 --- /dev/null +++ b/web.d.php @@ -0,0 +1,231 @@ +sessionId = hash("sha256", + $_SERVER["REMOTE_ADDR"] . "\r\n" . + $_SERVER["HTTP_USER_AGENT"] . "\r\n" . + $token); + + $path = "/tmp/arsd_session_file_" . $this->sessionId; + if(file_exists($path)) + $this->data = + json_decode(file_get_contents($path)); + } + } + + public $sessionId = ""; + + /// The data in the session, as a PHP object. Note that any writes + /// to it will be discarded. + public $data = null; +} + +/// This provides a base for exceptions thrown by D +class WebDotDException extends Exception {} + +/** + If you've used the Javascript generated by web.d, you'll + find this very familiar; this is a port of that for the + most part. + + The ApiProvider methods don't make a call directly. Instead, + they return an object that you can tweak a little, pass + to other functions, and retreive the data. + + When getting synchronously, D exceptions are translated to PHP + exceptions, and the return value is returned right here. Use + the getSync() method to do this. + + NOT IMPLEMENTED IN PHP + When getting asynchrously, D exceptions are sent to an onError + delegate, and successes are sent to a handler delegate. Use + the get() method to do this. + DONE WITH NOT IMPLEMENTED + + For example: + + // using it anonymously (probably the easiest way) + $result = $api->getMyData("hello")->getSync(); // it waits for the + // D to respond. Fast if + // local, but can be slow if + // accessing remote servers. + + // using it with a name + $call = $api->getMyData("hello"); + // you can change the returned format with a method on the object + $call->format("html"); + // and now get it + $result = $call.getSync(); + + // you can also chain method calls in one line + $result = $api->getMyData("hello")->format("html")->getSync(); + + + You can also change the parameters of the request. You shouldn't + need this most the time, but sometimes it's useful to have more + control. + + $call = $api->getMyData("hello"); + // add an additional request param + $call->setValue("my-request-param", "whatever"); + $call->setMethod("POST"); // override the default HTTP verb for the call + + $call->getSync(); // execute the request + + + But, more often than not, you can use the call pretty easily with the + anonymous one-liner. +*/ +class WebDotDMethodCall { + public function __construct($apiProvider, $method, $url, $params) { + $this->apiProvider = $apiProvider; + $this->method = $method; + $this->url = $url; + $this->requestedDataFormat = "json"; + $num = 0; + foreach($params as $arg) { + $this->urlargs["positional-arg-" . $num] = $arg; + $num++; + } + } + + public function format($dataFormat) { + $this->requestedDataFormat = $dataFormat; + return $this; + } + + public function setMethod($httpMethod) { + $this->method = $httpMethod; + return $this; + } + + public function setValue($name, $value) { + $this->urlargs[$name] = $value; + return $this; + } + + private $apiProvider; + private $url; + private $urlargs; + private $method; + private $requestedDataFormat; + + public function getSync() { + $args = ""; + $num = 0; + + $params = $this->urlargs; + $params["envelopeFormat"] = "json"; + $params["format"] = $this->requestedDataFormat; + + $outputted = false; + foreach($params as $k => $arg) { + if($outputted) { + $args .= "&"; + } else { + $outputted = true; + } + + $args .= urlencode($k); + $args .= "="; + $args .= urlencode($arg); + } + + $url = $this->url; + + if($this->method == "GET") + $url .= "?" . $args; + + + $ch = curl_init($url); + if($this->method == "POST") { + curl_setopt($ch, CURLOPT_POST,1); + curl_setopt($ch, CURLOPT_POSTFIELDS, $args); + } + curl_setopt($ch, CURLOPT_HEADER,0); + curl_setopt($ch, CURLOPT_RETURNTRANSFER,1); + $data = curl_exec($ch); + + $resultObj = json_decode($data); + + if($resultObj == null) { + echo $data; + throw new WebDotDException("Got null JSON"); + } + + if($resultObj->success) { + return $resultObj->result; + } else { + // FIXME: maybe we can use type for better info? + $msg = $resultObj->type; + if(strlen($msg) > 0) + $msg .= ": "; + $msg .= $resultObj->errorMessage; + throw new WebDotDException($msg); + } + + // assert(0); // not reached + } +} + +/// Base class for accessing web.d ApiProviders. +/// It doesn't do authentication, so you should use a subclass of it. +/// If you are on the same server as the api you are accessing, you can use +/// WebDotDLocalApiProvider, passing it a session object. This works with +/// all web.d classes, since the local authentication is built in. +/// +/// Developers: you might use this as a base for your own remote classes, +/// if you are making a web service, adding some authentication or +/// custom branding. See the protected functions for available hooks. +class WebDotDApiProvider { + private $endpoint; + // The endpoint is a full URL to the base of your web.d program, with trailing slash. + // for example: http://mywebsite.com/myapp/ + public function __construct($endpoint) { + $this->endpoint = $endpoint; + } + + public function __call($name, $params = null) { + $url = $this->endpoint . $name; + + return new WebDotDMethodCall($this, + strpos($name, "get") === 0 ? "GET" : "POST", + $url, + $params); + } +} + +/// Provides access to a *local* D ApiProvider. +class LocalWebDotDProvider extends WebDotDApiProvider { + /// Takes a WebDotDSession + public function __construct($session) { + + } +}