Nested arrays in a POST request are not parsed completely by PHP - php

I have been researching this problem for over 12 hours now, with no success.
We have a large custom CMS we have built for a governmental client. The software was developed on PHP 5.3.3. The initial deployment was done on PHP 5.2.2, which caused a few problems, but they finally upgraded their server to PHP 5.3.8. We have little control on exactly which versions gets deployed to their servers.
We have encountered a show-stopper problem. We have an AJAX request which submits a large form via POST with up to 5 levels deep of nested arrays. This has worked fine for several months, but all of a sudden using the new PHP install, we are only getting a partial decode of the data inside the $_POST variable. I have confirmed that PHP is received all the data by inspecting php://input (I also checked that the data was being sent from the browser via Firebug).
This is what we are receiving as the decoded output (via var_dump, I've shortened it for brevity, this should give you a good idea)
Array
(
[db_required_fields] => Array
(
[awr_title] => Array
(
[en] => phil test eng
)
)
[subtitle_intro] => Array
(
[awr_subtitle] => Array
(
[en] =>
)
)
[products] => Array
(
[cp_recall] => Array
(
[1] => Array
(
[product_common_name] => Array
(
[en] =>
)
)
)
)
)
What is missing: each of the [en] should have a peer [fr] array index entry. For example, there should be a [fr] phil test fr entry. Several other index entries at the 2nd array level are missing. The request data itself is not particularly large, roughly 6-7Kb.
What I've done:
- I have had suhosin disabled since it was often mentioned as the cause of similar problems.
- Pored over the phpinfo(); from both a working and the now-working server, trying to identify relevant differences.
- Investigated every module and option within which might affect things (mbstring, for example).
I am now considering writing my own parser for the php://input data, but this seems fraught with (potentially hidden) danger.
Any suggestion or hint ?

I would suggest serializing the post data before sending it. And I would send it as a single string of JSON in one "field." Something like this:
$.ajax({
type: 'POST',
url: 'YOUR URL',
data: {
json: JSON.stringify(form_data) // Where form_data is the JSON object.
},
success: function(response)
{
// Do stuff.
}
});
Then on the server-side, json_decode as follows:
<?php
$_POST = json_decode($_POST['json'], true);
?>
EDIT:
You want json_decode instead of unserialize. Whoops.

You are probably being affected by the new PHP configuration variables max_input_nesting_level or max_input_vars (particularly the latter). Try setting it to a higher value so that PHP doesn't start ignoring some input.

Note, that when you want to change settings like max_input_vars and max_input_nesting_level and you have Suhosin running, you also need to change these params for Suhosin. Example for max_input_vars:
You need to add this to the .htaccess file:
php_value suhosin.post.max_vars 4000
php_value suhosin.request.max_vars 4000
You also need to add the following to your php.ini file in order to allow the change of the suhosin parameters within the .htaccess:
suhosin.perdir = "pr"
"p" allows the change for "post" settings, "r" for request settings.

Related

json_decode differences between two physical PCs

Last few weeks I have been working from home for obvious reasons. We run our development environment via a stack of docker microservices for which we have a standard set of docker images and docker-compose files.
At work my stack works 100% without issue with regard to the calls for json_decode but when I am home and use the same files whenever json_decode is called the process "hangs". Putting some logging after the call is never reached.
One example of the call is
$ret[$row['an']]['sc'] = json_decode($row['channel']);
When the code reaches this it never gets out of it, no errors logged either.
To fix this I have to change the call to the following (please note this is running on PHP version 5.6.40)
$ret[$row['an']]['sc'] = json_decode($row['channel'],false,512,JSON_INVALID_UTF8_IGNORE);
My home dev machine is a Windows PC (Win 10) but I also have a Linux drive which I can boot into but this experiences the same problem.
Additional info:
This is working upon an array of json strings such as
{"phones":["44123456789","44123456788","44123456787"]}
{"phones":[]}
It hangs when the value been worked on is {"phones":[]} but if the json value has numbers it runs fine.
The json_decode is in fact hanging everything except when the value is NULL. If the value been decoded is null is carries on without issue.
On my work machine where everything runs without issue the data is the same oddly.
Additional info to support comments:
A var_dump of the first item that json is choking on
string(56) "{"phones":["44123456789","447838588850","447838588850"]}"
Output of the byte string for the failing item as per Gavins recommendation:
(
[1] => 7b2270686f6e6573223a5b223434313233343536373839222c22343437383338353838383530222c22343437383338353838383530225d7d
)
I also have tried the three methods outlined in the solution at How to detect malformed utf-8 string in PHP?'%2C%20%24string)%3B and all are returning true (true = valid)
UPDATED 19/06/2020 below
Testing the simple php code below even this fails on the json_decode. Json_encode works fine
<?php
$job[123] = [
'id' => 123,
'position' => [
'title' => 'PHP Developer',
],
];
$json = json_encode($job[123]);
echo($json);
$jsonStr = json_decode($json);
print_r($jsonStr);
```

CakePHP excel download troubleshooting

I'm trying to follow this solution to export data to excel but when I click the download link it just says "Server Error. May be down for maintenance....etc"
The only thing I had to change from the tutorial is the name of the Csv helper. The tutorial specifies "Csv.php" but I had to name it "CsvHelper.php". When I print the variable that goes to this view, it displays the array. However, when I remove this and just have the code listed exactly as it appears in that linked post from above I get a server error
HTTP Error 500 (Internal Server Error): An unexpected condition was encountered while the server was attempting to fulfill the request.
These are the files that I had to add to my server as directed by the "tutorial"
//Helper
/App/View/Helper/CsvHelper.php
//Vendor
/App/Vendor/excel/PHPExcel.PHP
/App/Vendor/excel/PHPExcel/ //contains the rest of PHPExcel
//view
/App/View/Orders/download.ctp //Tutorial specifies /App/View/Homes/download.ctp so I made sure to change the link accordingly in the view which actually "links" to this
As I mentioned previously when I print the array on download.ctp see this
Array ( [0] => Array ( [Order] => Array ( [id] => 1 [userid] => 2 [order_status] => completed [email] => test#gmail.com [total] => 8.00 ) )
My array's structure matches that of the tutorial which is
$orders[0]['Order'];
Is there something I have to configure with CakePHP for downloading files? I have no idea where to go from here.
Outputting different types of content in cake 2.x is now easy and a "piece of cake" :)
View classes can easily be switched to whatever output you need (json, xml, csv, ..).
In your case I would use https://github.com/josegonzalez/CsvView .
$this->viewClass = 'CsvView.Csv';
and export the data as documented in the plugin readme.

ZF2 : Trouble with session for authentication

I have a strange problem with the session after an authentication.
The whole authentification part works, troubles come after that :
$result = $this->getAuthService()->authenticate();
if ($result->isValid()) {
$storage = $this->getAuthService()->getStorage();
$storage->write(($this->getAuthService()
->getAdapter()
->getResultRowObject(array(
'email_utilisateur',
'password_utilisateur',
))));
$redirect = 'success';
}
Right now, I am logged, and email+password are stored, in the "Zend_Auth" key (don't pay attention to the fact that I store password btw, it's for the example ^^).
But when I go on another page (even if it's the same), my Session key "Zend_auth" gets broken, and I have an incomplete PHP object....
Array
(
[__ZF] => Array
(
[_REQUEST_ACCESS_TIME] => 1369667659.7526
)
[Zend_Auth] => __PHP_Incomplete_Class Object
(
[__PHP_Incomplete_Class_Name] => Zend\Stdlib\ArrayObject
)
)
So, any idea why changing page would screw my session variable ?
Thanks in advance, I've spent like 5 hours on this problem, testing things etc...
EDIT 28/05/2013 :
So, I still didn't find.
Anyway, the object that gets corrupted is a Zend\Stdlib\ArrayObject. A reason why this arrayobject gets corrupted would be that the session starts before the inclusion avec Zend\Stdlib\ArrayObject. I'll try to figure it out, but if that's the reason, then it's a bug of the framework. By the way, I'm using ZF 2.2.
I FOUND !
So, as said, the reason was that the session started before the ArrayObject thing was known by the application. And, as you can read there :
https://zf2-docs.readthedocs.org/en/latest/modules/zend.session.advanced-usage.html
**Do not enable PHP‘s session.auto_start setting. If you do not have the ability to disable this.**
And that was the thing. session.auto_start was enabled in my php.ini. In order to fix this, you must set it to 0 in your php.ini file :
php_value session.auto_start 0
If your PHP is used for several applications/sites, then add this line to your .htaccess instead :
php_value session.auto_start 0
This will override the actual value of the php.ini
Hope it will help someone ^^.

Unserialized COOKIE returns empty

I'm trying to save an array into a cookie, in a serialized manner. So what I do is this:
$serial_auth = serialize($_SESSION['auth']);
setcookie("auth_cookie", $serial_auth , 2592000 + time());
and in the next page I'm trying to use this data like this:
if(isset($_COOKIE['auth_cookie']))
{
$_SESSION['auth'] = unserialize($_COOKIE['auth_cookie']); //but it returns an empty array.
}
now the strange thing is the whole thing works in my localhost, but it does not work on 000webhost site.
and a note: when I try to echo those, I get this:
$_SESSION['auth'] =
Array ( [status] => ok [userid] => 1 [username] => user11 [visiblename] => user11 )
SERIALIZED =
a:4:{s:6:"status";s:2:"ok";s:6:"userid";s:1:"1";s:8:"username";s:6:"user11";s:11:"visiblename";s:6:"user11";}
This may be a PHP configuration issue, but I would like to learn if there is a way for this, without changing any PHP configuration. Thanks for any help.
This has severe security drawbacks and shouldn't be done.
An attacker can set the cookie value to anything, including serialized objects. These objects may execute code when recreated. So an attacker may execute code on your machine by sending you a properly crafted serialization string! One cannot want attackers to be able to do this.
See the warning at the bottom of this page: http://www.php.net/manual/en/function.unserialize.php
The second thing is: Why the hell do you need the authentication info in a separate cookie, and what is connected with it? What would an attacker be able to do if he changes any of the values, especially the userid or the status? I assume he might gain access to things he shouldn't be able to.

PHP - Using data from url, but not via post nor get

I'm sorry if is a repeated question, but i having trouble with PHP. I'm working with the code of another programer, and he is using php. In one of the pages que get the information from the url, but no via post nor get, but by attaching it to the url and putting / between them, like this:
www.example.com/memorial/31/john
the he uses 31 and john as data. I have no memorial directory, neither a file called memorial.
Is there a way to do this in PHP without a framework, he doesn't seem to be using any libraries either.
The most likely explanation is that he is using an URL rewrite engine, such as Apache's mod_rewrite. This will be doing something like turning the directory parts into GET variables.
You can find that information in the global $_SERVER variable: $_SERVER['REQUEST_URI']. As #Oli mentioned, this is probably through a rewrite engine.
For example if you went to the URL you mentioned (www.example.com/memorial/31/john):
$uriPieces = explode('/',$_SERVER['REQUEST_URI'],'/');
// this gets rid of all of the cases of double-slashes as well as the initial
// and trailing. This is optional, but I will generally prefer it.
$uriPieces = array_filter($uriPieces);
print_r($uriPieces);
Outputs
Array
(
[0] => memorial
[1] => 34
[2] => john
)
If you search your project for REQUEST_URI, you will find where the variables are being set.

Categories