1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
16:
17: class Beatnik_Driver_pdnsgsql extends Beatnik_Driver
18: {
19: 20: 21: 22: 23:
24: var $_params = array();
25:
26: 27: 28: 29: 30:
31: var $_db;
32:
33: 34: 35: 36: 37: 38:
39: var $_write_db;
40:
41: 42: 43: 44: 45:
46: var $_connected = false;
47:
48: 49: 50: 51: 52:
53: function __construct($params = array())
54: {
55: $params = array_merge(array(
56: 'domains_table' => 'domains',
57: 'records_table' => 'records'
58: ), $params);
59:
60: parent::__construct($params);
61: }
62:
63: 64: 65: 66: 67: 68: 69:
70: function _getDomains()
71: {
72: $this->_connect();
73:
74: $query = 'SELECT d.id, d.name AS name, r.content AS content, ' .
75: 'r.ttl AS ttl FROM ' . $this->_params['domains_table'] .
76: ' AS d JOIN ' . $this->_params['records_table'] . ' AS r ON ' .
77: 'r.domain_id = d.id WHERE r.type = \'SOA\'';
78: Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::_getDomains(): ' . $query, 'DEBUG');
79:
80: $domainlist = $this->_db->getAll($query, null, DB_FETCHMODE_ASSOC);
81: if (is_a($domainlist, 'PEAR_Error')) {
82: Horde::logMessage($domainlist, 'ERR');
83: throw new Beatnik_Exception(_("Error getting domain list. Details have been logged for the administrator."));
84: }
85:
86: $results = array();
87: foreach ($domainlist as $info) {
88: $soa = explode(' ', $info['content']);
89: if (count($soa) != 7) {
90: Horde::logMessage(sprintf('Invalid SOA found for %s, skipping.', $info['name']), 'WARN');
91: continue;
92: }
93:
94: $d = array();
95: $d['id'] = $info['id'];
96: $d['zonename'] = $info['name'];
97: $d['zonemaster'] = $d['zonens'] = $soa[0];
98: $d['admin'] = $d['zonecontact'] = $soa[1];
99: $d['serial'] = $soa[2];
100: $d['refresh'] = $soa[3];
101: $d['retry'] = $soa[4];
102: $d['expire'] = $soa[5];
103: $d['minimum'] = $soa[6];
104: $results[] = $d;
105: }
106:
107: return $results;
108: }
109:
110: 111: 112: 113: 114: 115: 116:
117: function getDomain($domainname)
118: {
119: $this->_connect();
120:
121: $query = 'SELECT d.id AS id, d.name AS name, r.content AS content, ' .
122: 'r.ttl AS ttl FROM ' . $this->_params['domains_table'] .
123: ' AS d JOIN ' . $this->_params['records_table'] . ' AS r ON ' .
124: 'r.domain_id = d.id WHERE r.type = \'SOA\' AND d.name = ?';
125: $values = array($domainname);
126: Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::getDomain(): ' . $query, 'DEBUG');
127:
128: $result = $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC);
129: if (is_a($result, 'PEAR_Error')) {
130: Horde::logMessage($result, 'ERR');
131: throw new Beatnik_Exception(_("An error occurred while searching the database. Details have been logged for the administrator."), __FILE__, __LINE__, PEAR_LOG_ERR);
132: }
133:
134: if (count($result) != 1) {
135: throw new Beatnik_Exception(_("Too many domains matched that name. Contact your administrator."));
136: }
137:
138: $info = $result[0];
139:
140: $soa = explode(' ', $info['content']);
141: if (count($soa) != 7) {
142: Horde::logMessage(sprintf('Invalid SOA found for %s, skipping.', $info['name']), 'WARN');
143: throw new Beatnik_Exception(_("Corrupt SOA found for zone. Contact your administrator."), __FILE__, __LINE__, PEAR_LOG_ERR);
144: }
145:
146: $ret = array();
147: $ret['id'] = $info['id'];
148: $ret['zonename'] = $info['name'];
149: $ret['zonemaster'] = $soa[0];
150: $ret['admin'] = $soa[1];
151: $ret['serial'] = $soa[2];
152: $ret['refresh'] = $soa[3];
153: $ret['retry'] = $soa[4];
154: $ret['expire'] = $soa[5];
155: $ret['minimum'] = $soa[6];
156:
157: return $ret;
158: }
159:
160: 161: 162: 163: 164: 165: 166:
167: function getRecords($domain)
168: {
169: $this->_connect();
170:
171: $zonedata = array();
172:
173: $query = 'SELECT d.id AS domain_id, r.id AS id, d.name AS domain, ' .
174: 'r.name AS name, r.type AS type, r.content AS content, ' .
175: 'r.ttl AS ttl, r.prio AS prio FROM ' .
176: $this->_params['domains_table'] . ' AS d JOIN ' .
177: $this->_params['records_table'] . ' AS r ON ' .
178: 'd.id = r.domain_id AND d.name = ?';
179: $values = array($domain);
180:
181: Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::getRecords(): ' . $query, 'DEBUG');
182: $result = $this->_db->getAll($query, $values, DB_FETCHMODE_ASSOC);
183: if (is_a($result, 'PEAR_Error')) {
184: Horde::logMessage($result, 'ERR');
185: throw new Beatnik_Exception(_("An error occurred while searching the database. Details have been logged for the administrator."), __FILE__, __LINE__, PEAR_LOG_ERR);
186: }
187:
188: foreach ($result as $rec) {
189: $type = strtolower($rec['type']);
190: if (!isset($zonedata[$type])) {
191: $zonedata[$type] = array();
192: }
193:
194: $tmp = array();
195: $tmp['id'] = $rec['id'];
196: $tmp['ttl'] = $rec['ttl'];
197: switch($type) {
198: case 'soa':
199: $soa = explode(' ', $rec['content']);
200: if (count($soa) != 7) {
201: Horde::logMessage(sprintf('Invalid SOA found for %s, skipping.', $info['name']), 'WARN');
202: }
203:
204: $tmp['zonename'] = $rec['name'];
205: $tmp['zonens'] = $soa[0];
206: $tmp['zonecontact'] = $soa[1];
207: $tmp['serial'] = $soa[2];
208: $tmp['refresh'] = $soa[3];
209: $tmp['retry'] = $soa[4];
210: $tmp['expire'] = $soa[5];
211: $tmp['minimum'] = $soa[6];
212: break;
213:
214: case 'a':
215: $tmp['hostname'] = $rec['name'];
216: $tmp['ipaddr'] = $rec['content'];
217: break;
218:
219: case 'ptr':
220: $tmp['hostname'] = $rec['name'];
221: $tmp['pointer'] = $rec['content'];
222: break;
223:
224: case 'mx':
225: $tmp['pointer'] = $rec['content'];
226: $tmp['pref'] = $rec['prio'];
227: break;
228:
229: case 'cname':
230: $tmp['hostname'] = $rec['name'];
231: $tmp['pointer'] = $rec['content'];
232: break;
233:
234: case 'ns':
235: $tmp['hostname'] = $rec['name'];
236: $tmp['pointer'] = $rec['content'];
237: break;
238:
239: case 'srv':
240: $srv = preg_split('/\s+/', trim($rec['content']));
241: if (count($srv) != 3) {
242: Horde::logMessage(sprintf('Invalid SRV data found for %s, skipping.', $rec['name']), 'WARN');
243: continue;
244: }
245: $tmp['hostname'] = $rec['name'];
246: $tmp['weight'] = $srv[0];
247: $tmp['port'] = $srv[1];
248: $tmp['pointer'] = $srv[2];
249: $tmp['priority'] = $rec['prio'];
250: break;
251:
252: case 'txt':
253: $tmp['hostname'] = $rec['name'];
254: $tmp['text'] = $rec['content'];
255: break;
256: }
257:
258: $zonedata[$type][] = $tmp;
259: }
260:
261: return $zonedata;
262: }
263:
264: 265: 266: 267: 268: 269: 270: 271: 272:
273: function _saveRecord($info)
274: {
275: $this->_connect();
276:
277: $change_date = time();
278: $domain_id = $_SESSION['beatnik']['curdomain']['id'];
279:
280: switch($info['rectype']) {
281: case 'soa':
282: if (empty($info['refresh'])) {
283:
284: $info['refresh'] = 86400;
285: }
286: if (empty($info['retry'])) {
287:
288: $info['retry'] = 7200;
289: }
290: if (empty($info['expire'])) {
291:
292: $info['expire'] = 3600000;
293: }
294: if (empty($info['minimum'])) {
295:
296: $info['miniumum'] = 172800;
297: }
298:
299: $name = $info['zonename'];
300: $type = 'SOA';
301: $content = $info['zonens'] . ' ' . $info['zonecontact'] . ' ' .
302: $info['serial'] . ' ' . $info['refresh'] . ' ' .
303: $info['retry'] . ' ' . $info['expire'] . ' ' .
304: $info['minimum'];
305: $ttl = $info['ttl'];
306: $prio = null;
307: break;
308:
309: case 'a':
310: $name = $info['hostname'];
311: $type = 'A';
312: $content = $info['ipaddr'];
313: $ttl = $info['ttl'];
314: $prio = null;
315: break;
316:
317: case 'ptr':
318: $name = $info['hostname'];
319: $type = 'PTR';
320: $content = $info['pointer'];
321: $ttl = $info['ttl'];
322: $prio = null;
323: break;
324:
325: case 'mx':
326: $name = $_SESSION['beatnik']['curdomain']['zonename'];
327: $type = 'MX';
328: $content = $info['pointer'];
329: $ttl = $info['ttl'];
330: $prio = $info['pref'];
331: break;
332:
333: case 'cname':
334: $name = $info['hostname'];
335: $type = 'CNAME';
336: $content = $info['pointer'];
337: $ttl = $info['ttl'];
338: $prio = null;
339: break;
340:
341: case 'ns':
342: $name = $info['hostname'];
343: $type = 'NS';
344: $content = $info['pointer'];
345: $ttl = $info['ttl'];
346: $prio = null;
347: break;
348:
349: case 'srv':
350: $name = $info['hostname'];
351: $type = 'SRV';
352: $content = $info['weight'] . ' ' . $info['port'] . ' ' .
353: $info['pointer'];
354: $ttl = $info['ttl'];
355: $prio = $info['priority'];
356: break;
357:
358: case 'txt':
359: $name = $info['hostname'];
360: $type = 'TXT';
361: $content = $info['text'];
362: $ttl = $info['ttl'];
363: $prio = null;
364: break;
365: }
366:
367: if (!empty($info['id'])) {
368: $query = 'UPDATE ' . $this->_params['records_table'] . ' SET ' .
369: 'name = ?, type = ?, content = ?, ttl = ?, ' .
370: 'prio = ' . (empty($prio) ? 'NULL' : $prio) . ', ' .
371: 'change_date = ? WHERE id = ?';
372: $values = array($name, $type, $content, $ttl);
373: if (!empty($prio)) {
374: $values[] = $prio;
375: }
376: $values[] = $change_date;
377: $values[] = $info['id'];
378: } else {
379: $query = 'INSERT INTO ' . $this->_params['records_table'] . ' ' .
380: '(domain_id, name, type, content, ttl, prio, ' .
381: 'change_date) VALUES (?, ?, ?, ?, ?, ' .
382: (empty($prio) ? 'NULL' : '?') . ', ?)';
383: $values = array($domain_id, $name, $type, $content, $ttl);
384: if (!empty($prio)) {
385: $values[] = $prio;
386: }
387: $values[] = $change_date;
388: }
389:
390: Horde::logMessage('SQL Query by Beatnik_Driver_pdnsgsql::_saveRecord(): ' . $query, 'DEBUG');
391: $result = $this->_write_db->query($query, $values);
392: if (is_a($result, 'PEAR_Error')) {
393: return $result;
394: }
395:
396: return true;
397: }
398:
399: 400: 401: 402: 403: 404: 405: 406: 407:
408: function _deleteRecord($data)
409: {
410: $this->_connect();
411:
412: throw new Beatnik_Exception(_("Not implemented."));
413: }
414:
415: 416: 417: 418: 419: 420: 421:
422: function _connect()
423: {
424: if ($this->_connected) {
425: return true;
426: }
427:
428: $this->_db = $GLOBALS['injector']->getInstance('Horde_Core_Factory_DbPear')->create('read', 'beatnik', 'storage');
429: $this->_write_db = $GLOBALS['injector']->getInstance('Horde_Core_Factory_DbPear')->create('rw', 'beatnik', 'storage');
430:
431: return true;
432: }
433:
434: 435: 436: 437: 438: 439: 440:
441: function _disconnect()
442: {
443: if ($this->_connected) {
444: $this->_connected = false;
445: $this->_db->disconnect();
446: $this->_write_db->disconnect();
447: }
448:
449: return true;
450: }
451:
452: }
453: