print_r blank space in output - php

I'm working with arrays in PHP and I have noticed strange output with some of the values having an extra line of blank space as shown below.
Array
(
[0] => Array
(
[token] => data
[tag] => data
)
[1] => Array
(
[token] => data
[tag] => data
)
etc.
This alternates with every other element having the extra blank space until element 5. Then they all look like [1] until they reach element [9] which has the strange whitespace line again.
Some data is duplicate too yet this doesn't effect whether the two elements will have the same whitespace issue.
Can this cause me problems or does it show an issue within my code? Why do some elements have this additional whitespace?
EDIT:
I did a var dump, and I have identified that some of the tags have a newline after them.
e.g.
"tagexample
"
rather than
"tagexample"
This is confusing however because as I said, a lot of the tags are duplicates and used for multiple tokens and it seems random which is affected.
EDIT2:
I did var export and that shows the same result as above, i.e.
'tag' => 'data
',

try this:
$arr = array(
array( 'token' => 'stuff 1',
'tag' => 'data 1
', ),
array( 'token' => 'stuff 2',
'tag' => 'data 2
', ),
array( 'token' => 'stuff 3',
'tag' => 'data 3
', ),
);
print "<pre>";
print_r($arr);
foreach($arr as $index => $sub) {
$arr[$index] = array_map('trim',$sub);
}
print "\n\n----------------------------------------------------\n\n";
print_r($arr);
/*
Array
(
[0] => Array
(
[token] => stuff 1
[tag] => data 1
)
[1] => Array
(
[token] => stuff 2
[tag] => data 2
)
[2] => Array
(
[token] => stuff 3
[tag] => data 3
)
)
----------------------------------------------------
Array
(
[0] => Array
(
[token] => stuff 1
[tag] => data 1
)
[1] => Array
(
[token] => stuff 2
[tag] => data 2
)
[2] => Array
(
[token] => stuff 3
[tag] => data 3
)
)
*/
could also be written as:
function trim_the_sub_array($sub) {
return array_map('trim',$sub);
}
$arr = array_map('trim_the_sub_array',$arr);

print_r() is a debugging function (http://php.net/print_r) and you need not worry about the whitespaces if you are using it for debugging. If you use it for output (say for a log), var_export() (http://php.net/var_export) would be a better choice since it prints actual PHP code for defining the array in question.
As you have mentioned, if some data is duplicated and if it's not the intended behavior then probably there is an issue in your code. You will be able figure that out by focusing on where the array is populated.

Related

Convert a json to multi-dimensional PHP array

I have the following json sent to my API endpoint
{"key":"levels","value":"[{role_id:1, access_level_id:3}, {role_id:2, access_level_id:1}, {role_id:3, access_level_id:2}]","description":""}
at the backend, I receive it as a Laravel request as follows:
public function functionName(Request $request){
$req=$request->all();
Log::debug($req['value']);
return;
}
And it returns the following expected result
array (
'key' => 'levels',
'value' => '[{role_id:1, access_level_id:3}, {role_id:2, access_level_id:1}, {role_id:3, access_level_id:2}]',
'description' => NULL,
)
But I need to convert the 'value' to array also. so that I can have a multidimensional PHP array. So I expect to get something like
array (
'key' => 'levels',
'value' => array(
array('role_id'=>1, 'access_level_id'=>3),
array('role_id'=>2, 'access_level_id'=>1),
array('role_id'=>3, 'access_level_id'=>2)
)
'description' => NULL,
)
but when in my Laravel method I do the following:
public function share_doc(Request $request){
$req=$request->all();
Log::debug(json_decode($req['value'],true));
return;
}
trying to convert the json received as 'value' to PHP array, it returns nothing -i.e. no value, no array, no string. Just nothing.
So, my struggle here is how I can convert the entire json string received as 'value' from the request to a PHP array so that I can iterate through the items with PHP
Thank you for helping
Your problem is that the value element is not valid JSON as the keys are not quoted. For the sample data you provide, you can fix that with preg_replace and then json_decode the changed value:
$x['value'] = json_decode(preg_replace('/(\w+)(?=:)/', '"$1"', $x['value']), true);
print_r($x);
Output:
Array
(
[key] => levels
[value] => Array
(
[0] => Array
(
[role_id] => 1
[access_level_id] => 3
)
[1] => Array
(
[role_id] => 2
[access_level_id] => 1
)
[2] => Array
(
[role_id] => 3
[access_level_id] => 2
)
)
[description] =>
)
Demo on 3v4l.org

PHP search JSON without looping

I have a large JSON array which is the result of querying the API of an Icinga2 monitoring system.
I have used json_decode like this in my code to decode it:
$response = json_decode($array, true);
and I can see the output looks like this:
Array
(
[results] => Array
(
[0] => Array
(
[attrs] => Array
(
[__name] => HOSTNAME0
[acknowledgement] => 0
[acknowledgement_expiry] => 0
...
...
[state] => 0
[state_type] => 1
[meta] => Array
(
)
[name] => HOSTNAME0
[type] => Host
)
[1] => Array
(
[attrs] => Array
(
[__name] => HOSTNAME1
[acknowledgement] => 0
[acknowledgement_expiry] => 0
...
...
[state] => 0
[state_type] => 1
[meta] => Array
(
)
[name] => HOSTNAME1
[type] => Host
)
There are 400 Records in total and it's quite a complex structure but the only bits I am really interested in are the name and state fields.
Basically my script has a list of 150 hostnames from another source and what I want to do is for each hostname, search for it in the array and return the value of the state field for that host.
So far I've been struggling to do this without looping through the entire array for each of the 150 hostnames. There must be a more efficient way to do a lookup in the array based on a hostname and return a single value but I can't figure it out.
Given, the name field has no logical sorting inside the json result, there is no way to look at least once at each element. If they are sorted alphabetical, you could use a simple binary search, which would give you the result in O(log(n)).
The other thing is, if you have to search for multiple names, you could put them inside an name assiciated array. This way, you only have an initial overhead of O(n) building the list and each following search would return you the state on O(1).
// building the array
$states = [];
foreach ($items as $item) {
$states[$item['name']] = $item['state'];
}
looking for HOSTNAME1
$state = $states['HOSTNAME1'];
I'm hoping that I've got the source data array in the correct layout as the format was a bit confusing from the original question. But the main idea is to use array_column to extract the "attrs" and key the result by the "name" element of this array.
$response = Array(
"results" => Array(
0 => Array(
"attrs" => Array(
"__name" => "HOSTNAME0",
"acknowledgement" => 0,
"acknowledgement_expiry" => 0,
"state" => 0,
"state_type" => 1
),
"name" => "HOSTNAME0",
"type" => "Host"
),
1 => Array(
"attrs" => Array(
"__name" => "HOSTNAME1",
"acknowledgement" => 0,
"acknowledgement_expiry" => 0,
"state" => 2,
"state_type" => 1
),
"name" => "HOSTNAME1",
"type" => "Host1"
)
)
);
$extract = array_column($response["results"], "attrs", "name");
print_r($extract);
With the sample data, this gives...
Array
(
[HOSTNAME0] => Array
(
[__name] => HOSTNAME0
[acknowledgement] => 0
[acknowledgement_expiry] => 0
[state] => 0
[state_type] => 1
)
[HOSTNAME1] => Array
(
[__name] => HOSTNAME1
[acknowledgement] => 0
[acknowledgement_expiry] => 0
[state] => 2
[state_type] => 1
)
)
So to find any server by name, you'd use
echo "HOSTNAME1=".$extract["HOSTNAME1"]["state"].PHP_EOL;
If you only wanted the state field (as you asked for) and wanted to simplify the array, you can then use...
array_walk($extract, function(&$data) {$data=$data["state"];});
print_r($extract);
The array_walk() goes through the array and just copies the state field to be the entry, so the result of this is...
Array
(
[HOSTNAME0] => 0
[HOSTNAME1] => 2
)
So now you just do...
echo "HOSTNAME1=".$extract["HOSTNAME1"].PHP_EOL;

preg_match doesn't works as expected

I'm working on some data loaded from an Excel file using PHPExcel. Everything is working fine with every fields but I'm having some troubles with a field which should contain a pattern.
The pattern is
(([0-2]?[0-9]\:[0-5]?[0-9]\:([0-5]?[0-9])\/([0-2]?[0-9]\:[0-5]?[0-9]\:([0-5]?[0-9])))\s?)*
that should check for time intervals such as "00:30:45/01:40:12 01:10:34/1:07:12" and so on.
My problem is that preg_match fails to check this pattern against the sting "1:00". If I add a variable to store the matches returns an one element array with the value "".
I check the pattern with an online tool (http://regexpal.com/) and work as expected but for an to me unknown reason, preg_match doesn't.
Is there something I am missing?
try this
<?php
$string = "00:30:45/01:40:12 01:10:34/1:07:12";
preg_match_all('!((\d{1,2}:\d{1,2}:\d{1,2}/(\d{1,2}:\d{1,2}:(\d{1,2}))))\s?!', $string, $matches);
echo "<pre>";
print_r($matches);
echo "</pre>";
you need to get this:
array (
0 =>
array (
0 => '00:30:45/01:40:12 ',
1 => '01:10:34/1:07:12',
),
1 =>
array (
0 => '00:30:45/01:40:12',
1 => '01:10:34/1:07:12',
),
2 =>
array (
0 => '00:30:45/01:40:12',
1 => '01:10:34/1:07:12',
),
3 =>
array (
0 => '01:40:12',
1 => '1:07:12',
),
4 =>
array (
0 => '12',
1 => '12',
),
)
demo
<?php
$str = '00:30:45/01:40:12 01:10:34/1:07:12/1:00';
//$str = '1:00';
$p = '/[0-9]+:[0-9]+(:[0-9]+|)/s';
preg_match_all($p, $str, $m);
print_r($m);
outputs
Array
(
[0] => Array
(
[0] => 00:30:45
[1] => 01:40:12
[2] => 01:10:34
[3] => 1:07:12
[4] => 1:00
)
[1] => Array
(
[0] => :45
[1] => :12
[2] => :34
[3] => :12
[4] =>
)
)
I finally managed to fix this up. After taking a break and come again to the code with a clear mind, I noticed the final '*' should by a '+' in order to force to have, at least, one instance of the time interval.
Thank you all for your responses.

Merge or join two multidimensional arrays and copy keys/values over

How can I merge two different multidimensional arrays but copy the keys and values from the first array to the second array?
How I'm trying to get it to work is; the first array sets the input fields, which are then cloneable (cloning using jQuery, exactly like this: http://jsfiddle.net/8M98y/). Once you save field data, the second array is the resulting output. The problem is, the second array lacks the specific keys and values from the first array that are needed to output the saved data correctly.
Is there was a way to join or merge the arrays while copying the keys and values from the first array into the second array?
The first array that I need to copy the keys/values from looks like this:
Array
(
[group-1] => Array
(
[fields] => Array
(
[text-field-1] => Array
(
[name] => Text Field 1
[value] => Value 1
[comments] => true
)
[text-field-2] => Array
(
[name] => Text Field 2
[value] => Value 2
[comments] => false
)
)
)
)
The second array looks like this:
Array
(
[group-1] => Array
(
[fields] => Array
(
[text-field-1] => New value here
[text-field-2] => New value also
)
)
[group-2] => Array
(
[fields] => Array
(
[text-field-1] => Cloned group with new value
[text-field-2] => Cloned group with new value also
)
)
)
So if these two arrays were able to be merged, would need the output of the merged array to look like this: http://pastebin.com/uzuZs73B
I've tried using just array_merge( $array2, $array1 ), but the resulting output looks like this: http://pastebin.com/DucKGMN3 where they are in fact merged, but the keys and values aren't copied over.
EDIT: Should describe a use case here.
So how this works, the initial, unsaved output is two text inputs in a group which is created by the first array. The group is cloneable, using jQuery clone (this example here: http://jsfiddle.net/8M98y/). So if you add/clone one of more groups and then save, the resulting saved data would be the second array. The strings in the second array is the actual saved input values. Those would go into [value] in the first array.
However, the output of the fields is still based on the first array, meaning it can't output the cloned groups correctly as they're not an array and don't have the same keys and values from the first array.
If anyone can provide some insight on this, it would be hugely and greatly appreciated.
Sorry if I misunderstood the question, but is merging a requirement? If you have access to both arrays you could iterate over the second array, mapping the original key values, and overwriting with the new values as you go.
Your arrays:
$arr1 = Array
(
'group-1' => Array
(
'fields' => Array
(
'text-field-1' => Array
(
'name' => 'Text Field 1',
'value' => 'Value 1',
'comments' => 'true'
),
'text-field-2' => Array
(
'name' => 'Text Field 2',
'value' => 'Value 2',
'comments' => 'false'
)
)
)
);
$arr2 = Array
(
'group-1' => Array
(
'fields' => Array
(
'text-field-1' => 'New value here',
'text-field-2' => 'New value also'
)
),
'group-2' => Array
(
'fields' => Array
(
'text-field-1' => 'Cloned group with new value',
'text-field-2' => 'Cloned group with new value also'
)
)
);
Secret sauce:
foreach($arr2 as $k=>$v){
// Get the new values for this iteration
$val1 = $arr2[$k]['fields']['text-field-1'];
$val2 = $arr2[$k]['fields']['text-field-2'];
// Duplicate the original array
$arr2[$k]['fields'] = $arr1['group-1']['fields'];
// Insert the new values
$arr2[$k]['fields']['text-field-1']['value'] = $val1;
$arr2[$k]['fields']['text-field-2']['value'] = $val2;
}
echo '<pre>';
print_r($arr2);
echo '</pre>';
exit();
Which returns:
Array
(
[group-1] => Array
(
[fields] => Array
(
[text-field-1] => Array
(
[name] => Text Field 1
[value] => New value here
[comments] => true
)
[text-field-2] => Array
(
[name] => Text Field 2
[value] => New value also
[comments] => false
)
)
)
[group-2] => Array
(
[fields] => Array
(
[text-field-1] => Array
(
[name] => Text Field 1
[value] => Cloned group with new value
[comments] => true
)
[text-field-2] => Array
(
[name] => Text Field 2
[value] => Cloned group with new value also
[comments] => false
)
)
)
)

Cakephp using Set class to fetch data with key starting at zero

I'm using Set class of Cakephp to format the find returned array but cannot seem to find a way to get the counter starting at zero and auto-increment for array keys so it is like
[0] => 3
[1] => 6
[2] => 12
I'm currently using below query to get the data from my HasAndBelongsToMany table.
$interest_ids = Set::combine($this->User->Interestsub->find('threaded', array
(
'conditions' => array
(
'Interestsub.name' => $interests
),
//'fields' => array('Interestsub.id'),
'recursive' => -1
)
),
'{n}.Interestsub.id',
'{n}.Interestsub.id'
);
The reason why I need this is that I'm currently trying to get the returned array as part of bigger parent array preparing to be saved for SaveAll function. To be formatted properly, I need below nested array coming out:
[0] => Array
(
[interestssub_id] => 12
[user_id] => 2
)
[1] => Array
(
[interestssub_id] => 22
[user_id] => 2
)
[2] => Array
(
[interestssub_id] => 32
[user_id] => 2
)
Is there a way we can use Combine class to format the returned array like above?
There's no real reason to use the Set class in this case. Just use good old fashioned php:
$threaded = $this->User->Interestsub->find('threaded', array(
'conditions' => array(
'Interestsub.name' => $interests
),
'recursive' => -1
));
$interest_ids = array();
foreach ($threaded as $thread) {
$interest_ids[] = array(
'interestssub_id' => $thread['Interestsub.id'],
'interestssub_id' => $thread['Interestsub.user_id']
);
}

Categories