/**
  * Retrieves an existing DNS zone.
  *
  * If no identifier is specified and no body is supplied, all zones will be
  * retrieved without records.
  *
  * ### Response: ###
  *
  * ~~~
  * [
  *      {
  *            "name": <string>,
  *            "type": MASTER|SLAVE|NATIVE,
  *            "master": <ipv4 optional>,
  *            "last_check": <int optional>,
  *            "notified_serial": <int optional>
  *      },0..n
  * ]
  * ~~~
  *
  * If a query is specified in the URL,  all zones matching the given wildcard
  * are returned. The * wildcard is supported.
  *
  * If an identifier is specified, one zone will be retrieved with records.
  *
  * ### Response: ###
  *
  * ~~~
  * {
  *      "name": <string>,
  *      "type": MASTER|SLAVE|NATIVE,
  *      "master": <ipv4>,
  *      "last_check": <int>,
  *      "records": [ {
  *              "name": <string>,
  *              "type": <string>,
  *              "content": <string>,
  *              "ttl": <int optional>,
  *              "priority: <int optional>,
  *              "change_date": <int optional>
  *      },0..n ]
  * }
  * ~~~
  * 
  * ### Errors (request without identifier): ###
  *
  * * 508 - Invalid request, missing required parameters or input validation failed.
  * * 500 - Failed to connect to database or query execution error.
  *
  * ### Errors (request with identifier): ###
  *
  * * 508 - Invalid request, missing required parameters or input validation failed.
  * * 500 - Failed to connect to database or query execution error.
  * * 404 - Could not find zone.
  *
  * @access public
  * @param mixed $request Request parameters
  * @param string $identifier Zone identifier
  * @return Response DNS zone data if successful, error message otherwise.
  */
 public function get($request, $identifier = null)
 {
     $response = new FormattedResponse($request);
     $data = $request->parseData();
     if (empty($identifier)) {
         if ($data == null) {
             return ZoneFunctions::get_all_zones($response);
         } else {
             $validator = new ZoneValidator($data);
             if (!isset($data->query)) {
                 $response->code = Response::BADREQUEST;
                 $response->error = "Query was missing. Ensure that the body is in valid format and all required parameters are present.";
                 $response->error_detail = "BODY_MALFORMED";
                 return $response;
             }
             if (!$validator->validates()) {
                 $response->code = Response::BADREQUEST;
                 $response->error = $validator->getFormattedErrors();
                 $response->error_detail = $validator->getErrorDetails();
                 return $response;
             }
             return ZoneFunctions::query_zones($response, $data->query);
         }
     } else {
         $validator = new ZoneValidator();
         $validator->identifier = $identifier;
         if (!$validator->validates()) {
             $response->code = Response::BADREQUEST;
             $response->error = $validator->getFormattedErrors();
             $response->error_detail = $validator->getErrorDetails();
             return $response;
         }
         return ZoneFunctions::get_zone($response, $identifier);
     }
 }
 public function get_all_arpa($response, &$out = null, $query = null)
 {
     $zones = array();
     $filter_ranges = array();
     if (empty($query)) {
         ZoneFunctions::query_zones($response, "*.in-addr.arpa", $temp);
         if (!empty($temp)) {
             foreach ($temp as $t) {
                 $zones[] = $t['name'];
             }
         }
         ZoneFunctions::query_zones($response, "*.ip6.arpa", $temp);
         if (!empty($temp)) {
             foreach ($temp as $t) {
                 $zones[] = $t['name'];
             }
         }
     } else {
         $q = explode(",", $query);
         $singles = array();
         $singles6 = array();
         $ranges = array();
         foreach ($q as $s) {
             if (preg_match(VALID_IPV4_RANGE, $s)) {
                 $range = HelperFunctions::calc_ipv4_range($s);
                 if (!empty($singles)) {
                     for ($i = count($singles) - 1; $i >= 0; $i--) {
                         if (HelperFunctions::is_ipv4_in_range($range, $singles[$i])) {
                             unset($singles[$i]);
                         }
                     }
                 }
                 $ranges[] = $range;
                 continue;
             }
             if (preg_match(VALID_IPV4, $s)) {
                 if (!empty($ranges)) {
                     $in_range = false;
                     foreach ($ranges as $range) {
                         if (HelperFunctions::is_ipv4_in_range($range, $s)) {
                             $in_range = true;
                             break;
                         }
                     }
                     if (!$in_range) {
                         $singles[] = $s;
                     }
                 } else {
                     $singles[] = $s;
                 }
                 continue;
             }
             if (preg_match(VALID_IPV6_RANGE, $s)) {
                 $r = explode("/", $s, 2);
                 $s = $r[0];
             }
             if (preg_match(VALID_IPV6, $s)) {
                 if (!in_array($s, $singles6)) {
                     $singles6[] = $s;
                 }
                 continue;
             }
         }
         $output = array();
         $filter_singles = $singles;
         foreach ($ranges as $range) {
             $singles = array_merge($singles, HelperFunctions::expand_ipv4_range($range));
         }
         $singles = array_merge($singles, $singles6);
         foreach ($singles as $single) {
             $arpa = HelperFunctions::ip_to_arpa($single);
             $found = null;
             for ($i = 0; ($ret = HelperFunctions::truncate_arpa($arpa, $i)) !== false; $i++) {
                 if (in_array($ret, $zones) !== false) {
                     $found = true;
                     break;
                 }
                 $res = ZoneFunctions::get_zone($response, $ret, $out, false, false);
                 if ($res->code !== Response::NOTFOUND) {
                     $found = $ret;
                     break;
                 }
             }
             if ($found === true) {
                 continue;
             } elseif ($found) {
                 $zones[] = $found;
             } else {
                 $output[] = array("name" => $arpa, "ip" => $single, "reverse_dns" => null, "arpa_zone" => null);
                 $index = array_search($single, $filter_singles);
                 if ($index !== false) {
                     unset($filter_singles[$index]);
                 }
             }
         }
         $filter_ranges = $ranges;
     }
     foreach ($zones as $zone) {
         $records = null;
         ZoneFunctions::get_zone($response, $zone, $records);
         if (empty($records)) {
             continue;
         }
         foreach ($records['records'] as $record) {
             if ($record['type'] == "PTR") {
                 $ip = HelperFunctions::arpa_to_ip($record['name']);
                 $allowed = false;
                 if (!empty($filter_ranges) && strpos(":", $ip) === false) {
                     foreach ($filter_ranges as $filter) {
                         if (HelperFunctions::is_ipv4_in_range($filter, $ip)) {
                             $allowed = true;
                             break;
                         }
                     }
                 }
                 if (!$allowed && !empty($filter_singles) && in_array($ip, $filter_singles)) {
                     $allowed = true;
                     $index = array_search($ip, $filter_singles);
                     unset($filter_singles[$index]);
                 }
                 if (!$allowed) {
                     continue;
                 }
                 $output[] = array("name" => $record['name'], "ip" => HelperFunctions::arpa_to_ip($record['name']), "reverse_dns" => $record['content'], "arpa_zone" => $zone);
             }
         }
     }
     foreach ($filter_singles as $missing) {
         if (preg_match(VALID_IPV4, $missing)) {
             foreach ($zones as $zone) {
                 if (HelperFunctions::is_ipv4_in_range(HelperFunctions::calc_ipv4_range(HelperFunctions::arpa_to_ipv4_cidr($zone)), $missing)) {
                     $output[] = array("name" => HelperFunctions::ip_to_arpa($missing), "ip" => $missing, "reverse_dns" => null, "arpa_zone" => $zone);
                 }
             }
         }
     }
     if (empty($output)) {
         $response->code = Response::NOTFOUND;
         $response->error = "Could not find any records for given query.";
         $response->error_detail = "ARPA_NO_RECORDS";
         $out = false;
     } else {
         $response->code = Response::OK;
         $response->body = $output;
         $response->log_message = sprintf("Query returned %d Arpa records", count($output));
         $out = $output;
     }
     return $response;
 }