diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1bf37c7..54daf0c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Fixed
- Fix PDF export of tabs renamed in GLPI 11
+- Prevent PDF exports from failing when a network port has no instantiation type
+ or has multiple IP addresses.
+- Prevent software and software-version PDF exports from failing when an
+ installation has no associated user.
+- Use entity restriction criteria compatible with the GLPI query builder when
+ exporting software versions.
## [4.1.4] - 2026-07-30
diff --git a/inc/computer_softwareversion.class.php b/inc/computer_softwareversion.class.php
index 306ba5a..cff99a5 100644
--- a/inc/computer_softwareversion.class.php
+++ b/inc/computer_softwareversion.class.php
@@ -246,7 +246,6 @@ public static function pdfForItem(PluginPdfSimplePDF $pdf, CommonDBTM $item)
$tmp[] = $licname;
}
}
- $linkUser = User::canView();
$pdf->displayLine(
$data['version'],
$compname,
@@ -255,13 +254,14 @@ public static function pdfForItem(PluginPdfSimplePDF $pdf, CommonDBTM $item)
$data['location'],
$data['state'],
$data['groupe'],
- formatUserName(
- $data['userid'],
- $data['username'],
- $data['userrealname'],
- $data['userfirstname'],
- $linkUser ? 1 : 0,
- ),
+ ($data['userid'] === null
+ ? ''
+ : formatUserName(
+ (int) $data['userid'],
+ $data['username'],
+ $data['userrealname'],
+ $data['userfirstname'],
+ )),
implode(', ', $tmp),
Html::convDate($data['date_install']),
);
@@ -307,7 +307,10 @@ public static function pdfForVersionByEntity(PluginPdfSimplePDF $pdf, SoftwareVe
}
$sql = ['SELECT' => ['id', 'completename'],
'FROM' => 'glpi_entities',
- 'WHERE' => $dbu->getEntitiesRestrictRequest('glpi_entities'),
+ // getEntitiesRestrictRequest() returns a raw SQL string; feeding it to the
+ // array query builder produced "WHERE glpi_entities ( 1 )" and a MySQL
+ // error 1305. The criteria variant returns the array the builder expects.
+ 'WHERE' => $dbu->getEntitiesRestrictCriteria('glpi_entities'),
'ORDER' => 'completename'];
foreach ($DB->request($sql) as $ID => $data) {
diff --git a/inc/item_softwareversion.class.php b/inc/item_softwareversion.class.php
index a67b47c..54b0fc1 100644
--- a/inc/item_softwareversion.class.php
+++ b/inc/item_softwareversion.class.php
@@ -284,7 +284,6 @@ public static function pdfForSoftware(PluginPdfSimplePDF $pdf, CommonDBTM $item)
$tmp[] = $licname;
}
}
- $linkUser = User::canView();
$pdf->displayLine(
$data['version'],
$data['item_type'],
@@ -294,13 +293,14 @@ public static function pdfForSoftware(PluginPdfSimplePDF $pdf, CommonDBTM $item)
$data['location'],
$data['state'],
$data['groupe'],
- formatUserName(
- $data['userid'],
- $data['username'],
- $data['userrealname'],
- $data['userfirstname'],
- $linkUser ? 1 : 0,
- ),
+ ($data['userid'] === null
+ ? ''
+ : formatUserName(
+ (int) $data['userid'],
+ $data['username'],
+ $data['userrealname'],
+ $data['userfirstname'],
+ )),
implode(', ', $tmp),
);
}
@@ -342,7 +342,10 @@ public static function pdfForVersionByEntity(PluginPdfSimplePDF $pdf, SoftwareVe
}
$sql = ['SELECT' => ['id', 'completename'],
'FROM' => 'glpi_entities',
- 'WHERE' => $dbu->getEntitiesRestrictRequest('glpi_entities'),
+ // getEntitiesRestrictRequest() returns a raw SQL string; feeding it to the
+ // array query builder produced "WHERE glpi_entities ( 1 )" and a MySQL
+ // error 1305. The criteria variant returns the array the builder expects.
+ 'WHERE' => $dbu->getEntitiesRestrictCriteria('glpi_entities'),
'ORDER' => 'completename'];
foreach ($DB->request($sql) as $ID => $data) {
diff --git a/inc/networkport.class.php b/inc/networkport.class.php
index 1d5a0ee..9a96040 100644
--- a/inc/networkport.class.php
+++ b/inc/networkport.class.php
@@ -73,8 +73,15 @@ public static function pdfForItem(PluginPdfSimplePDF $pdf, CommonDBTM $item)
foreach ($result as $devid) {
$netport = new NetworkPort();
$netport->getfromDB(current($devid));
- $instantiation_type = $netport->fields['instantiation_type'];
- $instname = call_user_func([$instantiation_type, 'getTypeName']);
+ // Ports created by the inventory may carry no instantiation type at
+ // all; call_user_func(['', 'getTypeName']) then raised a TypeError and
+ // aborted the whole document.
+ $instantiation_type = $netport->fields['instantiation_type'] ?? '';
+ if (!empty($instantiation_type) && is_a($instantiation_type, CommonDBTM::class, true)) {
+ $instname = call_user_func([$instantiation_type, 'getTypeName']);
+ } else {
+ $instname = NetworkPort::getTypeName(1);
+ }
$pdf->displayTitle('' . $instname . '');
$pdf->displayLine('' . sprintf(
@@ -138,26 +145,35 @@ public static function pdfForItem(PluginPdfSimplePDF $pdf, CommonDBTM $item)
$netport->fields['mac'],
));
- $sqlip = ['LEFT JOIN' => ['glpi_networknames'
- => ['FKEY' => ['glpi_ipaddresses' => 'items_id',
- 'glpi_networknames' => 'id'],
- ['glpi_ipaddresses.entities_id'
- => $_SESSION['glpiactive_entity']]]],
- 'WHERE' => ['glpi_networknames.items_id' => $netport->fields['id']]];
-
- $ipname = '';
- $ip = new IPAddress();
- if ($ip->getFromDBByRequest($sqlip)) {
- $ipname = $ip->fields['name'];
-
- $pdf->displayLine('' . sprintf(__s('%1$s: %2$s'), __s('ip') . '', $ipname));
+ // A network port usually carries several addresses (IPv4 + IPv6).
+ // IPAddress::getFromDBByRequest() expects a single result and throws
+ // a TooManyResultsException as soon as there are two, which aborted
+ // the whole PDF. Iterate over every address instead.
+ $sqlip = ['SELECT' => ['glpi_ipaddresses.id AS id',
+ 'glpi_ipaddresses.name AS name'],
+ 'FROM' => 'glpi_ipaddresses',
+ 'LEFT JOIN' => ['glpi_networknames'
+ => ['FKEY' => ['glpi_ipaddresses' => 'items_id',
+ 'glpi_networknames' => 'id']]],
+ 'WHERE' => ['glpi_networknames.items_id' => $netport->fields['id'],
+ 'glpi_ipaddresses.itemtype' => 'NetworkName',
+ 'glpi_ipaddresses.is_deleted' => 0]
+ + $dbu->getEntitiesRestrictCriteria('glpi_ipaddresses'),
+ 'ORDER' => 'glpi_ipaddresses.name'];
+
+ foreach ($DB->request($sqlip) as $ipdata) {
+ $pdf->displayLine('' . sprintf(
+ __s('%1$s: %2$s'),
+ __s('ip') . '',
+ $ipdata['name'],
+ ));
$sql = ['SELECT' => 'glpi_ipaddresses_ipnetworks.ipnetworks_id',
'FROM' => 'glpi_ipaddresses_ipnetworks',
'LEFT JOIN' => ['glpi_ipnetworks'
=> ['FKEY' => ['glpi_ipaddresses_ipnetworks' => 'ipnetworks_id',
'glpi_ipnetworks' => 'id']]],
- 'WHERE' => ['glpi_ipaddresses_ipnetworks.ipaddresses_id' => $ip->getID()]
+ 'WHERE' => ['glpi_ipaddresses_ipnetworks.ipaddresses_id' => $ipdata['id']]
+ $dbu->getEntitiesRestrictCriteria('glpi_ipnetworks')];
$res = $DB->request($sql);