a42c14ed2f4c4b2c811994e5898d363468c8d44d
[atutor.git] / mods / wiki / plugins / lib / phprpc.php
1 <?php
2 /*
3    Minimal raw RPC query support over HTTP. All variables are simply
4    serialized() and then transmitted, minimal access permission checks
5    are done (there is a $phprpc_methods like with the xmlrpc lib).
6 */
7
8 define("PHPRPC_VERSION", 1);
9 define("PHPRPC_TYPE", "application/vnd.php.serialized");
10 @$ewiki_config["ua"] .= " phprpc/1";
11
12
13 #-- do call
14 function phprpc($url, $func, $args) {
15    global $ewiki_config, $phprpc_error;
16
17    #-- prepare
18    $args = array(
19       "methodName" => $func,
20       "params" => $args,
21    );
22    $args = serialize($args);
23    $args = gzdeflate($args);
24    $len_args = strlen($args);
25
26    #-- prepare HTTP request
27    $c = parse_url($url);
28    extract($c);
29    ($port) || ($port=80);
30    ($query) && ($path .= "?$query");
31    $n = "\015\012";
32    $req = "POST $path HTTP/1.0$n"
33         . "Host: $host$n"
34         . ($user ? "Authorization: Basic ".base64_encode("$user:$pass").$n : "")
35         . "User-Agent: $ewiki_config[ua]$n"
36         . "Accept-Encoding: deflate$n"
37         . "Connection: close$n"
38         . "Accept: ".PHPRPC_TYPE."$n"
39         . "Content-Type: ".PHPRPC_TYPE."; version=".PHP_VERSION."$n"
40         . "$n";
41
42    #-- open connection
43    if ($f = fsockopen($host, $port, $io_err, $io_err_s, 20)) {
44       socket_set_blocking($f, true);
45       socket_set_timeout($f, 17, 555);
46
47       #-- send
48       fwrite($f, $req);
49       fwrite($f, "Content-Length: $len_args$n");
50       fwrite($f, "$n");
51       fwrite($f, $args);  $args = "";  //freemem()
52       fwrite($f, "$n");
53
54       #-- read
55       $result = "";
56       while (!feof($f)) {
57          $result .= fread($f, 1<<21);  // max 2MB (incl. headers)
58       }
59
60       #-- strip headers
61       while ($p = strpos($result, "\n")) {
62          $line = trim(substr($result, 0, $p));
63          $result = substr($result, $p + 1);
64          if (!strlen($line)) {
65             break;
66          }
67          $h[strtolower(strtok($line, ":"))] = trim(strtok("\000"));
68       }
69       fclose($f);
70 #print_r($h);
71 #print_r($result);
72
73       #-- decode
74       if (strtolower(trim(strtok($h["content-type"], ";"))) == PHPRPC_TYPE) {
75          if ($h["content-encoding"] == "gzip") {
76             $result = gzinflate(substr($result, 10, strlen($result)-18));
77          }
78          if ($h["content-encoding"] == "deflate") {
79             $result = gzinflate($result);
80          }
81          $result = unserialize($result);
82
83          #-- ok
84          if ($result) {
85             return($result);
86          }
87       }//decode
88
89    } else { $phprpc_error = "no socket/connection"; } //socket
90 }
91
92
93
94 #-- handle calls
95 function phprpc_server($allowed="*") {
96
97    global $phprpc_methods, $ewiki_config, $HTTP_RAW_POST_DATA;
98    if ($phprpc_methods) {
99       $allowed = $phprpc_methods;
100    }
101
102    if (($_SERVER["REQUEST_METHOD"] == "POST")
103    and (strtolower(trim(strtok($_SERVER["CONTENT_TYPE"], ";"))) == PHPRPC_TYPE))
104    {
105        #-- get raw data
106        if ($f = fopen("php://input", "rb")) {
107           $HTTP_RAW_POST_DATA = fread($f, 1<<21);  // 2MB max (packed)
108           fclose($f);
109        }
110        $call = unserialize(gzinflate($HTTP_RAW_POST_DATA));
111
112        #-- make function call
113        if (is_array($call)) {
114
115           #-- params
116           ($method = $call["method"]) || ($method = $call["func"]) || ($method = $call["function"]) || ($method = $call["methodName"]);
117           ($args = $call["args"]) || ($args = $call["params"]);
118
119           #-- plain function or static method call
120           if (strpos($method, ":") || strpos($method, ".")) {
121              $class = strtok($method, ":.");
122              $method = trim(strtok(" "), ":");
123           }
124           if ($class) {
125              $method = array($class, $method);
126           }
127           
128           #-- exec, if
129           if (($allowed=="*") || in_array(strtolower($method), $allowed)
130           || in_array(strtolower($class), $allowed)
131           || ($method = $allowed[strtolower($method)]))
132           {
133              $r = call_user_func_array($method, $args);
134           }
135           else {
136              header("Status: 400 Forbidden Method"); exit;
137           }
138        }
139        else {
140           header("Status: 500 Could Not Unserialize"); exit;
141        }
142
143        #-- return result
144        if ($r) {
145           header("X-Server: $ewiki_config[ua]");
146           header("Content-Type: ".PHPRPC_TYPE."; version=".PHP_VERSION);
147           header("Cache-Control: no-cache, private");
148           $r = serialize($r);
149           $r = gzdeflate($r);
150           header("Content-Encoding: deflate");
151           header("Content-Length: ".strlen($r));
152           print($r);
153           exit;
154        }
155
156        #-- error
157        header("Status: 500 Didn't Work");
158        exit;
159    }
160    else {
161       header("X-PHP-RPC-Error: Wrong request method $_SERVER[REQUEST_METHOD] and/or type $_SERVER[CONTENT_TYPE]");
162    }
163 }
164
165 ?>