[PECL-CVS] [pecl-file_formats-yaml] yaml12-schema-support: YAML 1.2 schema support
[email protected] (Rasmus Lerdorf) Fri, 10 Apr 2026 20:45:59 +0000
| Newsgroups | php.pecl.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: Rasmus Lerdorf (rlerdorf)
Date: 2026-04-10T16:45:37-04:00
Commit: https://github.com/php/pecl-file_formats-yaml/commit/8a93c3246f15d94293be027ebd827d8f77ebc528
Raw diff: https://github.com/php/pecl-file_formats-yaml/commit/8a93c3246f15d94293be027ebd827d8f77ebc528.diff
YAML 1.2 schema support
Changed paths:
A tests/yaml_parse_schema_12_bool.phpt
A tests/yaml_parse_schema_12_constants.phpt
A tests/yaml_parse_schema_12_default.phpt
A tests/yaml_parse_schema_12_float.phpt
A tests/yaml_parse_schema_12_int.phpt
A tests/yaml_parse_schema_12_null.phpt
A tests/yaml_parse_schema_12_timestamp.phpt
M detect.c
M parse.c
M php_yaml.h
M php_yaml_int.h
M yaml.c
Diff:
diff --git a/detect.c b/detect.c
index 0a18aba..5af2f72 100644
--- a/detect.c
+++ b/detect.c
@@ -616,6 +616,368 @@ scalar_is_numeric(const char *value, size_t length, zend_long *lval,
/* }}} */
+/* {{{ detect_scalar_type_12(const char *, size_t, yaml_event_t)
+ * Guess what datatype the scalar encodes using YAML 1.2 Core Schema
+ */
+const char *detect_scalar_type_12(const char *value, size_t length,
+ const yaml_event_t *event)
+{
+ int flags = 0;
+ zend_long lval = 0;
+ double dval = 0.0;
+
+ /* is value a null? */
+ if (0 == length || scalar_is_null(value, length, event)) {
+ return YAML_NULL_TAG;
+ }
+
+ /* is value numeric? (1.2 rules) */
+ flags = scalar_is_numeric_12(value, length, &lval, &dval, NULL);
+ if (flags != Y_SCALAR_IS_NOT_NUMERIC) {
+ return (flags & Y_SCALAR_IS_FLOAT) ? YAML_FLOAT_TAG : YAML_INT_TAG;
+ }
+
+ /* is value boolean? (1.2 rules: only true/false) */
+ flags = scalar_is_bool_12(value, length, event);
+ if (-1 != flags) {
+ return YAML_BOOL_TAG;
+ }
+
+ /* no implicit timestamp detection in 1.2 Core Schema */
+
+ /* no guess */
+ return NULL;
+}
+/* }}} */
+
+
+/* {{{ scalar_is_bool_12(const char *,size_t,yaml_event_t)
+ * Does this scalar encode a BOOL value under YAML 1.2 Core Schema?
+ *
+ * Only true/True/TRUE and false/False/FALSE are recognized.
+ */
+int
+scalar_is_bool_12(const char *value, size_t length, const yaml_event_t *event)
+{
+ if (NULL == event || IS_NOT_QUOTED_OR_TAG_IS((*event), YAML_BOOL_TAG)) {
+ if (STR_EQ("TRUE", value) ||
+ STR_EQ("True", value) ||
+ STR_EQ("true", value)) {
+ return 1;
+ }
+
+ if (STR_EQ("FALSE", value) ||
+ STR_EQ("False", value) ||
+ STR_EQ("false", value)) {
+ return 0;
+ }
+
+ } else if (NULL != event &&
+ IS_NOT_IMPLICIT_AND_TAG_IS((*event), YAML_BOOL_TAG)) {
+ if (0 == length || (1 == length && '0' == *value)) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ return -1;
+}
+/* }}} */
+
+
+/* {{{ scalar_is_numeric_12()
+ * Does this scalar encode a NUMERIC value under YAML 1.2 Core Schema?
+ *
+ * YAML 1.2 Core Schema integers:
+ * 0 | -?[1-9][0-9]* | 0x[0-9a-fA-F]+ | 0o[0-7]+
+ * YAML 1.2 Core Schema floats:
+ * [-+]?(\.[0-9]+|[0-9]+(\.[0-9]*)?)([eE][-+]?[0-9]+)?
+ * [-+]?(\.inf|\.Inf|\.INF)
+ * .nan|.NaN|.NAN
+ *
+ * No binary (0b), no sexagesimal, no underscores, no commas.
+ */
+int
+scalar_is_numeric_12(const char *value, size_t length, zend_long *lval,
+ double *dval, char **str)
+{
+ const char *end = value + length;
+ char *buf = { 0 }, *ptr = { 0 };
+ int negative = 0;
+ int type = 0;
+
+ if (0 == length) {
+ goto not_numeric_12;
+ }
+
+ /* trim */
+ while (value < end && (*(end - 1) == ' ' || *(end - 1) == '\t')) {
+ end--;
+ }
+
+ while (value < end && (*value == ' ' || *value == '\t')) {
+ value++;
+ }
+
+ if (value == end) {
+ goto not_numeric_12;
+ }
+
+ /* not a number */
+ if (STR_EQ(".NAN", value) ||
+ STR_EQ(".NaN", value) ||
+ STR_EQ(".nan", value)) {
+ type = Y_SCALAR_IS_FLOAT | Y_SCALAR_IS_NAN;
+ goto finish_12;
+ }
+
+ /* sign */
+ if (*value == '+') {
+ value++;
+
+ } else if (*value == '-') {
+ negative = 1;
+ value++;
+ }
+
+ if (value == end) {
+ goto not_numeric_12;
+ }
+
+ /* infinity */
+ if (STR_EQ(".INF", value) ||
+ STR_EQ(".Inf", value) ||
+ STR_EQ(".inf", value)) {
+ type = Y_SCALAR_IS_FLOAT;
+ type |= (negative ? Y_SCALAR_IS_INFINITY_N : Y_SCALAR_IS_INFINITY_P);
+ goto finish_12;
+ }
+
+ /* alloc */
+ buf = (char *) emalloc(length + 3);
+ ptr = buf;
+ if (negative) {
+ *ptr++ = '-';
+ }
+
+ /* parse */
+ if (*value == '0') {
+ *ptr++ = *value++;
+ if (value == end) {
+ goto return_zero_12;
+ }
+
+ if (*value == 'x') {
+ /* hexadecimal integer: 0x[0-9a-fA-F]+ */
+ *ptr++ = *value++;
+
+ if (value == end) {
+ goto not_numeric_12;
+ }
+
+ while (value < end) {
+ if ((*value >= '0' && *value <= '9') ||
+ (*value >= 'A' && *value <= 'F') ||
+ (*value >= 'a' && *value <= 'f')) {
+ *ptr++ = *value++;
+
+ } else {
+ goto not_numeric_12;
+ }
+ }
+
+ type = Y_SCALAR_IS_INT | Y_SCALAR_IS_HEXADECIMAL;
+
+ } else if (*value == 'o') {
+ /* octal integer: 0o[0-7]+ */
+ value++;
+
+ if (value == end) {
+ goto not_numeric_12;
+ }
+
+ while (value < end) {
+ if (*value >= '0' && *value <= '7') {
+ *ptr++ = *value++;
+
+ } else {
+ goto not_numeric_12;
+ }
+ }
+
+ type = Y_SCALAR_IS_INT | Y_SCALAR_IS_OCTAL;
+
+ } else if (*value == '.') {
+ goto check_float_12;
+
+ } else {
+ /* bare 0 followed by other digits is not valid in 1.2 */
+ goto not_numeric_12;
+ }
+
+ } else if (*value >= '1' && *value <= '9') {
+ /* decimal integer or float: [1-9][0-9]* */
+ *ptr++ = *value++;
+ while (value < end) {
+ if (*value >= '0' && *value <= '9') {
+ *ptr++ = *value++;
+
+ } else if (*value == '.') {
+ goto check_float_12;
+
+ } else if (*value == 'E' || *value == 'e') {
+ type = Y_SCALAR_IS_FLOAT | Y_SCALAR_IS_DECIMAL;
+ goto check_exp_12;
+
+ } else {
+ goto not_numeric_12;
+ }
+ }
+
+ type = Y_SCALAR_IS_INT | Y_SCALAR_IS_DECIMAL;
+
+ } else if (*value == '.') {
+ /* float starting with dot: .[0-9]+ */
+ *ptr++ = '0';
+
+check_float_12:
+ *ptr++ = *value++;
+ if (value == end) {
+ /* trailing dot with no digits - not a number */
+ goto not_numeric_12;
+ }
+
+ /* need at least one digit, or could be exponent directly */
+ while (value < end) {
+ if (*value >= '0' && *value <= '9') {
+ *ptr++ = *value++;
+
+ } else if (*value == 'E' || *value == 'e') {
+ goto check_exp_12;
+
+ } else {
+ goto not_numeric_12;
+ }
+ }
+
+ type = Y_SCALAR_IS_FLOAT | Y_SCALAR_IS_DECIMAL;
+ goto terminate_12;
+
+check_exp_12:
+ *ptr++ = *value++;
+ if (value == end || (*value != '+' && *value != '-' &&
+ (*value < '0' || *value > '9'))) {
+ goto not_numeric_12;
+ }
+
+ if (*value == '+' || *value == '-') {
+ *ptr++ = *value++;
+ }
+
+ if (value == end || *value < '0' || *value > '9') {
+ goto not_numeric_12;
+ }
+
+ while (value < end) {
+ if (*value >= '0' && *value <= '9') {
+ *ptr++ = *value++;
+
+ } else {
+ goto not_numeric_12;
+ }
+ }
+
+ type = Y_SCALAR_IS_FLOAT | Y_SCALAR_IS_DECIMAL;
+
+ } else {
+ goto not_numeric_12;
+ }
+
+terminate_12:
+ /* terminate */
+ *ptr = '\0';
+
+finish_12:
+ /* convert & assign */
+ if ((type & Y_SCALAR_IS_INT) && lval != NULL) {
+ switch (type & Y_SCALAR_FORMAT_MASK) {
+ case Y_SCALAR_IS_OCTAL:
+ *lval = ZEND_STRTOL(buf, (char **) NULL, 8);
+ break;
+
+ case Y_SCALAR_IS_HEXADECIMAL:
+ *lval = ZEND_STRTOL(buf, (char **) NULL, 16);
+ break;
+
+ default:
+#if PHP_VERSION_ID < 80100
+ ZEND_ATOL(*lval, buf);
+#else
+ *lval = ZEND_ATOL(buf);
+#endif
+ break;
+ }
+
+ } else if ((type & Y_SCALAR_IS_FLOAT) && dval != NULL) {
+ switch (type & Y_SCALAR_FORMAT_MASK) {
+ case Y_SCALAR_IS_INFINITY_P:
+ *dval = php_get_inf();
+ break;
+
+ case Y_SCALAR_IS_INFINITY_N:
+ *dval = -php_get_inf();
+ break;
+
+ case Y_SCALAR_IS_NAN:
+ *dval = php_get_nan();
+ break;
+
+ default:
+ *dval = zend_strtod(buf, (const char **) NULL);
+ break;
+ }
+ }
+
+ if (buf != NULL) {
+ if (str != NULL) {
+ *str = buf;
+
+ } else {
+ efree(buf);
+ }
+ }
+
+ /* return */
+ return type;
+
+
+return_zero_12:
+ if (lval != NULL) {
+ *lval = 0;
+ }
+
+ if (dval != NULL) {
+ *dval = 0.0;
+ }
+
+ if (buf != NULL) {
+ efree(buf);
+ }
+
+ return (Y_SCALAR_IS_INT | Y_SCALAR_IS_ZERO);
+
+
+not_numeric_12:
+ if (buf != NULL) {
+ efree(buf);
+ }
+
+ return Y_SCALAR_IS_NOT_NUMERIC;
+}
+/* }}} */
+
+
/* {{{ scalar_is_timestamp(const char *,size_t)
* Does this scalar encode a TIMESTAMP value?
*
diff --git a/parse.c b/parse.c
index c504cb3..3c7af98 100644
--- a/parse.c
+++ b/parse.c
@@ -702,6 +702,7 @@ void eval_scalar(yaml_event_t event,
char *value = (char *) event.data.scalar.value;
size_t length = event.data.scalar.length;
int flags = 0;
+ int schema_12 = (YAML_G(decode_schema) == Y_SCHEMA_CORE_1_2);
ZVAL_NULL(retval);
@@ -718,7 +719,12 @@ void eval_scalar(yaml_event_t event,
}
/* check for bool */
- if (-1 != (flags = scalar_is_bool(value, length, &event))) {
+ if (schema_12) {
+ flags = scalar_is_bool_12(value, length, &event);
+ } else {
+ flags = scalar_is_bool(value, length, &event);
+ }
+ if (-1 != flags) {
ZVAL_BOOL(retval, (zend_bool) flags);
return;
}
@@ -731,8 +737,13 @@ void eval_scalar(yaml_event_t event,
zend_long lval = 0;
double dval = 0.0;
- flags = scalar_is_numeric(
- value, length, &lval, &dval, NULL);
+ if (schema_12) {
+ flags = scalar_is_numeric_12(
+ value, length, &lval, &dval, NULL);
+ } else {
+ flags = scalar_is_numeric(
+ value, length, &lval, &dval, NULL);
+ }
if (flags != Y_SCALAR_IS_NOT_NUMERIC) {
if (flags & Y_SCALAR_IS_FLOAT) {
ZVAL_DOUBLE(retval, dval);
@@ -767,9 +778,12 @@ void eval_scalar(yaml_event_t event,
}
}
- /* check for timestamp */
+ /* check for timestamp
+ * In YAML 1.2 Core Schema, no implicit timestamp detection;
+ * explicit !!timestamp tags are still honored.
+ */
if (IS_NOT_IMPLICIT_AND_TAG_IS(event, YAML_TIMESTAMP_TAG) ||
- scalar_is_timestamp(value, length)) {
+ (!schema_12 && scalar_is_timestamp(value, length))) {
if (FAILURE == eval_timestamp(
&retval, value, (int) length)) {
ZVAL_NULL(retval);
@@ -837,9 +851,15 @@ void eval_scalar_with_callbacks(yaml_event_t event,
if (YAML_PLAIN_SCALAR_STYLE == event.data.scalar.style && NULL == tag) {
/* plain scalar with no specified type */
- tag = detect_scalar_type(
- (char *) event.data.scalar.value, event.data.scalar.length,
- &event);
+ if (YAML_G(decode_schema) == Y_SCHEMA_CORE_1_2) {
+ tag = detect_scalar_type_12(
+ (char *) event.data.scalar.value, event.data.scalar.length,
+ &event);
+ } else {
+ tag = detect_scalar_type(
+ (char *) event.data.scalar.value, event.data.scalar.length,
+ &event);
+ }
}
if (NULL == tag) {
/* couldn't/wouldn't detect tag type, assume string */
diff --git a/php_yaml.h b/php_yaml.h
index eae6793..9550ade 100644
--- a/php_yaml.h
+++ b/php_yaml.h
@@ -85,6 +85,7 @@ ZEND_BEGIN_MODULE_GLOBALS(yaml)
zend_bool decode_binary;
zend_long decode_timestamp;
zend_bool decode_php;
+ zend_long decode_schema;
zval *timestamp_decoder;
zend_bool output_canonical;
zend_long output_indent;
diff --git a/php_yaml_int.h b/php_yaml_int.h
index 6b65220..8c676c2 100644
--- a/php_yaml_int.h
+++ b/php_yaml_int.h
@@ -83,6 +83,10 @@ typedef struct y_emit_state_s {
#define YAML_PHP_TAG "!php/object"
#define YAML_NONSPECIFIC_TAG "!"
+#define Y_SCHEMA_DEFAULT 0
+#define Y_SCHEMA_YAML_1_1 1
+#define Y_SCHEMA_CORE_1_2 2
+
#define Y_SCALAR_IS_NOT_NUMERIC 0x00
#define Y_SCALAR_IS_INT 0x10
#define Y_SCALAR_IS_FLOAT 0x20
@@ -136,15 +140,24 @@ void eval_scalar_with_callbacks(
const char *detect_scalar_type(
const char *value, size_t length, const yaml_event_t *event);
+const char *detect_scalar_type_12(
+ const char *value, size_t length, const yaml_event_t *event);
+
int scalar_is_null(
const char *value, size_t length, const yaml_event_t *event);
int scalar_is_bool(
const char *value, size_t length, const yaml_event_t *event);
+int scalar_is_bool_12(
+ const char *value, size_t length, const yaml_event_t *event);
+
int scalar_is_numeric(
const char *value, size_t length, zend_long *lval, double *dval, char **str);
+int scalar_is_numeric_12(
+ const char *value, size_t length, zend_long *lval, double *dval, char **str);
+
int scalar_is_timestamp(const char *value, size_t length);
int php_yaml_write_impl(yaml_emitter_t *emitter, zval *data,
diff --git a/tests/yaml_parse_schema_12_bool.phpt b/tests/yaml_parse_schema_12_bool.phpt
new file mode 100644
index 0000000..31f96d9
--- /dev/null
+++ b/tests/yaml_parse_schema_12_bool.phpt
@@ -0,0 +1,58 @@
+--TEST--
+Yaml 1.2 Core Schema - bool (only true/false recognized)
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--INI--
+yaml.decode_schema=2
+--FILE--
+<?php
+var_dump(yaml_parse('
+# These are booleans in 1.2
+a: true
+b: True
+c: TRUE
+d: false
+e: False
+f: FALSE
+# These are NOT booleans in 1.2 (they were in 1.1)
+g: yes
+h: no
+i: on
+j: off
+k: y
+l: n
+m: Yes
+n: No
+'));
+?>
+--EXPECT--
+array(14) {
+ ["a"]=>
+ bool(true)
+ ["b"]=>
+ bool(true)
+ ["c"]=>
+ bool(true)
+ ["d"]=>
+ bool(false)
+ ["e"]=>
+ bool(false)
+ ["f"]=>
+ bool(false)
+ ["g"]=>
+ string(3) "yes"
+ ["h"]=>
+ string(2) "no"
+ ["i"]=>
+ string(2) "on"
+ ["j"]=>
+ string(3) "off"
+ ["k"]=>
+ string(1) "y"
+ ["l"]=>
+ string(1) "n"
+ ["m"]=>
+ string(3) "Yes"
+ ["n"]=>
+ string(2) "No"
+}
diff --git a/tests/yaml_parse_schema_12_constants.phpt b/tests/yaml_parse_schema_12_constants.phpt
new file mode 100644
index 0000000..b6ebb97
--- /dev/null
+++ b/tests/yaml_parse_schema_12_constants.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Yaml 1.2 Schema - PHP constants defined
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--FILE--
+<?php
+var_dump(YAML_SCHEMA_DEFAULT);
+var_dump(YAML_SCHEMA_YAML_1_1);
+var_dump(YAML_SCHEMA_CORE_1_2);
+?>
+--EXPECT--
+int(0)
+int(1)
+int(2)
diff --git a/tests/yaml_parse_schema_12_default.phpt b/tests/yaml_parse_schema_12_default.phpt
new file mode 100644
index 0000000..7c882cb
--- /dev/null
+++ b/tests/yaml_parse_schema_12_default.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Yaml schema default (0) behaves as 1.1
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--FILE--
+<?php
+// Verify default schema (0) gives YAML 1.1 behavior
+var_dump(ini_get('yaml.decode_schema'));
+var_dump(yaml_parse('
+bool_yes: yes
+bool_no: NO
+octal: 02472256
+'));
+?>
+--EXPECT--
+string(1) "0"
+array(3) {
+ ["bool_yes"]=>
+ bool(true)
+ ["bool_no"]=>
+ bool(false)
+ ["octal"]=>
+ int(685230)
+}
diff --git a/tests/yaml_parse_schema_12_float.phpt b/tests/yaml_parse_schema_12_float.phpt
new file mode 100644
index 0000000..cdf5d76
--- /dev/null
+++ b/tests/yaml_parse_schema_12_float.phpt
@@ -0,0 +1,52 @@
+--TEST--
+Yaml 1.2 Core Schema - float (no sexagesimal, no underscores)
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--INI--
+yaml.decode_schema=2
+--FILE--
+<?php
+var_dump(yaml_parse('
+# Valid 1.2 floats
+canonical: 6.8523015e+5
+fixed: 685230.15
+negative: -1.5
+leading_dot: .25
+inf_lower: .inf
+inf_upper: .INF
+inf_neg: -.inf
+nan_lower: .nan
+nan_upper: .NaN
+nan_all: .NAN
+# NOT floats in 1.2 (they were in 1.1)
+sexagesimal: 190:20:30.15
+underscored: 685_230.15
+'));
+?>
+--EXPECT--
+array(12) {
+ ["canonical"]=>
+ float(685230.15)
+ ["fixed"]=>
+ float(685230.15)
+ ["negative"]=>
+ float(-1.5)
+ ["leading_dot"]=>
+ float(0.25)
+ ["inf_lower"]=>
+ float(INF)
+ ["inf_upper"]=>
+ float(INF)
+ ["inf_neg"]=>
+ float(-INF)
+ ["nan_lower"]=>
+ float(NAN)
+ ["nan_upper"]=>
+ float(NAN)
+ ["nan_all"]=>
+ float(NAN)
+ ["sexagesimal"]=>
+ string(12) "190:20:30.15"
+ ["underscored"]=>
+ string(10) "685_230.15"
+}
diff --git a/tests/yaml_parse_schema_12_int.phpt b/tests/yaml_parse_schema_12_int.phpt
new file mode 100644
index 0000000..579dc55
--- /dev/null
+++ b/tests/yaml_parse_schema_12_int.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Yaml 1.2 Core Schema - int (0o octal, no binary, no sexagesimal, no underscores)
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--INI--
+yaml.decode_schema=2
+--FILE--
+<?php
+var_dump(yaml_parse('
+# Valid 1.2 integers
+decimal: 685230
+negative: -42
+hex: 0xFF
+octal_12: 0o777
+zero: 0
+# NOT integers in 1.2 (they were in 1.1)
+octal_11: 02472256
+binary: 0b1010
+sexagesimal: 190:20:30
+underscored: 1_000_000
+'));
+?>
+--EXPECT--
+array(9) {
+ ["decimal"]=>
+ int(685230)
+ ["negative"]=>
+ int(-42)
+ ["hex"]=>
+ int(255)
+ ["octal_12"]=>
+ int(511)
+ ["zero"]=>
+ int(0)
+ ["octal_11"]=>
+ string(8) "02472256"
+ ["binary"]=>
+ string(6) "0b1010"
+ ["sexagesimal"]=>
+ string(9) "190:20:30"
+ ["underscored"]=>
+ string(9) "1_000_000"
+}
diff --git a/tests/yaml_parse_schema_12_null.phpt b/tests/yaml_parse_schema_12_null.phpt
new file mode 100644
index 0000000..f80b3ef
--- /dev/null
+++ b/tests/yaml_parse_schema_12_null.phpt
@@ -0,0 +1,29 @@
+--TEST--
+Yaml 1.2 Core Schema - null (same as 1.1)
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--INI--
+yaml.decode_schema=2
+--FILE--
+<?php
+var_dump(yaml_parse('
+a: null
+b: Null
+c: NULL
+d: ~
+e:
+'));
+?>
+--EXPECT--
+array(5) {
+ ["a"]=>
+ NULL
+ ["b"]=>
+ NULL
+ ["c"]=>
+ NULL
+ ["d"]=>
+ NULL
+ ["e"]=>
+ NULL
+}
diff --git a/tests/yaml_parse_schema_12_timestamp.phpt b/tests/yaml_parse_schema_12_timestamp.phpt
new file mode 100644
index 0000000..2df1470
--- /dev/null
+++ b/tests/yaml_parse_schema_12_timestamp.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Yaml 1.2 Core Schema - no implicit timestamp detection
+--SKIPIF--
+<?php if(!extension_loaded('yaml')) die('skip yaml n/a'); ?>
+--INI--
+yaml.decode_schema=2
+yaml.decode_timestamp=1
+--FILE--
+<?php
+var_dump(yaml_parse('
+# These are strings in 1.2 Core Schema (no implicit timestamp)
+date: 2024-01-15
+datetime: 2024-01-15T10:30:00Z
+'));
+?>
+--EXPECT--
+array(2) {
+ ["date"]=>
+ string(10) "2024-01-15"
+ ["datetime"]=>
+ string(20) "2024-01-15T10:30:00Z"
+}
diff --git a/yaml.c b/yaml.c
index 7fb0a02..76c6f96 100644
--- a/yaml.c
+++ b/yaml.c
@@ -68,6 +68,8 @@ PHP_INI_BEGIN()
decode_timestamp, zend_yaml_globals, yaml_globals)
STD_PHP_INI_ENTRY("yaml.decode_php", "0", PHP_INI_ALL, OnUpdateBool,
decode_php, zend_yaml_globals, yaml_globals)
+ STD_PHP_INI_ENTRY("yaml.decode_schema", "0", PHP_INI_ALL, OnUpdateLong,
+ decode_schema, zend_yaml_globals, yaml_globals)
STD_PHP_INI_ENTRY("yaml.output_canonical", "0", PHP_INI_ALL, OnUpdateBool,
output_canonical, zend_yaml_globals, yaml_globals)
STD_PHP_INI_ENTRY("yaml.output_indent", "2", PHP_INI_ALL, OnUpdateLong,
@@ -234,6 +236,14 @@ static PHP_MINIT_FUNCTION(yaml)
REGISTER_LONG_CONSTANT("YAML_CRLN_BREAK", YAML_CRLN_BREAK,
CONST_PERSISTENT | CONST_CS);
+ /* schema constants */
+ REGISTER_LONG_CONSTANT("YAML_SCHEMA_DEFAULT", Y_SCHEMA_DEFAULT,
+ CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("YAML_SCHEMA_YAML_1_1", Y_SCHEMA_YAML_1_1,
+ CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("YAML_SCHEMA_CORE_1_2", Y_SCHEMA_CORE_1_2,
+ CONST_PERSISTENT | CONST_CS);
+
return SUCCESS;
}
/* }}} */
@@ -268,6 +278,7 @@ static PHP_GINIT_FUNCTION(yaml)
yaml_globals->decode_binary = 0;
yaml_globals->decode_timestamp = 0;
yaml_globals->decode_php = 0;
+ yaml_globals->decode_schema = Y_SCHEMA_DEFAULT;
yaml_globals->timestamp_decoder = NULL;
yaml_globals->output_canonical = 0;
yaml_globals->output_indent = 2;