Locate line variable in JSON dumpzone data

mikelegg

Well-Known Member
Mar 29, 2005
330
3
166
In the documentation for the EditZoneRecord function it says "In the output of the dumpzone function, locate the Line variable corresponding to the data you wish to edit."

This is easier said than done.

I've just about gone nuts using json_decode() and then trying to write a recursive search function that will loop through a multi-dimensional array (in which not all of the mid-level elements are arrays), find a match on two elements (name and type) and then return the value of another element (Line).

So instead, I've written my own function that just treats the JSON data as a string, which is then manipulated into a two dimensional array using split(). I can then use in_array() to identify and extract the line number.

It's not as elegant as I would like and it doesn't work with any of the SOA data - only the individual DNS records, but it does the job that I need it to.

Code:
function GetLineNumber($strZoneDump, $strType, $strName){

	// Set a default return value of zero
	$intReturn = 0;

	// Remove double quotes
	$strZoneDump = str_replace('"', '', $strZoneDump);
	
	// Split on },{ to create an array of rows
	$arrRows = split("},{", $strZoneDump);
	
	$i = 0;
	$blnFound = false;
	
	// Loop through rows 
	foreach($arrRows as $key => $value){
	
		// Create a multi-dimensional array from each row by splitting on commas
		$arrDetails[$i] = split(",", $value);
		
		// Loop through each detail array
		foreach($arrDetails[$i] as $key2 => $value2){
			
			// Look for an array that contains matches for both the 'name' and 'type' specified 
			if(in_array('name:'. $strName, $arrDetails[$i]) && in_array('type:'. $strType, $arrDetails[$i])){
			
				// if found, set the return value to the number part of the 'Line' element
				$intReturn = substr($arrDetails[$i][0], 5, strlen($arrDetails[$i][0]) - 5);
				$blnFound = true;
				break;
			}
		}
		
		// break out of the outer loop once the line has been located
		if($blnFound){
			break;
		}
             
                $i++;
	}
	
	return $intReturn;
}
What is everybody else doing to locate the line numbers?
 
Last edited:

mikelegg

Well-Known Member
Mar 29, 2005
330
3
166
Here's a slightly more elegant version using json_decode

PHP:
function GetLineNumber($strZoneDump, $strType, $strName){

	$intReturn = 0;
	$blnFound = false;
	
	$arrZoneDump = json_decode($strZoneDump, true);

	foreach($arrZoneDump as $key0 => $value0){
		foreach($value0 as $key1 => $value1){
			foreach($value1 as $key2 => $value2){
				if(is_array($value2)){
					foreach($value2 as $key3 => $value3){
						if( in_array($strName, $value3) && in_array($strType, $value3) ){
							$intReturn = $value3["Line"];
							$blnFound = true;
							break;
						}
					}
				} 
				if($blnFound){break;}
			}
			if($blnFound){break;}
		}
		if($blnFound){break;}
	}
	
	return $intReturn;
}
If I can make it recursive I'll be happier, but this works because there is a known depth to the sub-arrays.
 

mikelegg

Well-Known Member
Mar 29, 2005
330
3
166
Slightly more compact version ...

PHP:
function GetLineNumber($strZoneDump, $strType, $strName){
	
	$arrZoneDump = json_decode($strZoneDump, true);

	foreach($arrZoneDump as $key0 => $value0){
		foreach($value0 as $key1 => $value1){
			foreach($value1 as $key2 => $value2){
				if(is_array($value2)){
					foreach($value2 as $key3 => $value3){
						if(in_array($strName, $value3) && in_array($strType, $value3)){
							return $value3["Line"];
						}
					}
				} 
			}
		}
	}
	
	return 0;
}
 

MattDees

Well-Known Member
Apr 29, 2005
416
1
243
Houston, TX
cPanel Access Level
Root Administrator
With dumpzone, I have been unable to find a circumstance where those arrays contain more than one element. So something like the following should be alot more elegant and easier to work with:

PHP:
include("../xmlapi.php");

$xmlapi = new xmlapi($ip, 'root', $pass);

$xmlapi->set_debug(1);
$xmlapi->set_output('json');
$out = $xmlapi->dumpzone( $domain );
$parsed_out = json_decode( $out );
// Every line above this is merely performing query + placing the response from the API and json_decode into $parsed_out

foreach ( $parsed_out->result[0]->record as $record ) {
    // Do individual record logic here
    //print_r($record);
    print "line: " . $record->Line . "\n";
    print "type:  " . $record->type . "\n\n";
}
 

mikelegg

Well-Known Member
Mar 29, 2005
330
3
166
I've tried to get this working on the understanding that $parsed_out is just json_decode(<dumpzone output>)
But I just get ...
Warning: Invalid argument supplied for foreach()
on the line
foreach ( $parsed_out->result[0]->record as $record ) {
I can loop through the data using a normal foreach, but that just takes me back to square one where I have to loop within loops to get to the actual data I want.
 
Last edited:

cPanelDavidN

Well-Known Member
Staff member
Dec 17, 2009
571
3
68
Houston, TX
cPanel Access Level
Root Administrator
Hi mikelegg,

I tested the example that Matt provided and it worked fine for me.
The only thing I did, to reproduced your issue, that came close to the error that you are reporting was by passing an invalid zone in the query:


Code:
URL: https://10.1.1.1:2087/json-api/dumpzone
DATA: domain=asfaewrowejknfasierfaerf.fake
Authentication Header: Authorization: Basic cm9vdDpyb290c2VjcmF0


RESPONSE:
 {"result":[{"status":0,"statusmsg":"Zone does not exist."}]}
PHP Notice:  Undefined property: stdClass::$record in /Users/david/tmp/cp_xmlapi_php/dumpzone.php on line 14
PHP Warning:  Invalid argument supplied for foreach() in /Users/david/tmp/cp_xmlapi_php/dumpzone.php on line 14
This situation should be easy to test for before performing the loop
PHP:
$parsed_out = json_decode( $out );

if ( !is_array($parsed_out->result) 
 15    || $parsed_out->result[0]->status == 0 
 16    || !array_key_exists('record', get_object_vars($parsed_out->result[0]))
 17    || !is_array($parsed_out->result[0]->record))
 18 {    
 19     print "Cannot iterate over returned result.\nThere must be an error.\n";
 20     exit;
 21 }
Regards,
-DavidN
 

mikelegg

Well-Known Member
Mar 29, 2005
330
3
166
I think I might know why I'm having problems, I'm writing my code from scratch, but the example provided uses the xmlapi.php which I didn't know existed until today.