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.

asked Oct 29, 2019 at 16:53
\$\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.

answered Oct 30, 2019 at 15:02
\$\endgroup\$
4
  • \$\begingroup\$ this trown error: filter_var($data, FILTER_VALIDATE_BOOLEAN); \$\endgroup\$ Commented Oct 30, 2019 at 21:08
  • \$\begingroup\$ is and error of the website sandbox test... sorry \$\endgroup\$ Commented Oct 30, 2019 at 21:13
  • 1
    \$\begingroup\$ I love it when I see this: &$build optimizing memory usage with pointers. \$\endgroup\$ Commented 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\$ Commented 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

answered Nov 1, 2019 at 11:41
\$\endgroup\$
8
  • \$\begingroup\$ This wouldn't work if a php object were passed. Or rather, it wouldn't parse it into an array. \$\endgroup\$ Commented Nov 1, 2019 at 12:47
  • 1
    \$\begingroup\$ @Rager: a POST variable doesn't contain php object. \$\endgroup\$ Commented 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\$ Commented Nov 1, 2019 at 17:50
  • \$\begingroup\$ @Rager: are you serious? \$\endgroup\$ Commented Nov 1, 2019 at 17:53
  • \$\begingroup\$ I guess you're right. $_POST cannot be object. \$\endgroup\$ Commented Nov 1, 2019 at 18:00

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.