JSON encode data type errors in PHP

json_encode() working weirdly? Please read this before you go mad

The quick solution

Ensure you are NOT using the Mysql Client Library but the Mysql Native Driver

sudo apt-get install php5-mysqlnd

This is the story, maybe you have a similar problem, continue reading:


To be concrete:

  1. You've got a Nginx/PHP web app up&running.

  2. All works perfectly in your vagrant local environment.

  3. Also you have 2 Heroku replica instances (test and production) and your app is working there for months.

  4. You decide to move from Heroku to EC2 servers and you follow this cool guide.

  5. Everything (seems to) work well, but then (3-4 days after the migration) the Mobile Team Head of Develpment (one of your friendly co-workers) says "Hey Jose, the iOS app is crashing, the api is returning bad data" (oh sorry, I didn't mention your web app is providing a RestFUL API for mobile apps.

Your COO aslo says: "The customer has a demo tomorrow!" (wat)!!!! Defo, you're in a hurry...

Your roadmap

Fix it! (It doesn't sound like plan of action, huh?)

Action 1: Identify the problem

Your colleague comes to you and says: "Hey I got it. That's the problem: the json object returned is wrong, it looks like integers are strings and app is crashing." You can not believe it and, of course, you go and double check it. Then you face something like that:

[{"id":"34","user_id":"675", ... }, ...]


Action 2: Denial

It can not be, no, impossible. Let's double-check in your vagrant local environment... You try the same request in your local environment and you get the same wrong result

(WAT) ????

Mmmm, hold on, you got it... Obviously, you did a mistake, you introduced an error in the source code at any time but nobody realized, yeah! that's it! For sure! Time to go to Heroku intance and repeat that test. Ok, third test: you repeat your request in your Heroku instance (obviously you know it will fail) and... IT WORKS!!!!!

Jesus! Black magic definitely!

Action 3: Finding solutions

There's a frenetic activity among your team, everybody trying to get a miraculous solution. Someone tells you about JSON_NUMERIC_CHECK in PHP,... mmm... doesn't look like a good clue.

Ok, ok, in summary: the same code magically works in Heroku and doesn't in EC2 and vagrant!!!??? Any difference between instances?

Oh man, you run php -v all around ... php 5.5.x in vagrant, Heroku and EC2...


Action 3.1: RUSH. Magic required!

Of course, the customer has a demo tomorrow. Even more, they have to do a MP4 demo video tonight


Let's give a try to that JSON_NUMERIC_CHECK thing (Notice you don't like this because IT IS NOT A GOOD IDEA AT ALL but you have to do something). Our application uses Slim Framework and Twig Templating system, any API request renders a Twig template calling json_encode(), soooo, I do something like this:

{{ data|json_encode(constant('JSON_NUMERIC_CHECK'))|raw }}

Wow, it works!

You decide to use this approach by now. You ask your colleague for any failing api request to ensure all of them works with you brand new patch. After 30 mins: "Hey Jose, it seems the request X is crashing again".

Good and bad news. The first problem is solved but we introduced a second one. This flag is converting to integer some parts of the json which are actually strings. Actually, this flag, if you use it... it must be used in a very limited scenario, be really carefull

Definitely, we need a real SOLUTION, not a patch.

Action 4: Look for a good solution

Ok, keep calm. As a last resort, we can repoint a DNS to the old Heroku instance then the mobile app will work, but we'll only do that if any other solution fail.

I quietly look for some extra information and I find this link (btw, we're using Slim, Twig, and Eloquent, the Laravel ORM, out-of-the-box). Yes, it looks like a solution.

What's the point?

Well, give a quiet read to this link if you like but, basically, when you get records from your tables you might get (depending on some stuff) the wrong data type if you're using Mysql Client library, named, rather than getting integer, float or double, you'll get (generically) type 'string' and value for that field stringified. Finally, when you json_encode() it (no matter if using json_encode() or something like "toJSON" in Eloquent which internally call json_encode()) you will encode "string" rather than "integer" and enconde type will be obviously "string".

Action 5: Apply the solution

First in my vagrant machine

sudo apt-get install php5-mysqlnd

YEEEAH! No, source code changes, all working!

Now, test and production EC2 instances

sudo apt-get install php5-mysqlnd