%PDF- %PDF-
Direktori : /var/www/projetos/suporte.iigd.com.br/src/ |
Current File : /var/www/projetos/suporte.iigd.com.br/src/IPAddress.php |
<?php /** * --------------------------------------------------------------------- * * GLPI - Gestionnaire Libre de Parc Informatique * * http://glpi-project.org * * @copyright 2015-2024 Teclib' and contributors. * @copyright 2003-2014 by the INDEPNET Development Team. * @licence https://www.gnu.org/licenses/gpl-3.0.html * * --------------------------------------------------------------------- * * LICENSE * * This file is part of GLPI. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * * --------------------------------------------------------------------- */ /** * Represent an IPv4 or an IPv6 address. Both textual (ie. human readable) * and binary (ie. : used for request) are present * @since 0.84 */ /** Class IPAddress : Represents an IPv4 or an IPv6 address. Both textual (ie. human readable) * and binary (ie. : used for SQL requests) are present inside the DB. * The class itself contains three protected attributes. If the address is valid, then, these * attributes are not empty. * This object is usefull for SQL research and binary<=>textual conversions. * @warning textual (ie. human readable) representation is not unique for IPv6 addresses : * 2001:db8:0:85a3\::ac1f:8001 = 2001:db8:0:85a3:0:0:ac1f:8001 * @warning All textual representation of IPv6 addresses conforms to RFC 5952 : they are * automatically converted by IPAddress::setAddressFromString(). * @since 0.84 **/ class IPAddress extends CommonDBChild { // From CommonDBChild public static $itemtype = 'itemtype'; public static $items_id = 'items_id'; public $dohistory = false; public $history_blacklist = ['binary_0', 'binary_1', 'binary_2', 'binary_3']; /// $version (integer) : version of the adresse. Should be 4 or 6, or empty if not valid address protected $version = ''; /// $this->textual (string) : human readable of the IP adress (for instance : 192.168.0.0, /// 2001:db8:0:85a3\::ac1f:8001) protected $textual = ''; /// $this->binary (bytes[4]) : binary version for the SQL requests. For IPv4 addresses, the /// first three bytes are set to [0, 0, 0xffff] protected $binary = [0, 0, 0, 0]; //to know is IPV4 is Dotted quoad Format protected $isDottedQuoadFormat = false; public static $rightname = 'internet'; ////////////////////////////////////////////////////////////////////////////// // CommonDBTM related methods ////////////////////////////////////////////////////////////////////////////// /** * @param IPAddress|string|integer[] $ipaddress (default '') **/ public function __construct($ipaddress = '') { // First, be sure that the parent is correctly initialised parent::__construct(); // If $ipaddress if empty, then, empty address ! if ($ipaddress != '') { // If $ipaddress if an IPAddress, then just clone it if ($ipaddress instanceof IPAddress) { $this->version = $ipaddress->version; $this->textual = $ipaddress->textual; $this->binary = $ipaddress->binary; $this->fields = $ipaddress->fields; } else { // Else, check a binary then a string if (!$this->setAddressFromBinary($ipaddress)) { $this->setAddressFromString($ipaddress); } } } } public static function getTypeName($nb = 0) { return _n('IP address', 'IP addresses', $nb); } /** * @param $input **/ public function prepareInput($input) { // If $input['name'] does not exists, then, don't check anything ! if (isset($input['name'])) { // WARNING: we must in every case, because, sometimes, fields are partially feels // If previous value differs from current one, then check it ! $this->setAddressFromString($input['name']); if (!$this->is_valid()) { if (isset($input['is_dynamic']) && $input['is_dynamic']) { // We allow invalid IPs that are dynamics ! $input['version'] = 0; $input['binary_0'] = 0; $input['binary_1'] = 0; $input['binary_2'] = 0; $input['binary_3'] = 0; return $input; } //TRANS: %s is the invalid address $msg = sprintf(__('%1$s: %2$s'), __('Invalid IP address'), $input['name']); Session::addMessageAfterRedirect($msg, false, ERROR); return false; } } if (isset($input['itemtype']) && isset($input['items_id'])) { $input['mainitemtype'] = 'NULL'; $input['mainitems_id'] = 0; if ($input['itemtype'] == 'NetworkName') { $name = new NetworkName(); if ($name->getFromDB($input['items_id'])) { if ($port = getItemForItemtype($name->getField('itemtype'))) { if ($port->getFromDB($name->getField('items_id'))) { if (isset($port->fields['itemtype']) && isset($port->fields['items_id'])) { $input['mainitemtype'] = $port->fields['itemtype']; $input['mainitems_id'] = $port->fields['items_id']; } } } } } } return array_merge($input, $this->setArrayFromAddress($input, "version", "name", "binary")); } public function prepareInputForAdd($input) { return parent::prepareInputForAdd($this->prepareInput($input)); } public function prepareInputForUpdate($input) { return parent::prepareInputForUpdate($this->prepareInput($input)); } public function post_addItem() { IPAddress_IPNetwork::addIPAddress($this); parent::post_addItem(); } public function post_updateItem($history = true) { if ( (isset($this->oldvalues['name'])) || (isset($this->oldvalues['entities_id'])) ) { $link = new IPAddress_IPNetwork(); $link->cleanDBonItemDelete($this->getType(), $this->getID()); $link->addIPAddress($this); } parent::post_updateItem($history); } public function cleanDBonPurge() { $this->deleteChildrenAndRelationsFromDb( [ IPAddress_IPNetwork::class, ] ); } public function post_getFromDB() { // Don't forget set local object from DB field $this->setAddressFromArray($this->fields, "version", "name", "binary"); } public static function showForItem(CommonGLPI $item, $withtemplate = 0) { /** @var array $CFG_GLPI */ global $CFG_GLPI; if ($item->getType() == 'IPNetwork') { if (isset($_GET["start"])) { $start = $_GET["start"]; } else { $start = 0; } if (!empty($_GET["order"])) { $table_options['order'] = $_GET["order"]; } else { $table_options['order'] = 'ip'; } $order_by_itemtype = ($table_options['order'] == 'itemtype'); $table_options['SQL_options'] = [ 'LIMIT' => $_SESSION['glpilist_limit'], 'START' => $start ]; $table = new HTMLTableMain(); $content = "<a href='javascript:reloadTab(\"order=ip\");'>" . self::getTypeName(Session::getPluralNumber()) . "</a>"; $internet_column = $table->addHeader('IP Address', $content); $content = sprintf( __('%1$s - %2$s'), _n('Item', 'Items', Session::getPluralNumber()), "<a href='javascript:reloadTab(\"order=itemtype\");'>" . __('Order by item type') . "</a>" ); $item_column = $table->addHeader('Item', $content); if ($order_by_itemtype) { foreach ($CFG_GLPI["networkport_types"] as $itemtype) { $table_options['group_' . $itemtype] = $table->createGroup( $itemtype, $itemtype::getTypeName(Session::getPluralNumber()) ); self::getHTMLTableHeader( $item->getType(), $table_options['group_' . $itemtype], $item_column, null, $table_options ); } } $table_options['group_None'] = $table->createGroup('Main', __('Other kind of items')); self::getHTMLTableHeader( $item->getType(), $table_options['group_None'], $item_column, null, $table_options ); self::getHTMLTableCellsForItem(null, $item, null, $table_options); if ($table->getNumberOfRows() > 0) { $count = self::countForItem($item); Html::printAjaxPager(self::getTypeName(Session::getPluralNumber()), $start, $count); Session::initNavigateListItems( __CLASS__, //TRANS : %1$s is the itemtype name, // %2$s is the name of the item (used for headings of a list) sprintf( __('%1$s = %2$s'), $item->getTypeName(1), $item->getName() ) ); $table->display(['display_title_for_each_group' => $order_by_itemtype, 'display_super_for_each_group' => false, 'display_tfoot' => false ]); Html::printAjaxPager(self::getTypeName(Session::getPluralNumber()), $start, $count); } else { echo "<table class='tab_cadre_fixe'>"; echo "<tr><th>" . __('No IP address found') . "</th></tr>"; echo "</table>"; } } } public static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { switch ($item->getType()) { case 'IPNetwork': self::showForItem($item, $withtemplate); break; } return true; } /** * @param $item CommonDBTM object **/ public static function countForItem(CommonDBTM $item) { /** @var \DBmysql $DB */ global $DB; switch ($item->getType()) { case 'IPNetwork': $result = $DB->request([ 'COUNT' => 'cpt', 'FROM' => 'glpi_ipaddresses_ipnetworks', 'WHERE' => [ 'ipnetworks_id' => $item->getID() ] ])->current(); return $result['cpt']; } } /** * @param $item CommonGLPI object * @param $withtemplate (default 0) * * @return string **/ public function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { if ( $item->getID() && $item->can($item->getField('id'), READ) ) { $nb = 0; if ($_SESSION['glpishow_count_on_tabs']) { $nb = self::countForItem($item); } return self::createTabEntry(self::getTypeName(Session::getPluralNumber()), $nb); } return ''; } ////////////////////////////////////////////////////////////////////////////// // IP address specific methods (check, transformation ...) ////////////////////////////////////////////////////////////////////////////// /** * Disable the address **/ public function disableAddress() { $this->version = ''; $this->textual = ''; $this->binary = ''; } /** * \brief Fill an array from the the local address object * Fill an array from the the local address object. Usefull for feeding $input variable for * preparing input to alter database. * If the field name is empty, then, the field is not set * If the object is not valid, then, version = 0, textual = "" and binary = (0, 0, 0, 0) * * @param array $array the array to Fill * @param string $versionField the name of the key inside $array that contains de IP version number * @param string $textualField the name of the key inside $array that contains de textual version * @param string $binaryField the name of the key inside $array that contains de binary. * Each element of the array is post-fixed by _i, with i the index * * @return array the array altered **/ public function setArrayFromAddress(array $array, $versionField, $textualField, $binaryField) { if (!empty($versionField)) { $version = $this->getVersion(); if ($version !== false) { $array[$versionField] = $version; } else { $array[$versionField] = "0"; } } if (!empty($textualField)) { $textual = $this->getTextual(); if ($textual !== false) { $array[$textualField] = $textual; } else { $array[$textualField] = ""; } } if (!empty($binaryField)) { $binary = $this->getBinary(); for ($i = 0; $i < 4; ++$i) { if ($binary !== false) { $array[$binaryField . "_" . $i] = $binary[$i]; } else { $array[$binaryField . "_" . $i] = '0'; } } } return $array; } /** * \brief Fill the local address object from an array * Fill the local address object from an array. Usefull for reading $input * * @param array $array the array to Fill * @param string $versionField the name of the key inside $array that contains de IP version number * @param string $textualField the name of the key inside $array that contains de textual version * @param string $binaryField the name of the key inside $array that contains de binary. * Each element of the array is post-fixed by _i, with i the index * * If the field name is empty, then, the field is not set * * @return boolean successfully defined **/ public function setAddressFromArray(array $array, $versionField, $textualField, $binaryField) { // First, we empty the fields to notify that this address is not valid $this->disableAddress(); if (!isset($array[$versionField])) { return false; } if (!isset($array[$textualField])) { return false; } if ( (!isset($array[$binaryField . "_0"]) || !is_numeric($array[$binaryField . "_0"])) || (!isset($array[$binaryField . "_1"]) || !is_numeric($array[$binaryField . "_0"])) || (!isset($array[$binaryField . "_2"]) || !is_numeric($array[$binaryField . "_0"])) || (!isset($array[$binaryField . "_3"]) || !is_numeric($array[$binaryField . "_0"])) ) { return false; } $this->version = $array[$versionField]; $this->textual = $array[$textualField]; $this->binary = []; $this->binary[0] = ($array[$binaryField . "_0"] + 0); $this->binary[1] = ($array[$binaryField . "_1"] + 0); $this->binary[2] = ($array[$binaryField . "_2"] + 0); $this->binary[3] = ($array[$binaryField . "_3"] + 0); return true; } /** * Check address validity **/ public function is_valid() { return (($this->version != '') && ($this->textual != '') && ($this->binary != '')); } public function getVersion() { if ($this->version != '') { return $this->version; } return false; } public function is_ipv4() { return ($this->getVersion() == 4); } public function is_ipv6() { return ($this->getVersion() == 6); } public function getTextual() { if ($this->textual != '') { return $this->textual; } return false; } public function getBinary() { if ($this->binary != '') { return $this->binary; } return false; } /** * Transform an IPv4 address to IPv6 * * @param integer|integer[] $address (bytes[4] or bytes) the address to transform. * * @return integer[]|false IPv6 mapped address **/ public static function getIPv4ToIPv6Address($address) { if (is_numeric($address)) { return [0, 0, 0xffff, $address]; } if ((is_array($address)) && (count($address) == 4)) { return self::getIPv4ToIPv6Address($address[3]); } return false; } /** * Check an address to see if it is IPv4 mapped to IPv6 address * * @param integer[] $address (bytes[4]) the address to check * * @return boolean **/ public static function isIPv4MappedToIPv6Address($address) { if (is_array($address) && (count($address) == 4)) { if (($address[0] == 0) && ($address[1] == 0) && ($address[2] == 0xffff)) { return true; } return false; } return false; } /** * Replace textual representation by its canonical form. * * @return void **/ public function canonicalizeTextual() { $this->setAddressFromBinary($this->getBinary()); } /** * \brief define an address from a string * Convert a textual address (string) to binary one. Opposite function that * setAddressFromBinary(). If item is valid ($itemtype not empty and $items_id > 0) then first * try to find it inside the database and load it from database. * \warning The resulting binary form is created inside the current object * * @param string $address textual (ie. human readable) address * @param string $itemtype type of the item this address has to be attached (default '') * @param integer $items_id id of the item this address has to be attached (default -1) * * @return boolean address is valid **/ public function setAddressFromString($address, $itemtype = "", $items_id = -1) { /** @var \DBmysql $DB */ global $DB; $this->disableAddress(); if (!is_string($address)) { return false; } $address = trim($address); if (empty($address)) { return false; } if ( !empty($itemtype) && ($items_id > 0) ) { $iterator = $DB->request([ 'SELECT' => 'id', 'FROM' => $this->getTable(), 'WHERE' => [ 'items_id' => $items_id, 'itemtype' => $itemtype, 'name' => $address ] ]); if (count($iterator) == 1) { $line = $iterator->current(); if ($this->getFromDB($line["id"])) { return true; } } } //if it IPV4 dotted-quoad format ::ffff:192.168.1.1 //remove ::ffff: to manage only IPV4 part //keep in memory that have a special format $this->isDottedQuoadFormat = false; if (preg_match("/^::ffff:(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/", $address, $regs)) { $address = substr($address, 7); $this->isDottedQuoadFormat = true; } $binary = null; $singletons = explode(".", $address); // First, check to see if it is an IPv4 address if (count($singletons) == 4) { $binary = 0; foreach ($singletons as $singleton) { if (!is_numeric($singleton)) { return false; } $singleton = intval($singleton); if (($singleton < 0) || ($singleton > 255)) { return false; } $binary *= 256; $binary += intval($singleton); } $binary = self::getIPv4ToIPv6Address($binary); } // Else, it should be an IPv6 address $singletons = explode(":", $address); // Minimum IPv6 address is "::". So, we check that there is at least 3 singletons in the array // And no more than 8 singletons if ((count($singletons) >= 3) && (count($singletons) <= 8)) { $empty_count = 0; foreach ($singletons as $singleton) { $singleton = trim($singleton); // First, we check that each singleton is 4 hexadecimal ! if (!preg_match("/^[0-9A-Fa-f]{0,4}$/", $singleton, $regs)) { return false; } if ($singleton === '') { $empty_count++; } } // EXTREMITY CHECKS : // If it starts with colon : the second one must be empty too (ie.: :2001 is not valid) $start_with_empty = ($singletons[0] === ''); if (($start_with_empty) && ($singletons[1] !== '')) { return false; } // If it ends with colon : the previous one must be empty too (ie.: 2001: is not valid) $end_with_empty = ($singletons[count($singletons) - 1] === ''); if (($end_with_empty) && ($singletons[count($singletons) - 2] !== '')) { return false; } // END OF EXTREMITY CHECKS // The number of empty singletons depends on the type of contraction switch ($empty_count) { case 0: // No empty singleton => no contraction at all // Thus, its side must be 8 ! if (count($singletons) != 8) { return false; } break; case 1: // One empty singleton : must be in the middle, otherwise EXTREMITY CHECKS // would return false break; case 2: // If there is two empty singletons then it must be at the beginning or the end if (!($start_with_empty xor $end_with_empty)) { return false; } // Thus remove one of both empty singletons. if ($start_with_empty) { unset($singletons[0]); } else { // $end_with_empty == true unset($singletons[count($singletons) - 1]); } break; case 3: // Only '::' allows three empty singletons ('::x::' = four empty singletons) if (!($start_with_empty and $end_with_empty)) { return false; } // Middle value must be '' otherwise EXTREMITY CHECKS returned an error if (count($singletons) != 3) { return false; } $singletons = ['']; break; default: return false; } // Here, we are sure that $singletons are valids and only contains 1 empty singleton that // will be convert to as many '0' as necessary to reach 8 singletons $numberEmpty = 9 - count($singletons); // = 8 - (count($singletons) - 1) $epanded = []; foreach ($singletons as $singleton) { if ($singleton === '') { $epanded = array_merge($epanded, array_fill(0, $numberEmpty, 0)); } else { $epanded[] = hexdec($singleton); } } $binary = []; for ($i = 0; $i < 4; $i++) { $binary[$i] = $epanded[2 * $i + 0] * 65536 + $epanded[2 * $i + 1]; } } // $binary is an array that is only defined for IPv4 or IPv6 address if ($binary !== null && $binary !== false) { // Calling setAddressFromBinary is usefull to recheck one more time inside // glpi_ipaddresses table and to make canonical textual version return $this->setAddressFromBinary($binary, $itemtype, $items_id); } // Else, it is not IPv4 nor IPv6 address return false; } /** * \brief define an address from a binary * Convert a binary address (bytes[4]) to textual one. Opposite function that * setAddressFromString(). If item is valid ($itemtype not empty and $items_id > 0) then first * try to find it inside the database and load it from database. textual version is condensed * one (ie : 2001:db8:0:85a3\::ac1f:8001 rather than 2001:0db8:0000:85a3:0000:0000:ac1f:8001) * \warning The resulting binary form is created inside the current object * * @param integer[] $address (bytes[4]) binary (ie. SQL requests) address * @param string $itemtype type of the item this address has to be attached (default '') * @param integer $items_id id of the item this address has to be attached (default -1) * * @return boolean address is valid **/ public function setAddressFromBinary($address, $itemtype = "", $items_id = -1) { /** @var \DBmysql $DB */ global $DB; $this->disableAddress(); if ((!is_array($address)) || (count($address) != 4)) { return false; } if ( !empty($itemtype) && ($items_id > 0) ) { $where = [ 'itemtype' => $itemtype, 'items_id' => $items_id ]; for ($i = 0; $i < 4; ++$i) { $where["binary_$i"] = $address[$i]; } $iterator = $DB->request([ 'SELECT' => 'id', 'FROM' => $this->getTable(), 'WHERE' => $where ]); if (count($iterator) == 1) { $line = $iterator->current(); if ($this->getFromDB($line["id"])) { return true; } } } $binary = []; $textual = []; $currentNull = ""; foreach ($address as $singleton) { if (!is_numeric($singleton)) { return false; } $singleton = (int)$singleton; $binary[] = $singleton; $singleton = str_pad(dechex($singleton), 8, "0", STR_PAD_LEFT); $elt = ltrim(substr($singleton, 0, 4), "0"); if (empty($elt)) { $textual[] = "0"; $currentNull .= "1"; } else { $currentNull .= "0"; $textual[] = $elt; } $elt = ltrim(substr($singleton, 4, 4), "0"); if (empty($elt)) { $textual[] = "0"; $currentNull .= "1"; } else { $currentNull .= "0"; $textual[] = $elt; } } if (count($binary) == 4) { if (self::isIPv4MappedToIPv6Address($binary)) { $this->version = 4; } else { $this->version = 6; } } else { return false; } $this->binary = $binary; if ($this->getVersion() == 4) { $hexValue = str_pad($textual[6], 4, "0", STR_PAD_LEFT) . str_pad( $textual[7], 4, "0", STR_PAD_LEFT ); $textual = []; for ($i = 0; $i < 4; $i++) { $textual[] = hexdec($hexValue[2 * $i + 0] . $hexValue[2 * $i + 1]); } $textual = implode('.', $textual); } else { foreach (["11111111", "1111111", "111111", "11111", "1111", "111", "11"] as $elt) { $pos = strpos($currentNull, $elt); if ($pos !== false) { $first = array_slice($textual, 0, $pos); if (count($first) == 0) { $first = [""]; } $second = array_slice($textual, $pos + strlen($elt)); if (count($second) == 0) { $second = [""]; } $textual = array_merge($first, [""], $second); break; } } $textual = implode(':', $textual); } $prefix = ""; //If it is a special format, add prefix previously removed (to manage IPV4 part) if ($this->isDottedQuoadFormat) { $prefix = "::ffff:"; } $this->textual = $prefix . $textual; return true; } /** * \brief add value to the address for iterator on addresses * * @param integer[] $address (in and out) the address to increment or decrement * @param integer $value the value to add or remove. Must be betwwen -0xffffffff and +0xffffffff * * @return boolean true if the increment is valid **/ public static function addValueToAddress(&$address, $value) { if ( !is_array($address) || (count($address) != 4) || !is_numeric($value) || ($value < -0xffffffff) || ($value > 0xffffffff) ) { return false; } for ($i = 3; $i >= 0; --$i) { $address[$i] += $value; if ($address[$i] < 0) { $address[$i] += (0x80000000 * 2); $value = -1; // For next value for right to left ... } else if ($address[$i] > 0xffffffff) { $address[$i] -= (0x80000000 * 2); $value = 1; // For next value for right to left ... } else { break; } } return true; } /** * \brief get absolute value of an integer * Convert a negative integer to positiv float. That is usefull as integer, in PHP are signed 32 * bits values. As such, they are limited from +2 147 483 647 to ???2 147 483 648. Thus, when * working on integer with bit-wise boolean operations (&, |, ^, ~), the sign of the operand * remain inside the result. That make problem as IP address are only positiv ones. * * @param integer $value the integer that we want the absolute value * * @return float value that is the absolute of $value * **/ public static function convertNegativeIntegerToPositiveFloat($value) { if (intval($value) && ($value < 0)) { $value = floatval($value) + floatval(0x80000000 * 2); } return $value; } /** * Search IP Addresses * * @param string $IPaddress the address to search * * @return array each value of the array (corresponding to one IPAddress) is an array of the * items from the master item to the IPAddress **/ public static function getItemsByIPAddress($IPaddress) { /** @var \DBmysql $DB */ global $DB; // We must resolv binary address : // 1??) we don't know if the IP address is valid // 2??) we don't know its version // 3??) binary request is more efficient than textual one (polymorphism of IPv6 addresses) $address = new self(); if (!$address->setAddressFromString($IPaddress)) { return []; } $criteria = [ 'SELECT' => 'gip.id', 'FROM' => 'glpi_ipaddresses AS gip', 'WHERE' => ['gip.version' => $address->version] ]; $startIndex = (($address->version == 4) ? 3 : 1); $binaryIP = $address->getBinary(); for ($i = $startIndex; $i < 4; ++$i) { $criteria['WHERE']["gip.binary_$i"] = $binaryIP[$i]; } $iterator = $DB->request($criteria); $addressesWithItems = []; foreach ($iterator as $result) { if ($address->getFromDB($result['id'])) { $addressesWithItems[] = array_merge( array_reverse($address->recursivelyGetItems()), [clone $address] ); } } return $addressesWithItems; } /** * Get an Object ID by its IP address (only if one result is found in the entity) * * @param string $value the ip address * @param integer $entity the entity to look for * * @return array containing the object ID * or an empty array is no value of serverals ID where found **/ public static function getUniqueItemByIPAddress($value, $entity) { $addressesWithItems = self::getItemsByIPAddress($value); // Filter : Do not keep ip not linked to asset if (count($addressesWithItems)) { foreach ($addressesWithItems as $key => $tab) { if ( isset($tab[0]) && (($tab[0] instanceof NetworkName) || ($tab[0] instanceof IPAddress) || ($tab[0] instanceof NetworkPort) || $tab[0]->isDeleted() || $tab[0]->isTemplate() || ($tab[0]->getEntityID() != $entity)) ) { unset($addressesWithItems[$key]); } } } if (count($addressesWithItems)) { // Get the first item that is matching entity foreach ($addressesWithItems as $items) { foreach ($items as $item) { if ($item->getEntityID() == $entity) { $result = ["id" => $item->getID(), "itemtype" => $item->getType() ]; unset($addressesWithItems); return $result; } } } } return []; } /** * Check if two addresses are equals * * @param IPAddress|string|integer[] $ipaddress the ip address to check with this * * @return boolean true if and only if both addresses are binary equals. **/ public function equals($ipaddress) { // To normalise the address, just make new one $ipaddress = new self($ipaddress); if ( !is_array($this->binary) || (count($this->binary) != 4) || (count($ipaddress->binary) != 4) || ($this->version != $ipaddress->version) ) { return false; } for ($index = 0; $index < 4; $index++) { if ($this->binary[$index] != $ipaddress->binary[$index]) { return false; } } return true; } /** * @param $itemtype * @param $base HTMLTableBase object * @param $super HTMLTableSuperHeader object (default NULL) * @param $father HTMLTableHeader object (default NULL) * @param $options array **/ public static function getHTMLTableHeader( $itemtype, HTMLTableBase $base, HTMLTableSuperHeader $super = null, HTMLTableHeader $father = null, array $options = [] ) { $column_name = __CLASS__; $content = self::getTypeName(); if ($itemtype == 'IPNetwork') { $base->addHeader('Item', _n('Item', 'Items', 1), $super, $father); $base->addHeader('NetworkPort', NetworkPort::getTypeName(0), $super, $father); $base->addHeader('NetworkName', NetworkName::getTypeName(1), $super, $father); $base->addHeader('Entity', Entity::getTypeName(1), $super, $father); } else { if (isset($options['dont_display'][$column_name])) { return; } if (isset($options['column_links'][$column_name])) { $content = "<a href='" . $options['column_links'][$column_name] . "'>$content</a>"; } $father = $base->addHeader($column_name, $content, $super, $father); if (isset($options['display_isDynamic']) && ($options['display_isDynamic'])) { $father = $base->addHeader( $column_name . '_dynamic', __('Automatic inventory'), $super, $father ); } IPNetwork::getHTMLTableHeader(__CLASS__, $base, $super, $father, $options); } } /** * @param $row HTMLTableRow object (default NULL) * @param $item CommonDBTM object (default NULL) * @param $father HTMLTableCell object (default NULL) * @param $options array **/ public static function getHTMLTableCellsForItem( HTMLTableRow $row = null, CommonDBTM $item = null, HTMLTableCell $father = null, array $options = [] ) { /** * @var array $CFG_GLPI * @var \DBmysql $DB */ global $CFG_GLPI, $DB; if ( ($item !== null) && ($item->getType() == 'IPNetwork') ) { $queries = []; $main_criteria = [ 'SELECT' => [ 'ADDR.binary_0 AS binary_0', 'ADDR.binary_1 AS binary_1', 'ADDR.binary_2 AS binary_2', 'ADDR.binary_3 AS binary_3', 'ADDR.name AS ip', 'ADDR.id AS id', 'ADDR.itemtype AS addr_item_type', 'ADDR.items_id AS addr_item_id', 'glpi_entities.completename AS entity', ], 'FROM' => 'glpi_ipaddresses_ipnetworks AS LINK', 'INNER JOIN' => [ 'glpi_ipaddresses AS ADDR' => [ 'ON' => [ 'ADDR' => 'id', 'LINK' => 'ipaddresses_id', [ 'AND' => [ 'ADDR.itemtype' => 'NetworkName', 'ADDR.is_deleted' => 0 ] ] ] ] ], 'LEFT JOIN' => [ 'glpi_entities' => [ 'ON' => [ 'ADDR' => 'entities_id', 'glpi_entities' => 'id' ] ] ], 'WHERE' => [ 'LINK.ipnetworks_id' => $item->getID(), ] ]; foreach ($CFG_GLPI["networkport_types"] as $itemtype) { $table = getTableForItemType($itemtype); $criteria = $main_criteria; $criteria['SELECT'] = array_merge($criteria['SELECT'], [ 'NAME.id AS name_id', 'PORT.id AS port_id', 'ITEM.id AS item_id', new \QueryExpression("'$itemtype' AS " . $DB->quoteName('item_type')) ]); $criteria['INNER JOIN'] = $criteria['INNER JOIN'] + [ 'glpi_networknames AS NAME' => [ 'ON' => [ 'NAME' => 'id', 'ADDR' => 'items_id', [ 'AND' => [ 'NAME.itemtype' => 'NetworkPort' ] ] ] ], 'glpi_networkports AS PORT' => [ 'ON' => [ 'NAME' => 'items_id', 'PORT' => 'id', [ 'AND' => [ 'PORT.itemtype' => $itemtype ] ] ] ], "$table AS ITEM" => [ 'ON' => [ 'ITEM' => 'id', 'PORT' => 'items_id' ] ] ]; $queries[] = $criteria; } $criteria = $main_criteria; $criteria['SELECT'] = array_merge($criteria['SELECT'], [ 'NAME.id AS name_id', 'PORT.id AS port_id', new \QueryExpression('NULL AS ' . $DB->quoteName('item_id')), new \QueryExpression("NULL AS " . $DB->quoteName('item_type')), ]); $criteria['INNER JOIN'] = $criteria['INNER JOIN'] + [ 'glpi_networknames AS NAME' => [ 'ON' => [ 'NAME' => 'id', 'ADDR' => 'items_id', [ 'AND' => [ 'NAME.itemtype' => 'NetworkPort' ] ] ] ], 'glpi_networkports AS PORT' => [ 'ON' => [ 'NAME' => 'items_id', 'PORT' => 'id', [ 'AND' => [ 'NOT' => [ 'PORT.itemtype' => $CFG_GLPI['networkport_types'] ] ] ] ] ] ]; $queries[] = $criteria; $criteria = $main_criteria; $criteria['SELECT'] = array_merge($criteria['SELECT'], [ 'NAME.id AS name_id', new \QueryExpression("NULL AS " . $DB->quoteName('port_id')), new \QueryExpression('NULL AS ' . $DB->quoteName('item_id')), new \QueryExpression("NULL AS " . $DB->quoteName('item_type')) ]); $criteria['INNER JOIN'] = $criteria['INNER JOIN'] + [ 'glpi_networknames AS NAME' => [ 'ON' => [ 'NAME' => 'id', 'ADDR' => 'items_id', [ 'AND' => [ 'NAME.itemtype' => ['!=', 'NetworkPort'] ] ] ] ] ]; $queries[] = $criteria; $criteria = $main_criteria; $criteria['SELECT'] = array_merge($criteria['SELECT'], [ new \QueryExpression("NULL AS name_id"), new \QueryExpression("NULL AS port_id"), new \QueryExpression('NULL AS item_id'), new \QueryExpression("NULL AS item_type") ]); $criteria['INNER JOIN']['glpi_ipaddresses AS ADDR']['ON'][0]['AND']['ADDR.itemtype'] = ['!=', 'NetworkName']; $queries[] = $criteria; $union = new \QueryUnion($queries); $criteria = [ 'FROM' => $union, ]; if ( ($options['order'] == 'ip') || ($options['order'] == 'itemtype') ) { $criteria['ORDERBY'] = [ 'binary_0', 'binary_1', 'binary_2', 'binary_3' ]; } if (isset($options['SQL_options'])) { $criteria = array_merge($criteria, $options['SQL_options']); } $iterator = $DB->request($criteria); $canedit = (isset($options['canedit']) && $options['canedit']); $options['createRow'] = false; $address = new self(); $ipaddress = new self(); $networkname = new NetworkName(); $networkport = new NetworkPort(); $item = null; foreach ($iterator as $line) { unset($row); if ( ($options['order'] == 'itemtype') && !empty($line['item_type']) ) { $row = $options['group_' . $line['item_type']]->createRow(); } if (!isset($row)) { $row = $options['group_None']->createRow(); } $ip_header = $row->getGroup()->getSuperHeaderByName('IP Address'); $item_header = $row->getGroup()->getHeaderByName('Item', 'Item'); $port_header = $row->getGroup()->getHeaderByName('Item', 'NetworkPort'); $name_header = $row->getGroup()->getHeaderByName('Item', 'NetworkName'); $entity_header = $row->getGroup()->getHeaderByName('Item', 'Entity'); $row->addCell($ip_header, $line['ip'], $father); if (!empty($line['name_id'])) { $networkname->getFromDB($line['name_id']); $row->addCell($name_header, $networkname->getLink(), $father); if (!empty($line['port_id'])) { $networkport->getFromDB($line['port_id']); $row->addCell($port_header, $networkport->getLink(), $father); if ((!empty($line['item_id'])) && (!empty($line['item_type']))) { $itemtype = $line['item_type']; $item = new $itemtype(); $item->getFromDB($line['item_id']); $row->addCell($item_header, $item->getLink(), $father); } } $row->addCell($entity_header, $line['entity'], $father); } else if ((!empty($line['addr_item_id'])) && (!empty($line['addr_item_type']))) { $itemtype = $line['addr_item_type']; $item = new $itemtype(); $item->getFromDB($line['addr_item_id']); if ($item instanceof CommonDBChild) { $items = $item->recursivelyGetItems(); $elements = [$item->getLink()]; foreach ($items as $item_) { $elements[] = $item_->getLink(); } $row->addCell($item_header, implode(' > ', $elements), $father); } else { $row->addCell($item_header, $item->getLink(), $father); } $row->addCell($entity_header, $line['entity'], $father); } } } else { if (isset($options['dont_display']['IPAddress'])) { return; } $header = $row->getGroup()->getHeaderByName('Internet', __CLASS__); if (!$header) { return; } if (empty($item)) { if (empty($father)) { return; } $item = $father->getItem(); } $iterator = $DB->request([ 'SELECT' => 'id', 'FROM' => self::getTable(), 'WHERE' => [ 'items_id' => $item->getID(), 'itemtype' => $item->getType(), 'is_deleted' => 0 ] ]); $canedit = (isset($options['canedit']) && $options['canedit']); $createRow = (isset($options['createRow']) && $options['createRow']); $options['createRow'] = false; $address = new self(); foreach ($iterator as $ipaddress) { if ($address->getFromDB($ipaddress['id'])) { if ($createRow) { $row = $row->createRow(); } $content = $address->fields['name']; $this_cell = $row->addCell($header, $content, $father); if (isset($options['display_isDynamic']) && ($options['display_isDynamic'])) { $dyn_header = $row->getGroup()->getHeaderByName('Internet', __CLASS__ . '_dynamic'); $this_cell = $row->addCell( $dyn_header, Dropdown::getYesNo($address->fields['is_dynamic']), $this_cell ); } IPNetwork::getHTMLTableCellsForItem($row, $address, $this_cell, $options); } } } } }