fix: corrige falsos positivos de IPs disponibles y actualiza versión a 1.7.1

- Se eliminó el parámetro `suspended=true` en las consultas a la API de UISP (/devices/ips) en `public.php` y `ApiHandlers.php`.
- Este parámetro causaba un error crítico donde la API excluía a los dispositivos activos de la red, devolviendo únicamente los dispositivos suspendidos. Como resultado, las IPs asignadas a clientes sanos (ej. segmento 54) se mostraban erróneamente como "disponibles".
- Se actualizó el manifest.json a la versión 1.7.1.
- Se actualizó el CHANGELOG.md y README.md reflejando la corrección del error y las fechas de lanzamiento.
This commit is contained in:
DANYDHSV 2026-05-04 13:03:54 -06:00
parent a8dd6a8f38
commit 695f327ccd
17 changed files with 2836 additions and 149 deletions

View File

@ -7,6 +7,37 @@ y este proyecto adhiere a [Semantic Versioning](https://semver.org/lang/es/).
--- ---
## [1.7.1] - 2026-05-04
### 🐛 Corregido
- **Falsos Positivos de IPs Disponibles**: Se eliminó el parámetro `suspended=true` en las consultas a la API de UISP (`/devices/ips`). Esto solucionó un error crítico donde los clientes activos eran excluidos de los resultados, lo que causaba que sus IPs asignadas (ej. segmento 54) se mostraran erróneamente como "disponibles". Ahora se muestran correctamente como "en uso".
## [1.7.0] - 2026-03-26
### ✨ Añadido
- **Detección de IPs Flotantes**: Nuevo sistema para identificar dispositivos con `authorized: false` (estado "Pending Adoption") que no eran detectados por `/devices/ips`.
- Método `obtenerIpsFlotantes()` en `IpSearchService.php`
- Campo `floating` en la respuesta JSON del backend
- Badge naranja "IP Flotante" con estado `⚠️ IP Flotante - {nombre} ({modelo})`
- Las IPs flotantes cuentan como "en uso" en las estadísticas
- **Workers Paralelos**: Sistema de pool de workers para validación concurrente de IPs.
- `runProgressiveValidation()` ahora usa 7 workers simultáneos (configurable)
- `runProgressiveVerification()` también usa 7 workers paralelos
- Progreso en tiempo real: `"Validando IP's... 45/100 procesadas, 8 disponibles"`
- Mejora de rendimiento de ~5-7x respecto a la versión secuencial
- **Inserción Ordenada**: Función `insertRowSorted()` que inserta IPs en la tabla manteniendo el orden por último octeto, sin importar qué worker termina primero.
### 🐛 Corregido
- **Numeración Consecutiva**: La columna `#` ahora muestra números consecutivos (1, 2, 3...) solo para filas visibles.
- Función `renumberVisibleRows()` recalcula la numeración al ocultar/mostrar IPs administrativas
- Corregido bug donde la numeración comenzaba en 49+ al ocultar filas admin
### 🔧 Mejorado
- **Rendimiento Frontend**: Búsqueda ~7x más rápida gracias a workers paralelos
- **Mensajes de progreso**: Actualizados para indicar modo paralelo y conteo de IPs procesadas
---
## [1.6.2] - 2025-12-09 ## [1.6.2] - 2025-12-09
### 🐛 Bug Fixes ### 🐛 Bug Fixes
@ -419,4 +450,4 @@ Este proyecto sigue [Semantic Versioning](https://semver.org/lang/es/):
--- ---
**Última actualización**: 26 de noviembre de 2025 **Última actualización**: 4 de mayo de 2026

View File

@ -1,6 +1,6 @@
# SIIP - Buscador de IP's Disponibles UISP # SIIP - Buscador de IP's Disponibles UISP
[![Version](https://img.shields.io/badge/version-1.6.2-blue.svg)](manifest.json) [![Version](https://img.shields.io/badge/version-1.7.1-blue.svg)](manifest.json)
[![UCRM](https://img.shields.io/badge/UCRM-Compatible-green.svg)](https://uisp.com/) [![UCRM](https://img.shields.io/badge/UCRM-Compatible-green.svg)](https://uisp.com/)
[![UNMS](https://img.shields.io/badge/UNMS-Compatible-green.svg)](https://uisp.com/) [![UNMS](https://img.shields.io/badge/UNMS-Compatible-green.svg)](https://uisp.com/)
@ -732,17 +732,14 @@ Los logs se guardan en:
Para ver el historial completo de cambios y versiones, consulta el archivo **[CHANGELOG.md](CHANGELOG.md)**. Para ver el historial completo de cambios y versiones, consulta el archivo **[CHANGELOG.md](CHANGELOG.md)**.
### Versión Actual: 1.2.0 (2025-11-26) ### Versión Actual: 1.7.1 (2026-05-04)
**Cambios destacados**: **Cambios destacados**:
- 🏓 Verificación por ping para detectar dispositivos no registrados - 🐛 Corrección de falsos positivos en búsqueda de IPs por parámetro `suspended=true`
- ⚡ Ping paralelo de hasta 30 IPs simultáneamente - 🔶 Detección de IPs flotantes (dispositivos no autorizados/pendiente de adopción)
- 🎛️ Control opcional vía configuración - ⚡ Workers paralelos (7x más rápido) con inserción ordenada por octeto
- 📊 Estadísticas detalladas de verificación - 🔢 Numeración consecutiva corregida en tabla de resultados
- ✨ API REST completa con endpoints `event.ip_request` y `event.ip_check` - 📊 Progreso en tiempo real durante la validación paralela
- 🔌 Soporte para webhooks y eventos personalizados
- 🎯 Filtrado automático de IPs administrativas
- 📚 Documentación completa con ejemplos en múltiples lenguajes
[Ver changelog completo →](CHANGELOG.md) [Ver changelog completo →](CHANGELOG.md)
@ -771,7 +768,7 @@ Para ver el historial completo de cambios y versiones, consulta el archivo **[CH
--- ---
**Versión 1.5.1** - Diciembre 2025 **Versión 1.7.1** - Mayo 2026
Desarrollado por [SIIP Internet](https://siip.mx) Desarrollado por [SIIP Internet](https://siip.mx)
--- ---
@ -783,5 +780,5 @@ Este plugin es propiedad de **SIIP Internet**. Todos los derechos reservados.
--- ---
**Versión**: 1.5.0 **Versión**: 1.7.1
**Última actualización**: 27 de noviembre de 2025 **Última actualización**: 4 de mayo de 2026

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"displayName": "SIIP - Buscador de IP's Disponibles UISP", "displayName": "SIIP - Buscador de IP's Disponibles UISP",
"description": "Este plugin permite buscar IP's disponibles en UISP (UNMS) y asignarlas a los clientes en UCRM. Evitando así la asignación de IP's duplicadas y mejorando la gestión de direcciones IP en la red.", "description": "Este plugin permite buscar IP's disponibles en UISP (UNMS) y asignarlas a los clientes en UCRM. Evitando así la asignación de IP's duplicadas y mejorando la gestión de direcciones IP en la red.",
"url": "https://siip.mx", "url": "https://siip.mx",
"version": "1.6.2", "version": "1.7.1",
"ucrmVersionCompliancy": { "ucrmVersionCompliancy": {
"min": "1.0.0", "min": "1.0.0",
"max": null "max": null

View File

@ -296,7 +296,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
// URL de la API de UISP - Usar HTTPS // URL de la API de UISP - Usar HTTPS
// URL de la API de UISP - Usar HTTPS // URL de la API de UISP - Usar HTTPS
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=true&management=true&includeObsolete=true"; $apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?management=true&includeObsolete=true";
$apiToken = $config['unmsApiToken']; $apiToken = $config['unmsApiToken'];
$log->appendLog("URL de API: $apiUrl"); $log->appendLog("URL de API: $apiUrl");
@ -3010,7 +3010,7 @@ if ($systemUserId) {
* Usa N workers concurrentes para validar IPs simultáneamente * Usa N workers concurrentes para validar IPs simultáneamente
*/ */
async function runProgressiveValidation(clientIps, pingLimit, shouldVerifyPing) { async function runProgressiveValidation(clientIps, pingLimit, shouldVerifyPing) {
const WORKER_COUNT = 5; const WORKER_COUNT = 7;
console.log(`Iniciando validación PARALELA de ${clientIps.length} IPs con ${WORKER_COUNT} workers`); console.log(`Iniciando validación PARALELA de ${clientIps.length} IPs con ${WORKER_COUNT} workers`);
console.log(`Ping habilitado: ${shouldVerifyPing}, Límite: ${pingLimit}`); console.log(`Ping habilitado: ${shouldVerifyPing}, Límite: ${pingLimit}`);
@ -3176,7 +3176,7 @@ if ($systemUserId) {
} }
async function runProgressiveVerification(clientIps, limit) { async function runProgressiveVerification(clientIps, limit) {
const WORKER_COUNT = 5; const WORKER_COUNT = 7;
let ipsToVerify = []; let ipsToVerify = [];
if (limit > 0) { if (limit > 0) {

BIN
siip-available-ips.zip Executable file → Normal file

Binary file not shown.

View File

@ -99,7 +99,7 @@ function handleIpRequest($data, $log) {
} }
// Buscar IPs // Buscar IPs
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=true&management=true&includeObsolete=true"; $apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?management=true&includeObsolete=true";
$apiToken = $config['unmsApiToken']; $apiToken = $config['unmsApiToken'];
$ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log, $config); $ipService = new \SiipAvailableIps\IpSearchService($apiUrl, $apiToken, $log, $config);
@ -203,7 +203,7 @@ function handleIpCheck($data, $log) {
return; return;
} }
$apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?suspended=true&management=true&includeObsolete=true"; $apiUrl = "https://{$config['ipserver']}/nms/api/v2.1/devices/ips?management=true&includeObsolete=true";
$apiToken = $config['unmsApiToken']; $apiToken = $config['unmsApiToken'];
// Verificar si se solicita ping // Verificar si se solicita ping

18
test_ips.php Normal file
View File

@ -0,0 +1,18 @@
<?php
$token = '393eb3d0-9b46-4a47-b9b4-473e4e24a89c';
$baseUrl = 'https://sistema.siip.mx/nms/api/v2.1/devices/ips';
function fetchIps($url, $token) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['x-auth-token: ' . $token]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$res = curl_exec($ch);
curl_close($ch);
$data = json_decode($res, true);
return count($data);
}
echo "With suspended=true: " . fetchIps($baseUrl . '?suspended=true&management=true&includeObsolete=true', $token) . "\n";
echo "Without suspended=true: " . fetchIps($baseUrl . '?management=true&includeObsolete=true', $token) . "\n";
echo "With suspended=false: " . fetchIps($baseUrl . '?suspended=false&management=true&includeObsolete=true', $token) . "\n";

18
vendor/autoload.php vendored
View File

@ -2,6 +2,24 @@
// autoload.php @generated by Composer // autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
trigger_error(
$err,
E_USER_ERROR
);
}
require_once __DIR__ . '/composer/autoload_real.php'; require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInita8750288fc198a75aec345f4f4b7fd12::getLoader(); return ComposerAutoloaderInita8750288fc198a75aec345f4f4b7fd12::getLoader();

View File

@ -42,35 +42,37 @@ namespace Composer\Autoload;
*/ */
class ClassLoader class ClassLoader
{ {
/** @var ?string */ /** @var \Closure(string):void */
private static $includeFile;
/** @var string|null */
private $vendorDir; private $vendorDir;
// PSR-4 // PSR-4
/** /**
* @var array[] * @var array<string, array<string, int>>
* @psalm-var array<string, array<string, int>>
*/ */
private $prefixLengthsPsr4 = array(); private $prefixLengthsPsr4 = array();
/** /**
* @var array[] * @var array<string, list<string>>
* @psalm-var array<string, array<int, string>>
*/ */
private $prefixDirsPsr4 = array(); private $prefixDirsPsr4 = array();
/** /**
* @var array[] * @var list<string>
* @psalm-var array<string, string>
*/ */
private $fallbackDirsPsr4 = array(); private $fallbackDirsPsr4 = array();
// PSR-0 // PSR-0
/** /**
* @var array[] * List of PSR-0 prefixes
* @psalm-var array<string, array<string, string[]>> *
* Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2')))
*
* @var array<string, array<string, list<string>>>
*/ */
private $prefixesPsr0 = array(); private $prefixesPsr0 = array();
/** /**
* @var array[] * @var list<string>
* @psalm-var array<string, string>
*/ */
private $fallbackDirsPsr0 = array(); private $fallbackDirsPsr0 = array();
@ -78,8 +80,7 @@ class ClassLoader
private $useIncludePath = false; private $useIncludePath = false;
/** /**
* @var string[] * @var array<string, string>
* @psalm-var array<string, string>
*/ */
private $classMap = array(); private $classMap = array();
@ -87,29 +88,29 @@ class ClassLoader
private $classMapAuthoritative = false; private $classMapAuthoritative = false;
/** /**
* @var bool[] * @var array<string, bool>
* @psalm-var array<string, bool>
*/ */
private $missingClasses = array(); private $missingClasses = array();
/** @var ?string */ /** @var string|null */
private $apcuPrefix; private $apcuPrefix;
/** /**
* @var self[] * @var array<string, self>
*/ */
private static $registeredLoaders = array(); private static $registeredLoaders = array();
/** /**
* @param ?string $vendorDir * @param string|null $vendorDir
*/ */
public function __construct($vendorDir = null) public function __construct($vendorDir = null)
{ {
$this->vendorDir = $vendorDir; $this->vendorDir = $vendorDir;
self::initializeIncludeClosure();
} }
/** /**
* @return string[] * @return array<string, list<string>>
*/ */
public function getPrefixes() public function getPrefixes()
{ {
@ -121,8 +122,7 @@ class ClassLoader
} }
/** /**
* @return array[] * @return array<string, list<string>>
* @psalm-return array<string, array<int, string>>
*/ */
public function getPrefixesPsr4() public function getPrefixesPsr4()
{ {
@ -130,8 +130,7 @@ class ClassLoader
} }
/** /**
* @return array[] * @return list<string>
* @psalm-return array<string, string>
*/ */
public function getFallbackDirs() public function getFallbackDirs()
{ {
@ -139,8 +138,7 @@ class ClassLoader
} }
/** /**
* @return array[] * @return list<string>
* @psalm-return array<string, string>
*/ */
public function getFallbackDirsPsr4() public function getFallbackDirsPsr4()
{ {
@ -148,8 +146,7 @@ class ClassLoader
} }
/** /**
* @return string[] Array of classname => path * @return array<string, string> Array of classname => path
* @psalm-return array<string, string>
*/ */
public function getClassMap() public function getClassMap()
{ {
@ -157,8 +154,7 @@ class ClassLoader
} }
/** /**
* @param string[] $classMap Class to filename map * @param array<string, string> $classMap Class to filename map
* @psalm-param array<string, string> $classMap
* *
* @return void * @return void
*/ */
@ -176,23 +172,24 @@ class ClassLoader
* appending or prepending to the ones previously set for this prefix. * appending or prepending to the ones previously set for this prefix.
* *
* @param string $prefix The prefix * @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 root directories * @param list<string>|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories * @param bool $prepend Whether to prepend the directories
* *
* @return void * @return void
*/ */
public function add($prefix, $paths, $prepend = false) public function add($prefix, $paths, $prepend = false)
{ {
$paths = (array) $paths;
if (!$prefix) { if (!$prefix) {
if ($prepend) { if ($prepend) {
$this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0 = array_merge(
(array) $paths, $paths,
$this->fallbackDirsPsr0 $this->fallbackDirsPsr0
); );
} else { } else {
$this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0, $this->fallbackDirsPsr0,
(array) $paths $paths
); );
} }
@ -201,19 +198,19 @@ class ClassLoader
$first = $prefix[0]; $first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) { if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths; $this->prefixesPsr0[$first][$prefix] = $paths;
return; return;
} }
if ($prepend) { if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths, $paths,
$this->prefixesPsr0[$first][$prefix] $this->prefixesPsr0[$first][$prefix]
); );
} else { } else {
$this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix], $this->prefixesPsr0[$first][$prefix],
(array) $paths $paths
); );
} }
} }
@ -223,7 +220,7 @@ class ClassLoader
* appending or prepending to the ones previously set for this namespace. * appending or prepending to the ones previously set for this namespace.
* *
* @param string $prefix The prefix/namespace, with trailing '\\' * @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories * @param list<string>|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories * @param bool $prepend Whether to prepend the directories
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
@ -232,17 +229,18 @@ class ClassLoader
*/ */
public function addPsr4($prefix, $paths, $prepend = false) public function addPsr4($prefix, $paths, $prepend = false)
{ {
$paths = (array) $paths;
if (!$prefix) { if (!$prefix) {
// Register directories for the root namespace. // Register directories for the root namespace.
if ($prepend) { if ($prepend) {
$this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4 = array_merge(
(array) $paths, $paths,
$this->fallbackDirsPsr4 $this->fallbackDirsPsr4
); );
} else { } else {
$this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4, $this->fallbackDirsPsr4,
(array) $paths $paths
); );
} }
} elseif (!isset($this->prefixDirsPsr4[$prefix])) { } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
@ -252,18 +250,18 @@ class ClassLoader
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
} }
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths; $this->prefixDirsPsr4[$prefix] = $paths;
} elseif ($prepend) { } elseif ($prepend) {
// Prepend directories for an already registered namespace. // Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths, $paths,
$this->prefixDirsPsr4[$prefix] $this->prefixDirsPsr4[$prefix]
); );
} else { } else {
// Append directories for an already registered namespace. // Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix], $this->prefixDirsPsr4[$prefix],
(array) $paths $paths
); );
} }
} }
@ -273,7 +271,7 @@ class ClassLoader
* replacing any others previously set for this prefix. * replacing any others previously set for this prefix.
* *
* @param string $prefix The prefix * @param string $prefix The prefix
* @param string[]|string $paths The PSR-0 base directories * @param list<string>|string $paths The PSR-0 base directories
* *
* @return void * @return void
*/ */
@ -291,7 +289,7 @@ class ClassLoader
* replacing any others previously set for this namespace. * replacing any others previously set for this namespace.
* *
* @param string $prefix The prefix/namespace, with trailing '\\' * @param string $prefix The prefix/namespace, with trailing '\\'
* @param string[]|string $paths The PSR-4 base directories * @param list<string>|string $paths The PSR-4 base directories
* *
* @throws \InvalidArgumentException * @throws \InvalidArgumentException
* *
@ -425,7 +423,8 @@ class ClassLoader
public function loadClass($class) public function loadClass($class)
{ {
if ($file = $this->findFile($class)) { if ($file = $this->findFile($class)) {
includeFile($file); $includeFile = self::$includeFile;
$includeFile($file);
return true; return true;
} }
@ -476,9 +475,9 @@ class ClassLoader
} }
/** /**
* Returns the currently registered loaders indexed by their corresponding vendor directories. * Returns the currently registered loaders keyed by their corresponding vendor directories.
* *
* @return self[] * @return array<string, self>
*/ */
public static function getRegisteredLoaders() public static function getRegisteredLoaders()
{ {
@ -555,6 +554,14 @@ class ClassLoader
return false; return false;
} }
/**
* @return void
*/
private static function initializeIncludeClosure()
{
if (self::$includeFile !== null) {
return;
} }
/** /**
@ -564,9 +571,9 @@ class ClassLoader
* *
* @param string $file * @param string $file
* @return void * @return void
* @private
*/ */
function includeFile($file) self::$includeFile = \Closure::bind(static function($file) {
{
include $file; include $file;
}, null, null);
}
} }

View File

@ -21,12 +21,14 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions * See also https://getcomposer.org/doc/07-runtime.md#installed-versions
* *
* To require its presence, you can require `composer-runtime-api ^2.0` * To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/ */
class InstalledVersions class InstalledVersions
{ {
/** /**
* @var mixed[]|null * @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/ */
private static $installed; private static $installed;
@ -37,7 +39,7 @@ class InstalledVersions
/** /**
* @var array[] * @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/ */
private static $installedByVendor = array(); private static $installedByVendor = array();
@ -96,7 +98,7 @@ class InstalledVersions
{ {
foreach (self::getInstalled() as $installed) { foreach (self::getInstalled() as $installed) {
if (isset($installed['versions'][$packageName])) { if (isset($installed['versions'][$packageName])) {
return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;
} }
} }
@ -117,7 +119,7 @@ class InstalledVersions
*/ */
public static function satisfies(VersionParser $parser, $packageName, $constraint) public static function satisfies(VersionParser $parser, $packageName, $constraint)
{ {
$constraint = $parser->parseConstraints($constraint); $constraint = $parser->parseConstraints((string) $constraint);
$provided = $parser->parseConstraints(self::getVersionRanges($packageName)); $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
return $provided->matches($constraint); return $provided->matches($constraint);
@ -241,7 +243,7 @@ class InstalledVersions
/** /**
* @return array * @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/ */
public static function getRootPackage() public static function getRootPackage()
{ {
@ -255,7 +257,7 @@ class InstalledVersions
* *
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[] * @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/ */
public static function getRawData() public static function getRawData()
{ {
@ -278,7 +280,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations * Returns the raw data of all installed.php which are currently loaded for custom implementations
* *
* @return array[] * @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/ */
public static function getAllRawData() public static function getAllRawData()
{ {
@ -301,7 +303,7 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set * @param array[] $data A vendor/composer/installed.php data set
* @return void * @return void
* *
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/ */
public static function reload($data) public static function reload($data)
{ {
@ -311,7 +313,7 @@ class InstalledVersions
/** /**
* @return array[] * @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/ */
private static function getInstalled() private static function getInstalled()
{ {
@ -326,7 +328,9 @@ class InstalledVersions
if (isset(self::$installedByVendor[$vendorDir])) { if (isset(self::$installedByVendor[$vendorDir])) {
$installed[] = self::$installedByVendor[$vendorDir]; $installed[] = self::$installedByVendor[$vendorDir];
} elseif (is_file($vendorDir.'/composer/installed.php')) { } elseif (is_file($vendorDir.'/composer/installed.php')) {
$installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require $vendorDir.'/composer/installed.php';
$installed[] = self::$installedByVendor[$vendorDir] = $required;
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
self::$installed = $installed[count($installed) - 1]; self::$installed = $installed[count($installed) - 1];
} }
@ -338,12 +342,17 @@ class InstalledVersions
// only require the installed.php file if this file is loaded from its dumped location, // only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
if (substr(__DIR__, -8, 1) !== 'C') { if (substr(__DIR__, -8, 1) !== 'C') {
self::$installed = require __DIR__ . '/installed.php'; /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
$required = require __DIR__ . '/installed.php';
self::$installed = $required;
} else { } else {
self::$installed = array(); self::$installed = array();
} }
} }
if (self::$installed !== array()) {
$installed[] = self::$installed; $installed[] = self::$installed;
}
return $installed; return $installed;
} }

View File

@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer // autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(

View File

@ -2,7 +2,7 @@
// autoload_files.php @generated by Composer // autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(

View File

@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer // autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(

View File

@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer // autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__)); $vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir); $baseDir = dirname($vendorDir);
return array( return array(

View File

@ -25,47 +25,27 @@ class ComposerAutoloaderInita8750288fc198a75aec345f4f4b7fd12
require __DIR__ . '/platform_check.php'; require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInita8750288fc198a75aec345f4f4b7fd12', 'loadClassLoader'), true, true); spl_autoload_register(array('ComposerAutoloaderInita8750288fc198a75aec345f4f4b7fd12', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInita8750288fc198a75aec345f4f4b7fd12', 'loadClassLoader')); spl_autoload_unregister(array('ComposerAutoloaderInita8750288fc198a75aec345f4f4b7fd12', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require __DIR__ . '/autoload_static.php'; require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInita8750288fc198a75aec345f4f4b7fd12::getInitializer($loader)); call_user_func(\Composer\Autoload\ComposerStaticInita8750288fc198a75aec345f4f4b7fd12::getInitializer($loader));
} else {
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->setClassMapAuthoritative(true); $loader->setClassMapAuthoritative(true);
$loader->register(true); $loader->register(true);
if ($useStaticLoader) { $filesToLoad = \Composer\Autoload\ComposerStaticInita8750288fc198a75aec345f4f4b7fd12::$files;
$includeFiles = Composer\Autoload\ComposerStaticInita8750288fc198a75aec345f4f4b7fd12::$files; $requireFile = \Closure::bind(static function ($fileIdentifier, $file) {
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequirea8750288fc198a75aec345f4f4b7fd12($fileIdentifier, $file);
}
return $loader;
}
}
/**
* @param string $fileIdentifier
* @param string $file
* @return void
*/
function composerRequirea8750288fc198a75aec345f4f4b7fd12($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
require $file; require $file;
} }
}, null, null);
foreach ($filesToLoad as $fileIdentifier => $file) {
$requireFile($fileIdentifier, $file);
}
return $loader;
}
} }

View File

@ -1,58 +1,58 @@
<?php return array( <?php return array(
'root' => array( 'root' => array(
'name' => '__root__',
'pretty_version' => 'dev-main', 'pretty_version' => 'dev-main',
'version' => 'dev-main', 'version' => 'dev-main',
'reference' => 'a8dd6a8f38f63db29b864b5e3efb3a6a73048c90',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => '647bdfc6ae27ce6b2e5a3dec02067293bfa5359e',
'name' => '__root__',
'dev' => false, 'dev' => false,
), ),
'versions' => array( 'versions' => array(
'__root__' => array( '__root__' => array(
'pretty_version' => 'dev-main', 'pretty_version' => 'dev-main',
'version' => 'dev-main', 'version' => 'dev-main',
'reference' => 'a8dd6a8f38f63db29b864b5e3efb3a6a73048c90',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../../', 'install_path' => __DIR__ . '/../../',
'aliases' => array(), 'aliases' => array(),
'reference' => '647bdfc6ae27ce6b2e5a3dec02067293bfa5359e',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/guzzle' => array( 'guzzlehttp/guzzle' => array(
'pretty_version' => '7.9.3', 'pretty_version' => '7.9.3',
'version' => '7.9.3.0', 'version' => '7.9.3.0',
'reference' => '7b2f29fe81dc4da0ca0ea7d42107a0845946ea77',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle', 'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(), 'aliases' => array(),
'reference' => '7b2f29fe81dc4da0ca0ea7d42107a0845946ea77',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/promises' => array( 'guzzlehttp/promises' => array(
'pretty_version' => '2.2.0', 'pretty_version' => '2.2.0',
'version' => '2.2.0.0', 'version' => '2.2.0.0',
'reference' => '7c69f28996b0a6920945dd20b3857e499d9ca96c',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises', 'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(), 'aliases' => array(),
'reference' => '7c69f28996b0a6920945dd20b3857e499d9ca96c',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'guzzlehttp/psr7' => array( 'guzzlehttp/psr7' => array(
'pretty_version' => '2.7.1', 'pretty_version' => '2.7.1',
'version' => '2.7.1.0', 'version' => '2.7.1.0',
'reference' => 'c2270caaabe631b3b44c85f99e5a04bbb8060d16',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(), 'aliases' => array(),
'reference' => 'c2270caaabe631b3b44c85f99e5a04bbb8060d16',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/http-client' => array( 'psr/http-client' => array(
'pretty_version' => '1.0.3', 'pretty_version' => '1.0.3',
'version' => '1.0.3.0', 'version' => '1.0.3.0',
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-client', 'install_path' => __DIR__ . '/../psr/http-client',
'aliases' => array(), 'aliases' => array(),
'reference' => 'bb5906edc1c324c9a05aa0873d40117941e5fa90',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/http-client-implementation' => array( 'psr/http-client-implementation' => array(
@ -64,10 +64,10 @@
'psr/http-factory' => array( 'psr/http-factory' => array(
'pretty_version' => '1.1.0', 'pretty_version' => '1.1.0',
'version' => '1.1.0.0', 'version' => '1.1.0.0',
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-factory', 'install_path' => __DIR__ . '/../psr/http-factory',
'aliases' => array(), 'aliases' => array(),
'reference' => '2b4765fddfe3b508ac62f829e852b1501d3f6e8a',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/http-factory-implementation' => array( 'psr/http-factory-implementation' => array(
@ -79,10 +79,10 @@
'psr/http-message' => array( 'psr/http-message' => array(
'pretty_version' => '2.0', 'pretty_version' => '2.0',
'version' => '2.0.0.0', 'version' => '2.0.0.0',
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message', 'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(), 'aliases' => array(),
'reference' => '402d35bcb92c70c026d1a6a9883f06b2ead23d71',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'psr/http-message-implementation' => array( 'psr/http-message-implementation' => array(
@ -94,55 +94,55 @@
'ralouphie/getallheaders' => array( 'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3', 'pretty_version' => '3.0.3',
'version' => '3.0.3.0', 'version' => '3.0.3.0',
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders', 'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(), 'aliases' => array(),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/deprecation-contracts' => array( 'symfony/deprecation-contracts' => array(
'pretty_version' => 'v3.5.1', 'pretty_version' => 'v3.5.1',
'version' => '3.5.1.0', 'version' => '3.5.1.0',
'reference' => '74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts',
'aliases' => array(), 'aliases' => array(),
'reference' => '74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/filesystem' => array( 'symfony/filesystem' => array(
'pretty_version' => 'v6.4.13', 'pretty_version' => 'v6.4.13',
'version' => '6.4.13.0', 'version' => '6.4.13.0',
'reference' => '4856c9cf585d5a0313d8d35afd681a526f038dd3',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/filesystem', 'install_path' => __DIR__ . '/../symfony/filesystem',
'aliases' => array(), 'aliases' => array(),
'reference' => '4856c9cf585d5a0313d8d35afd681a526f038dd3',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-ctype' => array( 'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.32.0', 'pretty_version' => 'v1.32.0',
'version' => '1.32.0.0', 'version' => '1.32.0.0',
'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(), 'aliases' => array(),
'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'symfony/polyfill-mbstring' => array( 'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.32.0', 'pretty_version' => 'v1.32.0',
'version' => '1.32.0.0', 'version' => '1.32.0.0',
'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(), 'aliases' => array(),
'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
'ubnt/ucrm-plugin-sdk' => array( 'ubnt/ucrm-plugin-sdk' => array(
'pretty_version' => '0.9.0', 'pretty_version' => '0.9.0',
'version' => '0.9.0.0', 'version' => '0.9.0.0',
'reference' => '02ca1d4ce7fca1bc7f49ef0259a03d0bfedec19f',
'type' => 'library', 'type' => 'library',
'install_path' => __DIR__ . '/../ubnt/ucrm-plugin-sdk', 'install_path' => __DIR__ . '/../ubnt/ucrm-plugin-sdk',
'aliases' => array(), 'aliases' => array(),
'reference' => '02ca1d4ce7fca1bc7f49ef0259a03d0bfedec19f',
'dev_requirement' => false, 'dev_requirement' => false,
), ),
), ),