5 * @author Jan Altensen (Stricted)
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @copyright 2015-2016 Jan Altensen (Stricted)
22 private $lines = array();
36 private $soa = array();
39 * parsed resource records
43 private $records = array();
49 * param string $origin
51 public function __construct ($file, $origin = "") {
52 if (!empty($origin)) $this->origin
= $origin;
55 $file = preg_replace("/(\r\n)|(\r)/", "\n", $file);
58 $file = preg_replace_callback('/(\([^()]*\))/', function ($matches) {
59 $a = explode("\n", $matches[0]);
61 foreach ($a as $line) {
64 $line = preg_replace('/\s+/', ' ', $line);
67 $line = preg_replace('/(\s+)?(;|#)([\s\S]+)?/i', '', $line);
70 $line = implode("", $b);
72 return str_replace(array("( ", "(", " )", ")"), "", $line);
75 $this->lines
= explode("\n", $file);
78 * limit lines to 200, if more is needed we can change it
80 if (count($this->lines
) > 200) {
81 throw new \
Exception('zone file to big for parsing');
88 public function parse () {
89 foreach ($this->lines
as $line) {
91 $line = preg_replace('/\s+/', ' ', $line);
94 $line = preg_replace('/(\s+)?(;|#)([\s\S]+)?/i', '', $line);
96 /* ignore these lines */
97 if (empty($line)) continue;
98 if (strpos($line, "RRSIG") !== false) continue;
99 if (strpos($line, "NSEC") !== false) continue;
100 if (strpos($line, "DNSKEY") !== false) continue;
101 if (strpos($line, "SPF") !== false) continue;
103 $this->parseORIGIN($line);
104 $this->parseTTL($line);
106 if (strpos($line, "SOA") !== false) {
107 $this->parseSOA($line);
111 // parse all other records
112 $this->parseRR($line);
121 public function parseORIGIN ($line) {
122 if (preg_match('/\$ORIGIN ([*-a-z0-9.]+)/i', $line, $match)) {
124 if (empty($this->origin
)) {
125 $this->origin
= $origin;
128 if ($this->origin
!= $origin) {
129 throw new \
Exception('parse error');
140 public function parseTTL ($line) {
141 if (preg_match('/\$TTL ([0-9]+)([a-z]+)?/i', $line, $match)) {
142 if (isset($match[2])) {
143 $this->ttl
= $this->formatTime($match[1], $match[2]);
146 $this->ttl
= $match[1];
156 public function parseRR ($line) {
157 if (preg_match("/([*-a-z0-9.]+)? ([0-9]+)?(?: )?(IN)?(?: )?([a-z]+) ([\s\S]+)/i", $line, $matches)) {
160 if (!empty($this->origin
) && $matches[1] == "@") {
161 $record['name'] = $this->origin
;
164 if (empty($matches[1])) {
165 $record['name'] = $this->origin
;
168 $record['name'] = $matches[1];
173 if (empty($matches[2])) {
174 $record['ttl'] = $this->ttl
;
177 $record['ttl'] = $matches[2];
181 $record['type'] = $matches[4];
182 if ($matches[4] == 'MX' ||
$matches[4] == 'SRV' ||
$matches[4] == 'DS') {
183 $exp = explode(' ', $matches[5], 2);
184 $record['aux'] = $exp[0];
185 $record['data'] = $exp[1];
189 $record['data'] = $matches[5];
193 if (strpos($record['data'], "@") !== false && !empty($this->origin
)) {
194 $record['data'] = str_replace("@", $this->origin
, $record['data']);
197 $this->records
[] = $record;
206 public function parseSOA ($line) {
207 if (preg_match("/([@a-z0-9.-]+) ([0-9]+)?([a-z]+)?(?: )?(IN)?(?: )?(?:[a-z]+) ([-a-z0-9.]+) ([@-a-z0-9.]+) ([0-9a-]+) ([0-9]+)([a-z]+)? ([0-9]+)([a-z]+)? ([0-9]+)([a-z]+)? ([0-9]+)([a-z]+)?/i", $line, $matches)) {
209 if ($matches[1] == "@") {
210 if (empty($this->origin
)) {
211 throw new \
Exception('parse error');
215 if (empty($this->origin
)) {
216 if (empty($matches[1])) {
217 throw new \
Exception('parse error');
220 $this->origin
= $matches[1];
224 if ($this->origin
!= $matches[1]) {
225 throw new \
Exception('parse error');
230 $this->soa
['origin'] = $this->origin
;
231 $this->soa
['ns'] = $matches[5];
234 if (strpos($matches[6], "@") !== false) {
235 $this->soa
['mbox'] = str_replace("@", ".", $matches[6]);
238 $this->soa
['mbox'] = $matches[6];
241 $this->soa
['serial'] = $matches[7];
244 if (isset($matches[9]) && !empty($matches[9])) {
245 $this->soa
['refresh'] = $this->formatTime($matches[8], $matches[9]);
248 $this->soa
['refresh'] = $matches[8];
252 if (isset($matches[11]) && !empty($matches[11])) {
253 $this->soa
['retry'] = $this->formatTime($matches[10], $matches[11]);
256 $this->soa
['retry'] = $matches[10];
260 if (isset($matches[13]) && !empty($matches[13])) {
261 $this->soa
['expire'] = $this->formatTime($matches[12], $matches[13]);
264 $this->soa
['expire'] = $matches[12];
267 // parse minimum and ttl
268 if (isset($matches[3]) && !empty($matches[3]) && $matches[3] != "IN" && $matches[3] != "SO") {
269 $this->soa
['minimum'] = $this->formatTime($matches[2], $matches[3]);
270 $this->soa
['ttl'] = $this->formatTime($matches[2], $matches[3]);
273 if (!empty($matches[2])) {
274 $this->soa
['minimum'] = $matches[2];
275 $this->soa
['ttl'] = $matches[2];
276 $this->ttl
= $this->soa
['ttl'];
279 $this->soa
['minimum'] = $this->ttl
;
280 $this->soa
['ttl'] = $this->ttl
;
287 * returns the parsed zone file
291 public function getParsedData () {
292 return array('soa' => $this->soa
, 'rr' => $this->records
);
296 * format ttl to seconds
298 * @param integer $time
299 * @param string $modifier
302 public function formatTime ($time, $modifier = '') {
303 if (!empty($modifier)) {
307 $multiplier=86400*365;
332 return $time * $multiplier;