Skip to content

Commit f77b3cd

Browse files
committed
improve debugger support for php cli-webserver
1 parent 805d727 commit f77b3cd

File tree

3 files changed

+155
-131
lines changed

3 files changed

+155
-131
lines changed

NEWS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## XML-RPC for PHP version 4.xx.yy - unreleased
2+
3+
* improved: avoid stalling the webserver when using the debugger with the php built-in webserver and testing the demo
4+
server within the same install
5+
6+
17
## XML-RPC for PHP version 4.9.2 - 2022-12-18
28

39
* security fix: removed the possibility of an XSS attack in the debugger.

debugger/action.php

Lines changed: 141 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -94,153 +94,166 @@
9494

9595
if ($action) {
9696

97-
// make sure the script waits long enough for the call to complete...
98-
if ($timeout) {
99-
set_time_limit($timeout + 10);
97+
// avoid php hanging when using the builtin webserver and sending requests to itself
98+
$skip = false;
99+
if (php_sapi_name() === 'cli-server' && ((int)getenv('PHP_CLI_SERVER_WORKERS') < 2)) {
100+
$localHost = explode(':', $_SERVER['HTTP_HOST']);
101+
/// @todo support also case where port is null (on either side), and when there is a Proxy in the parameters,
102+
/// and that proxy is us
103+
if ($localHost[0] == $host && (@$localHost[1] == $port)) {
104+
$actionname = '[ERROR: can not make call to self when running php-cli webserver without setting PHP_CLI_SERVER_WORKERS]';
105+
$skip = true;
106+
}
100107
}
101108

102-
if ($wstype == 1) {
103-
//@include 'jsonrpc.inc';
104-
if (!class_exists('\PhpXmlRpc\JsonRpc\Client')) {
105-
die('Error: to debug the jsonrpc protocol the phpxmlrpc/jsonrpc package is needed');
109+
if (!$skip) {
110+
// make sure the script waits long enough for the call to complete...
111+
if ($timeout) {
112+
set_time_limit($timeout + 10);
106113
}
107-
$clientClass = '\PhpXmlRpc\JsonRpc\Client';
108-
$requestClass = '\PhpXmlRpc\JsonRpc\Request';
109-
$protoName = 'JSONRPC';
110-
} else {
111-
$clientClass = '\PhpXmlRpc\Client';
112-
$requestClass = '\PhpXmlRpc\Request';
113-
$protoName = 'XMLRPC';
114-
}
115114

116-
if ($port != "") {
117-
$client = new $clientClass($path, $host, $port);
118-
$server = "$host:$port$path";
119-
} else {
120-
$client = new $clientClass($path, $host);
121-
$server = "$host$path";
122-
}
123-
if ($protocol == 2 || $protocol == 3) {
124-
$server = 'https://' . $server;
125-
} else {
126-
$server = 'http://' . $server;
127-
}
128-
if ($proxy != '') {
129-
$pproxy = explode(':', $proxy);
130-
if (count($pproxy) > 1) {
131-
$pport = $pproxy[1];
115+
if ($wstype == 1) {
116+
if (!class_exists('\PhpXmlRpc\JsonRpc\Client')) {
117+
die('Error: to debug the jsonrpc protocol the phpxmlrpc/jsonrpc package is needed');
118+
}
119+
$clientClass = '\PhpXmlRpc\JsonRpc\Client';
120+
$requestClass = '\PhpXmlRpc\JsonRpc\Request';
121+
$protoName = 'JSONRPC';
132122
} else {
133-
$pport = 8080;
123+
$clientClass = '\PhpXmlRpc\Client';
124+
$requestClass = '\PhpXmlRpc\Request';
125+
$protoName = 'XMLRPC';
134126
}
135-
$client->setProxy($pproxy[0], $pport, $proxyuser, $proxypwd);
136-
}
137127

138-
if ($protocol == 2 || $protocol == 3) {
139-
$client->setSSLVerifyPeer($verifypeer);
140-
$client->setSSLVerifyHost($verifyhost);
141-
if ($cainfo) {
142-
$client->setCaCertificate($cainfo);
128+
if ($port != "") {
129+
$client = new $clientClass($path, $host, $port);
130+
$server = "$host:$port$path";
131+
} else {
132+
$client = new $clientClass($path, $host);
133+
$server = "$host$path";
143134
}
144-
if ($protocol == 3) {
145-
$httpprotocol = 'h2';
135+
if ($protocol == 2 || $protocol == 3) {
136+
$server = 'https://' . $server;
146137
} else {
147-
$httpprotocol = 'https';
138+
$server = 'http://' . $server;
139+
}
140+
if ($proxy != '') {
141+
$pproxy = explode(':', $proxy);
142+
if (count($pproxy) > 1) {
143+
$pport = $pproxy[1];
144+
} else {
145+
$pport = 8080;
146+
}
147+
$client->setProxy($pproxy[0], $pport, $proxyuser, $proxypwd);
148148
}
149-
} elseif ($protocol == 4) {
150-
$httpprotocol = 'h2c';
151-
} elseif ($protocol == 1) {
152-
$httpprotocol = 'http11';
153-
} else {
154-
$httpprotocol = 'http';
155-
}
156-
157-
if ($username) {
158-
$client->setCredentials($username, $password, $authtype);
159-
}
160149

161-
$client->setDebug($debug);
150+
if ($protocol == 2 || $protocol == 3) {
151+
$client->setSSLVerifyPeer($verifypeer);
152+
$client->setSSLVerifyHost($verifyhost);
153+
if ($cainfo) {
154+
$client->setCaCertificate($cainfo);
155+
}
156+
if ($protocol == 3) {
157+
$httpprotocol = 'h2';
158+
} else {
159+
$httpprotocol = 'https';
160+
}
161+
} elseif ($protocol == 4) {
162+
$httpprotocol = 'h2c';
163+
} elseif ($protocol == 1) {
164+
$httpprotocol = 'http11';
165+
} else {
166+
$httpprotocol = 'http';
167+
}
162168

163-
switch ($requestcompression) {
164-
case 0:
165-
$client->request_compression = '';
166-
break;
167-
case 1:
168-
$client->request_compression = 'gzip';
169-
break;
170-
case 2:
171-
$client->request_compression = 'deflate';
172-
break;
173-
}
169+
if ($username) {
170+
$client->setCredentials($username, $password, $authtype);
171+
}
174172

175-
switch ($responsecompression) {
176-
case 0:
177-
$client->accepted_compression = '';
178-
break;
179-
case 1:
180-
$client->accepted_compression = array('gzip');
181-
break;
182-
case 2:
183-
$client->accepted_compression = array('deflate');
184-
break;
185-
case 3:
186-
$client->accepted_compression = array('gzip', 'deflate');
187-
break;
188-
}
173+
$client->setDebug($debug);
174+
175+
switch ($requestcompression) {
176+
case 0:
177+
$client->request_compression = '';
178+
break;
179+
case 1:
180+
$client->request_compression = 'gzip';
181+
break;
182+
case 2:
183+
$client->request_compression = 'deflate';
184+
break;
185+
}
189186

190-
$cookies = explode(',', $clientcookies);
191-
foreach ($cookies as $cookie) {
192-
if (strpos($cookie, '=')) {
193-
$cookie = explode('=', $cookie);
194-
$client->setCookie(trim($cookie[0]), trim(@$cookie[1]));
187+
switch ($responsecompression) {
188+
case 0:
189+
$client->accepted_compression = '';
190+
break;
191+
case 1:
192+
$client->accepted_compression = array('gzip');
193+
break;
194+
case 2:
195+
$client->accepted_compression = array('deflate');
196+
break;
197+
case 3:
198+
$client->accepted_compression = array('gzip', 'deflate');
199+
break;
195200
}
196-
}
197201

198-
$msg = array();
199-
switch ($action) {
200-
// fall thru intentionally
201-
case 'describe':
202-
case 'wrap':
203-
$msg[0] = new $requestClass('system.methodHelp', array(), $id);
204-
$msg[0]->addparam(new PhpXmlRpc\Value($method));
205-
$msg[1] = new $requestClass('system.methodSignature', array(), (int)$id + 1);
206-
$msg[1]->addparam(new PhpXmlRpc\Value($method));
207-
$actionname = 'Description of method "' . $method . '"';
208-
break;
209-
case 'list':
210-
$msg[0] = new $requestClass('system.listMethods', array(), $id);
211-
$actionname = 'List of available methods';
212-
break;
213-
case 'execute':
214-
if (!payload_is_safe($payload)) {
215-
die("Tsk tsk tsk, please stop it or I will have to call in the cops!");
202+
$cookies = explode(',', $clientcookies);
203+
foreach ($cookies as $cookie) {
204+
if (strpos($cookie, '=')) {
205+
$cookie = explode('=', $cookie);
206+
$client->setCookie(trim($cookie[0]), trim(@$cookie[1]));
216207
}
217-
$msg[0] = new $requestClass($method, array(), $id);
218-
// hack! build xml payload by hand
219-
if ($wstype == 1) {
220-
$msg[0]->payload = "{\n" .
221-
'"method": "' . $method . "\",\n\"params\": [" .
222-
$payload .
223-
"\n],\n\"id\": ";
224-
// fix: if user gave an empty string, use NULL, or we'll break json syntax
225-
if ($id == "") {
226-
$msg[0]->payload .= "null\n}";
227-
} else {
228-
if (is_numeric($id) || $id == 'false' || $id == 'true' || $id == 'null') {
229-
$msg[0]->payload .= "$id\n}";
208+
}
209+
210+
$msg = array();
211+
switch ($action) {
212+
// fall thru intentionally
213+
case 'describe':
214+
case 'wrap':
215+
$msg[0] = new $requestClass('system.methodHelp', array(), $id);
216+
$msg[0]->addparam(new PhpXmlRpc\Value($method));
217+
$msg[1] = new $requestClass('system.methodSignature', array(), (int)$id + 1);
218+
$msg[1]->addparam(new PhpXmlRpc\Value($method));
219+
$actionname = 'Description of method "' . $method . '"';
220+
break;
221+
case 'list':
222+
$msg[0] = new $requestClass('system.listMethods', array(), $id);
223+
$actionname = 'List of available methods';
224+
break;
225+
case 'execute':
226+
if (!payload_is_safe($payload)) {
227+
die("Tsk tsk tsk, please stop it or I will have to call in the cops!");
228+
}
229+
$msg[0] = new $requestClass($method, array(), $id);
230+
// hack! build xml payload by hand
231+
if ($wstype == 1) {
232+
$msg[0]->payload = "{\n" .
233+
'"method": "' . $method . "\",\n\"params\": [" .
234+
$payload .
235+
"\n],\n\"id\": ";
236+
// fix: if user gave an empty string, use NULL, or we'll break json syntax
237+
if ($id == "") {
238+
$msg[0]->payload .= "null\n}";
230239
} else {
231-
$msg[0]->payload .= "\"$id\"\n}";
240+
if (is_numeric($id) || $id == 'false' || $id == 'true' || $id == 'null') {
241+
$msg[0]->payload .= "$id\n}";
242+
} else {
243+
$msg[0]->payload .= "\"$id\"\n}";
244+
}
232245
}
246+
} else {
247+
$msg[0]->payload = $msg[0]->xml_header($inputcharset) .
248+
'<methodName>' . $method . "</methodName>\n<params>" .
249+
$payload .
250+
"</params>\n" . $msg[0]->xml_footer();
233251
}
234-
} else {
235-
$msg[0]->payload = $msg[0]->xml_header($inputcharset) .
236-
'<methodName>' . $method . "</methodName>\n<params>" .
237-
$payload .
238-
"</params>\n" . $msg[0]->xml_footer();
239-
}
240-
$actionname = 'Execution of method ' . $method;
241-
break;
242-
default: // give a warning
243-
$actionname = '[ERROR: unknown action] "' . $action . '"';
252+
$actionname = 'Execution of method ' . $method;
253+
break;
254+
default: // give a warning
255+
$actionname = '[ERROR: unknown action] "' . $action . '"';
256+
}
244257
}
245258

246259
// Before calling execute, echo out brief description of action taken + date and time ???
@@ -256,8 +269,7 @@
256269
$resp = array();
257270
$time = microtime(true);
258271
foreach ($msg as $message) {
259-
// catch errors: for older xmlrpc libs, send does not return by ref
260-
@$response = $client->send($message, $timeout, $httpprotocol);
272+
$response = $client->send($message, $timeout, $httpprotocol);
261273
$resp[] = $response;
262274
if (!$response || $response->faultCode()) {
263275
break;

debugger/controller.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,11 +226,17 @@ function buildparams(base64data) {
226226

227227
// use GET for ease of refresh, switch to POST when payload is too big to fit in url (in IE: 2048 bytes! see http://support.microsoft.com/kb/q208427/)
228228
function switchFormMethod() {
229-
/// @todo use a more precise calculation, adding the rest of the fields to the actual generated url lenght
229+
/// @todo use a more precise calculation, adding the rest of the fields to the actual generated url length -
230+
/// retrieve first max url length for current browsers and webservers
230231
if (document.frmaction.methodpayload.value.length > 1536) {
231232
document.frmaction.action = 'action.php?usepost=true';
232233
document.frmaction.method = 'post';
233234
}
235+
/*let form = document.forms[0];
236+
let formData = new FormData(form);
237+
let search = new URLSearchParams(formData);
238+
let queryString = search.toString();
239+
alert(queryString);alert(queryString.length);*/
234240
}
235241
</script>
236242
</head>
@@ -305,7 +311,7 @@ function switchFormMethod() {
305311
</td>
306312
<td class="labelcell">Timeout:</td>
307313
<td><input type="text" name="timeout" size="3" value="<?php if ($timeout > 0) { echo $timeout; } ?>"/></td>
308-
<td</td>
314+
<td></td>
309315
<td></td>
310316
</tr>
311317
<tr>

0 commit comments

Comments
 (0)