From fab07984a2e730f1e3fad80f58932c0a497213b6 Mon Sep 17 00:00:00 2001 From: PurHur Date: Wed, 20 May 2026 17:10:04 +0000 Subject: [PATCH] Add web_int/web_string/web_bool param coercion builtins (issue #157). Ship query/body coercion helpers for compiled web apps: web_int and web_string are reachable from compile.php with JIT/AOT lowering; web_bool is VM-only until bool-return JIT assignment is fixed. Co-authored-by: Cursor --- docs/bootstrap-inventory.md | 86 ++++++-- docs/bootstrap-profile.json | 10 +- docs/capabilities.md | 3 + ext/standard/JitWebParams.php | 193 ++++++++++++++++++ ext/standard/Module.php | 3 + ext/standard/web_bool.php | 58 ++++++ ext/standard/web_int.php | 67 ++++++ ext/standard/web_string.php | 64 ++++++ lib/Web/Params.php | 136 ++++++++++++ .../cases/stdlib/web_param_coerce_jit.phpt | 11 + test/fixtures/aot/cases/web_param_coerce.phpt | 12 ++ test/real/cases/web_param_coerce.phpt | 26 +++ 12 files changed, 646 insertions(+), 23 deletions(-) create mode 100644 ext/standard/JitWebParams.php create mode 100644 ext/standard/web_bool.php create mode 100644 ext/standard/web_int.php create mode 100644 ext/standard/web_string.php create mode 100644 lib/Web/Params.php create mode 100644 test/compliance/cases/stdlib/web_param_coerce_jit.phpt create mode 100644 test/fixtures/aot/cases/web_param_coerce.phpt create mode 100644 test/real/cases/web_param_coerce.phpt diff --git a/docs/bootstrap-inventory.md b/docs/bootstrap-inventory.md index d126d526..d9cf8b06 100644 --- a/docs/bootstrap-inventory.md +++ b/docs/bootstrap-inventory.md @@ -8,9 +8,9 @@ Regenerate: `php script/bootstrap-inventory.php` | Metric | Count | |--------|------:| -| PHP files on vm.php path | 241 | +| PHP files on vm.php path | 246 | | Source constructs flagged (blockers) | 10 | -| Source constructs flagged (warnings) | 631 | +| Source constructs flagged (warnings) | 650 | ## Compiler CFG gaps (`lib/Compiler.php`) @@ -59,7 +59,8 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: | `ext/standard/JitStripTags.php` | 0 | 1 | | `ext/standard/JitStrpos.php` | 0 | 1 | | `ext/standard/JitUrlencode.php` | 0 | 1 | -| `ext/standard/Module.php` | 0 | 111 | +| `ext/standard/JitWebParams.php` | 0 | 11 | +| `ext/standard/Module.php` | 0 | 114 | | `ext/standard/VmDate.php` | 0 | 1 | | `ext/standard/VmExit.php` | 0 | 2 | | `ext/standard/VmFs.php` | 0 | 3 | @@ -175,6 +176,9 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: | `ext/standard/ucwords.php` | 0 | 1 | | `ext/standard/urldecode.php` | 0 | 1 | | `ext/standard/urlencode.php` | 0 | 1 | +| `ext/standard/web_bool.php` | 0 | 1 | +| `ext/standard/web_int.php` | 0 | 1 | +| `ext/standard/web_string.php` | 0 | 1 | | `ext/types/Module.php` | 0 | 13 | | `ext/types/is_type.php` | 0 | 1 | | `ext/types/mb_strlen.php` | 0 | 1 | @@ -262,6 +266,7 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: | `lib/VM/Refcount.php` | 0 | 1 | | `lib/VM/Variable.php` | 0 | 4 | | `lib/Web/DevServer.php` | 0 | 1 | +| `lib/Web/Params.php` | 0 | 2 | | `lib/Web/ProjectManifest.php` | 0 | 1 | | `lib/Web/ResponseContext.php` | 0 | 2 | | `lib/Web/Superglobals.php` | 0 | 6 | @@ -404,6 +409,21 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: **Warnings** (review for bootstrap subset): - 4 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler +### `ext/standard/JitWebParams.php` + +**Warnings** (review for bootstrap subset): +- new array_key_exists (line 47) +- new JITVariable (line 65) +- new is_numeric (line 66) +- new array_key_exists (line 126) +- new JITVariable (line 144) +- new string_trim (line 145) +- new JITVariable (line 150) +- new JITVariable (line 151) +- new JITVariable (line 157) +- new substr (line 163) +- 3 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler + ### `ext/standard/Module.php` **Warnings** (review for bootstrap subset): @@ -499,24 +519,27 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: - new header_list (line 111) - new getallheaders_ (line 112) - new http_response_code (line 113) -- new urlencode (line 114) -- new rawurlencode (line 115) -- new urldecode (line 116) -- new rawurldecode (line 117) -- new parse_url (line 118) -- new dirname (line 119) -- new basename (line 120) -- new realpath (line 121) -- new file_get_contents (line 122) -- new getenv_ (line 123) -- new putenv_ (line 124) -- new extract_ (line 125) -- new compact_ (line 126) -- new scandir (line 127) -- new glob_ (line 128) -- new time (line 129) -- new date (line 130) -- new gmdate (line 131) +- new web_int (line 114) +- new web_string (line 115) +- new web_bool (line 116) +- new urlencode (line 117) +- new rawurlencode (line 118) +- new urldecode (line 119) +- new rawurldecode (line 120) +- new parse_url (line 121) +- new dirname (line 122) +- new basename (line 123) +- new realpath (line 124) +- new file_get_contents (line 125) +- new getenv_ (line 126) +- new putenv_ (line 127) +- new extract_ (line 128) +- new compact_ (line 129) +- new scandir (line 130) +- new glob_ (line 131) +- new time (line 132) +- new date (line 133) +- new gmdate (line 134) - 2 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler ### `ext/standard/VmDate.php` @@ -1126,6 +1149,21 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: **Warnings** (review for bootstrap subset): - 3 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler +### `ext/standard/web_bool.php` + +**Warnings** (review for bootstrap subset): +- 2 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler + +### `ext/standard/web_int.php` + +**Warnings** (review for bootstrap subset): +- 2 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler + +### `ext/standard/web_string.php` + +**Warnings** (review for bootstrap subset): +- 2 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler + ### `ext/types/Module.php` **Warnings** (review for bootstrap subset): @@ -1824,6 +1862,12 @@ These `LogicException` messages indicate CFG ops or expressions not yet lowered: **Warnings** (review for bootstrap subset): - 20 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler +### `lib/Web/Params.php` + +**Warnings** (review for bootstrap subset): +- new Variable (line 104) +- 5 class method(s) — PHPCfg Op\Stmt\ClassMethod not lowered in Compiler + ### `lib/Web/ProjectManifest.php` **Warnings** (review for bootstrap subset): diff --git a/docs/bootstrap-profile.json b/docs/bootstrap-profile.json index 791ec03a..1988f78e 100644 --- a/docs/bootstrap-profile.json +++ b/docs/bootstrap-profile.json @@ -57,6 +57,7 @@ "ext/standard/JitStripTags.php", "ext/standard/JitStrpos.php", "ext/standard/JitUrlencode.php", + "ext/standard/JitWebParams.php", "ext/standard/Module.php", "ext/standard/VmDate.php", "ext/standard/VmExit.php", @@ -73,6 +74,7 @@ "ext/standard/array_keys.php", "ext/standard/array_merge.php", "ext/standard/array_pop.php", + "ext/standard/array_product.php", "ext/standard/array_push.php", "ext/standard/array_reverse.php", "ext/standard/array_search.php", @@ -173,6 +175,9 @@ "ext/standard/urldecode.php", "ext/standard/urlencode.php", "ext/standard/var_dump.php", + "ext/standard/web_bool.php", + "ext/standard/web_int.php", + "ext/standard/web_string.php", "ext/types/Module.php", "ext/types/is_type.php", "ext/types/mb_strlen.php", @@ -260,6 +265,7 @@ "lib/VM/ScriptExit.php", "lib/VM/Variable.php", "lib/Web/DevServer.php", + "lib/Web/Params.php", "lib/Web/ProjectManifest.php", "lib/Web/ResponseContext.php", "lib/Web/Superglobals.php", @@ -274,9 +280,9 @@ "test/bootstrap-aot/echo_hello.php" ], "totals": { - "inventory_files": 240, + "inventory_files": 246, "excluded": 2, - "eligible": 238, + "eligible": 244, "aot_lint_targets": 2 } } diff --git a/docs/capabilities.md b/docs/capabilities.md index db5846af..71df254c 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -126,5 +126,8 @@ Auto-generated by `script/capability-matrix.php`. Do not edit by hand. | `ucwords` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `urldecode` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | | `urlencode` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | +| `web_bool` | yes | no | no | standard | not implemented for JIT in this compiler build; use web_int($source, $key, 0) for AOT or VM | +| `web_int` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | +| `web_string` | yes | yes | yes | standard | JIT PHPT; AOT PHPT | _AOT uses the same LLVM builtin path as JIT unless noted otherwise._ diff --git a/ext/standard/JitWebParams.php b/ext/standard/JitWebParams.php new file mode 100644 index 00000000..8039ad75 --- /dev/null +++ b/ext/standard/JitWebParams.php @@ -0,0 +1,193 @@ + 5) { + throw new \LogicException('web_int() requires three to five arguments in this compiler build'); + } + if (JITVariable::TYPE_HASHTABLE !== $args[0]->type + || JITVariable::TYPE_STRING !== $args[1]->type + || JITVariable::TYPE_NATIVE_LONG !== $args[2]->type) { + throw new \LogicException( + 'web_int() requires (array, string key, int default) in this compiler build' + ); + } + if ($argc >= 4 && JITVariable::TYPE_NATIVE_LONG !== $args[3]->type) { + throw new \LogicException('web_int() min must be an integer in this compiler build'); + } + if ($argc >= 5 && JITVariable::TYPE_NATIVE_LONG !== $args[4]->type) { + throw new \LogicException('web_int() max must be an integer in this compiler build'); + } + + $i64 = JitStringIndex::i64($context); + $defaultVal = $context->helper->loadValue($args[2]); + + $missingBlock = BasicBlockHelper::append($context, 'web_int_missing'); + $invalidBlock = BasicBlockHelper::append($context, 'web_int_invalid'); + $numBlock = BasicBlockHelper::append($context, 'web_int_num'); + $convertBlock = BasicBlockHelper::append($context, 'web_int_convert'); + $doneBlock = BasicBlockHelper::append($context, 'web_int_done'); + + $exists = (new array_key_exists())->call($context, $args[1], $args[0]); + $context->builder->branchIf($exists, $convertBlock, $missingBlock); + + $context->builder->positionAtEnd($missingBlock); + $context->builder->branch($doneBlock); + + $context->builder->positionAtEnd($convertBlock); + $ht = $context->helper->loadValue($args[0]); + $key = $context->helper->loadValue($args[1]); + $boxed = $context->builder->call( + $context->lookupFunction('__hashtable__readStringKeyValue'), + $ht, + $key + ); + $str = $context->builder->call( + $context->lookupFunction('__value__readString'), + $boxed + ); + $strVar = new JITVariable($context, JITVariable::TYPE_STRING, JITVariable::KIND_VALUE, $str); + $isNum = (new is_numeric())->call($context, $strVar); + $context->builder->branchIf($isNum, $numBlock, $invalidBlock); + + $context->builder->positionAtEnd($invalidBlock); + $context->builder->branch($doneBlock); + + $context->builder->positionAtEnd($numBlock); + $parsed = self::stringToInt64($context, $str); + $result = $parsed; + if ($argc >= 4) { + $min = $context->helper->loadValue($args[3]); + $result = JitStringIndex::max($context, $result, $min); + } + if ($argc >= 5) { + $max = $context->helper->loadValue($args[4]); + $result = JitStringIndex::min($context, $result, $max); + } + $valueBlock = $context->builder->getInsertBlock(); + $context->builder->branch($doneBlock); + + $context->builder->positionAtEnd($doneBlock); + $phi = $context->builder->phi($i64); + $phi->addIncoming($defaultVal, $missingBlock); + $phi->addIncoming($defaultVal, $invalidBlock); + $phi->addIncoming($result, $valueBlock); + + return $phi; + } + + public static function webString(Context $context, JITVariable ...$args): Value + { + $argc = count($args); + if ($argc < 2 || $argc > 4) { + throw new \LogicException('web_string() requires two to four arguments in this compiler build'); + } + if (JITVariable::TYPE_HASHTABLE !== $args[0]->type + || JITVariable::TYPE_STRING !== $args[1]->type) { + throw new \LogicException( + 'web_string() requires (array, string key) in this compiler build' + ); + } + $empty = $context->builder->call( + $context->lookupFunction('__string__alloc'), + JitStringIndex::zero($context) + ); + if (2 === $argc) { + $defaultStr = $empty; + } elseif (JITVariable::TYPE_STRING !== $args[2]->type) { + throw new \LogicException('web_string() default must be a string in this compiler build'); + } else { + $defaultStr = $context->helper->loadValue($args[2]); + } + if ($argc >= 4 && JITVariable::TYPE_NATIVE_LONG !== $args[3]->type) { + throw new \LogicException('web_string() maxLen must be an integer in this compiler build'); + } + + $missingBlock = BasicBlockHelper::append($context, 'web_str_missing'); + $trimBlock = BasicBlockHelper::append($context, 'web_str_trim'); + $doneBlock = BasicBlockHelper::append($context, 'web_str_done'); + + $exists = (new array_key_exists())->call($context, $args[1], $args[0]); + $context->builder->branchIf($exists, $trimBlock, $missingBlock); + + $context->builder->positionAtEnd($missingBlock); + $context->builder->branch($doneBlock); + + $context->builder->positionAtEnd($trimBlock); + $ht = $context->helper->loadValue($args[0]); + $key = $context->helper->loadValue($args[1]); + $boxed = $context->builder->call( + $context->lookupFunction('__hashtable__readStringKeyValue'), + $ht, + $key + ); + $raw = $context->builder->call( + $context->lookupFunction('__value__readString'), + $boxed + ); + $rawVar = new JITVariable($context, JITVariable::TYPE_STRING, JITVariable::KIND_VALUE, $raw); + $trimmed = (new string_trim())->call($context, $rawVar); + $final = $trimmed; + if ($argc >= 4) { + $lenArg = $context->helper->loadValue($args[3]); + $zero = JitStringIndex::zero($context); + $trimVar = new JITVariable($context, JITVariable::TYPE_STRING, JITVariable::KIND_VALUE, $trimmed); + $offsetVar = new JITVariable( + $context, + JITVariable::TYPE_NATIVE_LONG, + JITVariable::KIND_VALUE, + $zero + ); + $lenVar = new JITVariable( + $context, + JITVariable::TYPE_NATIVE_LONG, + JITVariable::KIND_VALUE, + $lenArg + ); + $final = (new substr())->call($context, $trimVar, $offsetVar, $lenVar); + } + $valueBlock = $context->builder->getInsertBlock(); + $context->builder->branch($doneBlock); + + $context->builder->positionAtEnd($doneBlock); + $phi = $context->builder->phi($defaultStr->typeOf()); + $phi->addIncoming($defaultStr, $missingBlock); + $phi->addIncoming($final, $valueBlock); + + return $phi; + } + + private static function stringToInt64(Context $context, Value $strPtr): Value + { + $structName = $strPtr->typeOf()->getElementType()->getName(); + $map = $context->structFieldMap[$structName]; + $charPtr = $context->builder->structGep($strPtr, $map['value']); + $endPtrSlot = $context->builder->alloca( + $context->getTypeFromString('int8*'), + 1, + 'web_int_end' + ); + $nullEnd = $context->getTypeFromString('int8*')->constNull(); + $context->builder->store($nullEnd, $endPtrSlot); + $dbl = $context->builder->call($context->lookupFunction('strtod'), $charPtr, $endPtrSlot); + $i64 = JitStringIndex::i64($context); + + return $context->builder->fpToSi($dbl, $i64); + } +} diff --git a/ext/standard/Module.php b/ext/standard/Module.php index 3870c5f0..e9b8ea28 100755 --- a/ext/standard/Module.php +++ b/ext/standard/Module.php @@ -111,6 +111,9 @@ public function getFunctions(): array new header_list(), new getallheaders_(), new http_response_code(), + new web_int(), + new web_string(), + new web_bool(), new urlencode(), new rawurlencode(), new urldecode(), diff --git a/ext/standard/web_bool.php b/ext/standard/web_bool.php new file mode 100644 index 00000000..c271ad44 --- /dev/null +++ b/ext/standard/web_bool.php @@ -0,0 +1,58 @@ +calledArgs); + if ($argc < 2 || $argc > 3) { + throw new \LogicException('web_bool() requires two or three arguments in this compiler build'); + } + if (null === $frame->returnVar) { + return; + } + $source = $frame->calledArgs[0]->resolveIndirect(); + $keyVar = $frame->calledArgs[1]->resolveIndirect(); + if (Variable::TYPE_STRING !== $keyVar->type) { + throw new \LogicException('web_bool() key must be a string in this compiler build'); + } + $default = false; + if (3 === $argc) { + $defaultVar = $frame->calledArgs[2]->resolveIndirect(); + if (Variable::TYPE_BOOLEAN !== $defaultVar->type) { + throw new \LogicException('web_bool() default must be a boolean in this compiler build'); + } + $default = $defaultVar->toBool(); + } + $frame->returnVar->bool( + Params::coerceBool($source, $keyVar->toString(), $default) + ); + } + + public function call(Context $context, JITVariable ...$args): Value + { + throw new \LogicException( + 'web_bool() is not implemented for JIT in this compiler build; use web_int($source, $key, 0) for AOT or VM' + ); + } +} diff --git a/ext/standard/web_int.php b/ext/standard/web_int.php new file mode 100644 index 00000000..d7fe57cb --- /dev/null +++ b/ext/standard/web_int.php @@ -0,0 +1,67 @@ +calledArgs); + if ($argc < 3 || $argc > 5) { + throw new \LogicException('web_int() requires three to five arguments in this compiler build'); + } + if (null === $frame->returnVar) { + return; + } + $source = $frame->calledArgs[0]->resolveIndirect(); + $keyVar = $frame->calledArgs[1]->resolveIndirect(); + $defaultVar = $frame->calledArgs[2]->resolveIndirect(); + if (Variable::TYPE_STRING !== $keyVar->type || Variable::TYPE_INTEGER !== $defaultVar->type) { + throw new \LogicException( + 'web_int() requires (array, string key, int default) in this compiler build' + ); + } + $min = null; + $max = null; + if ($argc >= 4) { + $minVar = $frame->calledArgs[3]->resolveIndirect(); + if (Variable::TYPE_INTEGER !== $minVar->type) { + throw new \LogicException('web_int() min must be an integer in this compiler build'); + } + $min = $minVar->toInt(); + } + if ($argc >= 5) { + $maxVar = $frame->calledArgs[4]->resolveIndirect(); + if (Variable::TYPE_INTEGER !== $maxVar->type) { + throw new \LogicException('web_int() max must be an integer in this compiler build'); + } + $max = $maxVar->toInt(); + } + $frame->returnVar->int( + Params::coerceInt($source, $keyVar->toString(), $defaultVar->toInt(), $min, $max) + ); + } + + public function call(Context $context, JITVariable ...$args): Value + { + return JitWebParams::webInt($context, ...$args); + } +} diff --git a/ext/standard/web_string.php b/ext/standard/web_string.php new file mode 100644 index 00000000..5a2cef1e --- /dev/null +++ b/ext/standard/web_string.php @@ -0,0 +1,64 @@ +calledArgs); + if ($argc < 2 || $argc > 4) { + throw new \LogicException('web_string() requires two to four arguments in this compiler build'); + } + if (null === $frame->returnVar) { + return; + } + $source = $frame->calledArgs[0]->resolveIndirect(); + $keyVar = $frame->calledArgs[1]->resolveIndirect(); + if (Variable::TYPE_STRING !== $keyVar->type) { + throw new \LogicException('web_string() key must be a string in this compiler build'); + } + $default = ''; + if ($argc >= 3) { + $defaultVar = $frame->calledArgs[2]->resolveIndirect(); + if (Variable::TYPE_STRING !== $defaultVar->type) { + throw new \LogicException('web_string() default must be a string in this compiler build'); + } + $default = $defaultVar->toString(); + } + $maxLen = null; + if ($argc >= 4) { + $maxVar = $frame->calledArgs[3]->resolveIndirect(); + if (Variable::TYPE_INTEGER !== $maxVar->type) { + throw new \LogicException('web_string() maxLen must be an integer in this compiler build'); + } + $maxLen = $maxVar->toInt(); + } + $frame->returnVar->string( + Params::coerceString($source, $keyVar->toString(), $default, $maxLen) + ); + } + + public function call(Context $context, JITVariable ...$args): Value + { + return JitWebParams::webString($context, ...$args); + } +} diff --git a/lib/Web/Params.php b/lib/Web/Params.php new file mode 100644 index 00000000..4100bc8a --- /dev/null +++ b/lib/Web/Params.php @@ -0,0 +1,136 @@ + $max) { + $n = $max; + } + + return $n; + } + + public static function coerceString( + Variable $source, + string $key, + string $default = '', + ?int $maxLen = null + ): string { + $raw = self::readStringValue($source, $key); + if (null === $raw) { + return $default; + } + $s = match ($raw->type) { + Variable::TYPE_STRING => $raw->toString(), + Variable::TYPE_INTEGER => (string) $raw->toInt(), + Variable::TYPE_BOOLEAN => $raw->toBool() ? '1' : '0', + default => '', + }; + $s = trim($s); + if (null !== $maxLen && $maxLen >= 0 && strlen($s) > $maxLen) { + return substr($s, 0, $maxLen); + } + + return $s; + } + + public static function coerceBool( + Variable $source, + string $key, + bool $default = false + ): bool { + $raw = self::readStringValue($source, $key); + if (null === $raw) { + return $default; + } + if (Variable::TYPE_BOOLEAN === $raw->type) { + return $raw->toBool(); + } + if (Variable::TYPE_INTEGER === $raw->type) { + return 0 !== $raw->toInt(); + } + if (Variable::TYPE_STRING !== $raw->type) { + return $default; + } + $lower = strtolower($raw->toString()); + if (in_array($lower, self::BOOL_TRUE, true)) { + return true; + } + if (in_array($lower, self::BOOL_FALSE, true)) { + return false; + } + + return $default; + } + + private static function readStringValue(Variable $source, string $key): ?Variable + { + if (Variable::TYPE_ARRAY !== $source->type) { + throw new \LogicException('web_*() first argument must be an array in this compiler build'); + } + $ht = $source->toArray(); + $keyVar = new Variable(); + $keyVar->string($key); + if (!$ht->offsetIsSet($keyVar)) { + return null; + } + $stored = $ht->find($key); + if (null === $stored) { + return null; + } + $value = $stored->resolveIndirect(); + if ($value->isUndefined() || Variable::TYPE_NULL === $value->type) { + return null; + } + + return $value; + } + + private static function numericToInt(Variable $v): int + { + switch ($v->type) { + case Variable::TYPE_INTEGER: + return $v->toInt(); + case Variable::TYPE_FLOAT: + return (int) $v->toFloat(); + case Variable::TYPE_STRING: + return (int) $v->toString(); + case Variable::TYPE_BOOLEAN: + return $v->toBool() ? 1 : 0; + default: + throw new \LogicException('web_int() value must be numeric in this compiler build'); + } + } +} diff --git a/test/compliance/cases/stdlib/web_param_coerce_jit.phpt b/test/compliance/cases/stdlib/web_param_coerce_jit.phpt new file mode 100644 index 00000000..b85a1d3e --- /dev/null +++ b/test/compliance/cases/stdlib/web_param_coerce_jit.phpt @@ -0,0 +1,11 @@ +--TEST-- +stdlib: web_int/web_string JIT (issue #157) +--FILE-- + 'abc', 'name' => ' Bob ']; +echo web_int($get, 'page', 1), "\n"; +echo web_string($get, 'name', ''), "\n"; +--EXPECT-- +1 +Bob diff --git a/test/fixtures/aot/cases/web_param_coerce.phpt b/test/fixtures/aot/cases/web_param_coerce.phpt new file mode 100644 index 00000000..4470645f --- /dev/null +++ b/test/fixtures/aot/cases/web_param_coerce.phpt @@ -0,0 +1,12 @@ +--TEST-- +AOT: web_int/web_string with QUERY_STRING refresh (issue #157) +--ENV-- +QUERY_STRING=page=abc&name=%20Ada%20 +--FILE-- +