Unserialsed Array giving the weirdest results - php

I've a really odd issue today. I've got a serialised array that looks like this:
a:4:{i:0;s:7:"Perfect";i:1;s:10:"jawel hoor";i:2;s:14:"Ach jawohl joh";i:3;s:2:"Ja";}
Then after I execute this code:
include '../../database/connect.php';
Class Calc {
function getPrice($id) {
$Db = new Db();
$sth = $Db->dbh->prepare("SELECT * FROM orders WHERE id = :id");
$sth->execute(array(':id'=>$id));
$are_you_serial = $sth->fetchAll();
foreach($are_you_serial as $row) {
$serialised = $row['reply_array'];
$product_id = $row['product_id'];
$user_id = $row['user_id'];
}
$array = unserialize($serialised);
foreach($array as $row) {
echo $row[1];
}
}
}
$calc = new Calc();
$calc->getPrice(11);
eaca comes out. When I call row 0 PjAJ comes out.
When I call row 2 this seems to be the error:
rwh
Notice: Uninitialized string offset: 2 in index.php on line 29
This is what the array looks like if I just print_r the $array:
Array
(
[0] => Perfect
[1] => jawel hoor
[2] => Ach jawohl joh
[3] => Ja
)
I can also call $array[0] and it'll show the right things but once I put it in the foreach it doesn't work anymore.

Your first foreach keeps reassigning the variables, so $serialised (should be $serialized BTW) will only ever hold the value of the last row by the time you're actually calling unserialize. I'll add what I think you want bellow, but for now, some more details on why you're getting the "weird" or unexpected output:
A little info on how to read the PHP serialized format:
a:4:{i:0;s:7:"Perfect";i:1;s:10:"jawel hoor";...
a:4:{: What follows is an array, containing 4 key-value pairs
i:0;: An integer, value 0. Because this is part of an array, all odd values are keys, even values are values, so the first index of the array is 0
s:7:"Perfect";: A string, 7 chars long, and the string itself is "Perfect" (without the quotes)
Same applies to objects that are serialized:
O:8:"stdClass":2:{s:3:"bar";i:123;s:3:"foo";i:456;}
o:8:"stdClass":2:{: An object, the class name of which is 8 chars long (stdClass), with 2 properties set
s:3:"bar";i:123;: The property name is a 3-char long string ("bar"), its value is an int (123)
s:3:"foo";i:456;: 3-char long property ("foo") with value 456
}: End of serialized object
Knowing this, you should be able to work out that what you're doing with the data after you've unserialized, ie this:
foreach ($array as $row) {
echo $row[1];
}
Is just all shades of wrong, the value of $row will be a string, and getting an index/offset of a string is possible (preferably using the {} notation, as in $row{1}), but it'll return the character at offset n, where n is the digit/key between brackets. Strings are, like arrays, zero-indexed BTW, so $string = 'foo'; echo $string{0}; will echo "f", and echo $string{1}; will echo "o".
What you want, then is to write:
foreach ($array as $row) {
echo $row;
}
or shorter:
echo implode(PHP_EOL, $array);//PHP_EOL to add linebreaks between the strings
Like I said at the beginning, you're only really processing the very last serialized value, what you actually want is probably something more like this:
$unserialized = [];
foreach ($sth->fetchAll() as $row) {
//add unserialized values to an array
$unserialized[] = unserialize($row['reply_array']);
}
//$unserialized is now an array of arrays
foreach ($unserialized as $rowNr => $array) {
echo 'Row #', $rowNr+1, ': ', PHP_EOL,
implode(PHP_EOL, $array);
}
That ought to get you started...

Related

PHP - How to re-order data within a multidimensional array with only one reliable preceding string?

I am being passed inconsistent data. The problem is the individual rows of $data_array are not consistently in the same sequence but each has a reliable "text:" preceding the value.
Each row contains about 120 elements of data. I only need 24 of those elements.
It's also possible one of the elements I need could be missing, such as "cost".
(I'm using php version 5.4)
-- Task:
Using $order_array, create a new $data_array_new by reordering the data in each "row" into the same sequence as $order_array.
If an elements is missing from a row insert "NA".
Once the elements are in the correct sequence the "text" is no longer required.
$order_array = array("price", "cost", "vol", "eps")
$data_array = Array (
$one = Array ("cost":43.40, "vol":44000, "eps":1.27, "price":65.00),
$two = Array ("eps":5.14, "price":33.14, "vol":657000),
$thr = Array ("vol":650000, "cost":66.67, "eps":1.33, "price":44.31),
);
The resulting ouput should appear with the data in this order: ("price", "cost", "vol", "eps")
$data_array_new = Array (
$one = Array (65.00,43.40,44000,1.27),
$two = Array (33.14,"NA",657000,5.14),
$thr = Array (44.31,66.67,650000,1.33),
);
$data_array_new = [];
foreach ($data_array as $index => $data) {
$data_array_new[$index] = [];
foreach ($order_array as $key) {
if (isset($data[$key])) {
$data_array_new[$index][] = $data[$key];
} else {
$data_array_new[$index][] = 'NA';
}
}
}
You can view the original incoming data here: https://api.iextrading.com/1.0/stock/market/batch?symbols=aapl,tsla,ge&types=quote,earnings,stats
Here is the answer from : Andreas
Use json_decode on the string with the second parameter true and you get a associative array as output.
$url = "https://api.iextrading.com/1.0/stock/market/batch?
symbols=aapl,tsla,ge&types=quote,earnings,stats";
$arr = json_decode(file_get_contents($url), true);
Var_dump($arr);
See here;
I copied the string from the page and posted it as $str.
https://3v4l.org/duWrI
Two steps is all that is needed.

How to create and fill a new associative array with values created in a for each?

I am a noob attempting to solve a program for a word search app I am doing. My goal is to take a string and compare how many times each letter of that string appears in another string. Then put that information into an array of key value pairs, where the key is each letter of the first string and the value is the number of times. Then order it with ar(sort) and finally echo out the value of the letter that appears the most (so the key with the highest value).
So it would be something like array('t' => 4, 'k' => '9', 'n' => 55), echo the value of 'n'. Thank you.
This is what I have so far that is incomplete.
<?php
$i = array();
$testString= "endlessstringofletters";
$testStringArray = str_split($testString);
$longerTestString= "alphabetalphabbebeetalp
habetalphabetbealphhabeabetalphabetalphabetalphbebe
abetalphabetalphabetbetabetalphabebetalphabetalphab
etalphtalptalphabetalphabetalbephabetalphabetbetetalphabet";
foreach ($testStringArray AS $test) {
$value = substr_count($longerTestString, $testStringArray );
/* Instead of the results of this echo, I want each $value to be matched with each member of the $testStringArray and stored in an array. */
echo $test. $value;
}
/* I tried something like this outside of the foreach and it didn't work as intended */
$i = array_combine($testStringArray , $value);
print_r($i);
If I understand correctly what you are after, then it's as simple as this:
<?php
$shorterString= "abc";
$longerString= "abccbaabaaacccb";
// Split the short sring into an array of its charachters
$stringCharachters = str_split($shorterString);
// Array to hold the results
$resultsArray = array();
// Loop through every charachter and get their number of occurences
foreach ($stringCharachters as $charachter) {
$resultsArray[$charachter] = substr_count($longerString,$charachter);
}
print_r($resultsArray);

foreach loop scope with multidimensional arrays

Can someone explain the output of this code?
Why is it "fb" instead of "100100"?
$items = array();
$items[] = "foo";
$items[] = "bar";
foreach($items as $item) {
$item['points'] = 100;
}
foreach($items as $item) {
echo $item['points']; //output: "fb"
}
You loop though the $items array, which has two elements.
First: foo and second: bar. E.g.
Array (
[0] => foo
[1] => bar
)
Now you access them like this:
echo $item['points'];
PHP will convert points which is a string into an integer, as you can see from the manual warning:
Warning: [...] Non-integer types are converted to integer. [...]
Which in your case will be 0.
And so you access the two values (strings) as array:
string: f o o
index: 0 1 2 //$index["points"] -> $index[0]
string: b a r
index: 0 1 2 //$index["points"] -> $index[0]
So you print the first character of both strings (e.g. foo and bar), which are:
fb
EDIT:
Also worth to note here is, that PHP only silently converts it with PHP <5.4 from newer version you will get a warning, as from the manual:
As of PHP 5.4 string offsets have to either be integers or integer-like strings, otherwise a warning will be thrown. Previously an offset like "foo" was silently cast to 0.
Which in your case with PHP >=5.4 you would get:
Warning: Illegal string offset 'points' ...
I found this question intriguing.
I had my own walk-through and here is the result.
$items is defined as follows.
$items = [
0 => "foo",
1 => "bar"
];
Then, goes into the foreach loop.
foreach($items as $item) {
$item['points'] = 100;
}
At the beginning, $item contains a string "foo". The [] syntax is dominantly used for associative arrays, so it tricks us that $item might be an array, which is not the case. A less well-known usage of the [] is to get/set a single character in a string via [int] or {int} expression, as #Rizier123 has noted in his answer. For example, a "string"[0] gives "s". So, the following code
$item['points'] = 100;
is virtually similar to
"foo"['points'] = 100;
Now, a non-integer value given as a character position of a string, raises a PHP warning, and the position (here 'points') will be force-converted to an integer.
// Converting a string to integer:
echo intval('points'); // gives 0
As a result, the "foo"['points']" statement becomes "foo"[0], so
"foo"[0] = 100;
Now, the assignment part. The [] syntax operates on a single character. The numeric 100 is first converted to a string "100" and then only the first character is taken out for the assignment operation(=). The expression is now similar to
"foo"[0] = "1"; // result: "1oo"
To make things a bit twisted, the modified value of $item( which is "1oo") is not preserved. It's because the $item is not a reference. See https://stackoverflow.com/a/9920684/760211 for more information.
So, all the previous operations are negligible in terms of the end result. The $items are intact in the original state.
Now, in the last loop, we can see that the $item['point'] statement tries to read a character out of a string, in an erroneous way.
foreach($items as $item) {
echo $item['points']; //output: "fb"
}
echo "foo"[0]; // "f"
echo "boo"[0]; // "b"
You're not actually modifying the array by doing $items as $item. $item is its own variable, so it would make sense that you get the correct output when printing within that loop.

call_user_func_array + array_intersect with an array of array names, possible?

Sorry for the confusing title...
I need to perform an array_intersect() against a variable number of arrays. To do this it seems I need to use the call_user_func_array() function, however, this doesn't seem to be working and gives me the error:
Warning: array_intersect() [function.array-intersect]: Argument #1 is not an array in...
But, if I "print_r" the array to make sure then I see that it is an array:
Array ( [0] => arr_0 [1] => arr_1 )
My code (trimmed to just show the broken part):
$i = 0;
$arr_results = array();
foreach($arr_words as $word) {
$arrayname = "arr_".$i;
$$arrayname = array();
while ($row = mysql_fetch_assoc($search)) {
array_push($$arrayname, $row['id']);
}
array_push($arr_results, "$arrayname");
$i++
}
$matches = call_user_func_array('array_intersect',$arr_results);
In the full code I'm populating the arrays in the foreach loop with data obtained from sql queries.
From my comments:
"$arrayname" is a string, not an array. call_user_func_array will pass each element in $arr_results as argument to array_intersect. array_intersect expects arrays as arguments, but each item in $arr_results is a string, not an array.
All you have to do is create an array of arrays instead of array names:
$arr_results = array();
foreach($arr_words as $word) {
$ids = array();
while ($row = mysql_fetch_assoc($search)) {
$ids[] = $row['id'];
}
$arr_results[] = $ids;
}
$matches = call_user_func_array('array_intersect',$arr_results);
I turn $arrayname into an array with $$arrayname = array();
Right, you create a variable, lets say arr_0 which will point to array. But there is still a difference between the variable name arr_0 and the string containing the variable name "arr_0". You create an array of strings, and that just won't work. PHP does not know that the string contains a name of a variable. For example, consider this:
$arr = "arr_0";
echo $arr[0];
Based on your logic, it should output the first element of the array, but it does not, because $arr is a string, not an array, although it contains the name of a variable.
You'd have to use eval, but you really should not. You could also use variable variables again:
array_push($arr_results, $$arrayname);
that would work as well, but as I said, variable variables are confusing and in 99% of the cases, you are better of with an array.

Cannot conditionally push element into subarray -- instead it overwrites first character

I have this code which works as I expect:
$somearr['some']='value';
$arr[]="first";
$arr['first'][]=$somearr['some'];
echo "<br> Var dump of arr: " . var_dump($arr);
Yields:
array (size=2)
0 => string 'first' (length=5)
'first' =>
array (size=1)
0 => string 'value' (length=5)
Perfect.
Now attempting to apply the same principle (I assume) in my project:
function get_field_names($database, $table) {
$show_statement = "DESCRIBE `" . $database . "`.`" . $table . "`";
$column_result = mysql_query($show_statement);
if (mysql_num_rows($column_result) > 0) {
$f = 0;
while ($row = mysql_fetch_assoc($column_result, MYSQL_ASSOC)) {
$field_names[$f] = $row['Field'];
if ($row['Key'] != "") {
$field_names[$f][0] = $row['Key'];
}
$f++;
}
}
return $field_names;
}
But instead of creating a second dimension to my array $field_names[$f][0] with the value of $row['Key'], instead the first character in the string of $field_names[$f] is overwritten with the first character in $row['Key'] such that $field_names[$f] contains the string: "field_name" and after $field_names[$f][0] = $row['Key'] where $row['Key'] == "PRI", I get : "Pield_name".
I am sure I am misunderstanding the array $row, but I am beginning to go in circles.
That's easily explained by revisiting your original example:
$arr[]="first";
$arr['first'][]=$somearr['some'];
This doesn't do what you think it does. The first line doesn't create a new array key first. It just assigns a value to the indexed entry [0].
The second line however assigns a value to the alphanumeric key [first]. That's two distinct sub-entries in the $arr array.
In your second example, you are overwriting values:
$field_names[$f] = 'string...';
$field_names[$f][0] = 'something else...';
You can only have one array entry at the [$f] key. You cannot have a shared spot with a string and an array.
What actually happens here is that the second line is assigning a value to the first array-like index of the 'string...'. It's equivalent to the alternative string-index syntax:
$field_names[$f]{0} = 'something else...';
^
|
Not an array index. Because a string was here first.
Anyway, you cannot share an entry as string and key. That's the whole story. - I think it's cursorily explained somewhere in the manual under arrays.
This is because you can treat any string in PHP like an array
$test = "Hello, World";
echo $test[0];
Will result in "H" being echo'ed. What you are telling you code in
$field_names[$f][0] = $row['Key'];
is replace the first character in the string $field_names[$f] with $row['Key']. However since it is only 1 character that we are replacing PHP just uses the first character in $row['Key'] thus you get "Pield_name", the "P" from PRI replaced in for the "F" which was at the first position in the "string array"
I'm still confused however to what you want to do. If you could map out what you want the array to look like after you insert(?) the $row['Key']. I can help you with the code
EDIT:
The reason you top code is working is you are simply not specifying a key for your first item you add to the array:
$arr[]="first"; //Inserts string "first" at pos 0 of array same as $arr[0]="first";
$arr['first'][]=$somearr['some']; //Inserts array into $arr using key 'first'
echo "<br> Var dump of arr: " . var_dump($arr);
The same could be achieved with this code
$arr =array(
0 => 'first',
'first' => $somearr['some']
)

Categories