function is_ipv4_valid($ipv4_address, $ipv4_prefixlen = NULL)
{
    if (strpos($ipv4_address, '/') !== FALSE) {
        list($ipv4_address, $ipv4_prefixlen) = explode('/', $ipv4_address);
    }
    if (strpos($ipv4_prefixlen, '.')) {
        $ipv4_prefixlen = netmask2cidr($ipv4_prefixlen);
    }
    // False if prefix less or equal 0 and more 32
    if (is_numeric($ipv4_prefixlen) && ($ipv4_prefixlen < '0' || $ipv4_prefixlen > '32')) {
        return FALSE;
    }
    // False if invalid IPv4 syntax
    if (!Net_IPv4::validateIP($ipv4_address)) {
        return FALSE;
    }
    // False if 0.0.0.0
    if ($ipv4_address == '0.0.0.0') {
        return FALSE;
    }
    return TRUE;
}
Esempio n. 2
0
         </dl>';
     }
     echo "</a></li>";
 }
 /// SEARCH IP ADDRESSES
 list($addr, $mask) = explode('/', $queryString);
 $address_type = "ipv4";
 if (is_numeric(stripos($queryString, ':abcdef'))) {
     $address_type = 'ipv6';
 }
 switch ($address_type) {
     case 'ipv6':
         $ip_valid = Net_IPv6::checkIPv6($addr);
         break;
     case 'ipv4':
         $ip_valid = Net_IPv4::validateIP($addr);
         break;
 }
 #    if ($ip_valid)
 #    {
 #      // If address valid -> seek occurrence in network
 #      if (!$mask) { $mask = ($address_type === 'ipv4') ? '32' : '128'; }#
 #     } else {
 // If address not valid -> seek LIKE
 $where .= ' AND A.`ipv4_address` LIKE ?';
 $param[] = '%' . $addr . '%';
 #    }
 // FIXME no v6 yet.
 $query = 'SELECT * ';
 $query .= 'FROM `ipv4_addresses` AS A ';
 $query .= 'LEFT JOIN `ports` ON `A`.`port_id` = `ports`.`port_id` ';
 /**
  * Converts a dot-quad formmated IP address into a hexadecimal string
  */
 function atoh($addr)
 {
     if (!Net_IPv4::validateIP($addr)) {
         return FALSE;
     }
     $ap = explode(".", $addr);
     return sprintf("%02x%02x%02x%02x", $ap[0], $ap[1], $ap[2], $ap[3]);
 }
Esempio n. 4
0
    ini_set('error_reporting', E_ALL);
}
include "../includes/defaults.inc.php";
include "../config.php";
include_once "../includes/definitions.inc.php";
include "includes/functions.inc.php";
include "../includes/functions.inc.php";
include "includes/authenticate.inc.php";
if (!$_SESSION['authenticated']) {
    echo "unauthenticated";
    exit;
}
if ($_GET['query'] && $_GET['cmd']) {
    $host = $_GET['query'];
    $ip = '';
    if (Net_IPv4::validateIP($host)) {
        $ip = $host;
        $ip_version = 4;
    } elseif (Net_IPv6::checkIPv6($host)) {
        $ip = $host;
        $ip_version = 6;
    } else {
        $ip = gethostbyname($host);
        if ($ip && $ip != $host) {
            $ip_version = 4;
        } else {
            $ip = gethostbyname6($host, FALSE);
            if ($ip) {
                $ip_version = 6;
            }
        }
Esempio n. 5
0
include $config['install_dir'] . "/includes/common.inc.php";
$start = utime();
// Needs common.php
include $config['install_dir'] . "/includes/dbFacile.php";
include $config['install_dir'] . "/includes/rewrites.inc.php";
include $config['install_dir'] . "/includes/rrdtool.inc.php";
include $config['install_dir'] . "/includes/entities.inc.php";
include $config['html_dir'] . "/includes/functions.inc.php";
if (isset($config['allow_unauth_graphs']) && $config['allow_unauth_graphs']) {
    $auth = TRUE;
    // hardcode auth for all with config function
    print_debug('认证旁路 $config[\'allow_unauth_graphs\'].');
} elseif (isset($config['allow_unauth_graphs_cidr']) && count($config['allow_unauth_graphs_cidr'])) {
    foreach ($config['allow_unauth_graphs_cidr'] as $range) {
        list($net, $mask) = explode('/', trim($range));
        if (Net_IPv4::validateIP($net)) {
            // IPv4
            $mask = $mask != NULL ? $mask : '32';
            $range = $net . '/' . $mask;
            if ($mask >= 0 && $mask <= 32 && Net_IPv4::ipInNetwork($_SERVER['REMOTE_ADDR'], $range)) {
                $auth = TRUE;
                // hardcode authenticated for matched subnet
                print_debug("认证的CIDR匹配IPv4 {$range}.");
                break;
            }
        } elseif (Net_IPv6::checkIPv6($net)) {
            // IPv6
            $mask = $mask != NULL ? $mask : '128';
            $range = $net . '/' . $mask;
            if ($mask >= 0 && $mask <= 128 && Net_IPv6::isInNetmask($_SERVER['REMOTE_ADDR'], $range)) {
                $auth = TRUE;
 /**
  * convert an IP address into a hex value
  *
  * @param string $IP
  * @return string
  */
 protected function convertIpToHex($host)
 {
     if (!isset($host) || empty($host) || !is_string($host)) {
         static::raiseError(__METHOD__ . '(), $host parameter is invalid!');
         return false;
     }
     global $ms;
     $ipv4 = new Net_IPv4();
     $parsed = $ipv4->parseAddress($host);
     // if CIDR contains no netmask or was unparsable, we assume /32
     if (empty($parsed->netmask)) {
         $parsed->netmask = "255.255.255.255";
     }
     if (!$ipv4->validateIP($parsed->ip)) {
         $ms->throwError(_("Incorrect IP address! Can not convert it to hex!"));
     }
     if (!$ipv4->validateNetmask($parsed->netmask)) {
         $ms->throwError(_("Incorrect Netmask! Can not convert it to hex!"));
     }
     if (($hex_host = $ipv4->atoh($parsed->ip)) == false) {
         $ms->throwError(_("Failed to convert " . $parsed->ip . " to hex!"));
     }
     if (($hex_subnet = $ipv4->atoh($parsed->netmask)) == false) {
         $ms->throwError(_("Failed to convert " . $parsed->netmask . " to hex!"));
     }
     return array('ip' => $hex_host, 'netmask' => $hex_subnet);
 }
Esempio n. 7
0
/**
 * verify ip address /mask 10.10.10.10./24 - CIDR 
 *
 * if subnet == 0 we dont check if IP is subnet -> needed for ipCalc
 */
function verifyCidr($cidr, $issubnet = 1)
{
    /* split it to network and subnet */
    $temp = explode("/", $cidr);
    $network = $temp[0];
    $netmask = $temp[1];
    //if one part is missing die
    if (empty($network) || empty($netmask)) {
        $errors[] = _("Invalid CIDR format!");
    }
    /* Identify address type */
    $type = IdentifyAddress($network);
    /* IPv4 verification */
    if ($type == 'IPv4') {
        require_once 'PEAR/Net/IPv4.php';
        $Net_IPv4 = new Net_IPv4();
        if ($net = $Net_IPv4->parseAddress($cidr)) {
            //validate IP
            if (!$Net_IPv4->validateIP($net->ip)) {
                $errors[] = _("Invalid IP address!");
            } elseif ($net->network != $net->ip && $issubnet == 1) {
                $errors[] = _("IP address cannot be subnet! (Consider using") . " " . $net->network . ")";
            } elseif (!$Net_IPv4->validateNetmask($net->netmask)) {
                $errors[] = _('Invalid netmask') . ' ' . $net->netmask;
            }
        } else {
            $errors[] = _('Invalid CIDR format!');
        }
    } else {
        require_once 'PEAR/Net/IPv6.php';
        $Net_IPv6 = new Net_IPv6();
        //validate IPv6
        if (!$Net_IPv6->checkIPv6($cidr)) {
            $errors[] = _("Invalid IPv6 address!");
        } else {
            //validate subnet
            $subnet = $Net_IPv6->getNetmask($cidr);
            $subnet = $Net_IPv6->compress($subnet);
            //get subnet part
            $subnetParse = explode("/", $cidr);
            $subnetMask = $subnetParse[1];
            $subnetNet = $subnetParse[0];
            if ($subnetNet != $subnet && $issubnet == 1) {
                $errors[] = _("IP address cannot be subnet! (Consider using") . " " . $subnet . "/" . $subnetMask . ")";
            }
        }
    }
    /* return array of errors */
    return $errors;
}
Esempio n. 8
0
/**
 * Display IPv4/IPv6 addresses.
 *
 * Display pages with IP addresses from device Interfaces.
 *
 * @param array $vars
 * @return none
 *
 */
function print_addresses($vars)
{
    // With pagination? (display page numbers in header)
    $pagination = isset($vars['pagination']) && $vars['pagination'];
    pagination($vars, 0, TRUE);
    // Get default pagesize/pageno
    $pageno = $vars['pageno'];
    $pagesize = $vars['pagesize'];
    $start = $pagesize * $pageno - $pagesize;
    if (in_array($vars['search'], array('6', 'v6', 'ipv6')) || in_array($vars['view'], array('6', 'v6', 'ipv6'))) {
        $address_type = 'ipv6';
    } else {
        $address_type = 'ipv4';
    }
    $ip_array = array();
    $param = array();
    $where = ' WHERE 1 ';
    $param_netscaler = array();
    $where_netscaler = " WHERE `vsvr_ip` != '0.0.0.0' AND `vsvr_ip` != '' ";
    foreach ($vars as $var => $value) {
        if ($value != '') {
            switch ($var) {
                case 'device':
                case 'device_id':
                    $where .= generate_query_values($value, 'I.device_id');
                    $where_netscaler .= generate_query_values($value, 'N.device_id');
                    break;
                case 'interface':
                    $where .= generate_query_values($value, 'I.ifDescr', 'LIKE%');
                    break;
                case 'network':
                    list($net, $mask) = explode('/', $value);
                    if (is_numeric(stripos($net, ':abcdef'))) {
                        $address_type = 'ipv6';
                    }
                    $where .= generate_query_values($value, 'N.ip_network', 'LIKE%');
                    break;
                case 'address':
                    list($addr, $mask) = explode('/', $value);
                    if (is_numeric(stripos($addr, ':abcdef'))) {
                        $address_type = 'ipv6';
                    }
                    switch ($address_type) {
                        case 'ipv6':
                            $ip_valid = Net_IPv6::checkIPv6($addr);
                            break;
                        case 'ipv4':
                            $ip_valid = Net_IPv4::validateIP($addr);
                            break;
                    }
                    if ($ip_valid) {
                        // If address valid -> seek occurrence in network
                        if (!$mask) {
                            $mask = $address_type === 'ipv4' ? '32' : '128';
                        }
                        $where_netscaler .= generate_query_values($addr, 'N.vsvr_ip');
                    } else {
                        // If address not valid -> seek LIKE
                        $where .= generate_query_values($addr, 'A.ip_address', '%LIKE%');
                        $where_netscaler .= generate_query_values($addr, 'N.vsvr_ip', '%LIKE%');
                    }
                    break;
            }
        }
    }
    $query_device_permitted = generate_query_permitted(array('device'), array('device_table' => 'D'));
    $query_port_permitted = generate_query_permitted(array('port'), array('port_table' => 'I'));
    // Also search netscaler Vserver IPs
    $query_netscaler = 'FROM `netscaler_vservers` AS N ';
    $query_netscaler .= 'LEFT JOIN `devices` AS D ON N.`device_id` = D.`device_id` ';
    $query_netscaler .= $where_netscaler . $query_device_permitted;
    //$query_netscaler_count = 'SELECT COUNT(`vsvr_id`) ' . $query_netscaler;
    $query_netscaler = 'SELECT * ' . $query_netscaler;
    $query_netscaler .= ' ORDER BY N.`vsvr_ip`';
    // Override by address type
    if ($address_type == 'ipv6') {
        $query_netscaler = str_replace(array('vsvr_ip', '0.0.0.0'), array('vsvr_ipv6', '0:0:0:0:0:0:0:0'), $query_netscaler);
        //$query_netscaler_count = str_replace(array('vsvr_ip', '0.0.0.0'), array('vsvr_ipv6', '0:0:0:0:0:0:0:0'), $query_netscaler_count);
    }
    $entries = dbFetchRows($query_netscaler, $param_netscaler);
    // Rewrite netscaler addresses
    foreach ($entries as $entry) {
        $ip_address = $address_type == 'ipv4' ? $entry['vsvr_ip'] : $entry['vsvr_' . $address_type];
        $ip_network = $address_type == 'ipv4' ? $entry['vsvr_ip'] . '/32' : $entry['vsvr_' . $address_type] . '/128';
        $ip_array[] = array('type' => 'netscaler_vsvr', 'device_id' => $entry['device_id'], 'hostname' => $entry['hostname'], 'vsvr_id' => $entry['vsvr_id'], 'vsvr_label' => $entry['vsvr_label'], 'ifAlias' => 'Netscaler: ' . $entry['vsvr_type'] . '/' . $entry['vsvr_entitytype'], $address_type . '_address' => $ip_address, $address_type . '_network' => $ip_network);
    }
    //print_message($query_netscaler_count);
    $query = 'FROM `ip_addresses` AS A ';
    $query .= 'LEFT JOIN `ports`   AS I ON I.`port_id`   = A.`port_id` ';
    $query .= 'LEFT JOIN `devices` AS D ON I.`device_id` = D.`device_id` ';
    $query .= 'LEFT JOIN `ip_networks` AS N ON N.`ip_network_id` = A.`ip_network_id` ';
    $query .= $where . $query_port_permitted;
    //$query_count = 'SELECT COUNT(`ip_address_id`) ' . $query;
    $query = 'SELECT * ' . $query;
    $query .= ' ORDER BY A.`ip_address`';
    if ($ip_valid) {
        $pagination = FALSE;
    }
    // Override by address type
    $query = str_replace(array('ip_address', 'ip_network'), array($address_type . '_address', $address_type . '_network'), $query);
    //$query_count = str_replace(array('ip_address', 'ip_network'), array($address_type.'_address', $address_type.'_network'), $query_count);
    // Query addresses
    $entries = dbFetchRows($query, $param);
    $ip_array = array_merge($ip_array, $entries);
    $ip_array = array_sort($ip_array, $address_type . '_address');
    // Query address count
    //if ($pagination) { $count = dbFetchCell($query_count, $param); }
    if ($pagination) {
        $count = count($ip_array);
        $ip_array = array_slice($ip_array, $start, $pagesize);
    }
    $list = array('device' => FALSE);
    if (!isset($vars['device']) || empty($vars['device']) || $vars['page'] == 'search') {
        $list['device'] = TRUE;
    }
    $string = generate_box_open($vars['header']);
    $string .= '<table class="' . OBS_CLASS_TABLE_STRIPED . '">' . PHP_EOL;
    if (!$short) {
        $string .= '  <thead>' . PHP_EOL;
        $string .= '    <tr>' . PHP_EOL;
        if ($list['device']) {
            $string .= '      <th>Device</th>' . PHP_EOL;
        }
        $string .= '      <th>Interface</th>' . PHP_EOL;
        $string .= '      <th>Address</th>' . PHP_EOL;
        $string .= '      <th>Description</th>' . PHP_EOL;
        $string .= '    </tr>' . PHP_EOL;
        $string .= '  </thead>' . PHP_EOL;
    }
    $string .= '  <tbody>' . PHP_EOL;
    foreach ($ip_array as $entry) {
        $address_show = TRUE;
        if ($ip_valid) {
            // If address not in specified network, don't show entry.
            if ($address_type === 'ipv4') {
                $address_show = Net_IPv4::ipInNetwork($entry[$address_type . '_address'], $addr . '/' . $mask);
            } else {
                $address_show = Net_IPv6::isInNetmask($entry[$address_type . '_address'], $addr, $mask);
            }
        }
        if ($address_show) {
            list($prefix, $length) = explode('/', $entry[$address_type . '_network']);
            if (port_permitted($entry['port_id']) || $entry['type'] == 'netscaler_vsvr') {
                if ($entry['type'] == 'netscaler_vsvr') {
                    $entity_link = generate_entity_link($entry['type'], $entry);
                } else {
                    humanize_port($entry);
                    if ($entry['ifInErrors_delta'] > 0 || $entry['ifOutErrors_delta'] > 0) {
                        $port_error = generate_port_link($entry, '<span class="label label-important">Errors</span>', 'port_errors');
                    }
                    $entity_link = generate_port_link($entry, $entry['port_label_short']) . ' ' . $port_error;
                }
                $device_link = generate_device_link($entry);
                $string .= '  <tr>' . PHP_EOL;
                if ($list['device']) {
                    $string .= '    <td class="entity" style="white-space: nowrap">' . $device_link . '</td>' . PHP_EOL;
                }
                $string .= '    <td class="entity">' . $entity_link . '</td>' . PHP_EOL;
                if ($address_type === 'ipv6') {
                    $entry[$address_type . '_address'] = Net_IPv6::compress($entry[$address_type . '_address']);
                }
                $string .= '    <td>' . generate_popup_link('ip', $entry[$address_type . '_address'] . '/' . $length) . '</td>' . PHP_EOL;
                $string .= '    <td>' . $entry['ifAlias'] . '</td>' . PHP_EOL;
                $string .= '  </tr>' . PHP_EOL;
            }
        }
    }
    $string .= '  </tbody>' . PHP_EOL;
    $string .= '</table>';
    $string .= generate_box_close();
    // Print pagination header
    if ($pagination) {
        $string = pagination($vars, $count) . $string . pagination($vars, $count);
    }
    // Print addresses
    echo $string;
}
Esempio n. 9
0
 *
 * Requires PEAR GeoIP & IPv4
 * GeoLiteCity.dat needs to be in path
 *
 */
if (isset($_FILES["datafile"])) {
    $datafile = $_FILES["datafile"]["tmp_name"];
    require_once "Net/GeoIP.php";
    require_once 'Net/IPv4.php';
    $geoip = Net_GeoIP::getInstance("GeoLiteCity.dat");
    $iplist = array();
    $json = "";
    $file_handle = fopen($datafile, "r");
    while (!feof($file_handle)) {
        $line = fgets($file_handle);
        if (Net_IPv4::validateIP(trim($line))) {
            array_push($iplist, trim($line));
        }
    }
    fclose($file_handle);
    if (count($iplist) > 0) {
        $json = "{ 'items': " . count($iplist) . ", 'map_width': 0, 'map_length': 0, 'map_title': 'none', 'markers': [ ";
        $first = true;
        foreach ($iplist as $ip) {
            try {
                $data = $geoip->lookupLocation($ip);
                if (!$first) {
                    $json .= ", ";
                } else {
                    $first = false;
                }
/**
 * Display IPv4/IPv6 addresses.
 *
 * Display pages with IP addresses from device Interfaces.
 *
 * @param array $vars
 * @return none
 *
 */
function print_addresses($vars)
{
    // With pagination? (display page numbers in header)
    $pagination = isset($vars['pagination']) && $vars['pagination'];
    $pageno = isset($vars['pageno']) && !empty($vars['pageno']) ? $vars['pageno'] : 1;
    $pagesize = isset($vars['pagesize']) && !empty($vars['pagesize']) ? $vars['pagesize'] : 10;
    $start = $pagesize * $pageno - $pagesize;
    switch ($vars['search']) {
        case '6':
        case 'ipv6':
        case 'v6':
            $address_type = 'ipv6';
            break;
        default:
            $address_type = 'ipv4';
    }
    $param = array();
    $where = ' WHERE 1 ';
    foreach ($vars as $var => $value) {
        if ($value != '') {
            switch ($var) {
                case 'device':
                case 'device_id':
                    $where .= ' AND I.device_id = ?';
                    $param[] = $value;
                    break;
                case 'interface':
                    $where .= ' AND I.ifDescr LIKE ?';
                    $param[] = $value;
                    break;
                case 'network':
                    $where .= ' AND N.ip_network_id = ?';
                    $param[] = $value;
                    break;
                case 'address':
                    list($addr, $mask) = explode('/', $value);
                    if (is_numeric(stripos($addr, ':abcdef'))) {
                        $address_type = 'ipv6';
                    }
                    switch ($address_type) {
                        case 'ipv6':
                            $ip_valid = Net_IPv6::checkIPv6($addr);
                            break;
                        case 'ipv4':
                            $ip_valid = Net_IPv4::validateIP($addr);
                            break;
                    }
                    if ($ip_valid) {
                        // If address valid -> seek occurrence in network
                        if (!$mask) {
                            $mask = $address_type === 'ipv4' ? '32' : '128';
                        }
                    } else {
                        // If address not valid -> seek LIKE
                        $where .= ' AND A.ip_address LIKE ?';
                        $param[] = '%' . $addr . '%';
                    }
                    break;
            }
        }
    }
    if ($_SESSION['userlevel'] >= 5) {
        $query_perms = '';
        $query_user = '';
    } else {
        $query_perms = 'LEFT JOIN devices_perms AS P ON D.device_id = P.device_id ';
        $query_user = '******';
        $param[] = $_SESSION['user_id'];
    }
    // Don't show ignored and disabled devices
    $query_device = ' AND D.ignore = 0 ';
    if (!$config['web_show_disabled']) {
        $query_device .= 'AND D.disabled = 0 ';
    }
    $query = 'FROM `ip_addresses` AS A ';
    $query .= 'LEFT JOIN `ports`   AS I ON I.port_id   = A.port_id ';
    $query .= 'LEFT JOIN `devices` AS D ON I.device_id = D.device_id ';
    $query .= 'LEFT JOIN `ip_networks` AS N ON N.ip_network_id = A.ip_network_id ';
    $query .= $query_perms;
    $query .= $where . $query_device . $query_user;
    $query_count = 'SELECT COUNT(ip_address_id) ' . $query;
    $query = 'SELECT * ' . $query;
    $query .= ' ORDER BY A.ip_address';
    if ($ip_valid) {
        $pagination = FALSE;
    } else {
        $query .= " LIMIT {$start},{$pagesize}";
    }
    // Override by address type
    $query = str_replace(array('ip_address', 'ip_network'), array($address_type . '_address', $address_type . '_network'), $query);
    $query_count = str_replace(array('ip_address', 'ip_network'), array($address_type . '_address', $address_type . '_network'), $query_count);
    // Query addresses
    $entries = dbFetchRows($query, $param);
    // Query address count
    if ($pagination) {
        $count = dbFetchCell($query_count, $param);
    }
    $list = array('device' => FALSE);
    if (!isset($vars['device']) || empty($vars['device']) || $vars['page'] == 'search') {
        $list['device'] = TRUE;
    }
    $string = '<table class="table table-bordered table-striped table-hover table-condensed">' . PHP_EOL;
    if (!$short) {
        $string .= '  <thead>' . PHP_EOL;
        $string .= '    <tr>' . PHP_EOL;
        if ($list['device']) {
            $string .= '      <th>Device</th>' . PHP_EOL;
        }
        $string .= '      <th>Interface</th>' . PHP_EOL;
        $string .= '      <th>Address</th>' . PHP_EOL;
        $string .= '      <th>Description</th>' . PHP_EOL;
        $string .= '    </tr>' . PHP_EOL;
        $string .= '  </thead>' . PHP_EOL;
    }
    $string .= '  <tbody>' . PHP_EOL;
    foreach ($entries as $entry) {
        $address_show = TRUE;
        if ($ip_valid) {
            // If address not in specified network, don't show entry.
            if ($address_type === 'ipv4') {
                $address_show = Net_IPv4::ipInNetwork($entry[$address_type . '_address'], $addr . '/' . $mask);
            } else {
                $address_show = Net_IPv6::isInNetmask($entry[$address_type . '_address'], $addr, $mask);
            }
        }
        if ($address_show) {
            list($prefix, $length) = explode('/', $entry[$address_type . '_network']);
            if (port_permitted($entry['port_id'])) {
                humanize_port($entry);
                if ($entry['ifInErrors_delta'] > 0 || $entry['ifOutErrors_delta'] > 0) {
                    $port_error = generate_port_link($entry, '<span class="label label-important">Errors</span>', 'port_errors');
                }
                $string .= '  <tr>' . PHP_EOL;
                if ($list['device']) {
                    $string .= '    <td class="entity" nowrap>' . generate_device_link($entry) . '</td>' . PHP_EOL;
                }
                $string .= '    <td class="entity">' . generate_port_link($entry, makeshortif($entry['label'])) . ' ' . $port_error . '</td>' . PHP_EOL;
                if ($address_type === 'ipv6') {
                    $entry[$address_type . '_address'] = Net_IPv6::compress($entry[$address_type . '_address']);
                }
                $string .= '    <td>' . $entry[$address_type . '_address'] . '/' . $length . '</td>' . PHP_EOL;
                $string .= '    <td>' . $entry['ifAlias'] . '</td>' . PHP_EOL;
                $string .= '  </tr>' . PHP_EOL;
            }
        }
    }
    $string .= '  </tbody>' . PHP_EOL;
    $string .= '</table>';
    // Print pagination header
    if ($pagination) {
        echo pagination($vars, $count);
    }
    // Print addresses
    echo $string;
}