Apply html_entity_decode to objects and arrays using recursion - php

I'm trying to build a function that will apply html_entity_decode to objects and arrays. Since I don't know the structure beforehand, and the child properties can also be objects or arrays, a simple recursive function seemed to be the way to go. I'm unable to figure out why the following does not work:
function decode($data){
if(is_object($data) || is_array($data)){
foreach($data as &$value)
$value = $this->decode($value);
}
else $data = html_entity_decode($data);
return $data;
}
I have also tried the following, which doesn't work either:
function decode($data){
if(is_object($data))
$data = get_object_vars($data);
$data = is_array($data) ? array_map(array('MyClassName', 'decode'), $data) : html_entity_decode($data);
return $data;
}
Neither function has any affect on the data. What am I doing wrong?

The main issue is that you are trying to work with object like array is_object($data) || is_array($data) would not really work except you convert the object to array
Other Issues are base on incorrect variable name and not returning the proper variable You can try
$std = new stdClass();
$std->title = array("x" => "<a>XXX</a>","y" => "<b>YYY</b>");
$std->body = "<p> THis is the Body </p>";
$var = array(
"a" => "I'll \"walk\" the <b>dog</b> now",
"b" => array("<b>Hello World</b>",array(array("Yes am <strong> baba </strong>"))),
"c" => $std
);
$class = new MyClassName();
$encode = $class->encode($var); // encode
$decode = $class->decode($encode); // decode it back
print_r($encode);
print_r($decode);
Encoded Array
Array
(
[a] => I'll "walk" the <b>dog</b> now
[b] => Array
(
[0] => <b>Hello World</b>
[1] => Array
(
[0] => Array
(
[0] => Yes am <strong> baba </strong>
)
)
)
[c] => stdClass Object
(
[title] => Array
(
[x] => <a>XXX</a>
[y] => <b>YYY</b>
)
[body] => <p> THis is the Body </p>
)
)
Decoded Array
Array
(
[a] => I'll "walk" the <b>dog</b> now
[b] => Array
(
[0] => <b>Hello World</b>
[1] => Array
(
[0] => Array
(
[0] => Yes am <strong> baba </strong>
)
)
)
[c] => stdClass Object
(
[title] => Array
(
[x] => <a>XXX</a>
[y] => <b>YYY</b>
)
[body] => <p> THis is the Body </p>
)
)
See Live Demo
class MyClassName {
function encode($data) {
if (is_array($data)) {
return array_map(array($this,'encode'), $data);
}
if (is_object($data)) {
$tmp = clone $data; // avoid modifing original object
foreach ( $data as $k => $var )
$tmp->{$k} = $this->encode($var);
return $tmp;
}
return htmlentities($data);
}
function decode($data) {
if (is_array($data)) {
return array_map(array($this,'decode'), $data);
}
if (is_object($data)) {
$tmp = clone $data; // avoid modifing original object
foreach ( $data as $k => $var )
$tmp->{$k} = $this->decode($var);
return $tmp;
}
return html_entity_decode($data);
}
}

What exactly do you want to do: replace existing values with html entity decoded values or make a copy of the whole data structure with encoded values?
If you want to replace then you should pass function argument by reference:
function decode( &$data ){
If you want to make a copy -- it should work the way it is (or please explain what exactly do you mean by "the following does not work").

What about array-walk-recursive:
http://php.net/manual/en/function.array-walk-recursive.php
perhaps something like this:
function decode($data){
$data = html_entity_decode($data);
}
function decode_data($data){
if(is_object($data) || is_array($data)){
array_walk_recursive($data, 'decode');
}else{
$data = html_entity_decode($data);
}
return $data;
}

Related

Create PHP array from string for Mongo

I have a Laravel installed with Moloquent (Mongo). Mongo ins't necessarily the problem, when the model loads the "JSON" record, it becomes a PHP associative array.
I need to be able to create a function in a model that returns an array element by a string.
for example:
$search1 = 'folder1/folder2/folder3/item';
//would look like: $array['folder1'][folder2'][folder3']['item']
$search2 = 'folder1/picture1/picture';
//would look like: $array['folder1'][picture1']['picture']
echo getRecord($search1);
echo getRecord($search2);
function getRecord($str='') {
//this function take path as string and return array
return $result;
}
I guess I could use the ?? operator, but I have to form an array "check" meaning:
How would I form the $array['1']['2']['3'] if I have 3 elements deep or 1 ($array['1']), or 5 ($array['1']['2']['3']['4']['5']).
I am making an api to add an item or folder to Mongo.
Input : "f1/f2/item"
This function I have:
echo print_r($j->_arrayBuilder('f1/f2/item'), true);
public function _arrayBuilder($folderPath)
{
$ret = array();
$arr = explode('/', $folderPath);
Log::info("Path Array:\n" . print_r($arr, true));
$x = count($arr) - 1;
Log::info("Count: " . $x);
for ($i = 0; $i <= $x; $i++) {
Log::info("Element of arr: " . $arr[$i]);
$ret = array($arr[$i] => $ret);
}
return $ret;
}
Current output:
Array
(
[item] => Array
(
[f2] => Array
(
[f1] => Array
(
)
)
)
)
Desire output:
Array
(
[f1] => Array
(
[f2] => Array
(
[item] => Array
(
)
)
)
)
Note: I have tried PHP's array_reverse and it does not work on this.. Multidimensional and non-numeric..
Thank you.
If I understand correctly, You want to take input string f1/f2/f3/f4/f5/item and create array("f1" => array("f2" => array("f3" => array("f4" => array("f5" => array("item" => array()))))))
In order to do that you can use function close to what you tried as:
function buildArr($path) {
$path = array_reverse(explode("/", $path)); // getting the path and reverse it
$ret = array();
foreach($path as $key)
$ret = array($key => $ret);
return $ret;
}
For input of print_r(buildArr("f1/f2/item")); it prints:
Array
(
[f1] => Array
(
[f2] => Array
(
[item] => Array
(
)
)
)
)
Hope that what you meant. If not feel free to comment

Multidimensional Array to String conversion

I have a dynamic multidimensional array and I want to convert it to string.
here is an example:
Array
(
[data] => check
[test1] => Array
(
[data] => Hello
)
[test2] => Array
(
[data] => world
)
[test3] => Array
(
[data] => bar
[tst] => Array
(
[data] => Lorem
[bar] => Array
(
[data] => doller
[foo] => Array
(
[data] => sit
)
)
)
)
[test4] => Array
(
[data] => HELLO
[tst] => Array
(
[data] => ipsum
[bar] => Array
(
[data] => Lorem
)
)
)
)
The example for string is:
check&hello&world&bar...lorem&doller...sit ....
I have tried alot of things. I even checked the solutions given on other SO questions. like:
Convert Multidimensional array to single array & Multidimensional Array to String
But No luck.
You can simply use array_walk_recursive like as
$result = [];
array_walk_recursive($arr, function($v) use (&$result) {
$result[] = $v;
});
echo implode('&', $result);
Demo
First convert it to flat array, by
$it = new RecursiveIteratorIterator(new RecursiveArrayIterator($input_array));
$flat = iterator_to_array($it, false);
false prevents array key collision.
Then use implode,
$str = implode('&', $flat);
You can use following recursive function to convert any multidimensional array to string
public function _convertToString($data,&$converted){
foreach($data as $key => $value){
if(is_array($value)){
$this->_convertToString($value,$converted);
}else{
$converted .= '&'. $value;
}
}
}
You can call above function in following way:
$str = array(
"data" => "check",
"test1" => array(
"data" => "Hello",
"test3" => array(
"data" => "satish"
)
),
"test2" => array(
"data" => "world"
)
);
$converted = "";
//call your function and pass your array and reference string
$this->_convertToString($str,$converted);
echo $converted;
Output will be following:
check&Hello&satish&world
you can modify code to meet your requirement.
Let me know if any further help required.
php has some build in functions that can do this. Like var_dump, json_encode and var_export. But if you want to control the output more it can be doen with a recursive function
function arrToStr(array $data)
{
$str = "";
foreach ($data as $val) {
if (is_array($val)) {
$str .= arrToStr($val);
} else {
$str .= $val;
}
}
return $str;
}
You can format extra line breaks and spaces at will with this.
I would use recursion for this type of array :
echo visit($your_array);
function visit($val){
if( !is_array($val) ){
return $val;
}
$out="";
foreach($val as $v){
$out.= "&".visit($v);
}
return $out;
}

json encode return as objects instead array

I have already read this question and doesn't answer my issue.
I have an Array like this:
Array
(
[0] => Array
(
[COM] => 10659.68
)
[1] => Array
(
[MCD] => 1219.09
)
[2] => Array
(
[MCR] => 77047.65
)
)
And when I make a json_encode() it return this;
[{"COM":10659.68},{"MCD":1219.09},{"MCR":77047.65}]
What I need is get the data in this way:
[["COM":10659.68],["MCD":1219.09],["MCR":77047.65]]
Any idea how can I achieve this
Even though that's not a valid JSON, you can replace the { with [
echo str_replace(array('{','}'),array('[',']'),json_encode($your_array));
Depending on the content you might need a more complex replacement with regular expressions.
More complex solution:
function toJson($arr){
$return = array();
foreach($arr as $k => $v){
if(is_array($v)) $return[] = toJson($v);
else $return[] = sprintf('"%s":%s', $k, $v);
}
return sprintf('[%s]', implode(',', $return));
}
Test:
$input = array(
array('COM' => '10659.68'),
array('MCD' => '1219.09'),
array('MCR' => '77047.65'),
);
var_dump(toJson($input));
string(51) "[["COM":10659.68],["MCD":1219.09],["MCR":77047.65]]"

PHP foreach assigning of array

I'm trying to read recursively into an array until I'm getting a string. Then I try to explode it and return the newly created array. However, for some reason it does not assign the array:
function go_in($arr) { // $arr is a multi-dimensional array
if (is_array($arr))
foreach($arr as & $a)
$a = go_in($a);
else
return explode("\n", $arr);
}
EDIT:
Here's the array definition as printed by print_r:
Array
(
[products] => Array
(
[name] => Arduino Nano Version 3.0 mit ATMEGA328P
[id] => 10005
)
[listings] => Array
(
[category] =>
[title] => This is the first line
This is the second line
[subtitle] => This is the first subtitle
This is the second subtitle
[price] => 24.95
[quantity] =>
[stock] =>
[shipping_method] => Slow and cheap
[condition] => New
[defects] =>
)
[table_count] => 2
[tables] => Array
(
[0] => products
[1] => listings
)
)
I'd use this:
array_walk_recursive($array,function(&$value,$key){
$value = explode("\n",$value);
});
However, this fixes your function:
function &go_in(&$arr) { // $arr is a multi-dimensional array
if (is_array($arr)){
foreach($arr as & $a) $a = go_in($a);
} else {
$arr = explode("\n", $arr);
}
return $arr;
}
When writing nested conditions/loops - always add braces for better readability and to prevent bugs.. Also you should return the go_in function, because it is recursive, it needs to be passed to the calling function instance.
function go_in($arr) { // $arr is a multi-dimensional array
if (is_array($arr))
{
foreach($arr as &$a)
{
return go_in($a);
}
}
else
{
return ($arr);
}
}
The original array was not returned in the function:
function go_in($arr) {
if (is_array($arr))
foreach($arr as &$a)
$a = go_in($a);
else
if (strpos($arr, "\n") !== false)
return explode("\n", $arr);
return $arr;
}
EDIT:
Now, it only really edits the strings that contain a linebreak. Before it would edit every string which meant that every string was returned as an array.

php recursion global variable?

I have a recursion function that parses an object/array with a global variable. If I comment out the global variable I get nothing but if I leave it in it keeps adding to the array other values that should be in it own result set. Do I need to change something here?
UPDATE #2:
How can I get the return I want, I thought I was pushing all unique values to the array?
function getResp($objectPassed) {
foreach($objectPassed as $element) {
if(is_object($element)) {
// recursive call
$in_arr = getResp($element);
}elseif(is_array($element)) {
$in_arr = getResp($element);
} else {
// XML is being passed, need to strip it
$element = strip_tags($element);
// Trim whitespace
$element = trim($element);
// Push to array
if($element != '') {
if (!preg_match("/^[0-9]$/", $element)) {
if (!in_array($element,$in_arr)) {
$in_arr[] = $element;
}
}
}
}
}
return $in_arr;
}
INPUT:
stdClass Object
(
[done] => 1
[queryLocator] =>
[records] => Array
(
[0] => stdClass Object
(
[type] => typeName
[Id] => Array
(
[0] => a0E50000002jxhmEAA
[1] => a0E50000002jxhmEAA
)
)
[1] => stdClass Object
(
[type] => typeName
[Id] => Array
(
[0] => a0E50000002jxYkEAI
[1] => a0E50000002jxYkEAI
)
)
)
[size] => 2
)
RETURN:
Array
(
[0] => a0E50000002jxYkEAI
)
WANTED RETURN:
Array
(
[0] => a0E50000002jxYkEAI
[1] => a0E50000002jxhmEAA
)
Is a global variable necessary? Otherwise you could simplify it this way:
function getResp($objectPassed, &$in_arr = array()) { // <-- note the reference '&'
foreach($objectPassed as $element) {
if(is_object($element) || is_array($element)) { // <-- else if statement simplified
getResp($element,$in_arr);
} else {
// XML is being passed, need to strip it
$element = strip_tags($element);
// Trim whitespace
$element = trim($element);
// Push to array
if($element != '' && // <-- everything in one test
!preg_match("/^[0-9]$/", $element) &&
!in_array($element,$in_arr))
{
$in_arr[] = $element;
}
}
}
return $in_arr;
}
Then you do:
$result = getResp($data);
If a recursive function has to access the same resource over and over again (in this case the initial array), I would always pass this as a reference.
I don't know if is measurable but I would guess that this is much more efficient than copying values.

Categories