Avoiding array flattening in Lithium validator - php

How can I stop Lithium to flatten input values that are arrays before validation?
The Validator::check method in Lithium calls Set::flatten on the input before processing validators, see here:
http://li3.me/docs/lithium/util/Validator::check()
...
$values = Set::flatten($values);
...
The problem with this is that it assumes the values in $values are scalars. However, I am passing arrays to the model (which is a MongoDB document).
So
'users' => ['foo','bar']
will become
'users.0' => 'foo',
'users.1' => 'bar'
Which totally breaks validation, because it changes the property names.
I could actually just remove the flatten assignment, but I don't want to mess with the internals of the framework. Also I could convert the array to a JSON string, an object, etc. before validation, and convert it back later, but that just sounds lame :) On the other hand, I assume there should be an easy and nice way to skip flattening somehow.

Related

To call a particular column/field from an array using PHP [duplicate]

My problem is very basic.
I did not find any example to meet my needs as to what exactly serialize() and unserialize() mean in php? They just give an example - serialize an array and show an output in an unexplained format. It is really hard to understand the basic concept going through their jargon.
EDIT:
<?php
$a= array( '1' => 'elem 1', '2'=> 'elem 2', '3'=>' elem 3');
print_r($a);
echo ("<br></br>");
$b=serialize($a);
print_r($b);
?>
output:
Array ( [1] => elem 1 [2] => elem 2 [3] => elem 3 )
a:3:{i:1;s:6:"elem 1";i:2;s:6:"elem 2";i:3;s:7:" elem 3";}
I cannot understand the second output. Besides that, can anyone give an example of a situation that I need to serialize a php array before using it?
A PHP array or object or other complex data structure cannot be transported or stored or otherwise used outside of a running PHP script. If you want to persist such a complex data structure beyond a single run of a script, you need to serialize it. That just means to put the structure into a "lower common denominator" that can be handled by things other than PHP, like databases, text files, sockets. The standard PHP function serialize is just a format to express such a thing, it serializes a data structure into a string representation that's unique to PHP and can be reversed into a PHP object using unserialize. There are many other formats though, like JSON or XML.
Take for example this common problem:
How do I pass a PHP array to Javascript?
PHP and Javascript can only communicate via strings. You can pass the string "foo" very easily to Javascript. You can pass the number 1 very easily to Javascript. You can pass the boolean values true and false easily to Javascript. But how do you pass this array to Javascript?
Array ( [1] => elem 1 [2] => elem 2 [3] => elem 3 )
The answer is serialization. In case of PHP/Javascript, JSON is actually the better serialization format:
{ 1 : 'elem 1', 2 : 'elem 2', 3 : 'elem 3' }
Javascript can easily reverse this into an actual Javascript array.
This is just as valid a representation of the same data structure though:
a:3:{i:1;s:6:"elem 1";i:2;s:6:"elem 2";i:3;s:7:" elem 3";}
But pretty much only PHP uses it, there's little support for this format anywhere else.
This is very common and well supported as well though:
<array>
<element key='1'>elem 1</element>
<element key='2'>elem 2</element>
<element key='3'>elem 3</element>
</array>
There are many situations where you need to pass complex data structures around as strings. Serialization, representing arbitrary data structures as strings, solves how to do this.
PHP serialize() unserialize() usage
http://freeonlinetools24.com/serialize
echo '<pre>';
// say you have an array something like this
$multidimentional_array= array(
array(
array("rose", 1.25, 15),
array("daisy", 0.75, 25),
array("orchid", 4, 7)
),
array(
array("rose", 1.25, 15),
array("daisy", 0.75, 25),
array("orchid", 5, 7)
),
array(
array("rose", 1.25, 15),
array("daisy", 0.75, 25),
array("orchid", 8, 7)
)
);
// serialize
$serialized_array=serialize($multidimentional_array);
print_r($serialized_array);
Which gives you an output something like this
a:3:{i:0;a:3:{i:0;a:3:{i:0;s:4:"rose";i:1;d:1.25;i:2;i:15;}i:1;a:3:{i:0;s:5:"daisy";i:1;d:0.75;i:2;i:25;}i:2;a:3:{i:0;s:6:"orchid";i:1;i:4;i:2;i:7;}}i:1;a:3:{i:0;a:3:{i:0;s:4:"rose";i:1;d:1.25;i:2;i:15;}i:1;a:3:{i:0;s:5:"daisy";i:1;d:0.75;i:2;i:25;}i:2;a:3:{i:0;s:6:"orchid";i:1;i:5;i:2;i:7;}}i:2;a:3:{i:0;a:3:{i:0;s:4:"rose";i:1;d:1.25;i:2;i:15;}i:1;a:3:{i:0;s:5:"daisy";i:1;d:0.75;i:2;i:25;}i:2;a:3:{i:0;s:6:"orchid";i:1;i:8;i:2;i:7;}}}
again if you want to get the original array back just use PHP unserialize() function
$original_array=unserialize($serialized_array, ['allowed_classes' => false]);
var_export($original_array);
I hope this will help
Note: Set allowed_classes to false in unserialize for security reasons. See Warning https://www.php.net/manual/en/function.unserialize.php
<?php
$a= array("1","2","3");
print_r($a);
$b=serialize($a);
echo $b;
$c=unserialize($b, ['allowed_classes' => false]);
print_r($c);
Run this program its echo the output
a:3:{i:0;s:1:"1";i:1;s:1:"2";i:2;s:1:"3";}
Note: Set allowed_classes to false in unserialize for security reasons.
here
a=size of array
i=count of array number
s=size of array values
you can use serialize to store array of data in database and can retrieve and UN-serialize data to use. See Warning https://www.php.net/manual/en/function.unserialize.php
When you want to make your php value storable, you have to turn it to be a string value, that is what serialize() does. And unserialize() does the reverse thing.
Most storage mediums can store string types. They can not directly store a PHP data structure such as an array or object, and they shouldn't, as that would couple the data storage medium with PHP.
Instead, serialize() allows you to store one of these structs as a string. It can be de-serialised from its string representation with unserialize().
If you are familiar with json_encode() and json_decode() (and JSON in general), the concept is similar.
Please! please! please! DO NOT serialize data and place it into your database. Serialize can be used that way, but that's missing the point of a relational database and the datatypes inherent in your database engine. Doing this makes data in your database non-portable, difficult to read, and can complicate queries. If you want your application to be portable to other languages, like let's say you find that you want to use Java for some portion of your app that it makes sense to use Java in, serialization will become a pain in the buttocks. You should always be able to query and modify data in the database without using a third party intermediary tool to manipulate data to be inserted.
it makes really difficult to maintain code, code with portability issues, and data that is it more difficult to migrate to other RDMS systems, new schema, etc. It also has the added disadvantage of making it messy to search your database based on one of the fields that you've serialized.
That's not to say serialize() is useless. It's not... A good place to use it may be a cache file that contains the result of a data intensive operation, for instance. There are tons of others... Just don't abuse serialize because the next guy who comes along will have a maintenance or migration nightmare.
A good example of serialize() and unserialize() could be like this:
$posts = base64_encode(serialize($_POST));
header("Location: $_SERVER[REQUEST_URI]?x=$posts");
Unserialize on the page
if($_GET['x']) {
// unpack serialize and encoded URL
$_POST = unserialize(base64_decode($_GET['x']));
}
From http://php.net/manual/en/function.serialize.php :
Generates a storable representation of a value.
This is useful for storing or passing PHP values around without losing their type and structure.
Essentially, it takes a php array or object and converts it to a string (which you can then transmit or store as you see fit).
Unserialize is used to convert the string back to an object.
Basically, when you serialize arrays or objects you simply turn it to a valid string format so that you can easily store them outside of the php script.
Use serialize to save the state of an object in database (lets take the User class as an example) Next unserialize the data to load the previous state back to the object (methods are not serializer you need to include object class to be able to use it)
user personalization
Note for object you should use magic __sleep and __wakeup methods.
__sleep is called by serialize(). A sleep method will return an array of the values from the object that you want to persist.
__wakeup is called by unserialize(). A wakeup method should take the unserialized values and initialize them in them in the object.
For passing data between php and js you would use json_encode to turn php array to valid json format. Or other way round - use JSON.parese() to convert a output data (string) into valid json object. You would want to do that to make use of local storage. (offline data access)
Yes, I can. Assume we need to track your system means In your system has more than one admin and subadmin, All of these can insert or update or edit any information.Later you need to know who make this change. For solving this problem you need serialize.
**Explain:**Create a table named history which stores all changes. Each time there is a change insert a new row in this table. It might have this fields:
history(id,target_table(name of the table), target_id (ID of the saved entry),create/edit/change data (serialized data of the saved row),date)
I hope this will help you.
preg_match_all('/\".*?\"/i', $string, $matches);
foreach ($matches[0] as $i => $match) $matches[$i] = trim($match, '"');

Why does Laravel store two different array syntaxes in databases and which one is correct?

I come from a Javascript and Ruby background and this is baffling me. Laravel can store two different array syntaxes in my DB depending on how I handle my array serialization. In my understanding, collect() creates a true Laravel array. Why then is it storing a serialized array? Furthermore, is the {'key':'value'}syntax still an array despite having no square brackets surrounding it? It looks to me like a standard object or a hash, but if I try to do toArray() on it, it recognizes that it's already an array and throws an error. What am I misunderstanding and what is correct here?
Given a form:
edit.blade:
<select class="form-control m-bootstrap-select m_selectpicker" name="temp">
<option value={{ json_encode(array("$key"=>"$cph"), JSON_FORCE_OBJECT) }}>
</select>
The following two controllers syntaxes yield different database insertions.
PageController.php:
$page->cph_default = collect($request->temp);
$page->save();
Laravel stores an array with the following syntax in my database: ["{\"11\":\"1100\"}"]
PageController.php
$page->cph_default = json_decode($request->temp, true);
$page->save();
Laravel stores an array with the following syntax in my database: {"19": "1900"}
A PHP array with the syntax ['key' => 'value'] is called an associative array, and acts like a hash. A JSON-encoded associative array will show up as an object in JSON syntax. Examples and more info on PHP.net
Laravel's collect() function is a convenience wrapper for creating a new Collection. A Collection is not really a "true Laravel array" so much as it is an object wrapper with some convenience methods for modifying the underlying array. Think of it like a scalar object.
In your form when generating the option value, the submitted form value ($request->temp) will be a JSON-encoded string. Literally the string '{"19": "1900"}'.
Calling collect($request->temp) does no modification to that submitted data. It's simply creating a new Collection (array), containing a single string item. If you were to call toArray() on the collection, you'd see something like this:
[
0 => '{"19": "1900"}'
]
Note that this is not an associative array, it is a numeric array with a zero-based index. This array is encoded as a JSON array, not as a hash object. Hence your first result.
Calling json_decode($request->temp) is turning the string back into an associative array (hash) before saving it via Eloquent. Eloquent then calls json_encode() again internally, turning it back into the same JSON as your form's option value.
If you were to decode the form value before creating the collection, the resulting database save would look identical. You'd just have the convenience of the Collection wrapper:
$page->cph_default = collect(json_decode($request->temp, true));
$page->save();
If you're treating the column as a JSON type, you should ensure the data passed to Eloquent is NOT already encoded, or you'll get the double encoding experienced in your first example.
No Matter What is.
First If you are stroring the array into database convert to JSON FORMAT
For eg
$variable = json_encode($request->controlname);
This is the right way to store array
Into database

Why is my php array being saved to MongoDB as an object, then being retrieved as an associative array with stringified keys?

Background:
I have a class in this application I'm building whose job is:
__construct: $this->data = $this->mongoDB->collection->findOne();
Intermediate functions are employed to manipulate the data in tens of different ways each request. One manipulation could trigger one which would trigger another. This allows me to do unlimited updates to the mongo document with just one query, as long as $this->data['_id'] remains the same. This is the only place where data manipulation of this specific collection is allowed.
__destruct: $this->monboDB->collection->save($data)
Data is then read back, json_encode'd and sent to Javascript to draw the page
Intention:
I intended to delete a member of an array by looping through said array, matching a value within it, and unsetting that. Example:
foreach($this->data['documents'] as $key => $val){
if($val == $toBeDeleted){
unset($this->data['documents'][$key];
}
}
Then, this would be saved to the DB when the script finishes.
Problem:
When javascript reads back the data, rather than having ['a', 'b', 'd'], I had {'0': 'a', '1': 'b', '3': 'd'} - which can't be treated like an array and would pretty much break things.
I had this question half typed out before my a-hah! moment, so I figured I'd post my own answer to it too for future reference.
In php, an associative array and an array are all the same. You can have out of order keys, nonconsecutive keys, and almost any key that you'd like to use in calling your array member. Most, if not all, php array functions work with any array key. Objects are a totally different thing.
That being said, Javascript doesn't share the same rules for arrays. A javascript array must have consecutive keys starting at zero, otherwise it is an object. MongoDB is similar to Javascript in this way.
When php converts an object to be used in MongoDB or in Javascript, if the php array doesn't follow that rule, it becomes a Javascript object.
The problem was after unsetting an array index, it left a gap, causing nonconsecutive array keys, causing it to become an object. Simple fix would either be array_slice($array, $key, 1) or $array = array_values($array)

Empty associative array SOAP type conversion

I have a client server scenario where the type conversion did by the SoapClient class in PHP, cannot tell wether an empty array is associative or numeric, and so defaults to numeric.
All exposed functions use basic types, no classes.
An associative array such as array("something"=>123) gets converted to a map data type. However, when the same array is empty, such as array(), it gets converted to an array on the Ruby side. Type casting to object (object)array() will result in a struct data type on the Ruby side.
The argument is a bit more complex, not as simple as above:
array(
"options"=>array(
"plans"=>array(
0=>array(
"name"=>"abc",
"product_options"=>array(
"optional_key_determines_associative_array_data_type"=>0,
),
),
),
),
);
If the array under "product_options" is empty, it gets converted to an array in Ruby, instead of a map. Once again, type casting to object in PHP results in a struct in Ruby.
What can I do on the PHP side to make empty "associative" arrays end up as maps on the Ruby side?
PHP 5.3.3, using SoapClient.
Ruby 1.8.7, Rails 2.3.2 using Action Web Service.
You can wrap your array in a SoapVar class with APACHE_MAP as encoding parameter. Like This:
array(
"options"=>array(
"plans"=>array(
0=>array(
"name"=>"abc",
"product_options"=> new SoapVar(array(), APACHE_MAP),
),
),
),
);
Well, this is exactly what I mean: To overcome that problem you will need to change the logic in your scripts - not the PHP. As you can not define a PHP array to be associative you will need to modify the receiving script.
If it was me I would not send an empty array. Put a status field into the array. This could be a field counting the available products which in this case would count 0. You will have a more meaningful communication AND the array IS suddenly associative no matter what
e.g
"product_options" => array ('products'=>0,'...'=>...) and so forth.
What I say is you will need to change the logic, you can not change PHP.
Hope that helps,
Uwe
I might be wrong here, but by my understanding:
I do believe what you are trying to achieve is not possible. An array (and we are talking array only, no objects) is an array. The structure given by the content makes an array associative or not.
An empty array is not associative.

Is json_decode in PHP guaranteed to preserve ordering of elements when returning an array?

You can pass a boolean to json_decode to return an array instead of an object
json_decode('{"foo", "bar", "baz"}', true); // array(0 => 'foo', 1 => 'bar', 2 => 'baz')
My question is this. When parsing object literals, does this guarantee that the ordering of the items will be preserved? I know JSON object properties aren't ordered, but PHP arrays are. I can't find anywhere in the PHP manual where this is addressed explicitly. It probably pays to err on the side of caution, but I would like to avoid including some kind of "index" sub-property if possible.
Wouldn't it make more sense in this case to use an array when you pass the JSON to PHP. If you don't have any object keys in the JSON (which become associative array keys in PHP), just send it as an array. That way you will be guaranteed they will be in the same order in PHP as in javascript.
json_decode('{["foo", "bar", "baz"]}');
json_decode('["foo", "bar", "baz"]'); //I think this would work
If you need associative arrays (which is why you are passing the second argument as true), you will have to come up with some way to maintain their order when passing. You will pry have to do some post-processing on the resulting array after you decode it to format it how you want it.
$json = '{[ {"key" : "val"}, {"key" : "val"} ]}';
json_decode($json, true);
Personally, I've never trusted any system to return an exact order unless that order is specifically defined. If you really need an order, then use a dictionary aka 2dimension array and assigned a place value (0,1,2,3...) to each value in the list.
If you apply this rule to everything, you'll never have to worry about the delivery/storage of that array, be it XML, JSON or a database.
Remember, just because something happens to work a certain way, doesn't mean it does so intentionally. It's akin to thinking rows in a database have an order, when in fact they don't unless you use an ORDER BY clause. It's unsafe to think ID 1 always comes before ID 2 in a SELECT.
I've used json_decode() some times, and the results order was kept intact with PHP client apps. But with Python for instance it does not preserve the order.
One way to be reassured is to test it over with multiple examples.
Lacking an explicit statement I'd say, by definition, no explicit order will be preserved.
My primary line of thought it what order, exactly, would this be preserving? The json_decode function takes a string representation of a javascript object literal as it's argument, and then returns either an object or an array. The function's input (object literal as string) has no explicit ordering, which means there's no clear order for the json_decode function to maintain.

Categories