Skip to content

Commit 90553af

Browse files
committed
Merge branch 'PHP-8.1' into PHP-8.2
2 parents bda28eb + 5e64ead commit 90553af

File tree

9 files changed

+110
-17
lines changed

9 files changed

+110
-17
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ PHP NEWS
2020
- FPM:
2121
. Fixed bug GH-10461 (PHP-FPM segfault due to after free usage of
2222
child->ev_std(out|err)). (Jakub Zelenka)
23+
. Fixed bug #64539 (FPM status page: query_string not properly JSON encoded).
24+
(Jakub Zelenka)
2325

2426
- Hash:
2527
. Fixed bug GH-11180 (hash_file() appears to be restricted to 3 arguments).

ext/json/json.c

+15
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,21 @@ static PHP_MINFO_FUNCTION(json)
103103
}
104104
/* }}} */
105105

106+
PHP_JSON_API zend_string *php_json_encode_string(const char *s, size_t len, int options)
107+
{
108+
smart_str buf = {0};
109+
php_json_encoder encoder;
110+
111+
php_json_encode_init(&encoder);
112+
113+
if (php_json_escape_string(&buf, s, len, options, &encoder) == FAILURE) {
114+
smart_str_free(&buf);
115+
return NULL;
116+
}
117+
118+
return smart_str_extract(&buf);
119+
}
120+
106121
PHP_JSON_API zend_result php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth) /* {{{ */
107122
{
108123
php_json_encoder encoder;

ext/json/json_encoder.c

+1-5
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@
3131

3232
static const char digits[] = "0123456789abcdef";
3333

34-
static zend_result php_json_escape_string(
35-
smart_str *buf, const char *s, size_t len,
36-
int options, php_json_encoder *encoder);
37-
3834
static int php_json_determine_array_type(zval *val) /* {{{ */
3935
{
4036
zend_array *myht = Z_ARRVAL_P(val);
@@ -319,7 +315,7 @@ static zend_result php_json_encode_array(smart_str *buf, zval *val, int options,
319315
}
320316
/* }}} */
321317

322-
static zend_result php_json_escape_string(
318+
zend_result php_json_escape_string(
323319
smart_str *buf, const char *s, size_t len,
324320
int options, php_json_encoder *encoder) /* {{{ */
325321
{

ext/json/php_json.h

+2
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ PHP_JSON_API ZEND_EXTERN_MODULE_GLOBALS(json)
9797
ZEND_TSRMLS_CACHE_EXTERN()
9898
#endif
9999

100+
PHP_JSON_API zend_string *php_json_encode_string(const char *s, size_t len, int options);
101+
100102
PHP_JSON_API zend_result php_json_encode_ex(smart_str *buf, zval *val, int options, zend_long depth);
101103
PHP_JSON_API zend_result php_json_encode(smart_str *buf, zval *val, int options);
102104
PHP_JSON_API zend_result php_json_decode_ex(zval *return_value, const char *str, size_t str_len, zend_long options, zend_long depth);

ext/json/php_json_encoder.h

+2
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,6 @@ static inline void php_json_encode_init(php_json_encoder *encoder)
3535

3636
zend_result php_json_encode_zval(smart_str *buf, zval *val, int options, php_json_encoder *encoder);
3737

38+
int php_json_escape_string(smart_str *buf, const char *s, size_t len, int options, php_json_encoder *encoder);
39+
3840
#endif /* PHP_JSON_ENCODER_H */

sapi/fpm/fpm/fpm_status.c

+26-8
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
#include "fpm_atomic.h"
1414
#include "fpm_conf.h"
1515
#include "fpm_php.h"
16-
#include <ext/standard/html.h>
16+
#include "ext/standard/html.h"
17+
#include "ext/json/php_json.h"
1718

1819
static char *fpm_status_uri = NULL;
1920
static char *fpm_status_ping_uri = NULL;
@@ -140,7 +141,8 @@ int fpm_status_handle_request(void) /* {{{ */
140141
struct fpm_scoreboard_proc_s *proc;
141142
char *buffer, *time_format, time_buffer[64];
142143
time_t now_epoch;
143-
int full, encode, has_start_time;
144+
int full, has_start_time;
145+
bool encode_html, encode_json;
144146
char *short_syntax, *short_post;
145147
char *full_pre, *full_syntax, *full_post, *full_separator;
146148
zend_string *_GET_str;
@@ -175,7 +177,8 @@ int fpm_status_handle_request(void) /* {{{ */
175177
full = (fpm_php_get_string_from_table(_GET_str, "full") != NULL);
176178
short_syntax = short_post = NULL;
177179
full_separator = full_pre = full_syntax = full_post = NULL;
178-
encode = 0;
180+
encode_html = false;
181+
encode_json = false;
179182
has_start_time = 1;
180183

181184
scoreboard_p = fpm_scoreboard_get();
@@ -218,7 +221,7 @@ int fpm_status_handle_request(void) /* {{{ */
218221
if (fpm_php_get_string_from_table(_GET_str, "html")) {
219222
sapi_add_header_ex(ZEND_STRL("Content-Type: text/html"), 1, 1);
220223
time_format = "%d/%b/%Y:%H:%M:%S %z";
221-
encode = 1;
224+
encode_html = true;
222225

223226
short_syntax =
224227
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
@@ -287,7 +290,7 @@ int fpm_status_handle_request(void) /* {{{ */
287290
} else if (fpm_php_get_string_from_table(_GET_str, "xml")) {
288291
sapi_add_header_ex(ZEND_STRL("Content-Type: text/xml"), 1, 1);
289292
time_format = "%s";
290-
encode = 1;
293+
encode_html = true;
291294

292295
short_syntax =
293296
"<?xml version=\"1.0\" ?>\n"
@@ -336,6 +339,8 @@ int fpm_status_handle_request(void) /* {{{ */
336339
sapi_add_header_ex(ZEND_STRL("Content-Type: application/json"), 1, 1);
337340
time_format = "%s";
338341

342+
encode_json = true;
343+
339344
short_syntax =
340345
"{"
341346
"\"pool\":\"%s\","
@@ -549,11 +554,24 @@ int fpm_status_handle_request(void) /* {{{ */
549554
query_string = NULL;
550555
tmp_query_string = NULL;
551556
if (proc->query_string[0] != '\0') {
552-
if (!encode) {
553-
query_string = proc->query_string;
557+
if (encode_html) {
558+
tmp_query_string = php_escape_html_entities_ex(
559+
(const unsigned char *) proc->query_string,
560+
strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT,
561+
NULL, /* double_encode */ 1, /* quiet */ 0);
562+
} else if (encode_json) {
563+
tmp_query_string = php_json_encode_string(proc->query_string,
564+
strlen(proc->query_string), PHP_JSON_INVALID_UTF8_IGNORE);
554565
} else {
555-
tmp_query_string = php_escape_html_entities_ex((const unsigned char *) proc->query_string, strlen(proc->query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, NULL, /* double_encode */ 1, /* quiet */ 0);
566+
query_string = proc->query_string;
567+
}
568+
if (tmp_query_string) {
556569
query_string = ZSTR_VAL(tmp_query_string);
570+
/* remove quotes around the string */
571+
if (encode_json && ZSTR_LEN(tmp_query_string) >= 2) {
572+
query_string[ZSTR_LEN(tmp_query_string) - 1] = '\0';
573+
++query_string;
574+
}
557575
}
558576
}
559577

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
FPM: bug64539 - status json format escaping
3+
--SKIPIF--
4+
<?php
5+
include "skipif.inc"; ?>
6+
--FILE--
7+
<?php
8+
9+
require_once "tester.inc";
10+
11+
$cfg = <<<EOT
12+
[global]
13+
error_log = {{FILE:LOG}}
14+
[unconfined]
15+
listen = {{ADDR}}
16+
pm = static
17+
pm.max_children = 2
18+
pm.status_path = /status
19+
catch_workers_output = yes
20+
EOT;
21+
22+
$code = <<<EOT
23+
<?php
24+
usleep(200000);
25+
EOT;
26+
27+
$tester = new FPM\Tester($cfg, $code);
28+
$tester->start();
29+
$tester->expectLogStartNotices();
30+
$responses = $tester
31+
->multiRequest([
32+
['query' => 'a=b"c'],
33+
['uri' => '/status', 'query' => 'full&json', 'delay' => 100000],
34+
]);
35+
$data = json_decode($responses[1]->getBody('application/json'), true);
36+
var_dump(explode('?', $data['processes'][0]['request uri'])[1]);
37+
$tester->terminate();
38+
$tester->expectLogTerminatingNotices();
39+
$tester->close();
40+
41+
?>
42+
Done
43+
--EXPECT--
44+
string(5) "a=b"c"
45+
Done
46+
--CLEAN--
47+
<?php
48+
require_once "tester.inc";
49+
FPM\Tester::clean();
50+
?>

sapi/fpm/tests/response.inc

+8-4
Original file line numberDiff line numberDiff line change
@@ -218,18 +218,22 @@ class Response
218218

219219
/**
220220
* Print raw body.
221+
*
222+
* @param string $contentType Expect body to have specified content type.
221223
*/
222-
public function dumpBody()
224+
public function dumpBody(string $contentType = 'text/html')
223225
{
224-
var_dump($this->getBody());
226+
var_dump($this->getBody($contentType));
225227
}
226228

227229
/**
228230
* Print raw body.
231+
*
232+
* @param string $contentType Expect body to have specified content type.
229233
*/
230-
public function printBody()
234+
public function printBody(string $contentType = 'text/html')
231235
{
232-
echo $this->getBody() . "\n";
236+
echo $this->getBody($contentType) . "\n";
233237
}
234238

235239
/**

sapi/fpm/tests/tester.inc

+4
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,10 @@ class Tester
826826
$requestData['uri'] ?? null
827827
);
828828

829+
if (isset($requestData['delay'])) {
830+
usleep($requestData['delay']);
831+
}
832+
829833
return [
830834
'client' => $client,
831835
'requestId' => $client->async_request($params, false),

0 commit comments

Comments
 (0)