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\$
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.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ this trown error: filter_var($data, FILTER_VALIDATE_BOOLEAN); \$\endgroup\$ – walter nuñez Oct 30 '19 at 21:08
  • \$\begingroup\$ is and error of the website sandbox test... sorry \$\endgroup\$ – walter nuñez Oct 30 '19 at 21:13
  • 1
    \$\begingroup\$ I love it when I see this: &$build optimizing memory usage with pointers. \$\endgroup\$ – walter nuñez Oct 30 '19 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 '19 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

| improve this answer | |
\$\endgroup\$
  • \$\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 '19 at 12:47
  • 1
    \$\begingroup\$ @Rager: a POST variable doesn't contain php object. \$\endgroup\$ – Casimir et Hippolyte Nov 1 '19 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 '19 at 17:50
  • \$\begingroup\$ @Rager: are you serious? \$\endgroup\$ – Casimir et Hippolyte Nov 1 '19 at 17:53
  • \$\begingroup\$ I guess you're right. $_POST cannot be object. \$\endgroup\$ – Rager Nov 1 '19 at 18:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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