doni49

Well-Known Member
Oct 4, 2006
74
0
156
Hi all. I tried all day yesterday to find the solution to this with no luck (and yes that did include searching the forums). So now I'm here to specifically ask.

I have a RaspberryPi at home and want to connect to it remotely but my IP address is not static. I'd really prefer not to pay for a dynamic DNS service when I'm already paying for a personal domain name and hosting service. I've already added a dns zone that points to my home and it works. I can use raspihome.domainname.com to access the RasPi.

Now I want to set up a script on my hosting account that will update the IP address as needed. My intention is to set up a cron job on the RasPi that will connect to the server script (via HTTPS) to provide it with the updated IP address.

I found the following script for using cPanel's JSON API to manange the dnszone entries. But it's not working.

The first php file is what I've got in public_html (this is the page I load in my web browser). When I load it in my browser, the page is blank. I looked at the page source code just to be sure and the following is all that's there.

Why won't it return the DNS entries?

Code:
<html><body>
<pre></pre></body></html>
ShowDNSRecords.php:
PHP:
<html><body>
<?php
  include "/home/username/cron-scripts/classdns.php";
  $zones = new zone_records("username", "password", "domainname", "domainname");
  $r = $zones->DNSrecords;
  echo "<pre>";
  $r;
  echo "</pre>";
?>
</body></html>
classdns.inc.php
PHP Script to Edit DNS Records in CPanel - Stack Overflow
PHP:
<?php
//Code by Scott Stevens
//Last Edited 21 December 2012
//This code is in the public domain

//While not required (there can be no requirements in the
//public domain) I ask that you please include this
//information in any derivative works, along with a summary
//of the modifications made.


class zone_records {
	private $auth = "";
	private $connection = "";
	private $basequery = "";
	private $zonedomain = "";
	private $DNSrecords = array();

	public function __construct($user, $pass, $location, $domain) {
		$this->auth = "Authorization: Basic ".base64_encode($user.":".$pass);
		$this->connection = $location;
		$this->basequery = "https://".$location.":2083/json-api/cpanel?";
		$this->zonedomain = $domain;
		$this->updaterecords(); //get new records
	}

	public function __get($var) {
		return ($var=="DNSrecords" ? $this->DNSrecords : NULL);
	}

	public function doquery($function, $params, $headers=array()) {
		//query the cpanel server and do the query's bidding
		$curl = curl_init();
		$init_params = array( "cpanel_jsonapi_module" => "ZoneEdit", "cpanel_jsonapi_func" => $function, "cpanel_jsonapi_version" => "2", "domain" => $this->zonedomain );
		$query = $this->basequery.http_build_query($init_params)."&".http_build_query($params);
		$headers[] = $this->auth;
		$options = array(	CURLOPT_URL				=> $query,
							CURLOPT_SSL_VERIFYPEER 	=> 0,		//Allow self-signed cert :P
							CURLOPT_SSL_VERIFYHOST 	=> 0,		//Allow cert hostname mismatch
							CURLOPT_HEADER			=> 0,		//Output: Header not included
							CURLOPT_RETURNTRANSFER	=> 1,		//Output: Contents included
							CURLOPT_HTTPHEADER		=> $headers	//Auth
							);
		curl_setopt_array($curl, $options);
		$result = curl_exec($curl);

		if ($result === false) { throw new Exception("cURL Execution Error ".curl_error($curl)." in $query", 0); } //error handling for failure
		curl_close($curl);
		//echo $result;
		return json_decode($result, true);
	}

	public function updaterecords() {
		//A RECORDS
		$records = $this->doquery("fetchzone", array(), array());

		if ($records["cpanelresult"]["data"][0]["status"]!=1 || !array_key_exists("record", $records["cpanelresult"]["data"][0])) {
			throw new Exception("Bad zonefile result ".var_export($records, true), 404); }
		$records = $records["cpanelresult"]["data"][0]["record"];
		//now start sorting records

		$newrecords = array();
		foreach ($records as $i) {
			if ($i["type"]=="A") {
				//MUST MATCH: address==record, class==IN, **type==A, line==Line
				if ($i["address"]!=$i["record"] || $i["Line"]!=$i["line"] || $i["class"]!="IN" || array_key_exists($i["line"], $newrecords)) {
					throw new Exception("Bad A record ".var_export($i, true), 404); }
			$newrecords[$i["line"]] = new DNSrecord("A", $i["name"], $i["record"], $i["line"], $i["ttl"], $this);
			}
			if ($i["type"]=="CNAME") {
				//MUST MATCH: cname==record, class==IN, **type==CNAME, line==Line
				if ($i["cname"]!=$i["record"] || $i["Line"]!=$i["line"] || $i["class"]!="IN" || array_key_exists($i["line"], $newrecords)) {
					throw new Exception("Bad CNAME record ".var_export($i, true), 404); }
			$newrecords[$i["line"]] = new DNSrecord("CNAME", $i["name"], $i["record"], $i["line"], $i["ttl"], $this);
			}
		}

		$this->DNSrecords = array();
		foreach ($newrecords as $key => $value) { $this->DNSrecords[$key] = $value; }
	}

	public function addrecord($type, $name, $target, $ttl) {
		if ($type!="A" && $type!="CNAME") {
			throw new Exception("Invalid type '$type'", 0); }
		if (!preg_match("/^([a-zA-Z0-9\-]+\.)*".preg_quote($this->zonedomain)."\.$/", $name)) {
			throw new Exception("Invalid name '$name'", 0); }
		if (!is_numeric($ttl)) {
			throw new Exception("Invalid TTL '$ttl'", 0); }
		if (($type=="A" && !preg_match(DNSrecord::$valid_ip, $target)) || ($type=="CNAME" && !preg_match(DNSrecord::$valid_domain, $target))) {
			throw new Exception("Invalid target '$target'", 0); }

		$targetname = ($type=="A" ? "address" : ($type=="CNAME" ? "cname" : "txtdata"));
		$params = array(	"type"		=> $type,
							"name"		=> $name,
							$targetname	=> $target,
							"ttl"		=> $ttl,
							"class"		=> DNSrecord::$class);
		$result = $this->doquery("add_zone_record", $params, array());
		$this->updaterecords();
		return $result; //todo: check status?
	}

	public function deleterecord($line) {
		if (!array_key_exists($line, $this->DNSrecords)) { throw new Exception("Record does not exist", 0); }
		$result = $this->doquery("remove_zone_record", array("line" => $line), array());
		$this->updaterecords();
		return $result; //todo: check status?
	}
}

/********************************************************************************/

class DNSrecord {
	public static $class = "IN";
	public static $valid_ip = "/^(((((1[0-9])|[1-9])?[0-9])|(2(([0-4][0-9])|(5[0-5]))))\.){3}((((1[0-9])|[1-9])?[0-9])|(2(([0-4][0-9])|(5[0-5]))))$/";
	//"((((1[0-9])|[1-9])?[0-9])|(2(([0-4][0-9])|(5[0-5]))))"
	public static $valid_domain = "/^([a-zA-Z0-9\-]+\.){2,}[a-zA-Z0-9\-]{2,}$/";
	private $type = "";
	private $name = "";
	private $target = "";
	private $line = 0;
	private $ttl = 0;
	public $zone_records = NULL;

	public function __construct($type, $name, $target, $line, $ttl, $zone_records) {
		$this->type = $type;
		$this->name = $name;
		$this->target = $target;
		$this->line = $line;
		$this->ttl = $ttl;
		$this->zone_records = $zone_records;
	}

	public function __get($var) {
		/************ This function allows the properties to be fetched (but not the zone records object) *************/
		$temp_array = array(	"type"		=> $this->type,
								"name"		=> $this->name,
								"target"	=> $this->target,
								"line"		=> $this->line,
								"ttl"		=> $this->ttl);
		return (array_key_exists($var, $temp_array) ? $temp_array[$var] : NULL);
	}

	public function __set($var, $val) {
		if ($var=="target") {
			if ($this->type=="A" && preg_match(self::$valid_ip, $val)===0) { throw new Exception("Invalid IP record '$val', ".self::$valid_ip, 0); }
			if ($this->type=="CNAME" && !preg_match(self::$valid_domain, $val)) { throw new Exception("Invalid subdomain record '$val'", 0); }
			$this->target = $val;
			$this->update();
		} else if ($var=="ttl") {
			if (!is_numeric($val)) { throw new Exception("Invalid TTL '$val'", 0); }
			$this->ttl = $val;
			$this->update();
		} else { throw new Exception("Tried to edit inaccessible property '$var'", 403); }
	}

	private function update() {
		//curl call to update line
		$targetname = ($this->type=="A" ? "address" : ($this->type=="CNAME" ? "cname" : "txtdata"));
		$params = array(	"line"			=> $this->line,
							"type"			=> $this->type,
							$targetname		=> $this->target,
							"ttl"			=> $this->ttl,
							"class"			=> self::$class);
		$result = $this->zone_records->doquery("edit_zone_record", $params, array());
		$this->zone_records->updaterecords();
		//todo: return result or check status?
	}
}
?>
 
Last edited: