3
\$\begingroup\$

I am verifying certain codes that work well and I don't know what else to optimize in them or what other tests to do: in this case it is a php script that takes the data of the $_POST variable analyzes them and converts them into an array, this is since in some cases the post field may contain a JSon string.

I leave a functional example where I have manually set the $_POST variable to do the Demonstration:

https://wtools.io/php-sandbox/bqsT

Original Code example:

<?php

#Example Array

$_POST = array(
    "valor1" => 1200,
    "valor2" => "texto",
    "valor3" => true,
    "valor4" => '{"seclvl_text":"datp","seclvl_boolean":"false"}',
);
#Validate Function for Json
function ValidateJson($Var) {
    if (!is_array($Var)) {
        return ((json_decode($Var) != null) AND (is_object(json_decode($Var)) OR is_array(json_decode($Var)))) ? true : false;
    } else {
        return false;
    }
}
#Parse Function
function buildVirtualData($data) {
    if (is_array($data)) {
        $result = [];
        foreach ($data as $key1 => $val1) {
            $valJson = ValidateJson($val1);
            if ($valJson) {
                $jsonObj       = json_decode($val1, true);
                $result[$key1] = buildVirtualData($jsonObj);
            } elseif ($valJson == false && is_array($val1)) {
                foreach ($val1 as $key2 => $val2) {
                    $result[$key1][$key2] = buildVirtualData($val2);
                }
            } else {
                if ($val1 === 'true') {
                    $val1 = true;
                } else if ($val1 === 'false') {
                    $val1 = false;
                }
                $result[$key1] = $val1;
            }
        }
        return $result;
    } else {
        if (ValidateJson($data)) {
            $jsonObj = json_decode($data, true);
            return buildVirtualData($jsonObj);
        } else {
            return $data;
        }
    }
}
# call to Function:
$data = buildVirtualData($_POST);
echo '<pre>';
echo var_dump($data);
echo '</pre>';

this parse have the feature that convert any text true or false to Boolean.

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

I think you're are definitely on the right track here. I spent a good deal of time trying to refactor, here's what I came up with

#Validate Function for Json
function jsonDecodeAndValidate($var, $assoc = false) {
    if(!is_string($var))
        return false;
    if(!$decoded = json_decode($var, $assoc))
        return false;
    if(!is_object($decoded) && !is_array($decoded))
        return false;
    return $decoded;
}
#Parse Function
function buildVirtualData($data) {
    if (is_array($data) || is_object($data)) {
        foreach ($data as $key1 => $val1) {

            if(is_array($val1)){
                foreach ($val1 as $key2 => $val2) {
                    $result[$key1][$key2] = buildVirtualData($val2);
                }
            }
            else if($decoded = jsonDecodeAndValidate($val1)){
                $result[$key1] = buildVirtualData($decoded);
            } else {
                if(in_array($val1, ['true', 'false']))
                    $val1 = filter_var($val1, FILTER_VALIDATE_BOOLEAN);
                $result[$key1] = $val1;
            }
        }
        return $result;
    } else {
        if ($decoded = jsonDecodeAndValidate($data, true)) {
            return buildVirtualData($decoded);
        } else {
            return $data;
        }
    }
}

At the very least this will save you some calls to json_decode as the decoding is done once per iteration.

EDIT: I took another stab at it. I think you can boil it down to this.

#decodeand validate
function jsonDecodeAndValidate($var) {
    if(!is_string($var))
        return $var;
    if(!$decoded = json_decode($var, true))
        return $var;
    if(!is_array($decoded))
        return $var;
    return $decoded;
}
#Parse Function
function buildVirtualData($data, &$build) {
    $data = jsonDecodeAndValidate($data);
    if(is_array($data) || is_object($data)){
        foreach($data as $key => $value){
            buildVirtualData($value, $build[$key]);
        }
    } else {
        if ($data === 'true')
          $data = true;
        if ($data === 'false')
          $data = false;
        $build = $data;
    }
}
# call to Function:
$build = [];
buildVirtualData($_POST, $build);
echo '<pre>';
echo json_encode($build, JSON_PRETTY_PRINT);
echo '</pre>';

You just have to declare your array outside of the function.

\$\endgroup\$
4
  • \$\begingroup\$ this trown error: filter_var($data, FILTER_VALIDATE_BOOLEAN); \$\endgroup\$ Oct 30, 2019 at 21:08
  • \$\begingroup\$ is and error of the website sandbox test... sorry \$\endgroup\$ Oct 30, 2019 at 21:13
  • 1
    \$\begingroup\$ I love it when I see this: &$build optimizing memory usage with pointers. \$\endgroup\$ Oct 30, 2019 at 21:18
  • \$\begingroup\$ I changed that part back to what it was. Seems you need a module installed to use filter_var \$\endgroup\$
    – Rager
    Oct 30, 2019 at 21:42
1
\$\begingroup\$

I don't think your JSON validation function is very useful because it does more or less what does the json_decode function itself, except that it tests if the result is an array or an object (that is useless too, since buildVirtualData always uses json_decode with the second parameter set to true and since the $_POST variable can't contain an object but only strings and arrays.).

Always use a strict comparison with null when you want to check the return of json_decode for validity. As a counter-example, elements like an empty string, 0 or false that are valid JSON themselves, return true in this non-strict comparison: var_dump(json_decode('""') == null);

Manualy replacing the strings "true" or "false" with a boolean isn't needed since json_decode does that automatically.

You can rewrite your function like that:

function buildVirtualData($var) {

    if ( is_string($var) ) {

        $json = json_decode($var, true);

        if ( $json !== null )
            $var = $json;

    }

    if ( is_array($var) )
        return array_map('buildVirtualData', $var);

    return $var;
}

demo

\$\endgroup\$
8
  • \$\begingroup\$ This wouldn't work if a php object were passed. Or rather, it wouldn't parse it into an array. \$\endgroup\$
    – Rager
    Nov 1, 2019 at 12:47
  • 1
    \$\begingroup\$ @Rager: a POST variable doesn't contain php object. \$\endgroup\$ Nov 1, 2019 at 15:42
  • \$\begingroup\$ $_POST = json_decode( <<<JSON { "valor1" : 1200, "valor2: : "texto", "valor3" : true, "valor4" : "{\"seclvl_text\":\"datp\",\"seclvl_boolean\":\"false\"}" } JSON ); \$\endgroup\$
    – Rager
    Nov 1, 2019 at 17:50
  • \$\begingroup\$ @Rager: are you serious? \$\endgroup\$ Nov 1, 2019 at 17:53
  • \$\begingroup\$ I guess you're right. $_POST cannot be object. \$\endgroup\$
    – Rager
    Nov 1, 2019 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.