diff --git a/dns/dyndns/src/etc/inc/plugins.inc.d/dyndns/r53.inc b/dns/dyndns/src/etc/inc/plugins.inc.d/dyndns/r53.inc
index d7ebc65fb..46a83a380 100644
--- a/dns/dyndns/src/etc/inc/plugins.inc.d/dyndns/r53.inc
+++ b/dns/dyndns/src/etc/inc/plugins.inc.d/dyndns/r53.inc
@@ -45,709 +45,733 @@
*/
class Route53
{
- const API_VERSION = '2010-10-01';
-
- protected $__accessKey; // AWS Access key
- protected $__secretKey; // AWS Secret key
- protected $__host;
-
- public function getAccessKey() { return $this->__accessKey; }
- public function getSecretKey() { return $this->__secretKey; }
- public function getHost() { return $this->__host; }
-
- protected $__verifyHost = 1;
- protected $__verifyPeer = 1;
-
- // verifyHost and verifyPeer determine whether curl verifies ssl certificates.
- // It may be necessary to disable these checks on certain systems.
- // These only have an effect if SSL is enabled.
- public function verifyHost() { return $this->__verifyHost; }
- public function enableVerifyHost($enable = true) { $this->__verifyHost = $enable; }
-
- public function verifyPeer() { return $this->__verifyPeer; }
- public function enableVerifyPeer($enable = true) { $this->__verifyPeer = $enable; }
-
- /**
- * Constructor
- *
- * @param string $accessKey Access key
- * @param string $secretKey Secret key
- * @return void
- */
- public function __construct($accessKey = null, $secretKey = null, $host = 'route53.amazonaws.com') {
- if ($accessKey !== null && $secretKey !== null) {
- $this->setAuth($accessKey, $secretKey);
- }
- $this->__host = $host;
- }
-
- /**
- * Set AWS access key and secret key
- *
- * @param string $accessKey Access key
- * @param string $secretKey Secret key
- * @return void
- */
- public function setAuth($accessKey, $secretKey) {
- $this->__accessKey = $accessKey;
- $this->__secretKey = $secretKey;
- }
-
- /**
- * Lists the hosted zones on the account
- *
- * @param string marker A pagination marker returned by a previous truncated call
- * @param int maxItems The maximum number of items per page. The service uses min($maxItems, 100).
- * @return A list of hosted zones
- */
- public function listHostedZones($marker = null, $maxItems = 100) {
- $rest = new Route53Request($this, 'hostedzone', 'GET');
-
- if($marker !== null) {
- $rest->setParameter('marker', $marker);
- }
- if($maxItems !== 100) {
- $rest->setParameter('maxitems', $maxItems);
- }
-
- $rest = $rest->getResponse();
- if($rest->error === false && $rest->code !== 200) {
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
- }
- if($rest->error !== false) {
- $this->__triggerError('listHostedZones', $rest->error);
- return false;
- }
-
- $response = array();
- if (!isset($rest->body))
- {
- return $response;
- }
-
- $zones = array();
- foreach($rest->body->HostedZones->HostedZone as $z)
- {
- $zones[] = $this->parseHostedZone($z);
- }
- $response['HostedZone'] = $zones;
-
- if(isset($rest->body->MaxItems)) {
- $response['MaxItems'] = (string)$rest->body->MaxItems;
- }
-
- if(isset($rest->body->IsTruncated)) {
- $response['IsTruncated'] = (string)$rest->body->IsTruncated;
- if($response['IsTruncated'] == 'true') {
- $response['NextMarker'] = (string)$rest->body->NextMarker;
- }
- }
-
- return $response;
- }
-
- /**
- * Retrieves information on a specified hosted zone
- *
- * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
- * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
- * then that full value should be passed here, including the '/hostedzone/' prefix.
- * @return A data structure containing information about the specified zone
- */
- public function getHostedZone($zoneId) {
- // we'll strip off the leading forward slash, so we can use it as the action directly.
- $zoneId = trim($zoneId, '/');
-
- $rest = new Route53Request($this, $zoneId, 'GET');
-
- $rest = $rest->getResponse();
- if($rest->error === false && $rest->code !== 200) {
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
- }
- if($rest->error !== false) {
- $this->__triggerError('getHostedZone', $rest->error);
- return false;
- }
-
- $response = array();
- if (!isset($rest->body))
- {
- return $response;
- }
-
- $response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
- $response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
-
- return $response;
- }
-
- /**
- * Creates a new hosted zone
- *
- * @param string name The name of the hosted zone (e.g. "example.com.")
- * @param string reference A user-specified unique reference for this request
- * @param string comment An optional user-specified comment to attach to the zone
- * @return A data structure containing information about the newly created zone
- */
- public function createHostedZone($name, $reference, $comment = '') {
- // hosted zone names must end with a period, but people will forget this a lot...
- if(strrpos($name, '.') != (strlen($name) - 1)) {
- $name .= '.';
- }
-
- $data = "\n";
- $data .= '\n";
- $data .= ''.$name."\n";
- $data .= ''.$reference."\n";
- if(strlen($comment) > 0) {
- $data .= "\n";
- $data .= ''.$comment."\n";
- $data .= "\n";
- }
- $data .= "\n";
-
- $rest = new Route53Request($this, 'hostedzone', 'POST', $data);
-
- $rest = $rest->getResponse();
-
- if($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204)) ) {
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
- }
- if($rest->error !== false) {
- $this->__triggerError('createHostedZone', $rest->error);
- return false;
- }
-
- $response = array();
- if (!isset($rest->body))
- {
- return $response;
- }
-
- $response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
- $response['ChangeInfo'] = $this->parseChangeInfo($rest->body->ChangeInfo);
- $response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
-
- return $response;
- }
-
- /**
- * Retrieves information on a specified hosted zone
- *
- * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
- * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
- * then that full value should be passed here, including the '/hostedzone/' prefix.
- * @return The change request data corresponding to this delete
- */
- public function deleteHostedZone($zoneId) {
- // we'll strip off the leading forward slash, so we can use it as the action directly.
- $zoneId = trim($zoneId, '/');
-
- $rest = new Route53Request($this, $zoneId, 'DELETE');
-
- $rest = $rest->getResponse();
- if($rest->error === false && $rest->code !== 200) {
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
- }
- if($rest->error !== false) {
- $this->__triggerError('deleteHostedZone', $rest->error);
- return false;
- }
-
- if (!isset($rest->body))
- {
- return array();
- }
-
- return $this->parseChangeInfo($rest->body->ChangeInfo);
- }
-
- /**
- * Retrieves a list of resource record sets for a given zone
- *
- * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
- * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
- * then that full value should be passed here, including the '/hostedzone/' prefix.
- * @param string type The type of resource record set to begin listing from. If this is specified, $name must also be specified.
- * Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
- * @param string name The name at which to begin listing resource records (in the lexographic order of records).
- * @param int maxItems The maximum number of results to return. The service uses min($maxItems, 100).
- * @return The list of matching resource record sets
- */
- public function listResourceRecordSets($zoneId, $type = '', $name = '', $maxItems = 100) {
- // we'll strip off the leading forward slash, so we can use it as the action directly.
- $zoneId = trim($zoneId, '/');
-
- $rest = new Route53Request($this, $zoneId.'/rrset', 'GET');
-
- if(strlen($type) > 0) {
- $rest->setParameter('type', $type);
- }
- if(strlen($name) > 0) {
- $rest->setParameter('name', $name);
- }
- if($maxItems != 100) {
- $rest->setParameter('maxitems', $maxItems);
- }
-
- $rest = $rest->getResponse();
- if($rest->error === false && $rest->code !== 200) {
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
- }
- if($rest->error !== false) {
- $this->__triggerError('listResourceRecordSets', $rest->error);
- return false;
- }
-
- $response = array();
- if (!isset($rest->body))
- {
- return $response;
- }
-
- $recordSets = array();
- foreach($rest->body->ResourceRecordSets->ResourceRecordSet as $set) {
- $recordSets[] = $this->parseResourceRecordSet($set);
- }
-
- $response['ResourceRecordSets'] = $recordSets;
-
- if(isset($rest->body->MaxItems)) {
- $response['MaxItems'] = (string)$rest->body->MaxItems;
- }
-
- if(isset($rest->body->IsTruncated)) {
- $response['IsTruncated'] = (string)$rest->body->IsTruncated;
- if($response['IsTruncated'] == 'true') {
- $response['NextRecordName'] = (string)$rest->body->NextRecordName;
- $response['NextRecordType'] = (string)$rest->body->NextRecordType;
- }
- }
-
- return $response;
- }
-
- /**
- * Makes the specified resource record set changes (create or delete).
- *
- * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
- * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
- * then that full value should be passed here, including the '/hostedzone/' prefix.
- * @param array changes An array of change objects, as they are returned by the prepareChange utility method.
- * You may also pass a single change object.
- * @param string comment An optional comment to attach to the change request
- * @return The status of the change request
- */
- public function changeResourceRecordSets($zoneId, $changes, $comment = '') {
- // we'll strip off the leading forward slash, so we can use it as the action directly.
- $zoneId = trim($zoneId, '/');
-
- $data = "\n";
- $data .= '\n";
- $data .= "\n";
-
- if(strlen($comment) > 0) {
- $data .= ''.$comment."\n";
- }
-
- if(!is_array($changes)) {
- $changes = array($changes);
- }
-
- $data .= "\n";
- foreach($changes as $change) {
- $data .= $change;
- }
- $data .= "\n";
-
- $data .= "\n";
- $data .= "\n";
-
- $rest = new Route53Request($this, $zoneId.'/rrset', 'POST', $data);
-
- $rest = $rest->getResponse();
- if($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204))) {
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
- }
- if($rest->error !== false) {
- $this->__triggerError('changeResourceRecordSets', $rest->error);
- return false;
- }
-
- if (!isset($rest->body))
- {
- return array();
- }
-
- return $this->parseChangeInfo($rest->body->ChangeInfo);
- }
-
- /**
- * Retrieves information on a specified change request
- *
- * @param string changeId The id of the change, as returned by CreateHostedZoneResponse or ChangeResourceRecordSets
- * In other words, if CreateHostedZoneResponse showed the change's Id as '/change/C2682N5HXP0BZ4',
- * then that full value should be passed here, including the '/change/' prefix.
- * @return The status of the change request
- */
- public function getChange($changeId) {
- // we'll strip off the leading forward slash, so we can use it as the action directly.
- $zoneId = trim($changeId, '/');
-
- $rest = new Route53Request($this, $changeId, 'GET');
-
- $rest = $rest->getResponse();
- if($rest->error === false && $rest->code !== 200) {
- $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
- }
- if($rest->error !== false) {
- $this->__triggerError('getChange', $rest->error);
- return false;
- }
-
- if (!isset($rest->body))
- {
- return array();
- }
-
- return $this->parseChangeInfo($rest->body->ChangeInfo);
- }
-
-
-
- /**
- * Utility function to parse a HostedZone tag structure
- */
- private function parseHostedZone($tag) {
- $zone = array();
- $zone['Id'] = (string)$tag->Id;
- $zone['Name'] = (string)$tag->Name;
- $zone['CallerReference'] = (string)$tag->CallerReference;
-
- // these might always be set, but check just in case, since
- // their values are option on CreateHostedZone requests
- if(isset($tag->Config) && isset($tag->Config->Comment)) {
- $zone['Config'] = array('Comment' => (string)$tag->Config->Comment);
- }
-
- return $zone;
- }
-
- /**
- * Utility function to parse a ChangeInfo tag structure
- */
- private function parseChangeInfo($tag) {
- $info = array();
- $info['Id'] = (string)$tag->Id;
- $info['Status'] = (string)$tag->Status;
- $info['SubmittedAt'] = (string)$tag->SubmittedAt;
- return $info;
- }
-
- /**
- * Utility function to parse a DelegationSet tag structure
- */
- private function parseDelegationSet($tag) {
- $servers = array();
- foreach($tag->NameServers->NameServer as $ns) {
- $servers[] = (string)$ns;
- }
- return $servers;
- }
-
- /**
- * Utility function to parse a ResourceRecordSet tag structure
- */
- private function parseResourceRecordSet($tag) {
- $rrs = array();
- $rrs['Name'] = (string)$tag->Name;
- $rrs['Type'] = (string)$tag->Type;
- $rrs['TTL'] = (string)$tag->TTL;
- $rrs['ResourceRecords'] = array();
- foreach($tag->ResourceRecords->ResourceRecord as $rr) {
- $rrs['ResourceRecords'][] = (string)$rr->Value;
- }
- return $rrs;
- }
-
- /**
- * Utility function to prepare a Change object for ChangeResourceRecordSets requests.
- * All fields are required.
- *
- * @param string action The action to perform. One of: CREATE, DELETE
- * @param string name The name to perform the action on.
- * If it does not end with '.', then AWS treats the name as relative to the zone root.
- * @param string type The type of record being modified.
- * Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
- * @param int ttl The time-to-live value for this record, in seconds.
- * @param array records An array of resource records to attach to this change.
- * Each member of this array can either be a string, or an array of strings.
- * Passing an array of strings will attach multiple values to a single resource record.
- * If a single string is passed as $records instead of an array,
- * it will be treated as a single-member array.
- * @return object An opaque object containing the change request.
- * Do not write code that depends on the contents of this object, as it may change at any time.
- */
- public function prepareChange($action, $name, $type, $ttl, $records) {
- $change = "\n";
- $change .= ''.$action."\n";
- $change .= "\n";
- $change .= ''.$name."\n";
- $change .= ''.$type."\n";
- $change .= ''.$ttl."\n";
- $change .= "\n";
-
- if(!is_array($records)) {
- $records = array($records);
- }
-
- foreach($records as $record) {
- $change .= "\n";
- if(is_array($record)) {
- foreach($record as $value) {
- $change .= ''.$value."\n";
- }
- }
- else {
- $change .= ''.$record."\n";
- }
- $change .= "\n";
- }
-
- $change .= "\n";
- $change .= "\n";
- $change .= "\n";
-
- return $change;
- }
-
- /**
- * Trigger an error message
- *
- * @internal Used by member functions to output errors
- * @param array $error Array containing error information
- * @return string
- */
- public function __triggerError($functionname, $error)
- {
- if($error == false) {
- log_error(sprintf("Route53::%s(): Encountered an error, but no description given", $functionname));
- }
- else if(isset($error['curl']) && $error['curl'])
- {
- log_error(sprintf("Route53::%s(): %s %s", $functionname, $error['code'], $error['message']));
- }
- else if(isset($error['Error']))
- {
- $e = $error['Error'];
- $message = sprintf("Route53::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId']);
- log_error($message);
- }
- }
-
- /**
- * Callback handler for 503 retries.
- *
- * @internal Used by SimpleDBRequest to call the user-specified callback, if set
- * @param $attempt The number of failed attempts so far
- * @return The retry delay in microseconds, or 0 to stop retrying.
- */
- public function __executeServiceTemporarilyUnavailableRetryDelay($attempt)
- {
- if(is_callable($this->__serviceUnavailableRetryDelayCallback)) {
- $callback = $this->__serviceUnavailableRetryDelayCallback;
- return $callback($attempt);
- }
- return 0;
- }
+ const API_VERSION = '2010-10-01';
+
+ protected $__accessKey; // AWS Access key
+ protected $__secretKey; // AWS Secret key
+ protected $__host;
+
+ public function getAccessKey()
+ {
+ return $this->__accessKey;
+ }
+ public function getSecretKey()
+ {
+ return $this->__secretKey;
+ }
+ public function getHost()
+ {
+ return $this->__host;
+ }
+
+ protected $__verifyHost = 1;
+ protected $__verifyPeer = 1;
+
+ // verifyHost and verifyPeer determine whether curl verifies ssl certificates.
+ // It may be necessary to disable these checks on certain systems.
+ // These only have an effect if SSL is enabled.
+ public function verifyHost()
+ {
+ return $this->__verifyHost;
+ }
+ public function enableVerifyHost($enable = true)
+ {
+ $this->__verifyHost = $enable;
+ }
+
+ public function verifyPeer()
+ {
+ return $this->__verifyPeer;
+ }
+ public function enableVerifyPeer($enable = true)
+ {
+ $this->__verifyPeer = $enable;
+ }
+
+ /**
+ * Constructor
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function __construct($accessKey = null, $secretKey = null, $host = 'route53.amazonaws.com')
+ {
+ if ($accessKey !== null && $secretKey !== null) {
+ $this->setAuth($accessKey, $secretKey);
+ }
+ $this->__host = $host;
+ }
+
+ /**
+ * Set AWS access key and secret key
+ *
+ * @param string $accessKey Access key
+ * @param string $secretKey Secret key
+ * @return void
+ */
+ public function setAuth($accessKey, $secretKey)
+ {
+ $this->__accessKey = $accessKey;
+ $this->__secretKey = $secretKey;
+ }
+
+ /**
+ * Lists the hosted zones on the account
+ *
+ * @param string marker A pagination marker returned by a previous truncated call
+ * @param int maxItems The maximum number of items per page. The service uses min($maxItems, 100).
+ * @return A list of hosted zones
+ */
+ public function listHostedZones($marker = null, $maxItems = 100)
+ {
+ $rest = new Route53Request($this, 'hostedzone', 'GET');
+
+ if ($marker !== null) {
+ $rest->setParameter('marker', $marker);
+ }
+ if ($maxItems !== 100) {
+ $rest->setParameter('maxitems', $maxItems);
+ }
+
+ $rest = $rest->getResponse();
+ if ($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if ($rest->error !== false) {
+ $this->__triggerError('listHostedZones', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body)) {
+ return $response;
+ }
+
+ $zones = array();
+ foreach ($rest->body->HostedZones->HostedZone as $z) {
+ $zones[] = $this->parseHostedZone($z);
+ }
+ $response['HostedZone'] = $zones;
+
+ if (isset($rest->body->MaxItems)) {
+ $response['MaxItems'] = (string)$rest->body->MaxItems;
+ }
+
+ if (isset($rest->body->IsTruncated)) {
+ $response['IsTruncated'] = (string)$rest->body->IsTruncated;
+ if ($response['IsTruncated'] == 'true') {
+ $response['NextMarker'] = (string)$rest->body->NextMarker;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Retrieves information on a specified hosted zone
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @return A data structure containing information about the specified zone
+ */
+ public function getHostedZone($zoneId)
+ {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $rest = new Route53Request($this, $zoneId, 'GET');
+
+ $rest = $rest->getResponse();
+ if ($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if ($rest->error !== false) {
+ $this->__triggerError('getHostedZone', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body)) {
+ return $response;
+ }
+
+ $response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
+ $response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
+
+ return $response;
+ }
+
+ /**
+ * Creates a new hosted zone
+ *
+ * @param string name The name of the hosted zone (e.g. "example.com.")
+ * @param string reference A user-specified unique reference for this request
+ * @param string comment An optional user-specified comment to attach to the zone
+ * @return A data structure containing information about the newly created zone
+ */
+ public function createHostedZone($name, $reference, $comment = '')
+ {
+ // hosted zone names must end with a period, but people will forget this a lot...
+ if (strrpos($name, '.') != (strlen($name) - 1)) {
+ $name .= '.';
+ }
+
+ $data = "\n";
+ $data .= '\n";
+ $data .= '' . $name . "\n";
+ $data .= '' . $reference . "\n";
+ if (strlen($comment) > 0) {
+ $data .= "\n";
+ $data .= '' . $comment . "\n";
+ $data .= "\n";
+ }
+ $data .= "\n";
+
+ $rest = new Route53Request($this, 'hostedzone', 'POST', $data);
+
+ $rest = $rest->getResponse();
+
+ if ($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204))) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if ($rest->error !== false) {
+ $this->__triggerError('createHostedZone', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body)) {
+ return $response;
+ }
+
+ $response['HostedZone'] = $this->parseHostedZone($rest->body->HostedZone);
+ $response['ChangeInfo'] = $this->parseChangeInfo($rest->body->ChangeInfo);
+ $response['NameServers'] = $this->parseDelegationSet($rest->body->DelegationSet);
+
+ return $response;
+ }
+
+ /**
+ * Retrieves information on a specified hosted zone
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @return The change request data corresponding to this delete
+ */
+ public function deleteHostedZone($zoneId)
+ {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $rest = new Route53Request($this, $zoneId, 'DELETE');
+
+ $rest = $rest->getResponse();
+ if ($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if ($rest->error !== false) {
+ $this->__triggerError('deleteHostedZone', $rest->error);
+ return false;
+ }
+
+ if (!isset($rest->body)) {
+ return array();
+ }
+
+ return $this->parseChangeInfo($rest->body->ChangeInfo);
+ }
+
+ /**
+ * Retrieves a list of resource record sets for a given zone
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @param string type The type of resource record set to begin listing from. If this is specified, $name must also be specified.
+ * Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
+ * @param string name The name at which to begin listing resource records (in the lexographic order of records).
+ * @param int maxItems The maximum number of results to return. The service uses min($maxItems, 100).
+ * @return The list of matching resource record sets
+ */
+ public function listResourceRecordSets($zoneId, $type = '', $name = '', $maxItems = 100)
+ {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $rest = new Route53Request($this, $zoneId . '/rrset', 'GET');
+
+ if (strlen($type) > 0) {
+ $rest->setParameter('type', $type);
+ }
+ if (strlen($name) > 0) {
+ $rest->setParameter('name', $name);
+ }
+ if ($maxItems != 100) {
+ $rest->setParameter('maxitems', $maxItems);
+ }
+
+ $rest = $rest->getResponse();
+ if ($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if ($rest->error !== false) {
+ $this->__triggerError('listResourceRecordSets', $rest->error);
+ return false;
+ }
+
+ $response = array();
+ if (!isset($rest->body)) {
+ return $response;
+ }
+
+ $recordSets = array();
+ foreach ($rest->body->ResourceRecordSets->ResourceRecordSet as $set) {
+ $recordSets[] = $this->parseResourceRecordSet($set);
+ }
+
+ $response['ResourceRecordSets'] = $recordSets;
+
+ if (isset($rest->body->MaxItems)) {
+ $response['MaxItems'] = (string)$rest->body->MaxItems;
+ }
+
+ if (isset($rest->body->IsTruncated)) {
+ $response['IsTruncated'] = (string)$rest->body->IsTruncated;
+ if ($response['IsTruncated'] == 'true') {
+ $response['NextRecordName'] = (string)$rest->body->NextRecordName;
+ $response['NextRecordType'] = (string)$rest->body->NextRecordType;
+ }
+ }
+
+ return $response;
+ }
+
+ /**
+ * Makes the specified resource record set changes (create or delete).
+ *
+ * @param string zoneId The id of the hosted zone, as returned by CreateHostedZoneResponse or ListHostedZoneResponse
+ * In other words, if ListHostedZoneResponse shows the zone's Id as '/hostedzone/Z1PA6795UKMFR9',
+ * then that full value should be passed here, including the '/hostedzone/' prefix.
+ * @param array changes An array of change objects, as they are returned by the prepareChange utility method.
+ * You may also pass a single change object.
+ * @param string comment An optional comment to attach to the change request
+ * @return The status of the change request
+ */
+ public function changeResourceRecordSets($zoneId, $changes, $comment = '')
+ {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($zoneId, '/');
+
+ $data = "\n";
+ $data .= '\n";
+ $data .= "\n";
+
+ if (strlen($comment) > 0) {
+ $data .= '' . $comment . "\n";
+ }
+
+ if (!is_array($changes)) {
+ $changes = array($changes);
+ }
+
+ $data .= "\n";
+ foreach ($changes as $change) {
+ $data .= $change;
+ }
+ $data .= "\n";
+
+ $data .= "\n";
+ $data .= "\n";
+
+ $rest = new Route53Request($this, $zoneId . '/rrset', 'POST', $data);
+
+ $rest = $rest->getResponse();
+ if ($rest->error === false && !in_array($rest->code, array(200, 201, 202, 204))) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if ($rest->error !== false) {
+ $this->__triggerError('changeResourceRecordSets', $rest->error);
+ return false;
+ }
+
+ if (!isset($rest->body)) {
+ return array();
+ }
+
+ return $this->parseChangeInfo($rest->body->ChangeInfo);
+ }
+
+ /**
+ * Retrieves information on a specified change request
+ *
+ * @param string changeId The id of the change, as returned by CreateHostedZoneResponse or ChangeResourceRecordSets
+ * In other words, if CreateHostedZoneResponse showed the change's Id as '/change/C2682N5HXP0BZ4',
+ * then that full value should be passed here, including the '/change/' prefix.
+ * @return The status of the change request
+ */
+ public function getChange($changeId)
+ {
+ // we'll strip off the leading forward slash, so we can use it as the action directly.
+ $zoneId = trim($changeId, '/');
+
+ $rest = new Route53Request($this, $changeId, 'GET');
+
+ $rest = $rest->getResponse();
+ if ($rest->error === false && $rest->code !== 200) {
+ $rest->error = array('code' => $rest->code, 'message' => 'Unexpected HTTP status');
+ }
+ if ($rest->error !== false) {
+ $this->__triggerError('getChange', $rest->error);
+ return false;
+ }
+
+ if (!isset($rest->body)) {
+ return array();
+ }
+
+ return $this->parseChangeInfo($rest->body->ChangeInfo);
+ }
+
+
+
+ /**
+ * Utility function to parse a HostedZone tag structure
+ */
+ private function parseHostedZone($tag)
+ {
+ $zone = array();
+ $zone['Id'] = (string)$tag->Id;
+ $zone['Name'] = (string)$tag->Name;
+ $zone['CallerReference'] = (string)$tag->CallerReference;
+
+ // these might always be set, but check just in case, since
+ // their values are option on CreateHostedZone requests
+ if (isset($tag->Config) && isset($tag->Config->Comment)) {
+ $zone['Config'] = array('Comment' => (string)$tag->Config->Comment);
+ }
+
+ return $zone;
+ }
+
+ /**
+ * Utility function to parse a ChangeInfo tag structure
+ */
+ private function parseChangeInfo($tag)
+ {
+ $info = array();
+ $info['Id'] = (string)$tag->Id;
+ $info['Status'] = (string)$tag->Status;
+ $info['SubmittedAt'] = (string)$tag->SubmittedAt;
+ return $info;
+ }
+
+ /**
+ * Utility function to parse a DelegationSet tag structure
+ */
+ private function parseDelegationSet($tag)
+ {
+ $servers = array();
+ foreach ($tag->NameServers->NameServer as $ns) {
+ $servers[] = (string)$ns;
+ }
+ return $servers;
+ }
+
+ /**
+ * Utility function to parse a ResourceRecordSet tag structure
+ */
+ private function parseResourceRecordSet($tag)
+ {
+ $rrs = array();
+ $rrs['Name'] = (string)$tag->Name;
+ $rrs['Type'] = (string)$tag->Type;
+ $rrs['TTL'] = (string)$tag->TTL;
+ $rrs['ResourceRecords'] = array();
+ foreach ($tag->ResourceRecords->ResourceRecord as $rr) {
+ $rrs['ResourceRecords'][] = (string)$rr->Value;
+ }
+ return $rrs;
+ }
+
+ /**
+ * Utility function to prepare a Change object for ChangeResourceRecordSets requests.
+ * All fields are required.
+ *
+ * @param string action The action to perform. One of: CREATE, DELETE
+ * @param string name The name to perform the action on.
+ * If it does not end with '.', then AWS treats the name as relative to the zone root.
+ * @param string type The type of record being modified.
+ * Must be one of: A, AAAA, CNAME, MX, NS, PTR, SOA, SPF, SRV, TXT
+ * @param int ttl The time-to-live value for this record, in seconds.
+ * @param array records An array of resource records to attach to this change.
+ * Each member of this array can either be a string, or an array of strings.
+ * Passing an array of strings will attach multiple values to a single resource record.
+ * If a single string is passed as $records instead of an array,
+ * it will be treated as a single-member array.
+ * @return object An opaque object containing the change request.
+ * Do not write code that depends on the contents of this object, as it may change at any time.
+ */
+ public function prepareChange($action, $name, $type, $ttl, $records)
+ {
+ $change = "\n";
+ $change .= '' . $action . "\n";
+ $change .= "\n";
+ $change .= '' . $name . "\n";
+ $change .= '' . $type . "\n";
+ $change .= '' . $ttl . "\n";
+ $change .= "\n";
+
+ if (!is_array($records)) {
+ $records = array($records);
+ }
+
+ foreach ($records as $record) {
+ $change .= "\n";
+ if (is_array($record)) {
+ foreach ($record as $value) {
+ $change .= '' . $value . "\n";
+ }
+ } else {
+ $change .= '' . $record . "\n";
+ }
+ $change .= "\n";
+ }
+
+ $change .= "\n";
+ $change .= "\n";
+ $change .= "\n";
+
+ return $change;
+ }
+
+ /**
+ * Trigger an error message
+ *
+ * @internal Used by member functions to output errors
+ * @param array $error Array containing error information
+ * @return string
+ */
+ public function __triggerError($functionname, $error)
+ {
+ if ($error == false) {
+ log_error(sprintf("Route53::%s(): Encountered an error, but no description given", $functionname));
+ } elseif (isset($error['curl']) && $error['curl']) {
+ log_error(sprintf("Route53::%s(): %s %s", $functionname, $error['code'], $error['message']));
+ } elseif (isset($error['Error'])) {
+ $e = $error['Error'];
+ $message = sprintf("Route53::%s(): %s - %s: %s\nRequest Id: %s\n", $functionname, $e['Type'], $e['Code'], $e['Message'], $error['RequestId']);
+ log_error($message);
+ }
+ }
+
+ /**
+ * Callback handler for 503 retries.
+ *
+ * @internal Used by SimpleDBRequest to call the user-specified callback, if set
+ * @param $attempt The number of failed attempts so far
+ * @return The retry delay in microseconds, or 0 to stop retrying.
+ */
+ public function __executeServiceTemporarilyUnavailableRetryDelay($attempt)
+ {
+ if (is_callable($this->__serviceUnavailableRetryDelayCallback)) {
+ $callback = $this->__serviceUnavailableRetryDelayCallback;
+ return $callback($attempt);
+ }
+ return 0;
+ }
}
final class Route53Request
{
- private $r53, $action, $verb, $data, $parameters = array();
- public $response;
+ private $r53, $action, $verb, $data, $parameters = array();
+ public $response;
- /**
- * Constructor
- *
- * @param string $r53 The Route53 object making this request
- * @param string $action SimpleDB action
- * @param string $verb HTTP verb
- * @param string $data For POST requests, the data being posted (optional)
- * @return mixed
- */
- function __construct($r53, $action, $verb, $data = '') {
- $this->r53 = $r53;
- $this->action = $action;
- $this->verb = $verb;
- $this->data = $data;
- $this->response = new STDClass;
- $this->response->error = false;
- }
+ /**
+ * Constructor
+ *
+ * @param string $r53 The Route53 object making this request
+ * @param string $action SimpleDB action
+ * @param string $verb HTTP verb
+ * @param string $data For POST requests, the data being posted (optional)
+ * @return mixed
+ */
+ function __construct($r53, $action, $verb, $data = '')
+ {
+ $this->r53 = $r53;
+ $this->action = $action;
+ $this->verb = $verb;
+ $this->data = $data;
+ $this->response = new STDClass();
+ $this->response->error = false;
+ }
- /**
- * Set request parameter
- *
- * @param string $key Key
- * @param string $value Value
- * @param boolean $replace Whether to replace the key if it already exists (default true)
- * @return void
- */
- public function setParameter($key, $value, $replace = true) {
- if(!$replace && isset($this->parameters[$key]))
- {
- $temp = (array)($this->parameters[$key]);
- $temp[] = $value;
- $this->parameters[$key] = $temp;
- }
- else
- {
- $this->parameters[$key] = $value;
- }
- }
+ /**
+ * Set request parameter
+ *
+ * @param string $key Key
+ * @param string $value Value
+ * @param boolean $replace Whether to replace the key if it already exists (default true)
+ * @return void
+ */
+ public function setParameter($key, $value, $replace = true)
+ {
+ if (!$replace && isset($this->parameters[$key])) {
+ $temp = (array)($this->parameters[$key]);
+ $temp[] = $value;
+ $this->parameters[$key] = $temp;
+ } else {
+ $this->parameters[$key] = $value;
+ }
+ }
- /**
- * Get the response
- *
- * @return object | false
- */
- public function getResponse() {
+ /**
+ * Get the response
+ *
+ * @return object | false
+ */
+ public function getResponse()
+ {
- $params = array();
- foreach ($this->parameters as $var => $value)
- {
- if(is_array($value))
- {
- foreach($value as $v)
- {
- $params[] = $var.'='.$this->__customUrlEncode($v);
- }
- }
- else
- {
- $params[] = $var.'='.$this->__customUrlEncode($value);
- }
- }
+ $params = array();
+ foreach ($this->parameters as $var => $value) {
+ if (is_array($value)) {
+ foreach ($value as $v) {
+ $params[] = $var . '=' . $this->__customUrlEncode($v);
+ }
+ } else {
+ $params[] = $var . '=' . $this->__customUrlEncode($value);
+ }
+ }
- sort($params, SORT_STRING);
+ sort($params, SORT_STRING);
- $query = implode('&', $params);
+ $query = implode('&', $params);
- // must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
- $date = gmdate('D, d M Y H:i:s e');
+ // must be in format 'Sun, 06 Nov 1994 08:49:37 GMT'
+ $date = gmdate('D, d M Y H:i:s e');
- $headers = array();
- $headers[] = 'Date: '.$date;
- $headers[] = 'Host: '.$this->r53->getHost();
+ $headers = array();
+ $headers[] = 'Date: ' . $date;
+ $headers[] = 'Host: ' . $this->r53->getHost();
- $auth = 'AWS3-HTTPS AWSAccessKeyId='.$this->r53->getAccessKey();
- $auth .= ',Algorithm=HmacSHA256,Signature='.$this->__getSignature($date);
- $headers[] = 'X-Amzn-Authorization: '.$auth;
+ $auth = 'AWS3-HTTPS AWSAccessKeyId=' . $this->r53->getAccessKey();
+ $auth .= ',Algorithm=HmacSHA256,Signature=' . $this->__getSignature($date);
+ $headers[] = 'X-Amzn-Authorization: ' . $auth;
- $url = 'https://'.$this->r53->getHost().'/'.Route53::API_VERSION.'/'.$this->action.'?'.$query;
+ $url = 'https://' . $this->r53->getHost() . '/' . Route53::API_VERSION . '/' . $this->action . '?' . $query;
- // Basic setup
- $curl = curl_init();
- curl_setopt($curl, CURLOPT_USERAGENT, 'Route53/php');
+ // Basic setup
+ $curl = curl_init();
+ curl_setopt($curl, CURLOPT_USERAGENT, 'Route53/php');
- curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->r53->verifyHost() ? 1 : 0));
- curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->r53->verifyPeer() ? 1 : 0));
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, ($this->r53->verifyHost() ? 1 : 0));
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, ($this->r53->verifyPeer() ? 1 : 0));
- curl_setopt($curl, CURLOPT_URL, $url);
- curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
- curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
- curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
+ curl_setopt($curl, CURLOPT_URL, $url);
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
+ curl_setopt($curl, CURLOPT_WRITEFUNCTION, array(&$this, '__responseWriteCallback'));
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
- // Request types
- switch ($this->verb) {
- case 'GET': break;
- case 'POST':
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
- if(strlen($this->data) > 0) {
- curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
- $headers[] = 'Content-Type: text/plain';
- $headers[] = 'Content-Length: '.strlen($this->data);
- }
- break;
- case 'DELETE':
- curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
- break;
- default: break;
- }
- curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
- curl_setopt($curl, CURLOPT_HEADER, false);
+ // Request types
+ switch ($this->verb) {
+ case 'GET':
+ break;
+ case 'POST':
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);
+ if (strlen($this->data) > 0) {
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $this->data);
+ $headers[] = 'Content-Type: text/plain';
+ $headers[] = 'Content-Length: ' . strlen($this->data);
+ }
+ break;
+ case 'DELETE':
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
+ break;
+ default:
+ break;
+ }
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
+ curl_setopt($curl, CURLOPT_HEADER, false);
- // Execute, grab errors
- if (curl_exec($curl)) {
- $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
- } else {
- $this->response->error = array(
- 'curl' => true,
- 'code' => curl_errno($curl),
- 'message' => curl_error($curl),
- 'resource' => $this->resource
- );
- }
+ // Execute, grab errors
+ if (curl_exec($curl)) {
+ $this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ } else {
+ $this->response->error = array(
+ 'curl' => true,
+ 'code' => curl_errno($curl),
+ 'message' => curl_error($curl),
+ 'resource' => $this->resource
+ );
+ }
- @curl_close($curl);
+ @curl_close($curl);
- // Parse body into XML
- if ($this->response->error === false && isset($this->response->body)) {
- $this->response->body = simplexml_load_string($this->response->body);
+ // Parse body into XML
+ if ($this->response->error === false && isset($this->response->body)) {
+ $this->response->body = simplexml_load_string($this->response->body);
- // Grab Route53 errors
- if (!in_array($this->response->code, array(200, 201, 202, 204))
- && isset($this->response->body->Error)) {
- $error = $this->response->body->Error;
- $output = array();
- $output['curl'] = false;
- $output['Error'] = array();
- $output['Error']['Type'] = (string)$error->Type;
- $output['Error']['Code'] = (string)$error->Code;
- $output['Error']['Message'] = (string)$error->Message;
- $output['RequestId'] = (string)$this->response->body->RequestId;
+ // Grab Route53 errors
+ if (
+ !in_array($this->response->code, array(200, 201, 202, 204))
+ && isset($this->response->body->Error)
+ ) {
+ $error = $this->response->body->Error;
+ $output = array();
+ $output['curl'] = false;
+ $output['Error'] = array();
+ $output['Error']['Type'] = (string)$error->Type;
+ $output['Error']['Code'] = (string)$error->Code;
+ $output['Error']['Message'] = (string)$error->Message;
+ $output['RequestId'] = (string)$this->response->body->RequestId;
- $this->response->error = $output;
- unset($this->response->body);
- }
- }
+ $this->response->error = $output;
+ unset($this->response->body);
+ }
+ }
- return $this->response;
- }
+ return $this->response;
+ }
- /**
- * CURL write callback
- *
- * @param resource &$curl CURL resource
- * @param string &$data Data
- * @return integer
- */
- private function __responseWriteCallback(&$curl, &$data) {
- $this->response->body .= $data;
- return strlen($data);
- }
+ /**
+ * CURL write callback
+ *
+ * @param resource &$curl CURL resource
+ * @param string &$data Data
+ * @return integer
+ */
+ private function __responseWriteCallback(&$curl, &$data)
+ {
+ $this->response->body .= $data;
+ return strlen($data);
+ }
- /**
- * Contributed by afx114
- * URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
- * PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode
- * See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
- *
- * @param string $var String to encode
- * @return string
- */
- private function __customUrlEncode($var) {
- return str_replace('%7E', '~', rawurlencode($var));
- }
+ /**
+ * Contributed by afx114
+ * URL encode the parameters as per http://docs.amazonwebservices.com/AWSECommerceService/latest/DG/index.html?Query_QueryAuth.html
+ * PHP's rawurlencode() follows RFC 1738, not RFC 3986 as required by Amazon. The only difference is the tilde (~), so convert it back after rawurlencode
+ * See: http://www.morganney.com/blog/API/AWS-Product-Advertising-API-Requires-a-Signed-Request.php
+ *
+ * @param string $var String to encode
+ * @return string
+ */
+ private function __customUrlEncode($var)
+ {
+ return str_replace('%7E', '~', rawurlencode($var));
+ }
- /**
- * Generate the auth string using Hmac-SHA256
- *
- * @internal Used by SimpleDBRequest::getResponse()
- * @param string $string String to sign
- * @return string
- */
- private function __getSignature($string) {
- return base64_encode(hash_hmac('sha256', $string, $this->r53->getSecretKey(), true));
- }
+ /**
+ * Generate the auth string using Hmac-SHA256
+ *
+ * @internal Used by SimpleDBRequest::getResponse()
+ * @param string $string String to sign
+ * @return string
+ */
+ private function __getSignature($string)
+ {
+ return base64_encode(hash_hmac('sha256', $string, $this->r53->getSecretKey(), true));
+ }
}