@@ -71,62 +71,88 @@ class Script
71
71
* {@link static::escapeValue()}. That is, results from that method, if
72
72
* given to this method, should produce equivalent results.
73
73
*
74
- * @param string $value The value to be parsed. Must be a literal of a
75
- * value, e.g. what {@link static::escapeValue()} will give you.
74
+ * @param string $value The value to be parsed.
75
+ * Must be a literal of a value,
76
+ * e.g. what {@link static::escapeValue()} will give you.
77
+ * @param DateTimeZone|null $timezone The timezone which any resulting
78
+ * DateTime object (either the main value, or values within an array)
79
+ * will use. Defaults to UTC.
76
80
*
77
81
* @return mixed Depending on RouterOS type detected:
78
82
* - "nil" (the string "[]") or "nothing" (empty string) - NULL.
79
83
* - "number" - int or double for large values.
80
84
* - "bool" - a boolean.
81
85
* - "array" - an array, with the keys and values processed recursively.
82
- * - "str" - a string.
83
86
* - "time" - a {@link DateInterval} object.
84
87
* - "date" (pseudo type; string in the form "M/j/Y") - a DateTime
85
- * object with the specified date, at midnight UTC time .
88
+ * object with the specified date, at midnight.
86
89
* - "datetime" (pseudo type; string in the form "M/j/Y H:i:s") - a
87
- * DateTime object with the specified date and UTC time.
88
- * - Unrecognized type - treated as an unquoted string.
90
+ * DateTime object with the specified date and time.
91
+ * - "str" (a quoted string) - a string, with the contents escaped.
92
+ * - Unrecognized type - casted to a string, unmodified.
89
93
*/
90
- public static function parseValue ($ value )
94
+ public static function parseValue ($ value, DateTimeZone $ timezone = null )
91
95
{
92
96
$ value = static ::parseValueToSimple ($ value );
93
97
if (!is_string ($ value )) {
94
98
return $ value ;
95
- } elseif ('{ ' === $ value [0 ] && '} ' === $ value [strlen ($ value ) - 1 ]) {
96
- $ value = static ::parseValueToArray ($ value );
97
- if (!is_string ($ value )) {
98
- return $ value ;
99
- }
100
- } elseif ('" ' === $ value [0 ] && '" ' === $ value [strlen ($ value ) - 1 ]) {
101
- return str_replace (
102
- array ('\" ' , '\\\\' , "\\\n" , "\\\r\n" , "\\\r" ),
103
- array ('" ' , '\\' ),
104
- substr ($ value , 1 , -1 )
105
- );
99
+ }
100
+
101
+ $ value = static ::parseValueToArray ($ value , $ timezone );
102
+ if (!is_string ($ value )) {
103
+ return $ value ;
104
+ }
105
+
106
+ $ value = static ::parseValueToDateInterval ($ value );
107
+ if (!is_string ($ value )) {
108
+ return $ value ;
106
109
}
107
110
108
- $ value = static ::parseValueToObject ($ value );
111
+ $ value = static ::parseValueToDateTime ($ value, $ timezone );
109
112
if (!is_string ($ value )) {
110
113
return $ value ;
111
114
}
112
115
116
+ return static ::parseValueToString ($ value );
117
+ }
118
+
119
+ /**
120
+ * Parses a RouterOS value into a PHP string.
121
+ *
122
+ * @param string $value The value to be parsed.
123
+ * Must be a literal of a value,
124
+ * e.g. what {@link static::escapeValue()} will give you.
125
+ *
126
+ * @return string If a quoted string is provided, it would be parsed.
127
+ * Otherwise, the value is casted to a string, and returned unmodified.
128
+ */
129
+ public static function parseValueToString ($ value )
130
+ {
131
+ $ value = (string )$ value ;
132
+ if ('" ' === $ value [0 ] && '" ' === $ value [strlen ($ value ) - 1 ]) {
133
+ return str_replace (
134
+ array ('\" ' , '\\\\' , "\\\n" , "\\\r\n" , "\\\r" ),
135
+ array ('" ' , '\\' ),
136
+ substr ($ value , 1 , -1 )
137
+ );
138
+ }
113
139
return $ value ;
114
140
}
115
141
116
142
/**
117
143
* Parses a RouterOS value into a PHP simple type.
118
- *
144
+ *
119
145
* Parses a RouterOS value into a PHP simple type. "Simple" types being
120
146
* scalar types, plus NULL.
121
- *
147
+ *
122
148
* @param string $value The value to be parsed. Must be a literal of a
123
149
* value, e.g. what {@link static::escapeValue()} will give you.
124
- *
150
+ *
125
151
* @return string|bool|int|double|null Depending on RouterOS type detected:
126
152
* - "nil" (the string "[]") or "nothing" (empty string) - NULL.
127
153
* - "number" - int or double for large values.
128
154
* - "bool" - a boolean.
129
- * - Unrecognized type - treated as an unquoted string.
155
+ * - Unrecognized type - casted to a string, unmodified .
130
156
*/
131
157
public static function parseValueToSimple ($ value )
132
158
{
@@ -145,22 +171,79 @@ public static function parseValueToSimple($value)
145
171
}
146
172
147
173
/**
148
- * Parses a RouterOS value into a PHP object.
149
- *
150
- * Parses a RouterOS value into a PHP object.
151
- *
174
+ * Parses a RouterOS value into a PHP DateTime object
175
+ *
176
+ * Parses a RouterOS value into a PHP DateTime object.
177
+ *
178
+ * @param string $value The value to be parsed.
179
+ * Must be a literal of a value,
180
+ * e.g. what {@link static::escapeValue()} will give you.
181
+ * @param DateTimeZone|null $timezone The timezone which the resulting
182
+ * DateTime object will use. Defaults to UTC.
183
+ *
184
+ * @return string|DateTime Depending on RouterOS type detected:
185
+ * - "date" (pseudo type; string in the form "M/j/Y") - a DateTime
186
+ * object with the specified date, at midnight UTC time (regardless
187
+ * of timezone provided).
188
+ * - "datetime" (pseudo type; string in the form "M/j/Y H:i:s") - a
189
+ * DateTime object with the specified date and time.
190
+ * - Unrecognized type - casted to a string, unmodified.
191
+ */
192
+ public static function parseValueToDateTime (
193
+ $ value ,
194
+ DateTimeZone $ timezone = null
195
+ ) {
196
+ $ value = (string )$ value ;
197
+ if ('' === $ value ) {
198
+ return $ value ;
199
+ }
200
+ if (preg_match (
201
+ '#^
202
+ (?<mon>jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)
203
+ /
204
+ (?<day>\d\d?)
205
+ /
206
+ (?<year>\d{4})
207
+ (?:
208
+ \s+(?<time>\d{2}\:\d{2}:\d{2})
209
+ )?
210
+ $#uix ' ,
211
+ $ value ,
212
+ $ date
213
+ )) {
214
+ if (!isset ($ date ['time ' ])) {
215
+ $ date ['time ' ] = '00:00:00 ' ;
216
+ $ timezone = new DateTimeZone ('UTC ' );
217
+ } elseif (null === $ timezone ) {
218
+ $ timezone = new DateTimeZone ('UTC ' );
219
+ }
220
+ try {
221
+ return new DateTime (
222
+ $ date ['year ' ] .
223
+ '- ' . ucfirst ($ date ['mon ' ]) .
224
+ "- {$ date ['day ' ]} {$ date ['time ' ]}" ,
225
+ $ timezone
226
+ );
227
+ } catch (E $ e ) {
228
+ return $ value ;
229
+ }
230
+ }
231
+ return $ value ;
232
+ }
233
+
234
+ /**
235
+ * Parses a RouterOS value into a PHP DateInterval.
236
+ *
237
+ * Parses a RouterOS value into a PHP DateInterval.
238
+ *
152
239
* @param string $value The value to be parsed. Must be a literal of a
153
240
* value, e.g. what {@link static::escapeValue()} will give you.
154
- *
241
+ *
155
242
* @return string|DateInterval|DateTime Depending on RouterOS type detected:
156
243
* - "time" - a {@link DateInterval} object.
157
- * - "date" (pseudo type; string in the form "M/j/Y") - a DateTime
158
- * object with the specified date, at midnight UTC time.
159
- * - "datetime" (pseudo type; string in the form "M/j/Y H:i:s") - a
160
- * DateTime object with the specified date and UTC time.
161
- * - Unrecognized type - treated as an unquoted string.
244
+ * - Unrecognized type - casted to a string, unmodified.
162
245
*/
163
- public static function parseValueToObject ($ value )
246
+ public static function parseValueToDateInterval ($ value )
164
247
{
165
248
$ value = (string )$ value ;
166
249
if ('' === $ value ) {
@@ -199,7 +282,7 @@ public static function parseValueToObject($value)
199
282
if (empty ($ time [5 ])) {
200
283
$ time [5 ] = 0 ;
201
284
}
202
-
285
+
203
286
$ subsecondTime = 0.0 ;
204
287
//@codeCoverageIgnoreStart
205
288
// No PHP version currently supports sub-second DateIntervals,
@@ -239,51 +322,32 @@ public static function parseValueToObject($value)
239
322
);
240
323
}
241
324
//@codeCoverageIgnoreEnd
242
- } elseif (preg_match (
243
- '#^
244
- (?<mon>jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)
245
- /
246
- (?<day>\d\d?)
247
- /
248
- (?<year>\d{4})
249
- (?:
250
- \s+(?<time>\d{2}\:\d{2}:\d{2})
251
- )?
252
- $#uix ' ,
253
- $ value ,
254
- $ date
255
- )) {
256
- if (!isset ($ date ['time ' ])) {
257
- $ date ['time ' ] = '00:00:00 ' ;
258
- }
259
- try {
260
- return new DateTime (
261
- $ date ['year ' ] .
262
- '- ' . ucfirst ($ date ['mon ' ]) .
263
- "- {$ date ['day ' ]} {$ date ['time ' ]}" ,
264
- new DateTimeZone ('UTC ' )
265
- );
266
- } catch (E $ e ) {
267
- return $ value ;
268
- }
269
325
}
326
+
270
327
return $ value ;
271
328
}
272
329
273
330
/**
274
331
* Parses a RouterOS value into a PHP array.
275
- *
332
+ *
276
333
* Parses a RouterOS value into a PHP array.
277
- *
278
- * @param string $value The value to be parsed. Must be a literal of a
279
- * value, e.g. what {@link static::escapeValue()} will give you.
280
- *
334
+ *
335
+ * @param string $value The value to be parsed.
336
+ * Must be a literal of a value,
337
+ * e.g. what {@link static::escapeValue()} will give you.
338
+ * @param DateTimeZone|null $timezone The timezone which any resulting
339
+ * DateTime object within the array will use. Defaults to UTC.
340
+ *
281
341
* @return string|array Depending on RouterOS type detected:
282
- * - "array" - an array, with the keys and values processed recursively.
283
- * - Unrecognized type - treated as an unquoted string.
342
+ * - "array" - an array, with the and values processed recursively,
343
+ * the keys with {@link static::parseValueToSimple()},
344
+ * and the values with {@link static::parseValue()}
345
+ * - Unrecognized type - casted to a string, unmodified.
284
346
*/
285
- public static function parseValueToArray ($ value )
286
- {
347
+ public static function parseValueToArray (
348
+ $ value ,
349
+ DateTimeZone $ timezone = null
350
+ ) {
287
351
$ value = (string )$ value ;
288
352
if ('{ ' === $ value [0 ] && '} ' === $ value [strlen ($ value ) - 1 ]) {
289
353
$ value = substr ($ value , 1 , -1 );
@@ -319,10 +383,10 @@ public static function parseValueToArray($value)
319
383
break ;
320
384
case '= ' :
321
385
$ newKey = static ::parseValueToSimple ($ parsedValue [$ i - 1 ]);
322
- $ newVal = static ::parseValue ($ parsedValue [++$ i ]);
386
+ $ newVal = static ::parseValue ($ parsedValue [++$ i ], $ timezone );
323
387
break ;
324
388
default :
325
- $ newVal = static ::parseValue ($ parsedValue [$ i ]);
389
+ $ newVal = static ::parseValue ($ parsedValue [$ i ], $ timezone );
326
390
}
327
391
}
328
392
if (null === $ newKey ) {
@@ -437,13 +501,13 @@ public static function append(
437
501
* inserted as part of a RouterOS script.
438
502
*
439
503
* DateInterval objects will be casted to RouterOS' "time" type.
440
- *
504
+ *
441
505
* DateTime objects will be casted to a string following the "M/d/Y H:i:s"
442
506
* format. If the time is exactly midnight (including microseconds), and
443
507
* the timezone is UTC, the string will include only the "M/d/Y" date.
444
508
*
445
509
* Unrecognized types (i.e. resources and other objects) are casted to
446
- * strings.
510
+ * strings, and those strings are then escaped .
447
511
*
448
512
* @param mixed $value The value to be escaped.
449
513
*
@@ -508,10 +572,18 @@ public static function escapeValue($value)
508
572
* surrounded with quotes at a RouterOS script (or concatenated onto a
509
573
* larger string first), and you can be sure there won't be any code
510
574
* injections coming from it.
575
+ *
576
+ * For the sake of brevity of the output, alphanumeric characters and
577
+ * underscores are left untouched
511
578
*
512
579
* @param string $value Value to be escaped.
513
580
*
514
581
* @return string The escaped value.
582
+ *
583
+ * @internal Why leave ONLY those characters and not also others?
584
+ * Because those can't in any way be mistaken for language constructs,
585
+ * unlike many other "safe inside strings, but not outside" ASCII
586
+ * characters, like ",", ".", "+", "-", "~", etc.
515
587
*/
516
588
public static function escapeString ($ value )
517
589
{
0 commit comments