Files
site_for_glpi/glpi_api.php

388 lines
15 KiB
PHP

<?php
class GlpiApi {
private string $url;
private string $appToken;
private string $username;
private string $password;
private ?string $sessionToken = null;
public function __construct(string $url, string $appToken, string $username, string $password) {
$this->url = rtrim($url, '/');
$this->appToken = $appToken;
$this->username = $username;
$this->password = $password;
}
private function log(string $message) {
error_log('[GLPI API] ' . $message);
}
public function getSessionToken(): ?string {
return $this->sessionToken;
}
public function initSession(): bool {
$endpoint = $this->url . '/initSession';
$ch = curl_init($endpoint);
$auth = base64_encode($this->username . ':' . $this->password);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Authorization: Basic ' . $auth,
'Content-Type: application/json',
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
$data = json_decode($response, true);
$this->sessionToken = $data['session_token'] ?? null;
return true;
}
return false;
}
public function getItems(string $itemType, array $params = []): array {
if (!$this->sessionToken && !$this->initSession()) return [];
$endpoint = $this->url . '/' . $itemType;
if (!empty($params)) {
$endpoint .= '?' . http_build_query($params);
}
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
return json_decode($response, true) ?? [];
}
$this->log("getItems($itemType) HTTP $httpCode");
return [];
}
public function getItem(string $itemType, int $id): ?array {
if (!$this->sessionToken && !$this->initSession()) return null;
$endpoint = $this->url . '/' . $itemType . '/' . $id;
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
return json_decode($response, true);
}
$this->log("getItem($itemType/$id) HTTP $httpCode");
return null;
}
public function createTicket(array $ticketData): ?array {
if (!$this->sessionToken && !$this->initSession()) return null;
$endpoint = $this->url . '/Ticket';
$ch = curl_init($endpoint);
$payload = json_encode(['input' => $ticketData]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
'Content-Type: application/json',
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 201) {
return json_decode($response, true);
}
$this->log("createTicket HTTP $httpCode: " . substr($response, 0, 500));
return null;
}
public function getTicket(int $id): ?array {
if (!$this->sessionToken && !$this->initSession()) return null;
$endpoint = $this->url . '/Ticket/' . $id . '?expand_dropdowns=true';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
return json_decode($response, true);
}
$this->log("getTicket($id) HTTP $httpCode");
return null;
}
public function getTicketFollowups(int $ticketId): array {
if (!$this->sessionToken && !$this->initSession()) return [];
$endpoint = $this->url . '/Ticket/' . $ticketId . '/ITILFollowup?expand_dropdowns=true&range=0-100';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
return json_decode($response, true) ?? [];
}
$this->log("getTicketFollowups($ticketId) HTTP $httpCode");
return [];
}
public function getKnowbaseItems(int $start = 0, int $limit = 100): array {
if (!$this->sessionToken && !$this->initSession()) return [];
$params = ['range' => $start . '-' . ($start + $limit - 1), 'expand_dropdowns' => 'true'];
$endpoint = $this->url . '/KnowbaseItem?' . http_build_query($params);
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
return json_decode($response, true) ?? [];
}
return [];
}
public function getKnowbaseItem(int $id): ?array {
if (!$this->sessionToken && !$this->initSession()) return null;
$endpoint = $this->url . '/KnowbaseItem/' . $id . '?expand_dropdowns=true';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
return json_decode($response, true);
}
return null;
}
public function searchKnowbaseItems(string $query, int $limit = 30): array {
if (!$this->sessionToken && !$this->initSession()) return [];
$endpoint = $this->url . '/search/KnowbaseItem';
$criteria = [
'criteria' => [
['link' => 'OR', 'field' => 1, 'searchtype' => 'contains', 'value' => $query],
['link' => 'OR', 'field' => 2, 'searchtype' => 'contains', 'value' => $query]
],
'range' => "0-$limit",
'sort' => 2,
'order' => 'DESC'
];
$payload = json_encode($criteria);
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
'Content-Type: application/json',
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
$data = json_decode($response, true);
return $data['data'] ?? [];
}
$this->log("searchKnowbaseItems HTTP $httpCode");
return [];
}
public function searchKnowbaseItemsSince(string $since, int $limit = 1000): array {
if (!$this->sessionToken && !$this->initSession()) return [];
$endpoint = $this->url . '/search/KnowbaseItem';
$criteria = [
'criteria' => [
['field' => 15, 'searchtype' => 'morethan', 'value' => $since] // 15 = date_mod
],
'range' => "0-$limit",
'sort' => 15,
'order' => 'ASC'
];
$payload = json_encode($criteria);
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
'Content-Type: application/json',
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
$data = json_decode($response, true);
return $data['data'] ?? [];
}
$this->log("searchKnowbaseItemsSince HTTP $httpCode");
return [];
}
/**
* Получение документов, привязанных к статье базы знаний (улучшенная версия)
*/
public function getKnowbaseItemDocuments(int $kbItemId): array {
if (!$this->sessionToken && !$this->initSession()) return [];
$documents = [];
// Способ 1: через прямой фильтр Document
$params = [
'filter[itemtype]' => 'KnowbaseItem',
'filter[items_id]' => $kbItemId,
'range' => '0-100'
];
$endpoint = $this->url . '/Document?' . http_build_query($params);
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
$docs = json_decode($response, true);
if (is_array($docs) && count($docs) > 0) {
$this->log("Got " . count($docs) . " documents for KB $kbItemId via Document filter");
return $docs;
}
}
// Способ 2: через подресурс KnowbaseItem/{id}/Document
$endpoint = $this->url . '/KnowbaseItem/' . $kbItemId . '/Document?expand_dropdowns=true&range=0-100';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
$docs = json_decode($response, true);
if (is_array($docs) && count($docs) > 0) {
$this->log("Got " . count($docs) . " documents for KB $kbItemId via subresource");
return $docs;
}
}
// Способ 3: через Document_Item (если GLPI версии 10+)
$endpoint = $this->url . '/Document_Item?filter[itemtype]=KnowbaseItem&filter[items_id]=' . $kbItemId;
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 200) {
$links = json_decode($response, true);
if (is_array($links) && count($links) > 0) {
// Извлекаем ID документов
$docIds = array_column($links, 'documents_id');
if (!empty($docIds)) {
$ids = implode(',', $docIds);
$endpoint2 = $this->url . '/Document?filter[id]=' . $ids . '&range=0-100';
$ch2 = curl_init($endpoint2);
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch2, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$resp2 = curl_exec($ch2);
if (curl_getinfo($ch2, CURLINFO_HTTP_CODE) === 200) {
$docs = json_decode($resp2, true);
$this->log("Got " . count($docs) . " documents for KB $kbItemId via Document_Item");
return $docs;
}
}
}
}
$this->log("No documents found for KB $kbItemId (tried all methods)");
return [];
}
public function getDocumentContent(int $documentId): ?string {
if (!$this->sessionToken && !$this->initSession()) return null;
$endpoint = $this->url . '/Document/' . $documentId . '?download=true';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'App-Token: ' . $this->appToken,
'Session-Token: ' . $this->sessionToken,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode !== 200 || $response === false) {
$this->log("getDocumentContent($documentId) failed HTTP $httpCode");
return null;
}
$json = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
return $response;
}
if (isset($json['content'])) {
$data = base64_decode($json['content'], true);
if ($data !== false) {
return $data;
}
return $json['content'];
}
$this->log("getDocumentContent($documentId) returned unexpected JSON");
return null;
}
/**
* Получить имя компьютера по ID
*/
public function getComputerName(int $computerId): string {
$computer = $this->getItem('Computer', $computerId);
if ($computer) {
$name = $computer['name'] ?? '';
$serial = $computer['serial'] ?? $computer['otherserial'] ?? '';
if ($serial) {
return "$name (Инв.№ $serial)";
}
return $name;
}
return "Компьютер #$computerId";
}
/**
* Получить полное имя категории ITIL по ID
*/
public function getCategoryName(int $categoryId): string {
$category = $this->getItem('ITILCategory', $categoryId);
if ($category) {
return $category['completename'] ?? $category['name'] ?? "Категория #$categoryId";
}
return "Категория #$categoryId";
}
}