Skip to content

[Serializer] int is valid when float is expected when deserializing JSON #21165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

dunglas
Copy link
Member

@dunglas dunglas commented Jan 4, 2017

Q A
Branch? 3.1
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets api-platform/api-platform#37
License MIT
Doc PR n/a

JSON only has a Number type corresponding to both int and float PHP types.
PHP's json_encode, JavaScript's JSON.stringify, Go's json.Marshal as well as most other JSON encoders convert floating-point numbers like 12.0 to 12 (the decimal part is dropped when possible).
PHP's json_decode automatically converts Numbers without a decimal part to integers.

Actually, the Serializer rejects integers when a float is expected, this PR fixes this behavior when denormalizing JSON-based formats.

Port of api-platform/core#714.

/cc @gorghoa @Shine-neko

// PHP's json_decode automatically converts Numbers without a decimal part to integers.
// To circumvent this behavior, integers are converted to floats when denormalizing JSON based formats and when
// a float is expected.
if (Type::BUILTIN_TYPE_FLOAT === $builtinType && false !== strpos($format, JsonEncoder::FORMAT) && is_int($data)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the strpos($format, JsonEncoder::FORMAT) part really necessary? (Why not all formats?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is because some (most) formats make a difference between int and float.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, ok, but would it be harmful to always cast an int it to float if that's what is expected?
Just asking, I'm fine with it it, despite the format check looking kind of weird here. 😅

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would swap is_int and the string search. Checking a variable type is cheaper (yeah, this is a micro-optimization, but it does not hurt readability at all, and it may be called often when deserializing an object graph

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stof done

@ogizanagi I'm not sure to understand :) JSON has only a "Number" type, it's a limitation of the format, but for a format having a float type (like YAML for instance), it's not a good security practice to allow a int where a float is expected.

@ogizanagi
Copy link
Contributor

In any case: 👍

Status: Reviewed.

@nicolas-grekas
Copy link
Member

👍

@nicolas-grekas nicolas-grekas modified the milestones: 3.1, 3.3 Jan 6, 2017
@fabpot
Copy link
Member

fabpot commented Jan 6, 2017

Thank you @dunglas.

fabpot added a commit that referenced this pull request Jan 6, 2017
…rializing JSON (dunglas)

This PR was squashed before being merged into the 3.1 branch (closes #21165).

Discussion
----------

[Serializer] int is valid when float is expected when deserializing JSON

| Q             | A
| ------------- | ---
| Branch?       | 3.1
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | api-platform/api-platform#37
| License       | MIT
| Doc PR        | n/a

JSON only has a Number type corresponding to both `int` and `float` PHP types.
PHP's `json_encode`, JavaScript's `JSON.stringify`, Go's `json.Marshal` as well as most other JSON encoders convert floating-point numbers like `12.0` to `12` (the decimal part is dropped when possible).
PHP's `json_decode` automatically converts Numbers without a decimal part to integers.

Actually, the Serializer rejects integers when a float is expected, this PR fixes this behavior when denormalizing JSON-based formats.

Port of api-platform/core#714.

/cc @gorghoa @Shine-neko

Commits
-------

4125455 [Serializer] int is valid when float is expected when deserializing JSON
@fabpot fabpot closed this Jan 6, 2017
This was referenced Jan 12, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants