Coverage Report

Created: 2025-09-27 06:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/uri/php_uri.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright (c) The PHP Group                                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to version 3.01 of the PHP license,      |
6
   | that is bundled with this package in the file LICENSE, and is        |
7
   | available through the world-wide-web at the following url:           |
8
   | https://www.php.net/license/3_01.txt                                 |
9
   | If you did not receive a copy of the PHP license and are unable to   |
10
   | obtain it through the world-wide-web, please send a note to          |
11
   | license@php.net so we can mail you a copy immediately.               |
12
   +----------------------------------------------------------------------+
13
   | Authors: Máté Kocsis <kocsismate@php.net>                            |
14
   +----------------------------------------------------------------------+
15
*/
16
17
#ifdef HAVE_CONFIG_H
18
# include <config.h>
19
#endif
20
21
#include "php.h"
22
#include "Zend/zend_interfaces.h"
23
#include "Zend/zend_exceptions.h"
24
#include "Zend/zend_attributes.h"
25
#include "Zend/zend_enum.h"
26
#include "ext/standard/info.h"
27
28
#include "php_uri.h"
29
#include "uri_parser_whatwg.h"
30
#include "uri_parser_rfc3986.h"
31
#include "uri_parser_php_parse_url.h"
32
#include "php_uri_arginfo.h"
33
#include "uriparser/UriBase.h"
34
35
zend_class_entry *php_uri_ce_rfc3986_uri;
36
zend_class_entry *php_uri_ce_whatwg_url;
37
zend_class_entry *php_uri_ce_comparison_mode;
38
zend_class_entry *php_uri_ce_exception;
39
zend_class_entry *php_uri_ce_error;
40
zend_class_entry *php_uri_ce_invalid_uri_exception;
41
zend_class_entry *php_uri_ce_whatwg_invalid_url_exception;
42
zend_class_entry *php_uri_ce_whatwg_url_validation_error_type;
43
zend_class_entry *php_uri_ce_whatwg_url_validation_error;
44
45
static zend_object_handlers object_handlers_rfc3986_uri;
46
static zend_object_handlers object_handlers_whatwg_uri;
47
48
static const zend_module_dep uri_deps[] = {
49
  ZEND_MOD_REQUIRED("lexbor")
50
  ZEND_MOD_END
51
};
52
53
static zend_array uri_parsers;
54
55
static HashTable *uri_get_debug_properties(php_uri_object *object)
56
0
{
57
0
  const HashTable *std_properties = zend_std_get_properties(&object->std);
58
0
  HashTable *result = zend_array_dup(std_properties);
59
60
0
  const php_uri_parser * const parser = object->parser;
61
0
  void * const uri = object->uri;
62
63
0
  if (UNEXPECTED(uri == NULL)) {
64
0
    return result;
65
0
  }
66
67
0
  zval tmp;
68
0
  if (parser->property_handler.scheme.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
69
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_SCHEME), &tmp);
70
0
  }
71
72
0
  if (parser->property_handler.username.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
73
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_USERNAME), &tmp);
74
0
  }
75
76
0
  if (parser->property_handler.password.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
77
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PASSWORD), &tmp);
78
0
  }
79
80
0
  if (parser->property_handler.host.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
81
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_HOST), &tmp);
82
0
  }
83
84
0
  if (parser->property_handler.port.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
85
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PORT), &tmp);
86
0
  }
87
88
0
  if (parser->property_handler.path.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
89
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_PATH), &tmp);
90
0
  }
91
92
0
  if (parser->property_handler.query.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
93
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_QUERY), &tmp);
94
0
  }
95
96
0
  if (parser->property_handler.fragment.read(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &tmp) == SUCCESS) {
97
0
    zend_hash_update(result, ZSTR_KNOWN(ZEND_STR_FRAGMENT), &tmp);
98
0
  }
99
100
0
  return result;
101
0
}
102
103
PHPAPI const php_uri_parser *php_uri_get_parser(zend_string *uri_parser_name)
104
0
{
105
0
  if (uri_parser_name == NULL) {
106
0
    return zend_hash_str_find_ptr(&uri_parsers, PHP_URI_PARSER_PHP_PARSE_URL, sizeof(PHP_URI_PARSER_PHP_PARSE_URL) - 1);
107
0
  }
108
109
0
  return zend_hash_find_ptr(&uri_parsers, uri_parser_name);
110
0
}
111
112
ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri_internal *php_uri_parse(const php_uri_parser *uri_parser, const char *uri_str, size_t uri_str_len, bool silent)
113
0
{
114
0
  php_uri_internal *internal_uri = emalloc(sizeof(*internal_uri));
115
0
  internal_uri->parser = uri_parser;
116
0
  internal_uri->uri = uri_parser->parse(uri_str, uri_str_len, NULL, NULL, silent);
117
118
0
  if (UNEXPECTED(internal_uri->uri == NULL)) {
119
0
    efree(internal_uri);
120
0
    return NULL;
121
0
  }
122
123
0
  return internal_uri;
124
0
}
125
126
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_scheme(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
127
0
{
128
0
  return internal_uri->parser->property_handler.scheme.read(internal_uri->uri, read_mode, zv);
129
0
}
130
131
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_username(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
132
0
{
133
0
  return internal_uri->parser->property_handler.username.read(internal_uri->uri, read_mode, zv);
134
0
}
135
136
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_password(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
137
0
{
138
0
  return internal_uri->parser->property_handler.password.read(internal_uri->uri, read_mode, zv);
139
0
}
140
141
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_host(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
142
0
{
143
0
  return internal_uri->parser->property_handler.host.read(internal_uri->uri, read_mode, zv);
144
0
}
145
146
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_port(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
147
0
{
148
0
  return internal_uri->parser->property_handler.port.read(internal_uri->uri, read_mode, zv);
149
0
}
150
151
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_path(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
152
0
{
153
0
  return internal_uri->parser->property_handler.path.read(internal_uri->uri, read_mode, zv);
154
0
}
155
156
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_query(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
157
0
{
158
0
  return internal_uri->parser->property_handler.query.read(internal_uri->uri, read_mode, zv);
159
0
}
160
161
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_uri_get_fragment(const php_uri_internal *internal_uri, php_uri_component_read_mode read_mode, zval *zv)
162
0
{
163
0
  return internal_uri->parser->property_handler.fragment.read(internal_uri->uri, read_mode, zv);
164
0
}
165
166
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_free(php_uri_internal *internal_uri)
167
0
{
168
0
  internal_uri->parser->destroy(internal_uri->uri);
169
0
  internal_uri->uri = NULL;
170
0
  internal_uri->parser = NULL;
171
0
  efree(internal_uri);
172
0
}
173
174
ZEND_ATTRIBUTE_NONNULL PHPAPI php_uri *php_uri_parse_to_struct(
175
  const php_uri_parser *uri_parser, const char *uri_str, size_t uri_str_len, php_uri_component_read_mode read_mode, bool silent
176
0
) {
177
0
  php_uri_internal *uri_internal = php_uri_parse(uri_parser, uri_str, uri_str_len, silent);
178
0
  if (uri_internal == NULL) {
179
0
    return NULL;
180
0
  }
181
182
0
  php_uri *uri = ecalloc(1, sizeof(*uri));
183
0
  zval tmp;
184
0
  zend_result result;
185
186
0
  result = php_uri_get_scheme(uri_internal, read_mode, &tmp);
187
0
  if (result == FAILURE) {
188
0
    goto error;
189
0
  }
190
0
  if (Z_TYPE(tmp) == IS_STRING) {
191
0
    uri->scheme = Z_STR(tmp);
192
0
  }
193
194
0
  result = php_uri_get_username(uri_internal, read_mode, &tmp);
195
0
  if (result == FAILURE) {
196
0
    goto error;
197
0
  }
198
0
  if (Z_TYPE(tmp) == IS_STRING) {
199
0
    uri->user = Z_STR(tmp);
200
0
  }
201
202
0
  result = php_uri_get_password(uri_internal, read_mode, &tmp);
203
0
  if (result == FAILURE) {
204
0
    goto error;
205
0
  }
206
0
  if (Z_TYPE(tmp) == IS_STRING) {
207
0
    uri->password = Z_STR(tmp);
208
0
  }
209
210
0
  result = php_uri_get_host(uri_internal, read_mode, &tmp);
211
0
  if (result == FAILURE) {
212
0
    goto error;
213
0
  }
214
0
  if (Z_TYPE(tmp) == IS_STRING) {
215
0
    uri->host = Z_STR(tmp);
216
0
  }
217
218
0
  result = php_uri_get_port(uri_internal, read_mode, &tmp);
219
0
  if (result == FAILURE) {
220
0
    goto error;
221
0
  }
222
0
  if (Z_TYPE(tmp) == IS_LONG) {
223
0
    uri->port = Z_LVAL(tmp);
224
0
  }
225
226
0
  result = php_uri_get_path(uri_internal, read_mode, &tmp);
227
0
  if (result == FAILURE) {
228
0
    goto error;
229
0
  }
230
0
  if (Z_TYPE(tmp) == IS_STRING) {
231
0
    uri->path = Z_STR(tmp);
232
0
  }
233
234
0
  result = php_uri_get_query(uri_internal, read_mode, &tmp);
235
0
  if (result == FAILURE) {
236
0
    goto error;
237
0
  }
238
0
  if (Z_TYPE(tmp) == IS_STRING) {
239
0
    uri->query = Z_STR(tmp);
240
0
  }
241
242
0
  result = php_uri_get_fragment(uri_internal, read_mode, &tmp);
243
0
  if (result == FAILURE) {
244
0
    goto error;
245
0
  }
246
0
  if (Z_TYPE(tmp) == IS_STRING) {
247
0
    uri->fragment = Z_STR(tmp);
248
0
  }
249
250
0
  php_uri_free(uri_internal);
251
252
0
  return uri;
253
254
0
error:
255
0
  php_uri_free(uri_internal);
256
0
  php_uri_struct_free(uri);
257
258
0
  return NULL;
259
0
}
260
261
ZEND_ATTRIBUTE_NONNULL PHPAPI void php_uri_struct_free(php_uri *uri)
262
0
{
263
0
  if (uri->scheme) {
264
0
    zend_string_release(uri->scheme);
265
0
  }
266
0
  if (uri->user) {
267
0
    zend_string_release(uri->user);
268
0
  }
269
0
  if (uri->password) {
270
0
    zend_string_release(uri->password);
271
0
  }
272
0
  if (uri->host) {
273
0
    zend_string_release(uri->host);
274
0
  }
275
0
  if (uri->path) {
276
0
    zend_string_release(uri->path);
277
0
  }
278
0
  if (uri->query) {
279
0
    zend_string_release(uri->query);
280
0
  }
281
0
  if (uri->fragment) {
282
0
    zend_string_release(uri->fragment);
283
0
  }
284
285
0
  efree(uri);
286
0
}
287
288
/**
289
 * Pass the errors parameter by ref to errors_zv for userland, and frees it if
290
 * it is not not needed anymore.
291
 */
292
static zend_result pass_errors_by_ref_and_free(zval *errors_zv, zval *errors)
293
0
{
294
0
  ZEND_ASSERT(Z_TYPE_P(errors) == IS_UNDEF || Z_TYPE_P(errors) == IS_ARRAY);
295
296
  /* There was no error during parsing */
297
0
  if (Z_ISUNDEF_P(errors)) {
298
0
    return SUCCESS;
299
0
  }
300
301
  /* The errors parameter is an array, but the pass-by ref argument stored by
302
   * errors_zv was not passed - the URI implementation either doesn't support
303
   * returning additional error information, or the caller is not interested in it */
304
0
  if (errors_zv == NULL) {
305
0
    zval_ptr_dtor(errors);
306
0
    return SUCCESS;
307
0
  }
308
309
0
  ZEND_TRY_ASSIGN_REF_TMP(errors_zv, errors);
310
0
  if (EG(exception)) {
311
0
    return FAILURE;
312
0
  }
313
314
0
  return SUCCESS;
315
0
}
316
317
ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2) PHPAPI void php_uri_instantiate_uri(
318
    INTERNAL_FUNCTION_PARAMETERS, const zend_string *uri_str, const php_uri_object *base_url_object,
319
    bool should_throw, bool should_update_this_object, zval *errors_zv
320
0
) {
321
322
0
  php_uri_object *uri_object;
323
0
  if (should_update_this_object) {
324
0
    uri_object = Z_URI_OBJECT_P(ZEND_THIS);
325
0
    if (uri_object->uri != NULL) {
326
0
      zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
327
0
      RETURN_THROWS();
328
0
    }
329
0
  } else {
330
0
    if (EX(func)->common.fn_flags & ZEND_ACC_STATIC) {
331
0
      object_init_ex(return_value, Z_CE_P(ZEND_THIS));
332
0
    } else {
333
0
      object_init_ex(return_value, Z_OBJCE_P(ZEND_THIS));
334
0
    }
335
0
    uri_object = Z_URI_OBJECT_P(return_value);
336
0
  }
337
338
0
  const php_uri_parser *uri_parser = uri_object->parser;
339
340
0
  zval errors;
341
0
  ZVAL_UNDEF(&errors);
342
343
0
  void *base_url = NULL;
344
0
  if (base_url_object != NULL) {
345
0
    ZEND_ASSERT(base_url_object->std.ce == uri_object->std.ce);
346
0
    ZEND_ASSERT(base_url_object->uri != NULL);
347
0
    ZEND_ASSERT(base_url_object->parser == uri_parser);
348
0
    base_url = base_url_object->uri;
349
0
  }
350
351
0
  void *uri = uri_parser->parse(ZSTR_VAL(uri_str), ZSTR_LEN(uri_str), base_url, errors_zv != NULL ? &errors : NULL, !should_throw);
352
0
  if (UNEXPECTED(uri == NULL)) {
353
0
    if (should_throw) {
354
0
      zval_ptr_dtor(&errors);
355
0
      RETURN_THROWS();
356
0
    } else {
357
0
      if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) {
358
0
        RETURN_THROWS();
359
0
      }
360
0
      zval_ptr_dtor(return_value);
361
0
      RETURN_NULL();
362
0
    }
363
0
  }
364
365
0
  if (pass_errors_by_ref_and_free(errors_zv, &errors) == FAILURE) {
366
0
    uri_parser->destroy(uri);
367
0
    RETURN_THROWS();
368
0
  }
369
370
0
  uri_object->uri = uri;
371
0
}
372
373
static void create_rfc3986_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
374
5
{
375
5
  zend_string *uri_str;
376
5
  zend_object *base_url_object = NULL;
377
378
10
  ZEND_PARSE_PARAMETERS_START(1, 2)
379
10
    Z_PARAM_PATH_STR(uri_str)
380
0
    Z_PARAM_OPTIONAL
381
0
    Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_rfc3986_uri)
382
5
  ZEND_PARSE_PARAMETERS_END();
383
384
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU,
385
0
    uri_str, base_url_object ? php_uri_object_from_obj(base_url_object) : NULL, is_constructor, is_constructor, NULL);
386
0
}
387
388
static bool is_list_of_whatwg_validation_errors(const HashTable *array)
389
0
{
390
0
  if (!zend_array_is_list(array)) {
391
0
    return false;
392
0
  }
393
394
0
  ZEND_HASH_FOREACH_VAL(array, zval *val) {
395
    /* Do not allow references as they may change types after checking. */
396
397
0
    if (Z_TYPE_P(val) != IS_OBJECT) {
398
0
      return false;
399
0
    }
400
401
0
    if (!instanceof_function(Z_OBJCE_P(val), php_uri_ce_whatwg_url_validation_error)) {
402
0
      return false;
403
0
    }
404
0
  } ZEND_HASH_FOREACH_END();
405
406
0
  return true;
407
0
}
408
409
PHP_METHOD(Uri_Rfc3986_Uri, parse)
410
0
{
411
0
  create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
412
0
}
413
414
PHP_METHOD(Uri_Rfc3986_Uri, __construct)
415
5
{
416
5
  create_rfc3986_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
417
5
}
418
419
PHP_METHOD(Uri_WhatWg_InvalidUrlException, __construct)
420
5
{
421
5
  zend_string *message = NULL;
422
5
  zval *errors = NULL;
423
5
  zend_long code = 0;
424
5
  zval *previous = NULL;
425
426
15
  ZEND_PARSE_PARAMETERS_START(0, 4)
427
15
    Z_PARAM_OPTIONAL
428
15
    Z_PARAM_STR(message)
429
0
    Z_PARAM_ARRAY(errors)
430
0
    Z_PARAM_LONG(code)
431
0
    Z_PARAM_OBJECT_OF_CLASS_OR_NULL(previous, zend_ce_throwable)
432
5
  ZEND_PARSE_PARAMETERS_END();
433
434
5
  if (zend_update_exception_properties(INTERNAL_FUNCTION_PARAM_PASSTHRU, message, code, previous) == FAILURE) {
435
0
    RETURN_THROWS();
436
0
  }
437
438
5
  if (errors == NULL) {
439
5
    zval tmp;
440
5
    ZVAL_EMPTY_ARRAY(&tmp);
441
5
    zend_update_property(php_uri_ce_whatwg_invalid_url_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), &tmp);
442
5
  } else {
443
0
    if (!is_list_of_whatwg_validation_errors(Z_ARR_P(errors))) {
444
0
      zend_argument_value_error(2, "must be a list of %s", ZSTR_VAL(php_uri_ce_whatwg_url_validation_error->name));
445
0
      RETURN_THROWS();
446
0
    }
447
448
0
    zend_update_property(php_uri_ce_whatwg_invalid_url_exception, Z_OBJ_P(ZEND_THIS), ZEND_STRL("errors"), errors);
449
0
  }
450
5
  if (EG(exception)) {
451
0
    RETURN_THROWS();
452
0
  }
453
5
}
454
455
PHP_METHOD(Uri_WhatWg_UrlValidationError, __construct)
456
5
{
457
5
  zend_string *context;
458
5
  zval *type;
459
5
  bool failure;
460
461
10
  ZEND_PARSE_PARAMETERS_START(3, 3)
462
10
    Z_PARAM_STR(context)
463
0
    Z_PARAM_OBJECT_OF_CLASS(type, php_uri_ce_whatwg_url_validation_error_type)
464
0
    Z_PARAM_BOOL(failure)
465
5
  ZEND_PARSE_PARAMETERS_END();
466
467
0
  zend_update_property_str(php_uri_ce_whatwg_url_validation_error, Z_OBJ_P(ZEND_THIS), ZEND_STRL("context"), context);
468
0
  if (EG(exception)) {
469
0
    RETURN_THROWS();
470
0
  }
471
472
0
  zend_update_property_ex(php_uri_ce_whatwg_url_validation_error, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_TYPE), type);
473
0
  if (EG(exception)) {
474
0
    RETURN_THROWS();
475
0
  }
476
477
0
  zval failure_zv;
478
0
  ZVAL_BOOL(&failure_zv, failure);
479
0
  zend_update_property(php_uri_ce_whatwg_url_validation_error, Z_OBJ_P(ZEND_THIS), ZEND_STRL("failure"), &failure_zv);
480
0
  if (EG(exception)) {
481
0
    RETURN_THROWS();
482
0
  }
483
0
}
484
485
static void create_whatwg_uri(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
486
5
{
487
5
  zend_string *uri_str;
488
5
  zend_object *base_url_object = NULL;
489
5
  zval *errors = NULL;
490
491
10
  ZEND_PARSE_PARAMETERS_START(1, 3)
492
10
    Z_PARAM_PATH_STR(uri_str)
493
0
    Z_PARAM_OPTIONAL
494
0
    Z_PARAM_OBJ_OF_CLASS_OR_NULL(base_url_object, php_uri_ce_whatwg_url)
495
0
    Z_PARAM_ZVAL(errors)
496
5
  ZEND_PARSE_PARAMETERS_END();
497
498
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU,
499
0
    uri_str, base_url_object ? php_uri_object_from_obj(base_url_object) : NULL, is_constructor, is_constructor, errors);
500
0
}
501
502
PHP_METHOD(Uri_WhatWg_Url, parse)
503
0
{
504
0
  create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
505
0
}
506
507
PHP_METHOD(Uri_WhatWg_Url, __construct)
508
5
{
509
5
  create_whatwg_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
510
5
}
511
512
PHP_METHOD(Uri_Rfc3986_Uri, getScheme)
513
0
{
514
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
515
0
}
516
517
PHP_METHOD(Uri_Rfc3986_Uri, getRawScheme)
518
0
{
519
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_RAW);
520
0
}
521
522
PHP_METHOD(Uri_Rfc3986_Uri, withScheme)
523
0
{
524
0
  php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME);
525
0
}
526
527
static void rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAMETERS, php_uri_component_read_mode read_mode)
528
0
{
529
0
  ZEND_PARSE_PARAMETERS_NONE();
530
531
0
  php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS);
532
0
  ZEND_ASSERT(uri_object->uri != NULL);
533
534
0
  if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_read(uri_object->uri, read_mode, return_value) == FAILURE)) {
535
0
    zend_throw_error(NULL, "The userinfo component cannot be retrieved");
536
0
    RETURN_THROWS();
537
0
  }
538
0
}
539
540
PHP_METHOD(Uri_Rfc3986_Uri, getUserInfo)
541
0
{
542
0
  rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
543
0
}
544
545
PHP_METHOD(Uri_Rfc3986_Uri, getRawUserInfo)
546
0
{
547
0
  rfc3986_userinfo_read(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_COMPONENT_READ_MODE_RAW);
548
0
}
549
550
PHP_METHOD(Uri_Rfc3986_Uri, withUserInfo)
551
0
{
552
0
  zend_string *value;
553
554
0
  ZEND_PARSE_PARAMETERS_START(1, 1)
555
0
    Z_PARAM_PATH_STR_OR_NULL(value)
556
0
  ZEND_PARSE_PARAMETERS_END();
557
558
0
  zval zv;
559
0
  if (value == NULL) {
560
0
    ZVAL_NULL(&zv);
561
0
  } else {
562
0
    ZVAL_STR(&zv, value);
563
0
  }
564
565
0
  php_uri_object *old_uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS));
566
0
  ZEND_ASSERT(old_uri_object->uri != NULL);
567
568
0
  zend_object *new_object = old_uri_object->std.handlers->clone_obj(&old_uri_object->std);
569
0
  if (new_object == NULL) {
570
0
    RETURN_THROWS();
571
0
  }
572
573
  /* Assign the object early. The engine will take care of destruction in
574
   * case of an exception being thrown. */
575
0
  RETVAL_OBJ(new_object);
576
577
0
  php_uri_object *new_uri_object = php_uri_object_from_obj(new_object);
578
0
  ZEND_ASSERT(new_uri_object->uri != NULL);
579
580
0
  if (UNEXPECTED(php_uri_parser_rfc3986_userinfo_write(new_uri_object->uri, &zv, NULL) == FAILURE)) {
581
0
    RETURN_THROWS();
582
0
  }
583
0
}
584
585
PHP_METHOD(Uri_Rfc3986_Uri, getUsername)
586
0
{
587
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
588
0
}
589
590
PHP_METHOD(Uri_Rfc3986_Uri, getRawUsername)
591
0
{
592
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME, PHP_URI_COMPONENT_READ_MODE_RAW);
593
0
}
594
595
PHP_METHOD(Uri_Rfc3986_Uri, getPassword)
596
0
{
597
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
598
0
}
599
600
PHP_METHOD(Uri_Rfc3986_Uri, getRawPassword)
601
0
{
602
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD, PHP_URI_COMPONENT_READ_MODE_RAW);
603
0
}
604
605
PHP_METHOD(Uri_Rfc3986_Uri, getHost)
606
0
{
607
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
608
0
}
609
610
PHP_METHOD(Uri_Rfc3986_Uri, getRawHost)
611
0
{
612
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_RAW);
613
0
}
614
615
PHP_METHOD(Uri_Rfc3986_Uri, withHost)
616
0
{
617
0
  php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST);
618
0
}
619
620
PHP_METHOD(Uri_Rfc3986_Uri, getPort)
621
0
{
622
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PORT, PHP_URI_COMPONENT_READ_MODE_RAW);
623
0
}
624
625
PHP_METHOD(Uri_Rfc3986_Uri, withPort)
626
0
{
627
0
  php_uri_property_write_long_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PORT);
628
0
}
629
630
PHP_METHOD(Uri_Rfc3986_Uri, getPath)
631
0
{
632
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
633
0
}
634
635
PHP_METHOD(Uri_Rfc3986_Uri, getRawPath)
636
0
{
637
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH, PHP_URI_COMPONENT_READ_MODE_RAW);
638
0
}
639
640
PHP_METHOD(Uri_Rfc3986_Uri, withPath)
641
0
{
642
0
  php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PATH);
643
0
}
644
645
PHP_METHOD(Uri_Rfc3986_Uri, getQuery)
646
0
{
647
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
648
0
}
649
650
PHP_METHOD(Uri_Rfc3986_Uri, getRawQuery)
651
0
{
652
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY, PHP_URI_COMPONENT_READ_MODE_RAW);
653
0
}
654
655
PHP_METHOD(Uri_Rfc3986_Uri, withQuery)
656
0
{
657
0
  php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_QUERY);
658
0
}
659
660
PHP_METHOD(Uri_Rfc3986_Uri, getFragment)
661
0
{
662
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
663
0
}
664
665
PHP_METHOD(Uri_Rfc3986_Uri, getRawFragment)
666
0
{
667
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_RAW);
668
0
}
669
670
PHP_METHOD(Uri_Rfc3986_Uri, withFragment)
671
0
{
672
0
  php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT);
673
0
}
674
675
static void throw_cannot_recompose_uri_to_string(php_uri_object *object)
676
0
{
677
0
  zend_throw_exception_ex(php_uri_ce_error, 0, "Cannot recompose %s to a string", ZSTR_VAL(object->std.ce->name));
678
0
}
679
680
static void uri_equals(INTERNAL_FUNCTION_PARAMETERS, php_uri_object *that_object, zend_object *comparison_mode)
681
0
{
682
0
  php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS);
683
0
  ZEND_ASSERT(this_object->uri != NULL);
684
0
  ZEND_ASSERT(that_object->uri != NULL);
685
686
0
  if (this_object->std.ce != that_object->std.ce &&
687
0
    !instanceof_function(this_object->std.ce, that_object->std.ce) &&
688
0
    !instanceof_function(that_object->std.ce, this_object->std.ce)
689
0
  ) {
690
0
    RETURN_FALSE;
691
0
  }
692
693
0
  bool exclude_fragment = true;
694
0
  if (comparison_mode) {
695
0
    zval *case_name = zend_enum_fetch_case_name(comparison_mode);
696
0
    exclude_fragment = zend_string_equals_literal(Z_STR_P(case_name), "ExcludeFragment");
697
0
  }
698
699
0
  zend_string *this_str = this_object->parser->to_string(
700
0
    this_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, exclude_fragment);
701
0
  if (this_str == NULL) {
702
0
    throw_cannot_recompose_uri_to_string(this_object);
703
0
    RETURN_THROWS();
704
0
  }
705
706
0
  zend_string *that_str = that_object->parser->to_string(
707
0
    that_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, exclude_fragment);
708
0
  if (that_str == NULL) {
709
0
    zend_string_release(this_str);
710
0
    throw_cannot_recompose_uri_to_string(that_object);
711
0
    RETURN_THROWS();
712
0
  }
713
714
0
  RETVAL_BOOL(zend_string_equals(this_str, that_str));
715
716
0
  zend_string_release(this_str);
717
0
  zend_string_release(that_str);
718
0
}
719
720
PHP_METHOD(Uri_Rfc3986_Uri, equals)
721
0
{
722
0
  zend_object *that_object;
723
0
  zend_object *comparison_mode = NULL;
724
725
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
726
0
    Z_PARAM_OBJ_OF_CLASS(that_object, php_uri_ce_rfc3986_uri)
727
0
    Z_PARAM_OPTIONAL
728
0
    Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode)
729
0
  ZEND_PARSE_PARAMETERS_END();
730
731
0
  uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode);
732
0
}
733
734
PHP_METHOD(Uri_Rfc3986_Uri, toRawString)
735
0
{
736
0
  ZEND_PARSE_PARAMETERS_NONE();
737
738
0
  php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS);
739
0
  ZEND_ASSERT(uri_object->uri != NULL);
740
741
0
  zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false);
742
0
  if (uri_str == NULL) {
743
0
    throw_cannot_recompose_uri_to_string(uri_object);
744
0
    RETURN_THROWS();
745
0
  }
746
747
0
  RETURN_STR(uri_str);
748
0
}
749
750
PHP_METHOD(Uri_Rfc3986_Uri, toString)
751
0
{
752
0
  ZEND_PARSE_PARAMETERS_NONE();
753
754
0
  php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS);
755
0
  ZEND_ASSERT(uri_object->uri != NULL);
756
757
0
  zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_NORMALIZED_ASCII, false);
758
0
  if (uri_str == NULL) {
759
0
    throw_cannot_recompose_uri_to_string(uri_object);
760
0
    RETURN_THROWS();
761
0
  }
762
763
0
  RETURN_STR(uri_str);
764
0
}
765
766
PHP_METHOD(Uri_Rfc3986_Uri, resolve)
767
0
{
768
0
  zend_string *uri_str;
769
770
0
  ZEND_PARSE_PARAMETERS_START(1, 1)
771
0
    Z_PARAM_PATH_STR(uri_str)
772
0
  ZEND_PARSE_PARAMETERS_END();
773
774
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU,
775
0
    uri_str, Z_URI_OBJECT_P(ZEND_THIS), true, false, NULL);
776
0
}
777
778
PHP_METHOD(Uri_Rfc3986_Uri, __serialize)
779
0
{
780
0
  ZEND_PARSE_PARAMETERS_NONE();
781
782
0
  php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS);
783
0
  ZEND_ASSERT(uri_object->uri != NULL);
784
785
  /* Serialize state: "uri" key in the first array */
786
0
  zend_string *uri_str = uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false);
787
0
  if (uri_str == NULL) {
788
0
    throw_cannot_recompose_uri_to_string(uri_object);
789
0
    RETURN_THROWS();
790
0
  }
791
0
  zval tmp;
792
0
  ZVAL_STR(&tmp, uri_str);
793
794
0
  array_init(return_value);
795
796
0
  zval arr;
797
0
  array_init(&arr);
798
0
  zend_hash_str_add_new(Z_ARRVAL(arr), PHP_URI_SERIALIZE_URI_FIELD_NAME, sizeof(PHP_URI_SERIALIZE_URI_FIELD_NAME) - 1, &tmp);
799
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
800
801
  /* Serialize regular properties: second array */
802
0
  ZVAL_ARR(&arr, uri_object->std.handlers->get_properties(&uri_object->std));
803
0
  Z_TRY_ADDREF(arr);
804
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
805
0
}
806
807
static void uri_unserialize(INTERNAL_FUNCTION_PARAMETERS)
808
2
{
809
2
  HashTable *data;
810
811
6
  ZEND_PARSE_PARAMETERS_START(1, 1)
812
8
    Z_PARAM_ARRAY_HT(data)
813
2
  ZEND_PARSE_PARAMETERS_END();
814
815
2
  php_uri_object *uri_object = php_uri_object_from_obj(Z_OBJ_P(ZEND_THIS));
816
2
  if (uri_object->uri != NULL) {
817
    /* Intentionally throw two exceptions for proper chaining. */
818
0
    zend_throw_error(NULL, "Cannot modify readonly object of class %s", ZSTR_VAL(uri_object->std.ce->name));
819
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
820
0
    RETURN_THROWS();
821
0
  }
822
823
  /* Verify the expected number of elements, this implicitly ensures that no additional elements are present. */
824
2
  if (zend_hash_num_elements(data) != 2) {
825
2
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
826
2
    RETURN_THROWS();
827
2
  }
828
829
  /* Unserialize state: "uri" key in the first array */
830
0
  zval *arr = zend_hash_index_find(data, 0);
831
0
  if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
832
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
833
0
    RETURN_THROWS();
834
0
  }
835
836
  /* Verify the expected number of elements inside the first array, this implicitly ensures that no additional elements are present. */
837
0
  if (zend_hash_num_elements(Z_ARRVAL_P(arr)) != 1) {
838
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
839
0
    RETURN_THROWS();
840
0
  }
841
842
0
  zval *uri_zv = zend_hash_str_find_ind(Z_ARRVAL_P(arr), ZEND_STRL(PHP_URI_SERIALIZE_URI_FIELD_NAME));
843
0
  if (uri_zv == NULL || Z_TYPE_P(uri_zv) != IS_STRING) {
844
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
845
0
    RETURN_THROWS();
846
0
  }
847
848
0
  uri_object->uri = uri_object->parser->parse(Z_STRVAL_P(uri_zv), Z_STRLEN_P(uri_zv), NULL, NULL, true);
849
0
  if (uri_object->uri == NULL) {
850
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
851
0
    RETURN_THROWS();
852
0
  }
853
854
  /* Unserialize regular properties: second array */
855
0
  arr = zend_hash_index_find(data, 1);
856
0
  if (arr == NULL || Z_TYPE_P(arr) != IS_ARRAY) {
857
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
858
0
    RETURN_THROWS();
859
0
  }
860
861
  /* Verify that there is no regular property in the second array, because the URI classes have no properties and they are final. */
862
0
  if (zend_hash_num_elements(Z_ARRVAL_P(arr)) > 0) {
863
0
    zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(uri_object->std.ce->name));
864
0
    RETURN_THROWS();
865
0
  }
866
0
}
867
868
PHP_METHOD(Uri_Rfc3986_Uri, __unserialize)
869
1
{
870
1
  uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU);
871
1
}
872
873
PHP_METHOD(Uri_Rfc3986_Uri, __debugInfo)
874
0
{
875
0
  ZEND_PARSE_PARAMETERS_NONE();
876
877
0
  php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS);
878
879
0
  RETURN_ARR(uri_get_debug_properties(uri_object));
880
0
}
881
882
PHP_METHOD(Uri_WhatWg_Url, getScheme)
883
0
{
884
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
885
0
}
886
887
PHP_METHOD(Uri_WhatWg_Url, withScheme)
888
0
{
889
0
  php_uri_property_write_str_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_SCHEME);
890
0
}
891
892
PHP_METHOD(Uri_WhatWg_Url, withUsername)
893
0
{
894
0
  php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_USERNAME);
895
0
}
896
897
PHP_METHOD(Uri_WhatWg_Url, withPassword)
898
0
{
899
0
  php_uri_property_write_str_or_null_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_PASSWORD);
900
0
}
901
902
PHP_METHOD(Uri_WhatWg_Url, getAsciiHost)
903
0
{
904
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_ASCII);
905
0
}
906
907
PHP_METHOD(Uri_WhatWg_Url, getUnicodeHost)
908
0
{
909
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_HOST, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_UNICODE);
910
0
}
911
912
PHP_METHOD(Uri_WhatWg_Url, getFragment)
913
0
{
914
0
  php_uri_property_read_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_URI_PROPERTY_NAME_FRAGMENT, PHP_URI_COMPONENT_READ_MODE_NORMALIZED_UNICODE);
915
0
}
916
917
PHP_METHOD(Uri_WhatWg_Url, equals)
918
0
{
919
0
  zend_object *that_object;
920
0
  zend_object *comparison_mode = NULL;
921
922
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
923
0
    Z_PARAM_OBJ_OF_CLASS(that_object, php_uri_ce_whatwg_url)
924
0
    Z_PARAM_OPTIONAL
925
0
    Z_PARAM_OBJ_OF_CLASS(comparison_mode, php_uri_ce_comparison_mode)
926
0
  ZEND_PARSE_PARAMETERS_END();
927
928
0
  uri_equals(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_uri_object_from_obj(that_object), comparison_mode);
929
0
}
930
931
PHP_METHOD(Uri_WhatWg_Url, toUnicodeString)
932
0
{
933
0
  ZEND_PARSE_PARAMETERS_NONE();
934
935
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
936
0
  php_uri_object *uri_object = php_uri_object_from_obj(this_object);
937
0
  ZEND_ASSERT(uri_object->uri != NULL);
938
939
0
  RETURN_STR(uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_UNICODE, false));
940
0
}
941
942
PHP_METHOD(Uri_WhatWg_Url, toAsciiString)
943
0
{
944
0
  ZEND_PARSE_PARAMETERS_NONE();
945
946
0
  zend_object *this_object = Z_OBJ_P(ZEND_THIS);
947
0
  php_uri_object *uri_object = php_uri_object_from_obj(this_object);
948
0
  ZEND_ASSERT(uri_object->uri != NULL);
949
950
0
  RETURN_STR(uri_object->parser->to_string(uri_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false));
951
0
}
952
953
PHP_METHOD(Uri_WhatWg_Url, resolve)
954
0
{
955
0
  zend_string *uri_str;
956
0
  zval *errors = NULL;
957
958
0
  ZEND_PARSE_PARAMETERS_START(1, 2)
959
0
    Z_PARAM_PATH_STR(uri_str)
960
0
    Z_PARAM_OPTIONAL
961
0
    Z_PARAM_ZVAL(errors)
962
0
  ZEND_PARSE_PARAMETERS_END();
963
964
0
  php_uri_instantiate_uri(INTERNAL_FUNCTION_PARAM_PASSTHRU,
965
0
    uri_str, Z_URI_OBJECT_P(ZEND_THIS), true, false, errors);
966
0
}
967
968
PHP_METHOD(Uri_WhatWg_Url, __serialize)
969
0
{
970
0
  ZEND_PARSE_PARAMETERS_NONE();
971
972
0
  php_uri_object *this_object = Z_URI_OBJECT_P(ZEND_THIS);
973
0
  ZEND_ASSERT(this_object->uri != NULL);
974
975
  /* Serialize state: "uri" key in the first array */
976
0
  zend_string *uri_str = this_object->parser->to_string(this_object->uri, PHP_URI_RECOMPOSITION_MODE_RAW_ASCII, false);
977
0
  if (uri_str == NULL) {
978
0
    throw_cannot_recompose_uri_to_string(this_object);
979
0
    RETURN_THROWS();
980
0
  }
981
0
  zval tmp;
982
0
  ZVAL_STR(&tmp, uri_str);
983
984
0
  array_init(return_value);
985
986
0
  zval arr;
987
0
  array_init(&arr);
988
0
  zend_hash_str_add_new(Z_ARRVAL(arr), ZEND_STRL(PHP_URI_SERIALIZE_URI_FIELD_NAME), &tmp);
989
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
990
991
  /* Serialize regular properties: second array */
992
0
  ZVAL_ARR(&arr, this_object->std.handlers->get_properties(&this_object->std));
993
0
  Z_ADDREF(arr);
994
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &arr);
995
0
}
996
997
PHP_METHOD(Uri_WhatWg_Url, __unserialize)
998
1
{
999
1
  uri_unserialize(INTERNAL_FUNCTION_PARAM_PASSTHRU);
1000
1
}
1001
1002
PHP_METHOD(Uri_WhatWg_Url, __debugInfo)
1003
0
{
1004
0
  ZEND_PARSE_PARAMETERS_NONE();
1005
1006
0
  php_uri_object *uri_object = Z_URI_OBJECT_P(ZEND_THIS);
1007
1008
0
  RETURN_ARR(uri_get_debug_properties(uri_object));
1009
0
}
1010
1011
PHPAPI php_uri_object *php_uri_object_create(zend_class_entry *class_type, const php_uri_parser *parser)
1012
32
{
1013
32
  php_uri_object *uri_object = zend_object_alloc(sizeof(*uri_object), class_type);
1014
1015
32
  zend_object_std_init(&uri_object->std, class_type);
1016
32
  object_properties_init(&uri_object->std, class_type);
1017
1018
32
  uri_object->parser = parser;
1019
32
  uri_object->uri = NULL;
1020
1021
32
  return uri_object;
1022
32
}
1023
1024
static zend_object *php_uri_object_create_rfc3986(zend_class_entry *ce)
1025
6
{
1026
6
  return &php_uri_object_create(ce, &php_uri_parser_rfc3986)->std;
1027
6
}
1028
1029
static zend_object *php_uri_object_create_whatwg(zend_class_entry *ce)
1030
26
{
1031
26
  return &php_uri_object_create(ce, &php_uri_parser_whatwg)->std;
1032
26
}
1033
1034
PHPAPI void php_uri_object_handler_free(zend_object *object)
1035
32
{
1036
32
  php_uri_object *uri_object = php_uri_object_from_obj(object);
1037
1038
32
  uri_object->parser->destroy(uri_object->uri);
1039
32
  zend_object_std_dtor(&uri_object->std);
1040
32
}
1041
1042
PHPAPI zend_object *php_uri_object_handler_clone(zend_object *object)
1043
0
{
1044
0
  php_uri_object *uri_object = php_uri_object_from_obj(object);
1045
1046
0
  ZEND_ASSERT(uri_object->uri != NULL);
1047
1048
0
  php_uri_object *new_uri_object = php_uri_object_from_obj(object->ce->create_object(object->ce));
1049
0
  ZEND_ASSERT(new_uri_object->parser == uri_object->parser);
1050
1051
0
  void *uri = uri_object->parser->clone(uri_object->uri);
1052
0
  ZEND_ASSERT(uri != NULL);
1053
1054
0
  new_uri_object->uri = uri;
1055
1056
0
  zend_objects_clone_members(&new_uri_object->std, &uri_object->std);
1057
1058
0
  return &new_uri_object->std;
1059
0
}
1060
1061
PHPAPI zend_result php_uri_parser_register(const php_uri_parser *uri_parser)
1062
48
{
1063
48
  zend_string *key = zend_string_init_interned(uri_parser->name, strlen(uri_parser->name), true);
1064
1065
48
  ZEND_ASSERT(uri_parser->name != NULL);
1066
48
  ZEND_ASSERT(uri_parser->parse != NULL);
1067
48
  ZEND_ASSERT(uri_parser->clone != NULL || strcmp(uri_parser->name, PHP_URI_PARSER_PHP_PARSE_URL) == 0);
1068
48
  ZEND_ASSERT(uri_parser->to_string != NULL || strcmp(uri_parser->name, PHP_URI_PARSER_PHP_PARSE_URL) == 0);
1069
48
  ZEND_ASSERT(uri_parser->destroy != NULL);
1070
1071
48
  zend_result result = zend_hash_add_ptr(&uri_parsers, key, (void *) uri_parser) != NULL ? SUCCESS : FAILURE;
1072
1073
48
  zend_string_release_ex(key, true);
1074
1075
48
  return result;
1076
48
}
1077
1078
static PHP_MINIT_FUNCTION(uri)
1079
16
{
1080
16
  php_uri_ce_rfc3986_uri = register_class_Uri_Rfc3986_Uri();
1081
16
  php_uri_ce_rfc3986_uri->create_object = php_uri_object_create_rfc3986;
1082
16
  php_uri_ce_rfc3986_uri->default_object_handlers = &object_handlers_rfc3986_uri;
1083
16
  memcpy(&object_handlers_rfc3986_uri, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1084
16
  object_handlers_rfc3986_uri.offset = XtOffsetOf(php_uri_object, std);
1085
16
  object_handlers_rfc3986_uri.free_obj = php_uri_object_handler_free;
1086
16
  object_handlers_rfc3986_uri.clone_obj = php_uri_object_handler_clone;
1087
1088
16
  php_uri_ce_whatwg_url = register_class_Uri_WhatWg_Url();
1089
16
  php_uri_ce_whatwg_url->create_object = php_uri_object_create_whatwg;
1090
16
  php_uri_ce_whatwg_url->default_object_handlers = &object_handlers_whatwg_uri;
1091
16
  memcpy(&object_handlers_whatwg_uri, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1092
16
  object_handlers_whatwg_uri.offset = XtOffsetOf(php_uri_object, std);
1093
16
  object_handlers_whatwg_uri.free_obj = php_uri_object_handler_free;
1094
16
  object_handlers_whatwg_uri.clone_obj = php_uri_object_handler_clone;
1095
1096
16
  php_uri_ce_comparison_mode = register_class_Uri_UriComparisonMode();
1097
16
  php_uri_ce_exception = register_class_Uri_UriException(zend_ce_exception);
1098
16
  php_uri_ce_error = register_class_Uri_UriError(zend_ce_error);
1099
16
  php_uri_ce_invalid_uri_exception = register_class_Uri_InvalidUriException(php_uri_ce_exception);
1100
16
  php_uri_ce_whatwg_invalid_url_exception = register_class_Uri_WhatWg_InvalidUrlException(php_uri_ce_invalid_uri_exception);
1101
16
  php_uri_ce_whatwg_url_validation_error = register_class_Uri_WhatWg_UrlValidationError();
1102
16
  php_uri_ce_whatwg_url_validation_error_type = register_class_Uri_WhatWg_UrlValidationErrorType();
1103
1104
16
  zend_hash_init(&uri_parsers, 4, NULL, NULL, true);
1105
1106
16
  if (php_uri_parser_register(&php_uri_parser_rfc3986) == FAILURE) {
1107
0
    return FAILURE;
1108
0
  }
1109
1110
16
  if (php_uri_parser_register(&php_uri_parser_whatwg) == FAILURE) {
1111
0
    return FAILURE;
1112
0
  }
1113
1114
16
  if (php_uri_parser_register(&php_uri_parser_php_parse_url) == FAILURE) {
1115
0
    return FAILURE;
1116
0
  }
1117
1118
16
  return SUCCESS;
1119
16
}
1120
1121
static PHP_MINFO_FUNCTION(uri)
1122
9
{
1123
9
  php_info_print_table_start();
1124
9
  php_info_print_table_row(2, "URI support", "active");
1125
9
#ifdef URI_STATIC_BUILD
1126
9
  php_info_print_table_row(2, "uriparser bundled version", URI_VER_ANSI);
1127
#else
1128
  php_info_print_table_row(2, "uriparser compiled version", URI_VER_ANSI);
1129
  php_info_print_table_row(2, "uriparser loaded version", uriBaseRuntimeVersionA());
1130
#endif
1131
9
  php_info_print_table_end();
1132
9
}
1133
1134
static PHP_MSHUTDOWN_FUNCTION(uri)
1135
0
{
1136
0
  zend_hash_destroy(&uri_parsers);
1137
1138
0
  return SUCCESS;
1139
0
}
1140
1141
PHP_RINIT_FUNCTION(uri)
1142
278k
{
1143
278k
  if (PHP_RINIT(uri_parser_whatwg)(INIT_FUNC_ARGS_PASSTHRU) == FAILURE) {
1144
0
    return FAILURE;
1145
0
  }
1146
1147
278k
  return SUCCESS;
1148
278k
}
1149
1150
ZEND_MODULE_POST_ZEND_DEACTIVATE_D(uri)
1151
278k
{
1152
278k
  if (ZEND_MODULE_POST_ZEND_DEACTIVATE_N(uri_parser_whatwg)() == FAILURE) {
1153
0
    return FAILURE;
1154
0
  }
1155
1156
278k
  return SUCCESS;
1157
278k
}
1158
1159
zend_module_entry uri_module_entry = {
1160
  STANDARD_MODULE_HEADER_EX, NULL,
1161
  uri_deps,
1162
  "uri",                          /* Extension name */
1163
  NULL,                           /* zend_function_entry */
1164
  PHP_MINIT(uri),                 /* PHP_MINIT - Module initialization */
1165
  PHP_MSHUTDOWN(uri),             /* PHP_MSHUTDOWN - Module shutdown */
1166
  PHP_RINIT(uri),                 /* PHP_RINIT - Request initialization */
1167
  NULL,                           /* PHP_RSHUTDOWN - Request shutdown */
1168
  PHP_MINFO(uri),                 /* PHP_MINFO - Module info */
1169
  PHP_VERSION,                    /* Version */
1170
  NO_MODULE_GLOBALS,
1171
  ZEND_MODULE_POST_ZEND_DEACTIVATE_N(uri),
1172
  STANDARD_MODULE_PROPERTIES_EX
1173
};