Skip to content

ext/intl: NumberFormatter::parse() and parseCurrency() use UTF-16 offsets for UTF-8 strings#23094

Description

@LamentXU123

Description

This happens in my own app:

  <?php

  $formatter = new NumberFormatter('en_US', NumberFormatter::DECIMAL);

  $prefix = "\u{1F600}"; // 馃榾 
  $input = $prefix . '123';
  $offset = strlen($prefix);

  var_dump(strlen($input));
  var_dump($offset);
  var_dump($formatter->parse(
      $input,
      NumberFormatter::TYPE_INT32,
      $offset
  ));
  var_dump($offset);
  int(7)
  int(4)
  int(3)
  int(5)

While I expect

  int(7)
  int(4)
  int(123)
  int(7)

The emoji occupies 4 bytes in the PHP UTF-8 string but 2 UTF-16 code units in ICU. Very sure this is the reason.

The input offset should be converted from a UTF-8 byte offset to a UTF-16 code-unit offset before calling ICU. Ehhhhhhh unfortunately I think this happens commonly throughout the code base. So I might be planning some bigger refactor to solve this. Buggy stuff /_ \

Since this is a rather easy case to solve, I will open this as an issue here. If anyone want to start a contribution to the intl extension. They can try to solve this as a good head start. This should be easier than JIT bugs anyways. Feel free to open a PR :)

Note: The bug also effects parseCurrency as they use the exact same logic. Not sure if there are any similar functions effected :/

PHP Version

All supported version.

Operating System

N/A

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions