DNSMadeEasy.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. <?php
  2. namespace MGModule\DNSManager2\mgLibs\custom\dns\submodules;
  3. use \MGModule\DNSManager2\mgLibs\custom\dns;
  4. use \MGModule\DNSManager2\mgLibs\custom\dns\exceptions;
  5. use \MGModule\DNSManager2\mgLibs\custom\dns\interfaces;
  6. class DNSMadeEasy extends dns\SubmoduleAbstract implements interfaces\SubmoduleTTLInterface, interfaces\SubmoduleImportInterface, interfaces\SubmoduleRDNSInterface
  7. {
  8. public $configFields = [
  9. 'apikey' => [
  10. 'friendlyName' => 'API Key',
  11. 'validators' => [
  12. 'required' => 'required',
  13. ]
  14. ],
  15. 'api_secret' => [
  16. 'friendlyName' => 'API Secret',
  17. 'type' => 'password',
  18. 'validators' => [
  19. 'required' => 'required',
  20. ]
  21. ],
  22. 'test' => [
  23. 'friendlyName' => 'Test Mode',
  24. 'type' => 'yesno',
  25. ],
  26. ];
  27. public $availableTypes = ['A', 'AAAA', 'ANAME', 'NS', 'MX', 'CNAME', 'SPF', 'SRV', 'TXT', 'PTR','HTTPRED'];
  28. private $domain_id;
  29. const API_BASE_URL = 'http://api.dnsmadeeasy.com/V2.0/';
  30. const API_BASE_URL_TEST = 'http://api.sandbox.dnsmadeeasy.com/V2.0/';
  31. public function testConnection()
  32. {
  33. $info = $this->_get('dns/managed/');
  34. if( !isset($info['data']) )
  35. {
  36. throw new exceptions\DNSSubmoduleException('Unknown Error', dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
  37. }
  38. }
  39. public function zoneExists()
  40. {
  41. if( $this->domain_id() > 0 )
  42. {
  43. $result = $this->_get('dns/managed/' . $this->domain_id());
  44. if( $result['id'] > 0 )
  45. {
  46. return true;
  47. }
  48. }
  49. return false;
  50. }
  51. public function getRecords( $recordType = false )
  52. {
  53. $result = $this->_get('dns/managed/' . $this->domain_id() . '/records');
  54. $out = [];
  55. foreach( $result['data'] as $data )
  56. {
  57. if( in_array((string)$data['type'], $recordType ? [strtoupper($recordType)] : $this->getAvailableRecordTypes(), true) )
  58. {
  59. $record = new dns\record\Record();
  60. $record->line = (string)$data['id'];
  61. $record->name = (string)$data['name'];
  62. $record->type = (string)$data['type'];
  63. $record->ttl = (string)$data['ttl'];
  64. $record->createRDATAObject();
  65. switch( (string)$data['type'] )
  66. {
  67. case 'MX':
  68. $record->rdata->preference = (string)$data['mxLevel'];
  69. $record->rdata->exchange = (string)$data['value'];
  70. break;
  71. case 'HTTPRED':
  72. $record->rdata->link = $data['value'];
  73. $record->rdata->title = $data['title'];
  74. $record->rdata->keywords = $data['keywords'];
  75. $record->rdata->redirecttype = $data['redirectType'];
  76. $record->rdata->hardlink = (int)$data['hardLink'];
  77. break;
  78. case 'SRV':
  79. $record->rdata->setDataFromArray($data);
  80. $record->rdata->target = (string)$data['value'];
  81. break;
  82. default:
  83. $record->rdata->setFirstProperty((string)$data['value']);
  84. break;
  85. }
  86. $out[] = $record;
  87. }
  88. }
  89. return $out;
  90. }
  91. private function recordToParamsArray( dns\record\Record $record )
  92. {
  93. $params = [
  94. 'name' => str_replace('@', '', $record->nameToRelative($this->domain)),
  95. 'ttl' => $record->ttl,
  96. 'type' => $record->type
  97. ];
  98. switch( $record->type )
  99. {
  100. case 'PTR':
  101. $params['value'] = trim($record->rdata->ptrdname, '.') . '.';
  102. break;
  103. case 'MX':
  104. $params['mxLevel'] = $record->rdata->preference;
  105. $params['value'] = $this->makeAbsolute($record->rdata->exchange);
  106. break;
  107. case 'HTTPRED':
  108. $params['title'] = $record->rdata->title;
  109. $params['keywords'] = $record->rdata->keywords;
  110. $params['redirectType'] = $record->rdata->redirecttype;
  111. $params['hardLink'] = (bool)$record->rdata->hardlink;
  112. $params['value'] = $record->rdata->link;
  113. break;
  114. case 'SRV':
  115. $params = array_merge($params, $record->rdata->toArray(false));
  116. unset($params['target']);
  117. $params['value'] = $record->rdata->target;
  118. $params['ttl'] = $record->ttl;
  119. $params['type'] = $record->type;
  120. break;
  121. case 'NS':
  122. $params['value'] = $this->makeAbsolute($record->rdata->nsdname);
  123. break;
  124. case 'ANAME':
  125. $params['value'] = $this->makeAbsolute($record->rdata->aname);
  126. break;
  127. case 'CNAME':
  128. $params['value'] = $this->makeAbsolute($record->rdata->cname);
  129. break;
  130. default:
  131. $params['value'] = $record->rdata->toString();
  132. break;
  133. }
  134. return $params;
  135. }
  136. public function addRecord( dns\record\Record $record )
  137. {
  138. $params = $this->recordToParamsArray($record);
  139. $this->_post('dns/managed/' . $this->domain_id() . '/records/ ', $params);
  140. }
  141. public function editRecord( dns\record\Record $record )
  142. {
  143. $params = $this->recordToParamsArray($record);
  144. $params['gtdLocation'] = "DEFAULT";
  145. $params['id'] = $record->line;
  146. $this->_put('dns/managed/' . $this->domain_id() . '/records/' . $record->line . '/', $params);
  147. }
  148. public function deleteRecord( dns\record\Record $record )
  149. {
  150. $this->_delete('dns/managed/' . $this->domain_id() . '/records/' . $record->line);
  151. }
  152. public function activateZone()
  153. {
  154. $input = [
  155. 'names' => [$this->domain],
  156. ];
  157. $this->_post('dns/managed', $input);
  158. }
  159. public function terminateZone()
  160. {
  161. $this->_delete('dns/managed', [$this->domain_id()]);
  162. }
  163. private function _get( $operation )
  164. {
  165. return $this->_curl($operation, 'GET');
  166. }
  167. private function _delete( $operation, $data = [] )
  168. {
  169. return $this->_curl($operation, 'DELETE', $data);
  170. }
  171. private function _put( $operation, $data = [] )
  172. {
  173. return $this->_curl($operation, 'PUT', $data);
  174. }
  175. private function _post( $operation, $data = [] )
  176. {
  177. return $this->_curl($operation, 'POST', $data);
  178. }
  179. private function _curl( $operation, $method, $postData = null )
  180. {
  181. $url = ($this->config['test'] == 'on' ? self::API_BASE_URL_TEST : self::API_BASE_URL) . $operation;
  182. $ch = curl_init();
  183. curl_setopt($ch, CURLOPT_URL, $url);
  184. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
  185. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  186. //curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_headerCallback'));
  187. curl_setopt($ch, CURLOPT_HTTPHEADER, $this->_requestHeaders());
  188. if( $method === 'POST' || $method === 'DELETE' )
  189. {
  190. foreach( $postData as $key => $value )
  191. {
  192. if( in_array($key, ['PRIORITY', 'WEIGHT', 'PORT', 'TARGET'], true) )
  193. {
  194. if( $key === 'TARGET' )
  195. {
  196. unset($postData['TARGET']);
  197. }
  198. else
  199. {
  200. $postData[strtolower($key)] = $value;
  201. }
  202. unset($postData[$key]);
  203. }
  204. }
  205. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
  206. }
  207. elseif( $method === 'PUT' )
  208. {
  209. curl_setopt($ch, CURLOPT_HTTPHEADER, // Ask the remote end to PUT, curl won't PUT a raw body
  210. array_merge(['X-HTTP-Method-Override: PUT'], $this->_requestHeaders()));
  211. curl_setopt($ch, CURLOPT_POST, true);
  212. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
  213. }
  214. curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
  215. // reset the header values
  216. $this->_headers = [];
  217. $apiResponse = curl_exec($ch);
  218. if( curl_errno($ch) )
  219. {
  220. throw new exceptions\DNSSubmoduleException("cURL Error: " . curl_errno($ch) . " - " . curl_error($ch), dns\SubmoduleExceptionCodes::CONNECTION_PROBLEM);
  221. }
  222. if( empty($apiResponse) )
  223. {
  224. $apiResponse = '[]';
  225. }
  226. $apiResponse = preg_replace('/([{,]+)(\s*)([^"]+?)\s*:/', '$1"$3":', $apiResponse); //key => "key"
  227. $result = json_decode($apiResponse, true);
  228. if( !is_array($result) )
  229. {
  230. throw new exceptions\DNSSubmoduleException('Unable to parse response (' . $apiResponse . ')', dns\SubmoduleExceptionCodes::INVALID_RESPONSE);
  231. }
  232. $ci = curl_getinfo($ch);
  233. if( !empty($result['error']) || strpos($ci['http_code'], '2') !== 0 )
  234. {
  235. throw new exceptions\DNSSubmoduleException($result['error'][0] ? : 'Unknown Error', dns\SubmoduleExceptionCodes::COMMAND_ERROR);
  236. }
  237. return $result;
  238. }
  239. private function _requestHeaders()
  240. {
  241. $requestDate = gmdate('r');
  242. return [
  243. "x-dnsme-apiKey: {$this->config['apikey']}",
  244. "x-dnsme-requestDate: $requestDate",
  245. "x-dnsme-hmac: " . $this->_hash($requestDate),
  246. 'content-type:application/json',
  247. 'accept:application/json',
  248. ];
  249. }
  250. private function _hash( $requestDate )
  251. {
  252. return hash_hmac('sha1', $requestDate, $this->config['api_secret']);
  253. }
  254. private function domain_id()
  255. {
  256. if( isset($this->domain_id) )
  257. {
  258. return $this->domain_id;
  259. }
  260. $info = $this->_get('dns/managed/');
  261. foreach( $info['data'] as $value )
  262. {
  263. if( $value['name'] === $this->domain )
  264. {
  265. $this->domain_id = $value['id'];
  266. return $value['id'];
  267. }
  268. }
  269. }
  270. public function getZones()
  271. {
  272. $out = [];
  273. $info = $this->_get('dns/managed/');
  274. foreach( $info['data'] as $value )
  275. {
  276. $out[$value['name']] = '';
  277. }
  278. return $out;
  279. }
  280. /**
  281. * @param $name
  282. *
  283. * @return string
  284. */
  285. private function makeAbsolute( $name )
  286. {
  287. return rtrim($name, '. ') . '.';
  288. }
  289. }