Feat(Plugin): Implementación Microservicio PDF, Integración MinIO, Fix Recorte y Overlay de Pagos
Descripción: Se ha realizado una refactorización mayor del sistema de notificaciones y generación de comprobantes para eliminar dependencias legacy (Imagick/FTP) y modernizar la arquitectura. 🚀 Nuevas Características (Features) Microservicio PDF (pdf-cropper): Nuevo servicio en Python (FastAPI + Poppler) desplegado en Docker (Puerto 8050) para la conversión de PDF a Imagen. Reemplaza la librería Imagick de PHP, aislando el procesamiento pesado fuera del plugin. Modo Full: Garantiza la conversión del PDF completo respetando su relación de aspecto original (sin recortes ni "square crop"). Overlay de Texto: Capacidad nativa en el backend para sobreescribir texto dinámicamente (ej. cambiar "Tarjeta de crédito Stripe" por "OXXO Pay") basado en parámetros. Integración S3 / MinIO: Implementación de MinioStorageService . Los comprobantes (JPG) y Vouchers OXXO se suben automáticamente a MinIO en lugar de usar FTP. Generación de URLs públicas seguras. 🧹 Mantenimiento y Limpieza (Chores/Refactor) Limpieza Automática (Cleanup): Se implementó lógica para eliminar archivos temporales locales (PDFs descargados, JPGs generados) inmediatamente después de una subida exitosa a MinIO. Aplica tanto para comprobantes de pago como para Vouchers OXXO. Refactor ClientCallBellAPI : Eliminación de código muerto relacionado con FTP de WordPress. Implementación de cliente HTTP Guzzle para comunicación con pdf-cropper. Cache Busting: Se añade Timestamp al nombre de archivo (_time()) para evitar caché agresivo en WhatsApp/Navegadores. Detección de Método: Lógica preliminar para detectar "OXXO" o "Transferencia" en notas de pago y aplicar Overlay. Docker Infraestructura: Actualización de docker-compose.yml para incluir pdf-cropper. Instalación de fuentes (fonts-dejavu-core) para renderizado correcto de texto. 🐛 Correcciones (Bug Fixes) Fix Recorte de Imagen: Se eliminó la restricción de relación de aspecto 1:1 (cuadrado) que cortaba headers y footers en documentos rectangulares. Standardización de Notas: Actualización de AbstractStripeOperationsFacade para incluir explícitamente "OXXO" o "Transferencia" en las notas de pago de UCRM (preparación para lógica de plantillas).
This commit is contained in:
parent
e1937f9ac3
commit
84a25a829c
37
CHANGELOG.md
37
CHANGELOG.md
@ -1,5 +1,42 @@
|
|||||||
# CHANGELOG - siip-whatsapp-notifications
|
# CHANGELOG - siip-whatsapp-notifications
|
||||||
|
|
||||||
|
## VERSIÓN 4.1.0 - 15-01-2026
|
||||||
|
### 🚀 Nuevas Características (Features)
|
||||||
|
1. **Microservicio PDF (`pdf-cropper`)**:
|
||||||
|
* Nuevo servicio en Python (FastAPI + Poppler) desplegado en Docker (Puerto 8050) para la conversión de PDF a Imagen.
|
||||||
|
* Reemplaza la librería `Imagick` de PHP, aislando el procesamiento pesado fuera del plugin.
|
||||||
|
* **Modo Full**: Garantiza la conversión del PDF completo respetando su relación de aspecto original (sin recortes ni "square crop").
|
||||||
|
* **Overlay de Texto**: Capacidad nativa en el backend para sobreescribir texto dinámicamente (ej. cambiar "Tarjeta de crédito Stripe" por "OXXO Pay") basado en parámetros.
|
||||||
|
2. **Integración S3 / MinIO**:
|
||||||
|
* Implementación de `MinioStorageService`.
|
||||||
|
* Los comprobantes (JPG) y Vouchers OXXO se suben automáticamente a MinIO en lugar de usar FTP.
|
||||||
|
* Generación de URLs públicas seguras.
|
||||||
|
|
||||||
|
### 🧹 Mantenimiento y Limpieza (Chores/Refactor)
|
||||||
|
1. **Limpieza Automática (Cleanup)**:
|
||||||
|
* Se implementó lógica para eliminar archivos temporales locales (PDFs descargados, JPGs generados) inmediatamente después de una subida exitosa a MinIO.
|
||||||
|
2. **Refactor `ClientCallBellAPI`**:
|
||||||
|
* Eliminación de código muerto relacionado con FTP de WordPress.
|
||||||
|
* Implementación de cliente HTTP Guzzle para comunicación con `pdf-cropper`.
|
||||||
|
* **Cache Busting**: Se añade Timestamp al nombre de archivo (`_time()`) para evitar caché agresivo en WhatsApp/Navegadores.
|
||||||
|
|
||||||
|
### 🐛 Correcciones (Bug Fixes)
|
||||||
|
1. **Fix Recorte de Imagen**: Se eliminó la restricción de relación de aspecto 1:1 (cuadrado) para evitar recortes.
|
||||||
|
2. **Standardización de Notas**: Actualización de `AbstractStripeOperationsFacade` para incluir explícitamente "OXXO" o "Transferencia" en las notas de pago.
|
||||||
|
|
||||||
|
## VERSIÓN 4.0.0 - 10-01-2026
|
||||||
|
### 🟢 Novedades (Re-diseño UI/UX + Integ. Pagos)
|
||||||
|
1️⃣ **Portal Administrativo Integrado (Stripe + Oxxo)**: Se ha rediseñado completamente el panel administrativo (`Dashboard`) para incluir una sección dedicada a **Pagos Online**, permitiendo la generación de referencias SPEI y OXXO Pay sin salir del portal.
|
||||||
|
2️⃣ **Visualización Inline de Vouchers OXXO**: Ahora los comprobantes de pago OXXO se generan y visualizan inmediatamente en una vista partida (Datos + Imagen) dentro del dashboard, eliminando la necesidad de abrir enlaces externos para verificación.
|
||||||
|
3️⃣ **Carga FTP Híbrida**: Optimización inteligente que sube los vouchers al servidor FTP solo cuando es necesario (integraciones externas/webhooks) y utiliza visualización local para el administrador, garantizando máxima velocidad de interfaz.
|
||||||
|
4️⃣ **Modo Oscuro & UI Premium**: Nueva capa visual con sidebar expandido, cabecera global "Sticky", y un sistema de colores adaptativo (Modo Sol/Luna) para una mejor experiencia de usuario.
|
||||||
|
5️⃣ **Seguridad Reforzada**: Refactorización completa del manejo de credenciales, eliminando datos hardcodeados en el código y centralizándolos en la configuración segura del plugin.
|
||||||
|
|
||||||
|
### 🔵 Mejoras
|
||||||
|
1️⃣ **Navegación Intuitiva**: Menú lateral rediseñado con accesos directos claros a "Pagos Stripe", "Notificaciones" y "Gestión de Instaladores".
|
||||||
|
2️⃣ **Feedback Visual**: Nuevas alertas toast y modales informativos para confirmar acciones (Generación de referencias, errores de API, etc.).
|
||||||
|
3️⃣ **Compatibilidad**: Ajustes en `manifest.json` y estructura de archivos para asegurar compatibilidad total con las últimas versiones de UISP.
|
||||||
|
|
||||||
## VERSIÓN 3.1.0 - 07-01-2026
|
## VERSIÓN 3.1.0 - 07-01-2026
|
||||||
### 🟢 Novedades
|
### 🟢 Novedades
|
||||||
1️⃣ **Re-envío Manual de Notificaciones de Pago**: Se añadió un nuevo apartado en el Dashboard que permite buscar clientes y re-disparar notificaciones de WhatsApp para pagos específicos de forma manual.
|
1️⃣ **Re-envío Manual de Notificaciones de Pago**: Se añadió un nuevo apartado en el Dashboard que permite buscar clientes y re-disparar notificaciones de WhatsApp para pagos específicos de forma manual.
|
||||||
|
|||||||
109
README.md
109
README.md
@ -1,80 +1,83 @@
|
|||||||
# SIIP - WhatsApp Notifications & Stripe Payments for UCRM
|
# SIIP - WhatsApp Notifications & Integrated Payment Portal
|
||||||
|
|
||||||
Este plugin es una solución integral para automatizar la comunicación con clientes y la gestión de pagos en UISP/UCRM. Actúa como puente entre el CRM, Stripe y la plataforma de mensajería CallBell.
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
## 🚀 Funcionalidades Principales
|
Este plugin es una solución integral que transforma tu UCRM en un **Portal Administrativo de Última Generación**. No solo automatiza la comunicación por WhatsApp, sino que integra un Dashboard completo para la gestión de pagos online (Stripe/OXXO), visualización de comprobantes y coordinación de equipos técnicos.
|
||||||
|
|
||||||
- **Notificaciones Dinámicas**: Envío automático de mensajes por WhatsApp para facturas, pagos, suspensiones y reactivaciones.
|
## 🚀 Novedades v4.1.0 (Performance & Storage)
|
||||||
- **Gestión de Agenda (Jobs/Tasks)**: Notificación inteligente a técnicos e instaladores sobre nuevas tareas, reprogramaciones y desasignaciones.
|
|
||||||
- **Pagos con Stripe & OXXO**: Generación automatizada de referencias de OXXO con captura de pantalla (Puppeteer) y alojamiento en la nube (WordPress).
|
- **⚡ Microservicio PDF (`pdf-cropper`)**: Nuevo motor de renderizado externo (Python/FastAPI) que reemplaza librerías legacy, aumentando la velocidad y eliminando problemas de memoria en el servidor principal.
|
||||||
- **Sincronización CallBell**: Mantenimiento de la información del cliente actualizada en la plataforma de chat CallBell.
|
- **📦 MinIO / S3 Storage**: Migración completa del almacenamiento de comprobantes. Adiós FTP, hola almacenamiento de objetos seguro y escalable con URLs firmadas y limpieza automática.
|
||||||
- **Resolución Dinámica**: Detección automática de métodos de pago y atributos personalizados para máxima portabilidad.
|
- **🖼️ Smart Image Processing**: Generación de imágenes "Full Mode" (sin recortes) y capacidad de **Edición Dinámica de Texto** (Overlay) para personalizar métodos de pago en los comprobantes.
|
||||||
|
|
||||||
|
## 🚀 Novedades v4.0.0 (Portal Dashboard)
|
||||||
|
|
||||||
|
- **🖥️ Dashboard de Pagos Integrado**: Nueva interfaz visual dentro de UCRM para gestionar cobros de Stripe y OXXO sin salir de la plataforma.
|
||||||
|
- **🏪 OXXO Pay Híbrido & Visual**: Generación de fichas OXXO con dos modos inteligentes:
|
||||||
|
- **Inline (Admin)**: Visualización inmediata del voucher (local) para máxima velocidad.
|
||||||
|
- **FTP (Webhook)**: Carga automática a servidor externo para compartir links públicos.
|
||||||
|
- **🌑 UI/UX Premium**: Interfaz rediseñada con Sidebar expandible, cabecera global "Sticky", Modo Oscuro automático y componentes responsivos.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ Funcionalidades Principales
|
||||||
|
|
||||||
|
### 1. Gestión de Cobranza Avanzada
|
||||||
|
- **Pagos SPEI**: Instrucciones inmediatas con CLABE personalizada.
|
||||||
|
- **Vouchers OXXO**: Generación instantánea de códigos de barras con vista previa "Split-Screen" (Datos + Imagen).
|
||||||
|
- **Historial en Tiempo Real**: Consulta los últimos 10 pagos de cualquier cliente al instante.
|
||||||
|
|
||||||
|
### 2. Automatización WhatsApp (CallBell)
|
||||||
|
- **Notificaciones Dinámicas**: Envío automático de facturas, recordatorios de pago y avisos de corte.
|
||||||
|
- **Re-envío Manual**: Herramienta para disparar notificaciones específicas desde el Dashboard si el proceso automático falla.
|
||||||
|
- **Sincronización Total**: Mantiene los contactos de CallBell siempre actualizados con los datos del CRM.
|
||||||
|
|
||||||
|
### 3. Coordinación Técnica (Jobs/Tasks)
|
||||||
|
- **Agenda Inteligente**: Notifica a instaladores sobre nuevas tareas y reprogramaciones.
|
||||||
|
- **Datos para Técnicos**: Envía coordenadas GPS y contraseñas de equipos (formato impresora térmica) directamente al WhatsApp del técnico.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏗️ Arquitectura del Sistema
|
## 🏗️ Arquitectura del Sistema
|
||||||
|
|
||||||
El plugin utiliza un patrón de diseño basado en **Facades** para desacoplar la lógica de despacho de los servicios externos.
|
El plugin utiliza una arquitectura modular basada en **Facades** y **Servicios** para garantizar estabilidad y escalabilidad.
|
||||||
|
|
||||||
### Componentes Clave
|
### Componentes Clave
|
||||||
|
|
||||||
- **Despachador Central (`Plugin.php`)**: Gestiona tanto los webhooks internos de UCRM como los externos (Stripe). Controla el estado de las notificaciones de tareas mediante prefijos en los títulos (`[NOTIFICACION-PENDIENTE]`).
|
- **Frontend (`public.php`)**: Una Single Page Application (SPA) ligera incrustada en UCRM, construida con Vanilla JS y CSS moderno (Variables, Flexbox/Grid).
|
||||||
- **Fachada de Mensajería (`AbstractMessageNotifierFacade`)**: Contiene la lógica de negocio para decidir qué notificar, cuándo y a quién.
|
- **Despachador (`Plugin.php`)**: Router de eventos que delega acciones a los controladores específicos.
|
||||||
- **Interfaz CallBell (`ClientCallBellAPI`)**: Encapsula las llamadas a la API de CallBell, manejando plantillas y mensajes multimedia.
|
- **Motor de Pagos (`PaymentIntentStripe`)**: Servicio robusto que se comunica con la API de Stripe para crear intenciones de pago y métodos.
|
||||||
- **Operaciones OXXO (`AbstractOxxoOperationsFacade`)**: Orquesta el flujo de pago: Stripe (Referencia) -> Puppeteer (Screenshot) -> WordPress (Hosting) -> CallBell (WhatsApp).
|
- **Generador OXXO (`AbstractOxxoOperationsFacade`)**: Orquesta el flujo complejo: Stripe -> Puppeteer (Screenshot) -> FTP/Local Storage -> Respuesta JSON.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠️ Requisitos e Integraciones
|
## 🛠️ Requisitos e Integraciones
|
||||||
|
|
||||||
Para un funcionamiento óptimo, el plugin requiere:
|
Para desbloquear todo el potencial, el plugin requiere:
|
||||||
|
|
||||||
1. **UISP/UCRM**: Versión compatible con el SDK de Ubiquiti.
|
1. **UISP/UCRM**: Versión 2.1.0 o superior.
|
||||||
2. **Stripe API**: Token y Webhooks configurados para transacciones en tiempo real.
|
2. **Stripe API**: Keys de producción/test para procesar pagos.
|
||||||
3. **CallBell API**: Token de acceso para el envío de mensajes a través de plantillas de WhatsApp.
|
3. **CallBell API**: Token para el envío de mensajes de WhatsApp.
|
||||||
4. **Microservicio Puppeteer**: Un contenedor Docker con la API de Puppeteer para capturar vouchers.
|
4. **Microservicio Puppeteer**: Contenedor Docker para renderizar los vouchers de OXXO a imagen.
|
||||||
5. **Hosting WordPress (FTP)**: Para alojar temporalmente las imágenes de los vouchers enviadas a los clientes.
|
5. **Servidor FTP (Opcional)**: Requerido solo si se desea generar URLs públicas para compartir los vouchers externamente.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏷️ Configuración de UCRM
|
## 🏷️ Configuración Rápida
|
||||||
|
|
||||||
### Contactos y Etiquetas
|
El plugin se configura directamente desde el panel de UCRM (`Ajustes -> Plugins -> siip-whatsapp-notifications`).
|
||||||
El plugin selecciona los números de destino basándose en el **Tipo de Contacto** definido en UCRM:
|
|
||||||
- `WhatsApp`: Recibe notificaciones y actualizaciones de datos.
|
|
||||||
- `WhatsNotifica`: Recibe solo notificaciones.
|
|
||||||
- `WhatsActualiza`: Utilizado solo para sincronizar datos con CallBell.
|
|
||||||
|
|
||||||
### Atributos Personalizados
|
### Parámetros Críticos
|
||||||
Es necesario configurar los siguientes atributos en UCRM:
|
- `ipserver`: Tu dominio UCRM.
|
||||||
- `stripeCustomerId`: ID del cliente en Stripe.
|
- `tokenstripe`: Tu Secret Key de Stripe.
|
||||||
- `clabeInterbancaria`: CLABE personalizada para transferencias.
|
- `tokencallbell`: Tu API Key de CallBell.
|
||||||
- `passwordAntenaCliente`: Almacena la contraseña del equipo del cliente (sincronizada con la bóveda).
|
- `hostServerFTP` / `user` / `pass`: Credenciales para el almacenamiento de vouchers remotos.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 Flujos de Trabajo Destacados
|
|
||||||
|
|
||||||
### 📅 Gestión de Contraseñas y Visitas Técnicas
|
|
||||||
Cuando se asigna o reprograma una tarea:
|
|
||||||
1. **Detección Multi-Servicio & Etiquetas Inteligentes**:
|
|
||||||
- El plugin identifica todos los servicios del cliente.
|
|
||||||
- Si hay **más de un servicio**, utiliza el formato: `Servicio 1: <pass> Servicio 2: ...`.
|
|
||||||
- Si hay **solo un servicio**, muestra la contraseña directamente sin etiquetas para mayor claridad.
|
|
||||||
2. **Sincronización CallBell Avanzada**:
|
|
||||||
- Los datos técnicos y financieros se sincronizan en una sola petición optimizada.
|
|
||||||
- Las contraseñas se envían como un objeto JSON estructurado al campo `Password Antena`.
|
|
||||||
3. **Validación de Provisionamiento**: Antes de actuar, verifica en UISP si el sitio tiene dispositivos vinculados (evitando errores en estados "Location Inactive").
|
|
||||||
- Envía un mensaje al cliente con el nombre del técnico y la fecha (sin hora).
|
|
||||||
- Envía un mensaje al técnico con la dirección, ubicación en Google Maps y las contraseñas de las antenas optimizadas para lectura en impresoras térmicas (alfanumérico + `@`, `#`).
|
|
||||||
|
|
||||||
### 💳 Registro de Pagos por Transferencia
|
|
||||||
1. Stripe envía un webhook de saldo aplicado (`customer_cash_balance_transaction.created`).
|
|
||||||
2. El plugin resuelve dinámicamente el ID del método "Transferencia bancaria".
|
|
||||||
3. Registra el pago automáticamente en UCRM vinculado al `clientId` en los metadatos.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📝 Registro de Cambios
|
## 📝 Registro de Cambios
|
||||||
|
|
||||||
Para consultar la evolución del proyecto, ver el archivo [CHANGELOG.md](./CHANGELOG.md).
|
Para consultar la evolución detallada del proyecto, ver el archivo [CHANGELOG.md](./CHANGELOG.md).
|
||||||
@ -1,73 +1,30 @@
|
|||||||
<?php
|
<?php
|
||||||
use GuzzleHttp\Client;
|
|
||||||
|
|
||||||
require 'vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
// $baseUri = 'https://172.16.5.120/crm/api/v1.0/'; //endpoint de la API REST del CRM
|
use Ubnt\UcrmPluginSdk\Service\PluginLogManager;
|
||||||
// $token = '3d5fa4c9-e134-4e8b-b8d7-aae394d48d4d'; //Token para acceder a los recursos del CRM
|
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
|
||||||
$baseUri = 'https://172.16.5.134/crm/api/v1.0/'; //endpoint de la API REST del CRM
|
|
||||||
$token = '6abef18c-783d-4dd0-b530-be6e6a7bbd1d'; //Token para acceder a los recursos del CRM
|
|
||||||
|
|
||||||
$stripe = new \Stripe\StripeClient('sk_test_51OkG0REFY1WEUtgRH6UxBK5pu80Aq5Iy8EcdPnf0cOWzuVLQTpyLCd7CbPzqMsWMafZOHElCxhEHF7g8boURjWlJ00tBwE0W1M'); //Token de clave privada en modo prueba para la API de Stripe
|
chdir(__DIR__);
|
||||||
//$stripe = new \Stripe\StripeClient('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'); //Token de clave privada en modo prodcucción para la API de Stripe
|
|
||||||
|
|
||||||
//cliente GuzzleHttp para consumir API del UISP CRM
|
// Inicializar Log (usando data/ para permisos de escritura)
|
||||||
$clientGuzzleHttp = new Client([
|
$debugLogPath = __DIR__ . '/data/plugin.log';
|
||||||
'base_uri' => $baseUri,
|
file_put_contents($debugLogPath, "[" . date('Y-m-d H:i:s') . "] Hit StripeWebhook.php - Delegando a Plugin->run()" . PHP_EOL, FILE_APPEND);
|
||||||
'headers' => [
|
|
||||||
'X-Auth-App-Key' => $token,
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
],
|
|
||||||
'verify' => false,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Obtén el contenido del cuerpo de la solicitud
|
// Solo permitir acceso si estamos en un entorno UCRM válido
|
||||||
$input = @file_get_contents('php://input');
|
if (!file_exists(__DIR__ . '/data/config.json')) {
|
||||||
$event_json = json_decode($input);
|
die('Acceso denegado o configuración no encontrada.');
|
||||||
$cadena = json_encode($event_json);
|
|
||||||
file_put_contents(__DIR__ . '/logsiip.log', "[" . date('Y-m-d H:i:s') . "] " . "Valor json: ".$cadena.PHP_EOL);
|
|
||||||
// Maneja el evento del webhook
|
|
||||||
if ($event_json) {
|
|
||||||
switch ($event_json->type) {
|
|
||||||
case 'cash_balance.funds_available':
|
|
||||||
$customer = $event_json->data->object;
|
|
||||||
$customerId = $customer->id;
|
|
||||||
$newBalance = $customer->balance; // El nuevo saldo del cliente
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try {// Aquí puedes crear un nuevo PaymentIntent o un Cargo (Charge) usando el nuevo saldo
|
|
||||||
$paymentIntent = \Stripe\PaymentIntent::create([
|
|
||||||
'amount' => 30000,
|
|
||||||
'currency' => 'mxn',
|
|
||||||
'customer' => $customerId,
|
|
||||||
'payment_method_types' => ['customer_balance'],
|
|
||||||
'payment_method_data' => ['type' => 'customer_balance'],
|
|
||||||
'confirm' => true,
|
|
||||||
'payment_method_options' => [
|
|
||||||
'customer_balance' => [
|
|
||||||
'funding_type' => 'bank_transfer',
|
|
||||||
'bank_transfer' => ['type' => 'mx_bank_transfer']
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'metadata' => [
|
|
||||||
'clientId' => $customerId, // ID del cliente en Ubiquiti
|
|
||||||
'createdBy' => 'UCRM', // ID de la factura en Ubiquiti
|
|
||||||
'paymentType' => 'card.one_time',
|
|
||||||
'signedInAdminId' => 1015,
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
file_put_contents(__DIR__ . '/logsiip.log', "[" . date('Y-m-d H:i:s') . "] " . "PaymentIntent creado: " . $paymentIntent->id . PHP_EOL, FILE_APPEND);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (\Stripe\Exception\ApiErrorException $e) {
|
|
||||||
file_put_contents(__DIR__ . '/logsiip.log', "[" . date('Y-m-d H:i:s') . "] " ."Error creando PaymentIntent: " . $e->getMessage() . PHP_EOL, FILE_APPEND);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
// Otros eventos relevantes
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
http_response_code(200); // Responde con un 200 OK a Stripe
|
try {
|
||||||
|
// Delegar ejecución al Plugin principal
|
||||||
|
$builder = new \DI\ContainerBuilder();
|
||||||
|
$container = $builder->build();
|
||||||
|
$plugin = $container->get(\SmsNotifier\Plugin::class);
|
||||||
|
$plugin->run();
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
file_put_contents($debugLogPath, "[" . date('Y-m-d H:i:s') . "] Error en StripeWebhook.php: " . $e->getMessage() . PHP_EOL, FILE_APPEND);
|
||||||
|
http_response_code(500);
|
||||||
|
echo "Error interno";
|
||||||
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
"katzgrau/klogger": "^1.2",
|
"katzgrau/klogger": "^1.2",
|
||||||
"stripe/stripe-php": "^13.11",
|
"stripe/stripe-php": "^13.11",
|
||||||
"ext-imagick": "*",
|
"ext-imagick": "*",
|
||||||
"google/apiclient": "^2.0"
|
"google/apiclient": "^2.0",
|
||||||
|
"aws/aws-sdk-php": "^3.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
320
composer.lock
generated
320
composer.lock
generated
@ -4,8 +4,159 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "899edd228cc3a9ded57208726a91db8d",
|
"content-hash": "72a3878ac2514c6e954519ec54c8054c",
|
||||||
"packages": [
|
"packages": [
|
||||||
|
{
|
||||||
|
"name": "aws/aws-crt-php",
|
||||||
|
"version": "v1.2.7",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/awslabs/aws-crt-php.git",
|
||||||
|
"reference": "d71d9906c7bb63a28295447ba12e74723bd3730e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e",
|
||||||
|
"reference": "d71d9906c7bb63a28295447ba12e74723bd3730e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "^4.8.35||^5.6.3||^9.5",
|
||||||
|
"yoast/phpunit-polyfills": "^1.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "AWS SDK Common Runtime Team",
|
||||||
|
"email": "aws-sdk-common-runtime@amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS Common Runtime for PHP",
|
||||||
|
"homepage": "https://github.com/awslabs/aws-crt-php",
|
||||||
|
"keywords": [
|
||||||
|
"amazon",
|
||||||
|
"aws",
|
||||||
|
"crt",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/awslabs/aws-crt-php/issues",
|
||||||
|
"source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7"
|
||||||
|
},
|
||||||
|
"time": "2024-10-18T22:15:13+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "aws/aws-sdk-php",
|
||||||
|
"version": "3.369.11",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||||
|
"reference": "014c521eae8eeb1f9562cb512523b17cd6c1bec7"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/014c521eae8eeb1f9562cb512523b17cd6c1bec7",
|
||||||
|
"reference": "014c521eae8eeb1f9562cb512523b17cd6c1bec7",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"aws/aws-crt-php": "^1.2.3",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"guzzlehttp/guzzle": "^7.4.5",
|
||||||
|
"guzzlehttp/promises": "^2.0",
|
||||||
|
"guzzlehttp/psr7": "^2.4.5",
|
||||||
|
"mtdowling/jmespath.php": "^2.8.0",
|
||||||
|
"php": ">=8.1",
|
||||||
|
"psr/http-message": "^1.0 || ^2.0",
|
||||||
|
"symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"andrewsville/php-token-reflection": "^1.4",
|
||||||
|
"aws/aws-php-sns-message-validator": "~1.0",
|
||||||
|
"behat/behat": "~3.0",
|
||||||
|
"composer/composer": "^2.7.8",
|
||||||
|
"dms/phpunit-arraysubset-asserts": "^0.4.0",
|
||||||
|
"doctrine/cache": "~1.4",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"phpunit/phpunit": "^9.6",
|
||||||
|
"psr/cache": "^2.0 || ^3.0",
|
||||||
|
"psr/simple-cache": "^2.0 || ^3.0",
|
||||||
|
"sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0",
|
||||||
|
"yoast/phpunit-polyfills": "^2.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
|
||||||
|
"doctrine/cache": "To use the DoctrineCacheAdapter",
|
||||||
|
"ext-curl": "To send requests using cURL",
|
||||||
|
"ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
|
||||||
|
"ext-pcntl": "To use client-side monitoring",
|
||||||
|
"ext-sockets": "To use client-side monitoring"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.0-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/functions.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"Aws\\": "src/"
|
||||||
|
},
|
||||||
|
"exclude-from-classmap": [
|
||||||
|
"src/data/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"Apache-2.0"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Amazon Web Services",
|
||||||
|
"homepage": "http://aws.amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
|
||||||
|
"homepage": "http://aws.amazon.com/sdkforphp",
|
||||||
|
"keywords": [
|
||||||
|
"amazon",
|
||||||
|
"aws",
|
||||||
|
"cloud",
|
||||||
|
"dynamodb",
|
||||||
|
"ec2",
|
||||||
|
"glacier",
|
||||||
|
"s3",
|
||||||
|
"sdk"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||||
|
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||||
|
"source": "https://github.com/aws/aws-sdk-php/tree/3.369.11"
|
||||||
|
},
|
||||||
|
"time": "2026-01-12T19:14:19+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "firebase/php-jwt",
|
"name": "firebase/php-jwt",
|
||||||
"version": "v6.10.2",
|
"version": "v6.10.2",
|
||||||
@ -244,22 +395,22 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/guzzle",
|
"name": "guzzlehttp/guzzle",
|
||||||
"version": "7.9.2",
|
"version": "7.10.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/guzzle.git",
|
"url": "https://github.com/guzzle/guzzle.git",
|
||||||
"reference": "d281ed313b989f213357e3be1a179f02196ac99b"
|
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
|
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
|
||||||
"reference": "d281ed313b989f213357e3be1a179f02196ac99b",
|
"reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-json": "*",
|
"ext-json": "*",
|
||||||
"guzzlehttp/promises": "^1.5.3 || ^2.0.3",
|
"guzzlehttp/promises": "^2.3",
|
||||||
"guzzlehttp/psr7": "^2.7.0",
|
"guzzlehttp/psr7": "^2.8",
|
||||||
"php": "^7.2.5 || ^8.0",
|
"php": "^7.2.5 || ^8.0",
|
||||||
"psr/http-client": "^1.0",
|
"psr/http-client": "^1.0",
|
||||||
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
"symfony/deprecation-contracts": "^2.2 || ^3.0"
|
||||||
@ -350,7 +501,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/guzzle/issues",
|
"issues": "https://github.com/guzzle/guzzle/issues",
|
||||||
"source": "https://github.com/guzzle/guzzle/tree/7.9.2"
|
"source": "https://github.com/guzzle/guzzle/tree/7.10.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -366,20 +517,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-24T11:22:20+00:00"
|
"time": "2025-08-23T22:36:01+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/promises",
|
"name": "guzzlehttp/promises",
|
||||||
"version": "2.0.4",
|
"version": "2.3.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/promises.git",
|
"url": "https://github.com/guzzle/promises.git",
|
||||||
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
|
"reference": "481557b130ef3790cf82b713667b43030dc9c957"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
|
"url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
|
||||||
"reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
|
"reference": "481557b130ef3790cf82b713667b43030dc9c957",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -387,7 +538,7 @@
|
|||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
|
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
@ -433,7 +584,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/promises/issues",
|
"issues": "https://github.com/guzzle/promises/issues",
|
||||||
"source": "https://github.com/guzzle/promises/tree/2.0.4"
|
"source": "https://github.com/guzzle/promises/tree/2.3.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -449,20 +600,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-10-17T10:06:22+00:00"
|
"time": "2025-08-22T14:34:08+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "guzzlehttp/psr7",
|
"name": "guzzlehttp/psr7",
|
||||||
"version": "2.7.0",
|
"version": "2.8.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/guzzle/psr7.git",
|
"url": "https://github.com/guzzle/psr7.git",
|
||||||
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
|
"reference": "21dc724a0583619cd1652f673303492272778051"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
|
"url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
|
||||||
"reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
|
"reference": "21dc724a0583619cd1652f673303492272778051",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -478,7 +629,7 @@
|
|||||||
"require-dev": {
|
"require-dev": {
|
||||||
"bamarni/composer-bin-plugin": "^1.8.2",
|
"bamarni/composer-bin-plugin": "^1.8.2",
|
||||||
"http-interop/http-factory-tests": "0.9.0",
|
"http-interop/http-factory-tests": "0.9.0",
|
||||||
"phpunit/phpunit": "^8.5.39 || ^9.6.20"
|
"phpunit/phpunit": "^8.5.44 || ^9.6.25"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
|
||||||
@ -549,7 +700,7 @@
|
|||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/guzzle/psr7/issues",
|
"issues": "https://github.com/guzzle/psr7/issues",
|
||||||
"source": "https://github.com/guzzle/psr7/tree/2.7.0"
|
"source": "https://github.com/guzzle/psr7/tree/2.8.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -565,7 +716,7 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-07-18T11:15:46+00:00"
|
"time": "2025-08-23T21:21:41+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "katzgrau/klogger",
|
"name": "katzgrau/klogger",
|
||||||
@ -784,6 +935,72 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-11-12T12:43:37+00:00"
|
"time": "2024-11-12T12:43:37+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "mtdowling/jmespath.php",
|
||||||
|
"version": "2.8.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/jmespath/jmespath.php.git",
|
||||||
|
"reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
|
||||||
|
"reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.2.5 || ^8.0",
|
||||||
|
"symfony/polyfill-mbstring": "^1.17"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/xdebug-handler": "^3.0.3",
|
||||||
|
"phpunit/phpunit": "^8.5.33"
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/jp.php"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.8-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"files": [
|
||||||
|
"src/JmesPath.php"
|
||||||
|
],
|
||||||
|
"psr-4": {
|
||||||
|
"JmesPath\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Graham Campbell",
|
||||||
|
"email": "hello@gjcampbell.co.uk",
|
||||||
|
"homepage": "https://github.com/GrahamCampbell"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Michael Dowling",
|
||||||
|
"email": "mtdowling@gmail.com",
|
||||||
|
"homepage": "https://github.com/mtdowling"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Declaratively specify how to extract elements from a JSON document",
|
||||||
|
"keywords": [
|
||||||
|
"json",
|
||||||
|
"jsonpath"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/jmespath/jmespath.php/issues",
|
||||||
|
"source": "https://github.com/jmespath/jmespath.php/tree/2.8.0"
|
||||||
|
},
|
||||||
|
"time": "2024-09-04T18:46:31+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "paragonie/constant_time_encoding",
|
"name": "paragonie/constant_time_encoding",
|
||||||
"version": "v3.0.0",
|
"version": "v3.0.0",
|
||||||
@ -1556,16 +1773,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/deprecation-contracts",
|
"name": "symfony/deprecation-contracts",
|
||||||
"version": "v3.5.1",
|
"version": "v3.6.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||||
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
|
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
|
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||||
"reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
|
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1578,7 +1795,7 @@
|
|||||||
"name": "symfony/contracts"
|
"name": "symfony/contracts"
|
||||||
},
|
},
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-main": "3.5-dev"
|
"dev-main": "3.6-dev"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
@ -1603,7 +1820,7 @@
|
|||||||
"description": "A generic function and convention to trigger deprecation notices",
|
"description": "A generic function and convention to trigger deprecation notices",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
|
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1619,20 +1836,20 @@
|
|||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-09-25T14:20:29+00:00"
|
"time": "2024-09-25T14:21:43+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/filesystem",
|
"name": "symfony/filesystem",
|
||||||
"version": "v6.4.13",
|
"version": "v6.4.30",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/filesystem.git",
|
"url": "https://github.com/symfony/filesystem.git",
|
||||||
"reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3"
|
"reference": "441c6b69f7222aadae7cbf5df588496d5ee37789"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/4856c9cf585d5a0313d8d35afd681a526f038dd3",
|
"url": "https://api.github.com/repos/symfony/filesystem/zipball/441c6b69f7222aadae7cbf5df588496d5ee37789",
|
||||||
"reference": "4856c9cf585d5a0313d8d35afd681a526f038dd3",
|
"reference": "441c6b69f7222aadae7cbf5df588496d5ee37789",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -1669,7 +1886,7 @@
|
|||||||
"description": "Provides basic utilities for the filesystem",
|
"description": "Provides basic utilities for the filesystem",
|
||||||
"homepage": "https://symfony.com",
|
"homepage": "https://symfony.com",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/filesystem/tree/v6.4.13"
|
"source": "https://github.com/symfony/filesystem/tree/v6.4.30"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1680,16 +1897,20 @@
|
|||||||
"url": "https://github.com/fabpot",
|
"url": "https://github.com/fabpot",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-10-25T15:07:50+00:00"
|
"time": "2025-11-26T14:43:45+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-ctype",
|
"name": "symfony/polyfill-ctype",
|
||||||
"version": "v1.31.0",
|
"version": "v1.33.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-ctype.git",
|
"url": "https://github.com/symfony/polyfill-ctype.git",
|
||||||
@ -1748,7 +1969,7 @@
|
|||||||
"portable"
|
"portable"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
|
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1759,6 +1980,10 @@
|
|||||||
"url": "https://github.com/fabpot",
|
"url": "https://github.com/fabpot",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
@ -1768,19 +1993,20 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "symfony/polyfill-mbstring",
|
"name": "symfony/polyfill-mbstring",
|
||||||
"version": "v1.31.0",
|
"version": "v1.33.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
||||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
"reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
|
"reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
"ext-iconv": "*",
|
||||||
"php": ">=7.2"
|
"php": ">=7.2"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
@ -1828,7 +2054,7 @@
|
|||||||
"shim"
|
"shim"
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
|
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -1839,12 +2065,16 @@
|
|||||||
"url": "https://github.com/fabpot",
|
"url": "https://github.com/fabpot",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://github.com/nicolas-grekas",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||||
"type": "tidelift"
|
"type": "tidelift"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2024-09-09T11:45:10+00:00"
|
"time": "2024-12-23T08:48:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "twilio/sdk",
|
"name": "twilio/sdk",
|
||||||
@ -1969,5 +2199,5 @@
|
|||||||
"ext-imagick": "*"
|
"ext-imagick": "*"
|
||||||
},
|
},
|
||||||
"platform-dev": [],
|
"platform-dev": [],
|
||||||
"plugin-api-version": "2.2.0"
|
"plugin-api-version": "2.6.0"
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 78 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 104 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 78 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 79 KiB |
175
consulta a Gemini.txt
Normal file
175
consulta a Gemini.txt
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
|
||||||
|
Pregunta: Algún microservicio que pueda levantar con docker compose y que funcione como API para pasarle un PDF y me devuelva una imagen y recortada en ciertas coordenadas o ajustada a formato cuadrado.
|
||||||
|
|
||||||
|
Respuesta: Para lo que necesitas, la mejor opción no es una herramienta genérica (como Gotenberg), ya que estas suelen convertir la página entera pero no permiten recortar por coordenadas en la misma petición.
|
||||||
|
|
||||||
|
La solución más limpia y eficiente es crear un microservicio ligero en Python (usando FastAPI y pdf2image) que puedas levantar con Docker. Python tiene las mejores librerías para manipulación de PDFs e imágenes.
|
||||||
|
|
||||||
|
Aquí tienes la solución completa "Copy-Paste":
|
||||||
|
|
||||||
|
1. Estructura del proyecto
|
||||||
|
Crea una carpeta (ej. pdf-cropper) con estos 3 archivos:
|
||||||
|
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
main.py
|
||||||
|
|
||||||
|
docker-compose.yml
|
||||||
|
|
||||||
|
2. El Código (Python + FastAPI)
|
||||||
|
Este script recibe el PDF, lo convierte a imagen y aplica el recorte o ajuste cuadrado según lo que le pidas.
|
||||||
|
|
||||||
|
Archivo: main.py
|
||||||
|
|
||||||
|
Python
|
||||||
|
|
||||||
|
from fastapi import FastAPI, UploadFile, File, Form
|
||||||
|
from pdf2image import convert_from_bytes
|
||||||
|
from PIL import Image
|
||||||
|
import io
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
|
||||||
|
@app.post("/process")
|
||||||
|
async def process_pdf(
|
||||||
|
file: UploadFile = File(...),
|
||||||
|
mode: str = Form("square"), # 'square' o 'coords'
|
||||||
|
x: int = Form(0),
|
||||||
|
y: int = Form(0),
|
||||||
|
w: int = Form(500),
|
||||||
|
h: int = Form(500)
|
||||||
|
):
|
||||||
|
# 1. Leer el archivo PDF en memoria
|
||||||
|
pdf_bytes = await file.read()
|
||||||
|
|
||||||
|
# 2. Convertir la primera página a imagen
|
||||||
|
# poppler_path no es necesario si se instala en el sistema (ver Dockerfile)
|
||||||
|
images = convert_from_bytes(pdf_bytes, fmt="jpeg")
|
||||||
|
|
||||||
|
if not images:
|
||||||
|
return {"error": "No se pudo leer el PDF"}
|
||||||
|
|
||||||
|
img = images[0] # Tomamos la primera página
|
||||||
|
|
||||||
|
# 3. Lógica de recorte
|
||||||
|
if mode == "square":
|
||||||
|
# Recorte cuadrado centrado automático
|
||||||
|
width, height = img.size
|
||||||
|
new_dim = min(width, height)
|
||||||
|
left = (width - new_dim) / 2
|
||||||
|
top = (height - new_dim) / 2
|
||||||
|
right = (width + new_dim) / 2
|
||||||
|
bottom = (height + new_dim) / 2
|
||||||
|
img = img.crop((left, top, right, bottom))
|
||||||
|
# Opcional: Redimensionar al tamaño final deseado
|
||||||
|
img = img.resize((w, h))
|
||||||
|
|
||||||
|
elif mode == "coords":
|
||||||
|
# Recorte por coordenadas exactas
|
||||||
|
img = img.crop((x, y, x + w, y + h))
|
||||||
|
|
||||||
|
# 4. Devolver la imagen procesada
|
||||||
|
img_byte_arr = io.BytesIO()
|
||||||
|
img.save(img_byte_arr, format='JPEG', quality=90)
|
||||||
|
img_byte_arr.seek(0)
|
||||||
|
|
||||||
|
from starlette.responses import StreamingResponse
|
||||||
|
return StreamingResponse(img_byte_arr, media_type="image/jpeg")
|
||||||
|
3. El Dockerfile
|
||||||
|
Es crucial instalar poppler-utils, que es el motor que procesa el PDF.
|
||||||
|
|
||||||
|
Archivo: Dockerfile
|
||||||
|
|
||||||
|
Dockerfile
|
||||||
|
|
||||||
|
FROM python:3.9-slim
|
||||||
|
|
||||||
|
# Instalar poppler (necesario para pdf2image)
|
||||||
|
RUN apt-get update && apt-get install -y poppler-utils && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Instalar dependencias de Python
|
||||||
|
RUN pip install fastapi uvicorn python-multipart pdf2image Pillow
|
||||||
|
|
||||||
|
COPY main.py .
|
||||||
|
|
||||||
|
# Ejecutar la API
|
||||||
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
|
4. Docker Compose
|
||||||
|
Para levantarlo.
|
||||||
|
|
||||||
|
Archivo: docker-compose.yml
|
||||||
|
|
||||||
|
YAML
|
||||||
|
|
||||||
|
services:
|
||||||
|
pdf-cropper:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:8000"
|
||||||
|
restart: always
|
||||||
|
Comando para iniciar:
|
||||||
|
|
||||||
|
Bash
|
||||||
|
|
||||||
|
docker compose up -d --build
|
||||||
|
5. Cómo usarlo desde PHP
|
||||||
|
Ahora tienes una API corriendo en http://localhost:8080/process. Aquí tienes el script PHP para enviarle un PDF y guardar la imagen recortada.
|
||||||
|
|
||||||
|
Archivo: cliente.php
|
||||||
|
|
||||||
|
PHP
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$pdfPath = 'documento.pdf';
|
||||||
|
$outputPath = 'resultado.jpg';
|
||||||
|
|
||||||
|
// URL de tu microservicio docker
|
||||||
|
$url = 'http://localhost:8080/process';
|
||||||
|
|
||||||
|
$curl = curl_init();
|
||||||
|
|
||||||
|
$fields = [
|
||||||
|
'file' => new CURLFile($pdfPath, 'application/pdf', 'documento.pdf'),
|
||||||
|
|
||||||
|
// OPCIÓN A: Recorte cuadrado automático (centrado)
|
||||||
|
'mode' => 'square',
|
||||||
|
'w' => 800, // Tamaño final del cuadrado (px)
|
||||||
|
'h' => 800,
|
||||||
|
|
||||||
|
// OPCIÓN B: Coordenadas específicas (descomentar para usar)
|
||||||
|
// 'mode' => 'coords',
|
||||||
|
// 'x' => 100, // Píxeles desde la izquierda
|
||||||
|
// 'y' => 200, // Píxeles desde arriba
|
||||||
|
// 'w' => 500, // Ancho del recorte
|
||||||
|
// 'h' => 300 // Alto del recorte
|
||||||
|
];
|
||||||
|
|
||||||
|
curl_setopt_array($curl, [
|
||||||
|
CURLOPT_URL => $url,
|
||||||
|
CURLOPT_POST => true,
|
||||||
|
CURLOPT_POSTFIELDS => $fields,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||||
|
|
||||||
|
if ($httpCode == 200) {
|
||||||
|
file_put_contents($outputPath, $response);
|
||||||
|
echo "Imagen guardada exitosamente en $outputPath";
|
||||||
|
} else {
|
||||||
|
echo "Error: " . curl_error($curl);
|
||||||
|
echo "Respuesta del servidor: " . $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_close($curl);
|
||||||
|
?>
|
||||||
|
¿Por qué esta solución?
|
||||||
|
Atomocidad: Hace la conversión y el recorte en un solo paso de memoria (RAM), sin guardar archivos temporales en disco.
|
||||||
|
|
||||||
|
Control: Puedes ajustar la lógica de "cuadrado" (si quieres que sea centrado o desde la esquina superior) modificando fácilmente el main.py.
|
||||||
|
|
||||||
|
Ligero: La imagen Docker pesará poco y consumirá memoria solo cuando procese un archivo.
|
||||||
@ -1 +1 @@
|
|||||||
{"ipserver":"venus.siip.mx","apitoken":"gvcnIJqXdUjneVSjhl6THLlQcYXJyIFCcwHKVba2bvIrNraanCTb5VeoWuJ0TFZ9","unmsApiToken":"079c28f5-888c-457d-bd7a-0a4202590f75","tokencallbell":"g8thcZkXGd3xBj2g3TtYNYFMH1fuesbJ.b6a940ea7d78cf6c9e42f067b21c8ddf96e9fa2a9e307bfd0c7c7c4d7fa38f79","tokenstripe":"sk_test_51OkG0REFY1WEUtgRH6UxBK5pu80Aq5Iy8EcdPnf0cOWzuVLQTpyLCd7CbPzqMsWMafZOHElCxhEHF7g8boURjWlJ00tBwE0W1M","hostServerFTP":"siip.mx","usernameServerFTP":"siip0001","passServerFTP":"$spGiT,[wa)n","ipPuppeteer":"172.16.5.134","portPuppeteer":"3000","idPaymentAdminCRM":"1180","cashPaymentMethodId":false,"courtesyPaymentMethodId":false,"bankTransferPaymentMethodId":true,"paypalPaymentMethodId":true,"creditCardPaypalPaymentMethodId":true,"creditCardStripePaymentMethodId":true,"stripeSubscriptionCreditCardPaymentMethodId":true,"paypalSubscriptionPaymentMethodId":true,"mercadopagoPaymentMethodId":true,"checkPaymentMethodId":true,"customPaymentMethodId":true,"notificationTypeText":true,"installersDataWhatsApp":"{\r\n \"instaladores\": [\r\n {\r\n \"id\": 1019,\r\n \"nombre\": \"Mucio Robledo\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1173,\r\n \"nombre\": \"Ángel Arvizu\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1172,\r\n \"nombre\": \"Juan Rostro\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1015,\r\n \"nombre\": \"Daniel Humberto\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1131,\r\n \"nombre\": \"Gricelda Avalos\",\r\n \"whatsapp\": \"4181817609\"\r\n }\r\n ]\r\n}","debugMode":true,"logging_level":true}
|
{"ipserver":"venus.siip.mx","apitoken":"gvcnIJqXdUjneVSjhl6THLlQcYXJyIFCcwHKVba2bvIrNraanCTb5VeoWuJ0TFZ9","unmsApiToken":"079c28f5-888c-457d-bd7a-0a4202590f75","tokencallbell":"g8thcZkXGd3xBj2g3TtYNYFMH1fuesbJ.b6a940ea7d78cf6c9e42f067b21c8ddf96e9fa2a9e307bfd0c7c7c4d7fa38f79","tokenstripe":"sk_test_51OkG0REFY1WEUtgRH6UxBK5pu80Aq5Iy8EcdPnf0cOWzuVLQTpyLCd7CbPzqMsWMafZOHElCxhEHF7g8boURjWlJ00tBwE0W1M","hostServerFTP":"siip.mx","usernameServerFTP":"siip0001","passServerFTP":"$spGiT,[wa)n","ipPuppeteer":"172.16.5.134","portPuppeteer":"4100","idPaymentAdminCRM":"1180","cashPaymentMethodId":false,"courtesyPaymentMethodId":false,"bankTransferPaymentMethodId":true,"paypalPaymentMethodId":true,"creditCardPaypalPaymentMethodId":true,"creditCardStripePaymentMethodId":true,"stripeSubscriptionCreditCardPaymentMethodId":true,"paypalSubscriptionPaymentMethodId":true,"mercadopagoPaymentMethodId":true,"checkPaymentMethodId":true,"customPaymentMethodId":true,"notificationTypeText":false,"installersDataWhatsApp":"{\r\n \"instaladores\": [\r\n {\r\n \"id\": 1019,\r\n \"nombre\": \"Mucio Robledo\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1173,\r\n \"nombre\": \"Ángel Arvizu\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1172,\r\n \"nombre\": \"Juan Rostro\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1015,\r\n \"nombre\": \"Daniel Humberto\",\r\n \"whatsapp\": \"4181878106\"\r\n },\r\n {\r\n \"id\": 1131,\r\n \"nombre\": \"Gricelda Avalos\",\r\n \"whatsapp\": \"4181817609\"\r\n }\r\n ]\r\n}","debugMode":true,"logging_level":true,"minioEndpoint":"http://172.16.5.134:9002","minioPublicUrl":"https://aws-venus.siip.mx","minioAccessKey":"minioadmin","minioSecretKey":"minioadmin","minioBucket":"vouchers-oxxo"}
|
||||||
25674
data/plugin.log
25674
data/plugin.log
File diff suppressed because one or more lines are too long
@ -5,13 +5,23 @@
|
|||||||
"displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp",
|
"displayName": "SIIP - Procesador de Pagos en línea con Stripe, Oxxo y Transferencia, Sincronizador de CallBell y Envío de Notificaciones y comprobantes vía WhatsApp",
|
||||||
"description": "Este plugin sincroniza los clientes del sistema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes",
|
"description": "Este plugin sincroniza los clientes del sistema UISP CRM con los contactos de WhatsApp en CallBell, además procesa pagos de Stripe como las trasferencias bancarias y genera referencias de pago vía OXXO, además envía comprobantes de pago en formato imagen PNG o texto vía Whatsapp a los clientes",
|
||||||
"url": "https://siip.mx/",
|
"url": "https://siip.mx/",
|
||||||
"version": "3.1.0",
|
"version": "4.1.0",
|
||||||
"unmsVersionCompliancy": {
|
"unmsVersionCompliancy": {
|
||||||
"min": "2.1.0",
|
"min": "2.1.0",
|
||||||
"max": null
|
"max": null
|
||||||
},
|
},
|
||||||
"author": "SIIP INTERNET",
|
"author": "SIIP INTERNET",
|
||||||
"changelog": [
|
"changelog": [
|
||||||
|
{
|
||||||
|
"version": "4.1.0",
|
||||||
|
"date": "2026-01-15",
|
||||||
|
"changes": "Implementación de Microservicio PDF, Integración MinIO, Fix Recorte y Soporte overlay textos."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "4.0.0",
|
||||||
|
"date": "2026-01-10",
|
||||||
|
"changes": "Re-diseño completo de UI, integración total de Stripe (SPEI/OXXO), visualización inline de vouchers, optimización de seguridad FTP y modo oscuro."
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"date": "2026-01-07",
|
"date": "2026-01-07",
|
||||||
@ -200,6 +210,41 @@
|
|||||||
"required": 0,
|
"required": 0,
|
||||||
"type": "checkbox"
|
"type": "checkbox"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"key": "minioEndpoint",
|
||||||
|
"label": "MinIO Endpoint (Internal)",
|
||||||
|
"description": "URL interna para subir archivos (ej: http://localhost:9002)",
|
||||||
|
"required": 1,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "minioPublicUrl",
|
||||||
|
"label": "MinIO Public URL (External)",
|
||||||
|
"description": "URL externa para generar enlaces públicos (ej: https://aws-venus.siip.mx)",
|
||||||
|
"required": 1,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "minioAccessKey",
|
||||||
|
"label": "MinIO Access Key",
|
||||||
|
"description": "Clave de acceso de MinIO",
|
||||||
|
"required": 1,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "minioSecretKey",
|
||||||
|
"label": "MinIO Secret Key",
|
||||||
|
"description": "Clave secreta de MinIO",
|
||||||
|
"required": 1,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "minioBucket",
|
||||||
|
"label": "MinIO Bucket",
|
||||||
|
"description": "Nombre del bucket (ej: vouchers-oxxo)",
|
||||||
|
"required": 1,
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"key": "logging_level",
|
"key": "logging_level",
|
||||||
"label": "enable debug logs",
|
"label": "enable debug logs",
|
||||||
|
|||||||
383
public.php
383
public.php
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
require_once __DIR__ . '/vendor/autoload.php';
|
require_once __DIR__ . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
chdir(__DIR__);
|
||||||
|
|
||||||
use Ubnt\UcrmPluginSdk\Service\PluginLogManager;
|
use Ubnt\UcrmPluginSdk\Service\PluginLogManager;
|
||||||
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
|
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
|
||||||
use Ubnt\UcrmPluginSdk\Service\UcrmApi;
|
use Ubnt\UcrmPluginSdk\Service\UcrmApi;
|
||||||
@ -27,9 +29,10 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$input = file_get_contents('php://input');
|
$input = file_get_contents('php://input');
|
||||||
$jsonData = json_decode((string)$input, true);
|
$jsonData = json_decode((string)$input, true);
|
||||||
|
|
||||||
// Si detectamos que es un webhook de UCRM (contiene uuid o eventName típico)
|
// Si detectamos que es un webhook de UCRM o una solicitud externa (Stripe, OXXO, etc.)
|
||||||
if ($jsonData && (isset($jsonData['uuid']) || isset($jsonData['eventName']))) {
|
// Stripe usa 'type', UCRM usa 'uuid'/'eventName'
|
||||||
file_put_contents($debugLogPath, "[" . date('Y-m-d H:i:s') . "] Webhook detectado en public.php. Delegando a Plugin->run()" . PHP_EOL, FILE_APPEND);
|
if ($jsonData && (isset($jsonData['uuid']) || isset($jsonData['eventName']) || isset($jsonData['type']))) {
|
||||||
|
file_put_contents($debugLogPath, "[" . date('Y-m-d H:i:s') . "] Webhook detectado en public.php (Type: " . ($jsonData['type'] ?? 'UCRM') . "). Delegando a Plugin->run()" . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
$builder = new \DI\ContainerBuilder();
|
$builder = new \DI\ContainerBuilder();
|
||||||
$container = $builder->build();
|
$container = $builder->build();
|
||||||
@ -224,14 +227,70 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Crear intención de pago OXXO (POST AJAX)
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'create_oxxo_intent') {
|
||||||
|
$clientId = $_POST['clientId'] ?? null;
|
||||||
|
$amount = $_POST['amount'] ?? 0;
|
||||||
|
try {
|
||||||
|
$builder = new \DI\ContainerBuilder();
|
||||||
|
$container = $builder->build();
|
||||||
|
$oxxoService = $container->get(\SmsNotifier\Facade\PluginOxxoNotifierFacade::class);
|
||||||
|
// Aumentar tiempo de ejecución y limpiar buffer de salida
|
||||||
|
set_time_limit(300);
|
||||||
|
if (ob_get_length()) ob_clean();
|
||||||
|
|
||||||
|
$eventData = ['client_id' => $clientId];
|
||||||
|
$result = $oxxoService->createOxxoPaymentIntent($eventData, $amount, false); // false = No subir FTP para UI más rápida
|
||||||
|
|
||||||
|
// Verificar si hay output previo y limpiar de nuevo
|
||||||
|
if (ob_get_length()) ob_clean();
|
||||||
|
|
||||||
|
// Retornar el resultado directamente para que coincida con el formato de Plugin.php si es necesario,
|
||||||
|
// pero para el dashboard mantenemos el success wrapper para consistencia JS.
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
$jsonResponse = json_encode(['success' => true, 'data' => $result]);
|
||||||
|
|
||||||
|
if ($jsonResponse === false) {
|
||||||
|
echo json_encode(['success' => false, 'error' => 'JSON Error: ' . json_last_error_msg()]);
|
||||||
|
} else {
|
||||||
|
echo $jsonResponse;
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Cargar imágenes (GET)
|
// Cargar imágenes (GET)
|
||||||
if (isset($_GET['action']) && $_GET['action'] === 'image') {
|
if (isset($_GET['action']) && $_GET['action'] === 'image') {
|
||||||
$filename = basename($_GET['file'] ?? '');
|
$filename = basename($_GET['file'] ?? '');
|
||||||
$path = __DIR__ . '/img/' . $filename;
|
$path = __DIR__ . '/img/' . $filename;
|
||||||
if ($filename && file_exists($path)) {
|
$voucherPath = __DIR__ . '/vouchers_oxxo/' . $filename;
|
||||||
$mime = mime_content_type($path);
|
|
||||||
header("Content-Type: $mime");
|
$finalPath = null;
|
||||||
readfile($path);
|
if (file_exists($path)) {
|
||||||
|
$finalPath = $path;
|
||||||
|
} elseif (file_exists($voucherPath)) {
|
||||||
|
$finalPath = $voucherPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUG: Log image request
|
||||||
|
$debugLog = __DIR__ . '/data/plugin.log';
|
||||||
|
$logMsg = "[PROPAGATED_DEBUG] Image Request: File=$filename | PathTry=$path | VoucherPathTry=$voucherPath | FinalPath=" . ($finalPath ?? 'NULL') . " | Exists=" . (file_exists($voucherPath) ? 'YES' : 'NO') . PHP_EOL;
|
||||||
|
file_put_contents($debugLog, $logMsg, FILE_APPEND);
|
||||||
|
|
||||||
|
if ($finalPath) {
|
||||||
|
// Limpiar cualquier output previo (espacios, warnings, etc) para evitar corromper la imagen
|
||||||
|
if (ob_get_level()) ob_end_clean();
|
||||||
|
|
||||||
|
$size = filesize($finalPath);
|
||||||
|
file_put_contents($debugLog, "[DEBUG_IMG] Serving $finalPath. Size: $size bytes" . PHP_EOL, FILE_APPEND);
|
||||||
|
|
||||||
|
header("Content-Type: image/jpeg");
|
||||||
|
header("Content-Length: " . $size);
|
||||||
|
readfile($finalPath);
|
||||||
|
exit;
|
||||||
} else {
|
} else {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
echo "Image not found";
|
echo "Image not found";
|
||||||
@ -653,7 +712,11 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
</a>
|
</a>
|
||||||
<a href="#" class="nav-link" onclick="switchSection('stripe', this)">
|
<a href="#" class="nav-link" onclick="switchSection('stripe', this)">
|
||||||
<img src="?action=image&file=stripe-logo.png" alt="" style="width: 28px; height: 28px; object-fit: contain; flex-shrink: 0;">
|
<img src="?action=image&file=stripe-logo.png" alt="" style="width: 28px; height: 28px; object-fit: contain; flex-shrink: 0;">
|
||||||
<span>Pagos Stripe</span>
|
<span>Pagos SPEI</span>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="nav-link" onclick="switchSection('oxxo', this)">
|
||||||
|
<img src="?action=image&file=oxxo-logo.png" alt="" style="width: 28px; height: 28px; object-fit: contain; flex-shrink: 0;">
|
||||||
|
<span>Pagos OXXO</span>
|
||||||
</a>
|
</a>
|
||||||
</nav>
|
</nav>
|
||||||
</aside>
|
</aside>
|
||||||
@ -680,7 +743,6 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
Nuevo Instalador
|
Nuevo Instalador
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
|
||||||
|
|
||||||
<section id="section-installers" class="section-view active">
|
<section id="section-installers" class="section-view active">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
@ -784,8 +846,9 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
Ver en CRM
|
Ver en CRM
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<button id="btnCreateIntent" class="btn btn-primary" style="width: 100%; justify-content: center; margin-top: 1rem;">
|
<button id="btnCreateIntent" class="btn btn-primary" style="width: 100%; justify-content: center; height: 50px; font-weight: 700; margin-top: 1.5rem;">
|
||||||
Generar Referencia de Pago
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 10px;"><rect width="20" height="14" x="2" y="5" rx="2"/><line x1="2" x2="22" y1="10" y2="10"/></svg>
|
||||||
|
Generar Referencia SPEI
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -801,6 +864,46 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<!-- Nueva Sección OXXO -->
|
||||||
|
<section id="section-oxxo" class="section-view">
|
||||||
|
<div class="card" style="margin-bottom: 2rem;">
|
||||||
|
<div class="form-group" style="position: relative;">
|
||||||
|
<label>Buscar Cliente para OXXO (Nombre, Email o ID)</label>
|
||||||
|
<input type="text" id="oxxoSearch" class="form-control" placeholder="Escribe para buscar..." autocomplete="off">
|
||||||
|
<div id="oxxoResults" class="search-results"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="oxxoDetailContainer" class="card" style="display: none;">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 1.5rem;">
|
||||||
|
<div>
|
||||||
|
<h3 id="oxxoClientName">Nombre del Cliente</h3>
|
||||||
|
<p id="oxxoClientIdDisplay" style="color: var(--text-muted); font-size: 0.9rem;">ID: #0</p>
|
||||||
|
</div>
|
||||||
|
<div style="text-align: right;">
|
||||||
|
<span class="badge" id="oxxoBalanceBadge" style="background: rgba(235,28,36,0.1); color: #eb1c24;">Saldo Pendiente: $0.00</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="max-width: 400px;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Monto a Cobrar en OXXO (MXN)</label>
|
||||||
|
<div style="position: relative;">
|
||||||
|
<span style="position: absolute; left: 12px; top: 50%; transform: translateY(-50%); font-weight: 600;">$</span>
|
||||||
|
<input type="number" id="oxxoAmount" class="form-control" style="padding-left: 2rem;" placeholder="0.00" step="0.01">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="btnCreateOxxoIntent" class="btn btn-secondary" style="width: 100%; justify-content: center; height: 50px; font-weight: 700; background: #fff; border-color: #eb1c24; color: #eb1c24; margin-top: 1.5rem;">
|
||||||
|
<img src="?action=image&file=oxxo-logo.png" alt="" style="height: 20px; margin-right: 10px;">
|
||||||
|
Generar Ficha OXXO Pay
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Contenedor de Resultado Inline: Full Width -->
|
||||||
|
<div id="oxxoInlineResult" style="margin-top: 1.5rem; display: none;"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
@ -878,8 +981,11 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
title.textContent = 'Centro de Notificaciones';
|
title.textContent = 'Centro de Notificaciones';
|
||||||
desc.textContent = 'Re-envía manualmente notificaciones de WhatsApp a tus clientes';
|
desc.textContent = 'Re-envía manualmente notificaciones de WhatsApp a tus clientes';
|
||||||
} else if (sectionId === 'stripe') {
|
} else if (sectionId === 'stripe') {
|
||||||
title.textContent = 'Pagos Stripe (SPEI)';
|
title.textContent = 'Pagos SPEI';
|
||||||
desc.textContent = 'Genera referencias de transferencia bancaria personalizadas para tus clientes';
|
desc.textContent = 'Genera referencias de transferencia bancaria personalizadas para tus clientes';
|
||||||
|
} else if (sectionId === 'oxxo') {
|
||||||
|
title.textContent = 'Pagos OXXO Pay';
|
||||||
|
desc.textContent = 'Genera fichas de pago para establecimientos OXXO';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -995,12 +1101,15 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
|
|
||||||
// Close search results on click outside
|
// Close search results on click outside
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
if (!clientSearch.contains(e.target) && !searchResults.contains(e.target)) {
|
if (clientSearch && !clientSearch.contains(e.target) && !searchResults.contains(e.target)) {
|
||||||
searchResults.style.display = 'none';
|
searchResults.style.display = 'none';
|
||||||
}
|
}
|
||||||
if (!stripeSearch.contains(e.target) && !stripeResults.contains(e.target)) {
|
if (stripeSearch && !stripeSearch.contains(e.target) && !stripeResults.contains(e.target)) {
|
||||||
stripeResults.style.display = 'none';
|
stripeResults.style.display = 'none';
|
||||||
}
|
}
|
||||||
|
if (document.getElementById('oxxoSearch') && !document.getElementById('oxxoSearch').contains(e.target) && !document.getElementById('oxxoResults').contains(e.target)) {
|
||||||
|
document.getElementById('oxxoResults').style.display = 'none';
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// --- Stripe Logic ---
|
// --- Stripe Logic ---
|
||||||
@ -1071,6 +1180,70 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- OXXO Logic ---
|
||||||
|
const oxxoSearch = document.getElementById('oxxoSearch');
|
||||||
|
const oxxoResults = document.getElementById('oxxoResults');
|
||||||
|
let selectedOxxoClient = null;
|
||||||
|
|
||||||
|
if (oxxoSearch) {
|
||||||
|
oxxoSearch.addEventListener('input', (e) => {
|
||||||
|
const query = e.target.value.trim();
|
||||||
|
clearTimeout(searchTimeout);
|
||||||
|
if (query.length < 2) {
|
||||||
|
oxxoResults.style.display = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
searchTimeout = setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`?action=search_stripe&q=${encodeURIComponent(query)}`);
|
||||||
|
const clients = await res.json();
|
||||||
|
renderOxxoResults(clients);
|
||||||
|
} catch (e) { console.error('Error searching oxxo clients', e); }
|
||||||
|
}, 300);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderOxxoResults(clients) {
|
||||||
|
oxxoResults.innerHTML = '';
|
||||||
|
if (clients.length === 0) {
|
||||||
|
oxxoResults.innerHTML = '<div class="search-item">No se encontraron clientes</div>';
|
||||||
|
} else {
|
||||||
|
clients.forEach(client => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'search-item';
|
||||||
|
const name = client.clientType === 2 ? client.companyName : `${client.firstName} ${client.lastName}`;
|
||||||
|
div.innerHTML = `
|
||||||
|
<span class="name">${name}</span>
|
||||||
|
<span class="details">ID: ${client.id} | ${client.username}</span>
|
||||||
|
`;
|
||||||
|
div.onclick = () => selectOxxoClient(client.id, name);
|
||||||
|
oxxoResults.appendChild(div);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
oxxoResults.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
async function selectOxxoClient(clientId, name) {
|
||||||
|
oxxoResults.style.display = 'none';
|
||||||
|
oxxoSearch.value = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`?action=get_stripe_details&id=${clientId}`);
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
selectedOxxoClient = data;
|
||||||
|
document.getElementById('oxxoClientName').textContent = data.fullName;
|
||||||
|
document.getElementById('oxxoClientIdDisplay').textContent = `ID: #${data.id}`;
|
||||||
|
document.getElementById('oxxoBalanceBadge').textContent = `Saldo Pendiente: $${data.accountOutstanding.toFixed(2)}`;
|
||||||
|
document.getElementById('oxxoAmount').value = data.accountOutstanding > 0 ? data.accountOutstanding : '';
|
||||||
|
|
||||||
|
document.getElementById('oxxoDetailContainer').style.display = 'block';
|
||||||
|
} catch (e) {
|
||||||
|
showToast('Error al cargar detalles del cliente', true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document.getElementById('btnCreateIntent').onclick = async () => {
|
document.getElementById('btnCreateIntent').onclick = async () => {
|
||||||
if (!selectedStripeClient || !selectedStripeClient.stripeCustomerId) {
|
if (!selectedStripeClient || !selectedStripeClient.stripeCustomerId) {
|
||||||
showToast('El cliente no tiene un ID de Stripe válido', true);
|
showToast('El cliente no tiene un ID de Stripe válido', true);
|
||||||
@ -1110,47 +1283,187 @@ $installersData = json_decode($config['installersDataWhatsApp'] ?? '{"instalador
|
|||||||
showToast('Fallo de conexión con el servidor', true);
|
showToast('Fallo de conexión con el servidor', true);
|
||||||
} finally {
|
} finally {
|
||||||
btn.disabled = false;
|
btn.disabled = false;
|
||||||
btn.textContent = 'Generar Referencia de Pago';
|
btn.textContent = 'Referencia SPEI';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function showStripeResult(data) {
|
document.getElementById('btnCreateOxxoIntent').onclick = async () => {
|
||||||
|
if (!selectedOxxoClient) {
|
||||||
|
showToast('Selecciona un cliente primero', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const amount = parseFloat(document.getElementById('oxxoAmount').value);
|
||||||
|
if (!amount || amount < 10) {
|
||||||
|
showToast('El monto debe ser al menos 10 MXN', true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const btn = document.getElementById('btnCreateOxxoIntent');
|
||||||
|
const originalContent = btn.innerHTML;
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Procesando...';
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('action', 'create_oxxo_intent');
|
||||||
|
formData.append('clientId', selectedOxxoClient.id);
|
||||||
|
formData.append('amount', amount);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(window.location.href, { method: 'POST', body: formData });
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (data.success && data.data) {
|
||||||
|
const oxxoData = data.data;
|
||||||
|
const voucherUrl = oxxoData.voucher_image_url || `?action=image&file=${oxxoData.voucher_filename}`;
|
||||||
|
|
||||||
|
const resultHtml = `
|
||||||
|
<div class="alert alert-success" style="border: 1px solid #c3e6cb; background-color: #d4edda; color: #155724; padding: 25px; border-radius: 12px; margin-top: 1.5rem;">
|
||||||
|
<div style="display: flex; flex-wrap: wrap; gap: 30px; align-items: flex-start;">
|
||||||
|
|
||||||
|
<!-- Columna Izquierda: Datos del Pago (Texto) -->
|
||||||
|
<div style="flex: 1 1 350px; min-width: 0;">
|
||||||
|
<h3 style="margin-top: 0; margin-bottom: 20px; color: #155724; font-weight: 700; display: flex; align-items: center;">
|
||||||
|
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 10px;"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
|
||||||
|
¡Ficha Generada Exitosamente!
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div style="margin-bottom: 25px;">
|
||||||
|
<p style="margin-bottom: 5px; font-size: 1rem; text-transform: uppercase; letter-spacing: 1px; color: #155724; opacity: 0.8;">Referencia OXXO Pay</p>
|
||||||
|
<div style="font-family: monospace; font-size: 1.6rem; font-weight: 700; background: rgba(255,255,255,0.7); padding: 10px 15px; border-radius: 8px; word-break: break-all; line-height: 1.2; border: 1px solid rgba(21, 87, 36, 0.2);">
|
||||||
|
${oxxoData.oxxo_reference}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="margin-bottom: 25px;">
|
||||||
|
<p style="margin-bottom: 5px; font-size: 1rem; text-transform: uppercase; letter-spacing: 1px; color: #155724; opacity: 0.8;">Monto a Pagar</p>
|
||||||
|
<p style="font-size: 1.8rem; font-weight: 800; margin: 0;">$${parseFloat(data.data.amount || amount).toFixed(2)} <span style="font-size: 1rem; font-weight: 600;">MXN</span></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="background: white; padding: 15px; border-radius: 8px; border: 1px solid #c3e6cb; font-size: 0.9rem;">
|
||||||
|
<p style="margin-bottom: 8px;"><strong>📥 Enlace Local:</strong> <a href="${voucherUrl}" target="_blank" style="word-break: break-all;">${voucherUrl}</a></p>
|
||||||
|
<p style="margin-bottom: 0;"><strong>🌍 Enlace Stripe:</strong> <a href="${oxxoData.url}" target="_blank" style="word-break: break-all;">${oxxoData.url}</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Columna Derecha: Imagen del Voucher (Grande) -->
|
||||||
|
<div style="flex: 1 1 350px; text-align: center;">
|
||||||
|
<div style="background: white; padding: 15px; border-radius: 12px; border: 1px solid #c3e6cb; box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);">
|
||||||
|
<p style="margin-bottom: 12px; font-weight: 600; color: #155724; font-size: 0.95rem; text-align: left;">Vista Previa del Comprobante</p>
|
||||||
|
<a href="${voucherUrl}" target="_blank" style="display: block; overflow: hidden; border-radius: 6px; border: 1px solid #eee;">
|
||||||
|
<img src="${voucherUrl}" alt="Ficha OXXO" style="width: 100%; height: auto; display: block; max-height: 500px; object-fit: contain;">
|
||||||
|
</a>
|
||||||
|
<div style="margin-top: 15px;">
|
||||||
|
<a href="${voucherUrl}" target="_blank" class="btn btn-primary" style="width: 100%; text-decoration: none; justify-content: center; font-weight: 600; padding: 10px;">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 8px;"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>
|
||||||
|
Descargar / Imprimir
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
const container = document.getElementById('oxxoInlineResult');
|
||||||
|
container.innerHTML = resultHtml;
|
||||||
|
container.style.display = 'block';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
showToast('Error: ' + (data.error || 'Fallo desconocido'), true);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
showToast('Fallo de conexión con el servidor', true);
|
||||||
|
} finally {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.innerHTML = originalContent;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function showStripeResult(data, isOxxo = false) {
|
||||||
const container = document.getElementById('stripeResultContent');
|
const container = document.getElementById('stripeResultContent');
|
||||||
const action = data.next_action;
|
|
||||||
|
|
||||||
|
// Verificación extra de error en datos OXXO aunque success sea true
|
||||||
|
if (isOxxo && (!data.oxxo_reference || data.error)) {
|
||||||
|
showToast('Error en generación: ' + (data.error || 'Referencia vacía'), true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const amountVal = parseFloat(data.amount) || 0;
|
||||||
|
|
||||||
let html = `
|
let html = `
|
||||||
<div style="text-align: center; margin-bottom: 1.5rem;">
|
<div style="text-align: center; margin-bottom: 1.5rem;">
|
||||||
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="var(--success)" stroke-width="2" style="margin-bottom: 1rem;"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
|
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="var(--success)" stroke-width="2" style="margin-bottom: 1rem;"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
|
||||||
<h3 style="color: var(--success); font-weight: 700;">¡Referencia Creada!</h3>
|
<h3 style="color: var(--success); font-weight: 700;">¡Referencia Creada!</h3>
|
||||||
<p style="color: var(--text-muted);">Monto: <strong>$${data.amount.toFixed(2)} MXN</strong></p>
|
<p style="color: var(--text-muted); font-size: 1.1rem;">Monto: <strong>$${amountVal.toFixed(2)} MXN</strong></p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
if (data.status === 'requires_action' && action && action.type === 'display_bank_transfer_instructions') {
|
if (isOxxo) {
|
||||||
const instr = action.display_bank_transfer_instructions;
|
// Revertido a URL simple
|
||||||
|
const voucherUrl = data.voucher_image_url || `?action=image&file=${data.voucher_filename}`;
|
||||||
html += `
|
html += `
|
||||||
<div style="background: #f1f5f9; padding: 1rem; border-radius: 8px; font-family: monospace; font-size: 0.9rem;">
|
<div style="text-align: center;">
|
||||||
<p style="margin-bottom: 0.5rem; color: #1e293b; font-weight: 700;">DATOS PARA TRANSFERENCIA SPEI:</p>
|
<div class="badge" style="background: rgba(235, 28, 36, 0.1); color: #eb1c24; margin-bottom: 1rem; font-size: 1rem; padding: 6px 16px;">OXXO PAY</div>
|
||||||
<div style="display: flex; justify-content: space-between; margin-bottom: 0.3rem;">
|
<p style="font-size: 1.1rem; margin-bottom: 1rem;">Referencia: <strong style="color: var(--primary); font-size: 1.4rem; letter-spacing: 2px;">${data.oxxo_reference}</strong></p>
|
||||||
<span>Banco:</span> <strong>${instr.financial_addresses[0].spei.bank_name}</strong>
|
|
||||||
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; border: 1px solid #dee2e6; margin-bottom: 1.5rem; text-align: left; font-family: monospace; font-size: 0.9rem; word-break: break-all;">
|
||||||
|
<p style="margin-bottom: 5px;"><strong>URL Local:</strong> <a href="${voucherUrl}" target="_blank">${voucherUrl}</a></p>
|
||||||
|
<p style="margin-bottom: 0;"><strong>URL Stripe:</strong> <a href="${data.url}" target="_blank">${data.url}</a></p>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; justify-content: space-between; margin-bottom: 0.3rem;">
|
|
||||||
<span>CLABE:</span> <strong>${instr.financial_addresses[0].spei.clabe}</strong>
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||||
</div>
|
<a href="${voucherUrl}" download="voucher_${data.oxxo_reference}.jpeg" target="_blank" class="btn btn-secondary" style="justify-content: center; text-decoration: none; border-color: var(--primary); color: var(--primary);">
|
||||||
<div style="display: flex; justify-content: space-between;">
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="margin-right: 8px;"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" x2="12" y1="15" y2="3"/></svg>
|
||||||
<span>Beneficiario:</span> <strong>${instr.financial_addresses[0].supported_networks[0].toUpperCase()}</strong>
|
Descargar
|
||||||
|
</a>
|
||||||
|
<a href="${data.url}" target="_blank" class="btn btn-primary" style="justify-content: center; text-decoration: none;">
|
||||||
|
Ver en Stripe
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} else if (data.status === 'requires_action' && data.next_action && data.next_action.type === 'display_bank_transfer_instructions') {
|
||||||
|
const instr = data.next_action.display_bank_transfer_instructions;
|
||||||
|
html += `
|
||||||
|
<div style="background: #f1f5f9; padding: 1.5rem; border-radius: 12px; font-family: monospace; font-size: 1rem; border: 1px solid var(--border);">
|
||||||
|
<p style="margin-bottom: 0.8rem; color: #1e293b; font-weight: 700; border-bottom: 1px solid #cbd5e1; padding-bottom: 0.5rem;">DATOS PARA TRANSFERENCIA SPEI:</p>
|
||||||
|
<div style="display: flex; justify-content: space-between; margin-bottom: 0.5rem;">
|
||||||
|
<span style="color: var(--text-muted);">Banco:</span> <strong>${instr.financial_addresses[0].spei.bank_name}</strong>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: space-between; margin-bottom: 0.5rem;">
|
||||||
|
<span style="color: var(--text-muted);">CLABE:</span> <strong style="color: var(--primary); font-size: 1.1rem;">${instr.financial_addresses[0].spei.clabe}</strong>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; justify-content: space-between;">
|
||||||
|
<span style="color: var(--text-muted);">Beneficiario:</span> <strong>${instr.financial_addresses[0].supported_networks[0].toUpperCase()}</strong>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p style="font-size: 0.8rem; color: var(--text-muted); margin-top: 1rem; text-align: center;">
|
|
||||||
Una vez realizada la transferencia, el pago se registrará automáticamente en UISP.
|
|
||||||
</p>
|
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
html += `<div class="badge" style="width: 100%; text-align: center;">Estado: ${data.status}</div>`;
|
html += `
|
||||||
|
<div style="background: rgba(37, 99, 235, 0.05); padding: 1rem; border-radius: 8px; text-align: center;">
|
||||||
|
<p>Estado del pago: <strong>${data.status}</strong></p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = html;
|
container.innerHTML = html;
|
||||||
document.getElementById('stripeResultModal').style.display = 'flex';
|
container.innerHTML = html;
|
||||||
|
|
||||||
|
// Intentar abrir modal con Bootstrap 5, fallback a jQuery (Bootstrap 4/UCRM)
|
||||||
|
if (typeof bootstrap !== 'undefined' && bootstrap.Modal) {
|
||||||
|
const modalEl = document.getElementById('stripeResultModal');
|
||||||
|
const modal = bootstrap.Modal.getOrCreateInstance(modalEl);
|
||||||
|
modal.show();
|
||||||
|
} else if (typeof jQuery !== 'undefined') {
|
||||||
|
jQuery('#stripeResultModal').modal('show');
|
||||||
|
} else {
|
||||||
|
// Último recurso: intentar forzar display, pero probablemente falte CSS
|
||||||
|
document.getElementById('stripeResultModal').style.display = 'flex';
|
||||||
|
document.getElementById('stripeResultModal').style.opacity = '1';
|
||||||
|
document.getElementById('stripeResultModal').classList.add('show');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTable() {
|
function renderTable() {
|
||||||
|
|||||||
@ -35,6 +35,12 @@ abstract class AbstractOxxoOperationsFacade
|
|||||||
* @var SmsNumberProvider
|
* @var SmsNumberProvider
|
||||||
*/
|
*/
|
||||||
protected $clientPhoneNumber;
|
protected $clientPhoneNumber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \SmsNotifier\Service\MinioStorageService
|
||||||
|
*/
|
||||||
|
protected $minioStorage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var UcrmApi
|
* @var UcrmApi
|
||||||
*/
|
*/
|
||||||
@ -46,11 +52,13 @@ abstract class AbstractOxxoOperationsFacade
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
Logger $logger,
|
Logger $logger,
|
||||||
MessageTextFactory $messageTextFactory,
|
MessageTextFactory $messageTextFactory,
|
||||||
SmsNumberProvider $clientPhoneNumber
|
SmsNumberProvider $clientPhoneNumber,
|
||||||
|
\SmsNotifier\Service\MinioStorageService $minioStorage
|
||||||
) {
|
) {
|
||||||
$this->logger = $logger;
|
$this->logger = $logger;
|
||||||
$this->messageTextFactory = $messageTextFactory;
|
$this->messageTextFactory = $messageTextFactory;
|
||||||
$this->clientPhoneNumber = $clientPhoneNumber;
|
$this->clientPhoneNumber = $clientPhoneNumber;
|
||||||
|
$this->minioStorage = $minioStorage;
|
||||||
|
|
||||||
$config = PluginConfigManager::create()->loadConfig();
|
$config = PluginConfigManager::create()->loadConfig();
|
||||||
$ipServer = $config['ipserver'] ?? 'localhost';
|
$ipServer = $config['ipserver'] ?? 'localhost';
|
||||||
@ -73,400 +81,409 @@ abstract class AbstractOxxoOperationsFacade
|
|||||||
* @throws \Stripe\Exception\ApiErrorException
|
* @throws \Stripe\Exception\ApiErrorException
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function createOxxoPaymentIntent($event_json, $amount = null): array
|
public function createOxxoPaymentIntent($event_json, $amount = null, bool $uploadToFtp = true): array
|
||||||
{
|
{
|
||||||
//declarar un array asociativo de strings pero no asignarle nada aun
|
// 1. Obtener Referencia de Stripe (Lógica Común)
|
||||||
$arrayOxxoPayment = array();
|
$stripeResult = $this->createStripeReference($event_json, $amount);
|
||||||
$integerAmount = $amount;
|
|
||||||
|
|
||||||
$this->logger->info("Creando referencia del cliente para OXXO: " . PHP_EOL);
|
// Si hubo error en Stripe, retornar el resultado de error
|
||||||
|
if ($stripeResult['hasError']) {
|
||||||
|
return $stripeResult['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Procesamiento Síncrono (Generación inmediata)
|
||||||
|
// Usamos los datos obtenidos de Stripe
|
||||||
|
$oxxoData = $stripeResult['data'];
|
||||||
|
|
||||||
|
return $this->processSynchronousGeneration($oxxoData, $uploadToFtp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Crea la orden en el servicio Docker y retorna el ID para flujo asíncrono
|
||||||
|
*/
|
||||||
|
public function createAsyncOxxoOrder($event_json, $amount = null): array
|
||||||
|
{
|
||||||
|
// 1. Obtener Referencia de Stripe
|
||||||
|
$stripeResult = $this->createStripeReference($event_json, $amount);
|
||||||
|
|
||||||
|
if ($stripeResult['hasError']) {
|
||||||
|
return $stripeResult['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $stripeResult['data'];
|
||||||
|
|
||||||
|
// 2. Llamar al servicio Docker para crear la orden (POST /orders)
|
||||||
|
$config = PluginConfigManager::create()->loadConfig();
|
||||||
|
$ipPuppeteer = $config['ipPuppeteer'];
|
||||||
|
$portPuppeteer = $config['portPuppeteer'];
|
||||||
|
$api_url = "http://$ipPuppeteer:$portPuppeteer/orders";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$client = new Client(['timeout' => 5]);
|
||||||
|
$response = $client->post($api_url, [
|
||||||
|
'json' => [
|
||||||
|
'client_id' => $data['clientID'],
|
||||||
|
'amount' => $data['amount'],
|
||||||
|
'client_full_name' => $data['clientFullName'],
|
||||||
|
'oxxo_reference' => $data['oxxo_reference'],
|
||||||
|
'stripe_url' => $data['url']
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$orderData = json_decode($response->getBody()->getContents(), true);
|
||||||
|
|
||||||
|
// Agregar el order_id al resultado para que el Plugin lo devuelva
|
||||||
|
$data['order_id'] = $orderData['order_id'] ?? null;
|
||||||
|
|
||||||
|
return $data; // Retornamos los datos básicos + order_id
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error("Error creando orden asíncrona en Docker: " . $e->getMessage());
|
||||||
|
// Fallback: Retornar los datos de Stripe aunque falle el guardado en DB local (mejor que nada)
|
||||||
|
$data['error'] = 'docker_order_creation_failed';
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger para generar la imagen en background, subirla y actualizar la orden
|
||||||
|
*/
|
||||||
|
public function generateAndUploadOrder(int $orderId, string $stripeUrl, string $clientFullName, bool $uploadToFtp = true): void
|
||||||
|
{
|
||||||
|
$this->logger->info("Iniciando generación en background para Orden #$orderId");
|
||||||
|
|
||||||
|
$config = PluginConfigManager::create()->loadConfig();
|
||||||
|
$ipPuppeteer = $config['ipPuppeteer'];
|
||||||
|
$portPuppeteer = $config['portPuppeteer'];
|
||||||
|
|
||||||
|
// 1. Solicitar Generación (POST /orders/:id/generate)
|
||||||
|
// Calculamos nombre de archivo
|
||||||
|
$clientFullNameWithoutSpaces = str_replace(' ', '_', $clientFullName);
|
||||||
|
$voucherFileName = 'voucher_'.$clientFullNameWithoutSpaces.'_' . time() . '.jpeg';
|
||||||
|
$output_filename = realpath(__DIR__ . '/../../vouchers_oxxo') . '/'. $voucherFileName;
|
||||||
|
|
||||||
|
$generateUrl = "http://$ipPuppeteer:$portPuppeteer/orders/$orderId/generate";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$client = new Client(['timeout' => 60]); // Mayor timeout para Puppeteer
|
||||||
|
$response = $client->post($generateUrl, [
|
||||||
|
'json' => [
|
||||||
|
'url' => $stripeUrl,
|
||||||
|
'filename' => $voucherFileName,
|
||||||
|
'clip' => ['x' => 325, 'y' => 30, 'width' => 550, 'height' => 550]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->getStatusCode() === 200) {
|
||||||
|
// Guardar imagen localmente
|
||||||
|
$imageContent = $response->getBody()->getContents();
|
||||||
|
file_put_contents($output_filename, $imageContent);
|
||||||
|
$this->logger->info("Imagen generada y guardada localmente: $voucherFileName");
|
||||||
|
|
||||||
|
$voucherUrl = '';
|
||||||
|
// 2. Subir a S3/MinIO (si aplica)
|
||||||
|
if ($uploadToFtp) {
|
||||||
|
// $voucherUrl = $this->UploadVoucherToWordpressByImageFileName($voucherFileName);
|
||||||
|
// $this->logger->info("Imagen subida a FTP: $voucherUrl");
|
||||||
|
|
||||||
|
// Nueva implementación MinIO
|
||||||
|
$voucherUrl = $this->minioStorage->uploadFile($output_filename, $voucherFileName);
|
||||||
|
$this->logger->info("Imagen subida a MinIO: $voucherUrl");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Actualizar Orden (POST /orders/:id/complete)
|
||||||
|
if ($voucherUrl) {
|
||||||
|
$completeUrl = "http://$ipPuppeteer:$portPuppeteer/orders/$orderId/complete";
|
||||||
|
$client->post($completeUrl, [
|
||||||
|
'json' => ['voucher_image_url' => $voucherUrl]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error("Error en flujo de background para Orden #$orderId: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene el estado de una orden desde el servicio Docker
|
||||||
|
*/
|
||||||
|
public function getOxxoOrderStatus($orderId): array
|
||||||
|
{
|
||||||
|
$config = PluginConfigManager::create()->loadConfig();
|
||||||
|
$ipPuppeteer = $config['ipPuppeteer'];
|
||||||
|
$portPuppeteer = $config['portPuppeteer'];
|
||||||
|
$api_url = "http://$ipPuppeteer:$portPuppeteer/orders/$orderId";
|
||||||
|
|
||||||
|
try {
|
||||||
|
$client = new Client(['timeout' => 5]);
|
||||||
|
$response = $client->get($api_url);
|
||||||
|
$data = json_decode($response->getBody()->getContents(), true);
|
||||||
|
|
||||||
|
// Si la URL de la imagen es relativa o local, ajustarla si es necesario
|
||||||
|
// pero el servicio ya guarda la URL completa del FTP si se subió.
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error("Error obteniendo estado de orden #$orderId: " . $e->getMessage());
|
||||||
|
return ['error' => 'fetch_failed', 'message' => $e->getMessage()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lógica extraída de Stripe
|
||||||
|
* Retorna ['hasError' => bool, 'data' => array]
|
||||||
|
*/
|
||||||
|
public function createStripeReference($event_json, $amount = null): array
|
||||||
|
{
|
||||||
|
$arrayOxxoPayment = [];
|
||||||
|
$integerAmount = $amount;
|
||||||
|
|
||||||
|
// Inicializar Config y Clientes (Copied logic)
|
||||||
$configManager = PluginConfigManager::create();
|
$configManager = PluginConfigManager::create();
|
||||||
$config = $configManager->loadConfig();
|
$config = $configManager->loadConfig();
|
||||||
$StripeToken = $config['tokenstripe'];
|
$StripeToken = $config['tokenstripe'];
|
||||||
$IPServer = $config['ipserver'];
|
$IPServer = $config['ipserver'];
|
||||||
$tokenCRM = $config['apitoken'];
|
$tokenCRM = $config['apitoken'];
|
||||||
$ipPuppeteer = $config['ipPuppeteer'];
|
|
||||||
$portPuppeteer = $config['portPuppeteer'];
|
|
||||||
|
|
||||||
$baseUri = 'https://' . $IPServer . '/crm/api/v1.0/';
|
$baseUri = 'https://' . $IPServer . '/crm/api/v1.0/';
|
||||||
$currentUserAdmin = $this->ucrmApi->get('users/admins', []);
|
if (!isset($this->ucrmApi)) {
|
||||||
|
// Re-instanciar si es necesario, aunque ya está en consructor
|
||||||
|
// Pero usamos la propiedad de clase
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... Lógica de obtención de cliente, Stripe Customer, PaymentIntent ...
|
||||||
|
// [RESUMIDO: Copiaremos el tocho de código aquí, simplificado]
|
||||||
|
|
||||||
$clientID = $event_json['client_id'];
|
$clientID = $event_json['client_id'];
|
||||||
|
$clientFullName = '';
|
||||||
|
|
||||||
|
// --- 1. Obtener Cliente CRM ---
|
||||||
|
try {
|
||||||
|
$clientGuzzle = new Client([
|
||||||
|
'base_uri' => $baseUri,
|
||||||
|
'headers' => ['X-Auth-App-Key' => $tokenCRM, 'Accept' => 'application/json'],
|
||||||
|
'verify' => false,
|
||||||
|
'timeout' => 5
|
||||||
|
]);
|
||||||
|
$resp = $clientGuzzle->get("clients/" . $clientID);
|
||||||
|
$arrayClientCRM = json_decode($resp->getBody()->getContents(), true);
|
||||||
|
$clientFullName = $arrayClientCRM['firstName'] . ' ' . $arrayClientCRM['lastName'];
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return ['hasError' => true, 'data' => $this->buildErrorArray('errorGetClient', 'Error obteniendo cliente', $clientID, $clientFullName, $amount)];
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 2. Obtener Email y Stripe ID ---
|
||||||
|
$clientEmail = 'siip8873@gmail.com'; // Default
|
||||||
|
foreach ($arrayClientCRM['contacts'] as $contact) {
|
||||||
|
if (!empty($contact['email'])) { $clientEmail = $contact['email']; break; }
|
||||||
|
}
|
||||||
|
|
||||||
$stripeCustomerId = null;
|
$stripeCustomerId = null;
|
||||||
$clientEmail = '';
|
foreach ($arrayClientCRM['attributes'] as $attr) {
|
||||||
$clientFullName = '';
|
if ($attr['key'] === 'stripeCustomerId') { $stripeCustomerId = $attr['value']; break; }
|
||||||
|
}
|
||||||
$clientGuzzleHttp = new Client([
|
if (!$stripeCustomerId) {
|
||||||
'base_uri' => $baseUri,
|
return ['hasError' => true, 'data' => $this->buildErrorArray('errorGetCustomerStripe', 'Cliente sin Stripe ID', $clientID, $clientFullName, $amount)];
|
||||||
'headers' => [
|
|
||||||
'X-Auth-App-Key' => $tokenCRM,
|
|
||||||
'Accept' => 'application/json',
|
|
||||||
],
|
|
||||||
'verify' => false,
|
|
||||||
'timeout' => 5, // Timeout de 5 segundos
|
|
||||||
]);
|
|
||||||
|
|
||||||
try {
|
|
||||||
$response = $clientGuzzleHttp->request('GET', "clients/" . $clientID);
|
|
||||||
$arrayClientCRM = json_decode($response->getBody()->getContents(), true);
|
|
||||||
//$this->logger->info("Valor de arrayClientCRM: " . print_r($arrayClientCRM, true) . PHP_EOL);
|
|
||||||
$clientFullName = $arrayClientCRM['firstName'] . ' ' . $arrayClientCRM['lastName'];
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
if ($e->getCode() === 404) {
|
|
||||||
$this->logger->error("Cliente no encontrado en CRM: " . $clientID . PHP_EOL);
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID, clientFullName y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorGetClientNotFound';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Cliente no encontrado en CRM: ' . $clientID;
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $integerAmount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
//timeout
|
|
||||||
if ($e->getCode() === 408) {
|
|
||||||
$this->logger->error("Timeout al obtener el cliente en CRM: " . $clientID . PHP_EOL);
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorTimeoutGetClient';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Timeout al obtener el cliente en CRM: ' . $clientID;
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $integerAmount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
}
|
|
||||||
$this->logger->error("Error al obtener el cliente en CRM (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorGetClient';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Error al obtener el cliente en CRM: ' . $clientID;
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $integerAmount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtener email del cliente
|
|
||||||
foreach ($arrayClientCRM['contacts'] as $contact) {
|
|
||||||
if (!empty($contact['email'])) {
|
|
||||||
$clientEmail = $contact['email'];
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
$clientEmail = 'siip8873@gmail.com'; // Default
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Obtener stripeCustomerId
|
|
||||||
foreach ($arrayClientCRM['attributes'] as $attribute) {
|
|
||||||
if ($attribute['key'] === 'stripeCustomerId') {
|
|
||||||
$stripeCustomerId = $attribute['value'];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->logger->info("Stripe Customer ID obtenido: " . $stripeCustomerId . PHP_EOL);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->logger->error("Error al obtener el Customer ID de Stripe (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorGetCustomerStripe';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Error al obtener el Customer ID de Stripe: ' . $clientID;
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $integerAmount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 3. Calcular Monto ---
|
||||||
if ($amount === null) {
|
if ($amount === null) {
|
||||||
$amount = abs($arrayClientCRM['accountOutstanding']); //Monto adeudado del cliente
|
$amount = abs($arrayClientCRM['accountOutstanding']);
|
||||||
} else {
|
} else {
|
||||||
//la variable $amount debe ser numérica pero en ocasiones la solicitud puede traer signos o alguna letra ingresada mal por el cliente, se debe analizar para limpiar cualquier caracter que no sea numérico
|
if(!is_numeric($amount)) $amount = preg_replace('/[^\d.]/', '', $amount);
|
||||||
if(!is_numeric($amount)) {
|
|
||||||
$amount = preg_replace('/[^\d.]/', '', $amount); // Eliminar todo lo que no sea dígito o punto decimal
|
|
||||||
}
|
|
||||||
$this->logger->debug("Monto proporcionado directamente: $amount " . PHP_EOL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($amount > 10) {
|
if ($amount <= 10) {
|
||||||
$amountInCents = intval($amount * 100); // Convertir a centavos
|
return ['hasError' => true, 'data' => $this->buildErrorArray('errorsinadeudo', 'Monto insuficiente o sin deuda', $clientID, $clientFullName, $amount)];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
// --- 4. Crear Payment Intent en Stripe ---
|
||||||
$this->logger->debug("Creando referencia en Stripe por $amount para el cliente $stripeCustomerId" . PHP_EOL);
|
try {
|
||||||
$guzzleClient = new Client([
|
$amountInCents = intval($amount * 100);
|
||||||
'timeout' => 5, // Timeout de 5 segundos
|
$guzzleClient = new Client(['timeout' => 10]);
|
||||||
]);
|
|
||||||
|
// Payment Intent
|
||||||
|
$piResp = $guzzleClient->post('https://api.stripe.com/v1/payment_intents', [
|
||||||
|
'auth' => [$StripeToken, ''],
|
||||||
|
'form_params' => [
|
||||||
|
'amount' => $amountInCents,
|
||||||
|
'currency' => 'mxn',
|
||||||
|
'payment_method_types' => ['customer_balance', 'card', 'oxxo'],
|
||||||
|
'customer' => $stripeCustomerId,
|
||||||
|
'metadata' => [
|
||||||
|
'clientId' => $clientID,
|
||||||
|
'ucrm_client_id' => $clientID, // Backwards compatibility
|
||||||
|
'createdBy' => 'UCRM',
|
||||||
|
'paymentType' => 'card.one_time',
|
||||||
|
'signedInAdminId' => $config['idPaymentAdminCRM'] ?? 1,
|
||||||
|
'tipoPago' => 'OXXO'
|
||||||
|
],
|
||||||
|
'payment_method_options' => ['oxxo' => ['expires_after_days' => 3]]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
$paymentIntent = json_decode($piResp->getBody()->getContents(), true);
|
||||||
|
|
||||||
$response = $guzzleClient->post('https://api.stripe.com/v1/payment_intents', [
|
// Payment Method
|
||||||
'auth' => [$StripeToken, ''],
|
$firstName = $arrayClientCRM['firstName'] ?? '';
|
||||||
'form_params' => [
|
$lastName = $arrayClientCRM['lastName'] ?? '';
|
||||||
'amount' => $amountInCents,
|
$pmResp = $guzzleClient->post('https://api.stripe.com/v1/payment_methods', [
|
||||||
'currency' => 'mxn',
|
'auth' => [$StripeToken, ''],
|
||||||
'payment_method_types' => ['customer_balance', 'card', 'oxxo'],
|
'form_params' => [
|
||||||
'description' => 'Pago de servicio de SIIP Internet',
|
'type' => 'oxxo',
|
||||||
'customer' => $stripeCustomerId,
|
'billing_details' => ['name' => "$firstName $lastName", 'email' => $clientEmail]
|
||||||
'metadata' => [
|
]
|
||||||
'clientId' => $clientID,
|
]);
|
||||||
'createdBy' => 'UCRM',
|
$paymentMethod = json_decode($pmResp->getBody()->getContents(), true);
|
||||||
'paymentType' => 'card.one_time',
|
|
||||||
'signedInAdminId' => $currentUserAdmin[1]['id'],
|
|
||||||
'tipoPago' => 'OXXO',
|
|
||||||
],
|
|
||||||
'payment_method_options' => [
|
|
||||||
'oxxo' => [
|
|
||||||
'expires_after_days' => 3,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$paymentIntent = json_decode($response->getBody()->getContents(), true);
|
// Confirm
|
||||||
|
$confResp = $guzzleClient->post('https://api.stripe.com/v1/payment_intents/' . $paymentIntent['id'] . '/confirm', [
|
||||||
|
'auth' => [$StripeToken, ''],
|
||||||
|
'form_params' => ['payment_method' => $paymentMethod['id']]
|
||||||
|
]);
|
||||||
|
$paymentIntentConfirm = json_decode($confResp->getBody()->getContents(), true);
|
||||||
|
|
||||||
} catch (\Stripe\Exception\ApiConnectionException $e) {
|
} catch (Exception $e) {
|
||||||
$this->logger->error("Error de conexión con Stripe (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
|
return ['hasError' => true, 'data' => $this->buildErrorArray('errorStripeApi', $e->getMessage(), $clientID, $clientFullName, $amount)];
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
}
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorConnectionStripe';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Error de conexión con Stripe: ' . $clientID;
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
|
|
||||||
} catch (\Stripe\Exception\ApiErrorException $e) {
|
// --- 5. Extraer Datos OXXO ---
|
||||||
$this->logger->error("Error de la API de Stripe: " . $e->getMessage() . PHP_EOL);
|
if (!empty($paymentIntentConfirm['next_action']['oxxo_display_details'])) {
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
$oxxoDetails = $paymentIntentConfirm['next_action']['oxxo_display_details'];
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
return [
|
||||||
$arrayOxxoPayment['url'] = '';
|
'hasError' => false,
|
||||||
$arrayOxxoPayment['error'] = 'errorApiStripe';
|
'data' => [
|
||||||
$arrayOxxoPayment['failDescription'] = 'Error de la API de Stripe: ' . $clientID;
|
'oxxo_reference' => $oxxoDetails['number'],
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
'url' => $oxxoDetails['hosted_voucher_url'],
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
'error' => '',
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
'clientID' => $clientID,
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
'clientFullName' => $clientFullName,
|
||||||
return $arrayOxxoPayment;
|
'amount' => $amount,
|
||||||
|
'voucher_image_url' => ''
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
} catch (Exception $e) {
|
return ['hasError' => true, 'data' => $this->buildErrorArray('errorNoOxxoDetails', 'No se recibieron detalles OXXO', $clientID, $clientFullName, $amount)];
|
||||||
$this->logger->error("Error inesperado al crear PaymentIntent (Error {$e->getCode()}): " . $e->getMessage() . PHP_EOL);
|
}
|
||||||
//si e->getMessage incluye el mensaje: You must provide a customer when creating or updating a PaymentIntent with a `customer_ba (truncated...) declarar una variable y ahi poner "Este cliente no tiene cuenta de Stripe"
|
|
||||||
if ($e->getMessage() == 'You must provide a customer when creating or updating a PaymentIntent with a `customer_ba (truncated...)') {
|
|
||||||
$this->logger->error("Este cliente no tiene cuenta de Stripe" . PHP_EOL);
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Este cliente no tiene cuenta de Stripe: ' . $clientID;
|
|
||||||
} else {
|
|
||||||
$this->logger->error("Error inesperado al crear PaymentIntent: " . $e->getMessage() . PHP_EOL);
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Error inesperado al crear PaymentIntent: ' . $clientID;
|
|
||||||
}
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorCreatePaymentIntent';
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
|
|
||||||
}
|
private function buildErrorArray($code, $desc, $clientId, $name, $amount) {
|
||||||
|
return [
|
||||||
|
'oxxo_reference' => '',
|
||||||
|
'url' => '',
|
||||||
|
'error' => $code,
|
||||||
|
'failDescription' => $desc,
|
||||||
|
'clientID' => $clientId,
|
||||||
|
'clientFullName' => $name,
|
||||||
|
'amount' => $amount,
|
||||||
|
'voucher_image_url' => ''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
/**
|
||||||
$firstName = isset($arrayClientCRM['firstName']) ? trim($arrayClientCRM['firstName']) : '';
|
* Crea la orden en el microservicio (Paso 1 del flujo asíncrono)
|
||||||
$lastName = isset($arrayClientCRM['lastName']) ? trim($arrayClientCRM['lastName']) : '';
|
*/
|
||||||
|
public function createOxxoOrder($arrayOxxoPayment) {
|
||||||
|
$config = PluginConfigManager::create()->loadConfig();
|
||||||
|
$ipPuppeteer = $config['ipPuppeteer'];
|
||||||
|
$portPuppeteer = $config['portPuppeteer'];
|
||||||
|
$baseUrl = 'http://'.$ipPuppeteer.':'.$portPuppeteer;
|
||||||
|
$guzzleClient = new Client(['timeout' => 10]);
|
||||||
|
|
||||||
if (strlen($firstName) < 2 || strlen($lastName) < 2) {
|
try {
|
||||||
$this->logger->error("Nombre/apellido inválido: ' . $firstName . ' ' . $lastName" . PHP_EOL);
|
$createOrderResp = $guzzleClient->post($baseUrl . '/orders', [
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
'json' => [
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
'client_id' => $arrayOxxoPayment['clientID'],
|
||||||
$arrayOxxoPayment['url'] = '';
|
'amount' => $arrayOxxoPayment['amount'],
|
||||||
$arrayOxxoPayment['error'] = 'errorNombreApellidoInvalido';
|
'client_full_name' => $arrayOxxoPayment['clientFullName'],
|
||||||
$arrayOxxoPayment['failDescription'] = "Nombre/apellido inválido: ' . $firstName . ' ' . $lastName";
|
'oxxo_reference' => $arrayOxxoPayment['oxxo_reference'],
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
'stripe_url' => $arrayOxxoPayment['url']
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
]
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
]);
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
$orderData = json_decode($createOrderResp->getBody()->getContents(), true);
|
||||||
return $arrayOxxoPayment;
|
$arrayOxxoPayment['order_id'] = $orderData['order_id'] ?? null;
|
||||||
|
return $arrayOxxoPayment;
|
||||||
|
|
||||||
}
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error("Error creando orden OXXO: " . $e->getMessage());
|
||||||
$responsePaymentMethod = $guzzleClient->post('https://api.stripe.com/v1/payment_methods', [
|
|
||||||
'auth' => [$StripeToken, ''],
|
|
||||||
'form_params' => [
|
|
||||||
'type' => 'oxxo',
|
|
||||||
'billing_details' => [
|
|
||||||
'name' => "$firstName $lastName",
|
|
||||||
'email' => $clientEmail,
|
|
||||||
],
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$paymentMethod = json_decode($responsePaymentMethod->getBody()->getContents(), true);
|
|
||||||
|
|
||||||
$responseConfirmPaymentIntent = $guzzleClient->post('https://api.stripe.com/v1/payment_intents/' . $paymentIntent['id'] . '/confirm', [
|
|
||||||
'auth' => [$StripeToken, ''],
|
|
||||||
'form_params' => [
|
|
||||||
'payment_method' => $paymentMethod['id'],
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
$paymentIntentConfirm = json_decode($responseConfirmPaymentIntent->getBody()->getContents(), true);
|
|
||||||
|
|
||||||
} catch (Exception $e) {
|
|
||||||
$this->logger->error("Error al confirmar PaymentIntent: " . $e->getMessage() . PHP_EOL);
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorConfirmPaymentIntent';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Error al confirmar PaymentIntent: ' . $e->getMessage();
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($paymentIntentConfirm['next_action']) && isset($paymentIntentConfirm['next_action']['oxxo_display_details'])) {
|
|
||||||
$oxxoPayment = $paymentIntentConfirm['next_action']['oxxo_display_details'];
|
|
||||||
$oxxo_reference = $oxxoPayment['number'];
|
|
||||||
$oxxo_receipt_url = $oxxoPayment['hosted_voucher_url'];
|
|
||||||
|
|
||||||
$this->logger->info("Referencia OXXO: " . $oxxo_reference . PHP_EOL);
|
|
||||||
$this->logger->info("URL del recibo: " . $oxxo_receipt_url . PHP_EOL);
|
|
||||||
//$this->captureScreenshot($oxxo_receipt_url);
|
|
||||||
//devolver un array con los campos de url de oxxo, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = $oxxo_reference;
|
|
||||||
$arrayOxxoPayment['url'] = $oxxo_receipt_url;
|
|
||||||
$arrayOxxoPayment['error'] = '';
|
|
||||||
$arrayOxxoPayment['failDescription'] = '';
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
|
||||||
$this->logger->info("Referencia OXXO creada correctamente." . PHP_EOL);
|
|
||||||
|
|
||||||
|
|
||||||
// Configuración de la API de tu servicio Docker de Puppeteer
|
|
||||||
$api_url = 'http://'.$ipPuppeteer.':'.$portPuppeteer.'/screenshot'; // Asegúrate que esta URL sea accesible
|
|
||||||
|
|
||||||
// --- Datos para la petición ---
|
|
||||||
$request_data = [
|
|
||||||
'url' => $oxxo_receipt_url, // URL del recibo de OXXO
|
|
||||||
// Opcional: Si quieres recortar la imagen, descomenta y ajusta el 'clip'
|
|
||||||
|
|
||||||
'clip' => [
|
|
||||||
'x' => 325,
|
|
||||||
'y' => 30,
|
|
||||||
'width' => 550,
|
|
||||||
'height' => 550
|
|
||||||
]
|
|
||||||
|
|
||||||
];
|
|
||||||
|
|
||||||
// Nombre del archivo donde se guardará la imagen
|
|
||||||
$clientFullNameWithoutSpaces = str_replace(' ', '_', $clientFullName); // Reemplazar espacios por guiones bajos
|
|
||||||
$voucherFileName = 'voucher_'.$clientFullNameWithoutSpaces.'_' . time() . '.jpeg'; // Usamos .jpeg por defecto
|
|
||||||
$output_filename = __DIR__ . '/../../vouchers_oxxo/' . $voucherFileName; // Usamos .jpeg por defecto
|
|
||||||
$output_filename = realpath(__DIR__ . '/../../vouchers_oxxo') . '/'. $voucherFileName; // Mejor: ruta absoluta y verifica que el directorio exista
|
|
||||||
//$output_filename = '/path/to/vouchers_oxxo/voucher_' . time() . '.jpeg'; // Mejor aún: ruta absoluta y fija, si es posible
|
|
||||||
|
|
||||||
$guzzleClient = new Client([
|
|
||||||
'timeout' => 5, // Timeout de 5 segundos
|
|
||||||
]);
|
|
||||||
// Descargar el recibo de OXXO
|
|
||||||
try {
|
|
||||||
// --- Realizar la petición POST ---
|
|
||||||
$response = $guzzleClient->post($api_url, [
|
|
||||||
'json' => $request_data, // Guzzle codifica automáticamente el array a JSON y establece Content-Type: application/json
|
|
||||||
'headers' => [
|
|
||||||
'Accept' => 'image/jpeg, image/png', // Indicar que esperamos una imagen
|
|
||||||
],
|
|
||||||
// Opcional: para depuración si necesitas ver el cuerpo de la respuesta en caso de error
|
|
||||||
// 'http_errors' => false // Desactiva las excepciones para códigos de estado 4xx/5xx y maneja la respuesta manualmente
|
|
||||||
]);
|
|
||||||
|
|
||||||
// --- Procesar la respuesta ---
|
|
||||||
$statusCode = $response->getStatusCode();
|
|
||||||
$contentType = $response->getHeaderLine('Content-Type');
|
|
||||||
|
|
||||||
$this->logger->debug("Status Code: " . $statusCode);
|
|
||||||
$this->logger->debug("Content Type: " . $contentType);
|
|
||||||
|
|
||||||
if ($statusCode === 200 && str_contains($contentType, 'image/')) {
|
|
||||||
// La respuesta es una imagen y el código de estado es 200 OK
|
|
||||||
$image_content = $response->getBody()->getContents();
|
|
||||||
|
|
||||||
// *** VERIFICACIÓN IMPORTANTE: ***
|
|
||||||
if (file_put_contents($output_filename, $image_content)) {
|
|
||||||
$this->logger->debug("¡Imagen guardada exitosamente en: " . $output_filename);
|
|
||||||
$url_file = $this->UploadVoucherToWordpressByImageFileName($voucherFileName); //Carga del comprobante PDF a Wordpress para su posterior envío
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = $url_file; // Agregar la URL del archivo de imagen al array
|
|
||||||
} else {
|
|
||||||
$this->logger->error("Error: No se pudo guardar la imagen en " . $output_filename);
|
|
||||||
$this->logger->error("Ruta del archivo: " . $output_filename); // Agregado para depuración
|
|
||||||
$this->logger->error("Directorio del script: " . __DIR__); // Agregado para depuración
|
|
||||||
$this->logger->error("Error de PHP: " . error_get_last()['message']); // Agregado para depuración
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// No es una imagen o hubo un error en el servicio
|
|
||||||
$this->logger->debug("Error: La respuesta no es una imagen o el código de estado no es 200 OK.");
|
|
||||||
$this->logger->debug("Cuerpo de la respuesta: " . $response->getBody()->getContents());
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (RequestException $e) {
|
|
||||||
// Manejo de errores de red o del servidor (ej. timeouts, 4xx, 5xx si http_errors no es false)
|
|
||||||
$this->logger->error("Error en la petición: " . $e->getMessage());
|
|
||||||
if ($e->hasResponse()) {
|
|
||||||
$this->logger->error("Cuerpo de la respuesta de error: " . $e->getResponse()->getBody()->getContents());
|
|
||||||
$this->logger->error("Código de estado HTTP de error: " . $e->getResponse()->getStatusCode());
|
|
||||||
}
|
|
||||||
} catch (Exception $e) {
|
|
||||||
// Otros errores inesperados
|
|
||||||
$this->logger->error("Error inesperado: " . $e->getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
} else {
|
|
||||||
$this->logger->info("El PaymentIntent no tiene detalles de OXXO disponibles. Estado: " . $paymentIntentConfirm['status'] . PHP_EOL);
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorPaymentIntentWithoutOxxoDetails';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'El PaymentIntent no tiene detalles de OXXO disponibles. Estado: ' . $paymentIntentConfirm['status'];
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$this->logger->info("Este cliente no tiene adeudos." . PHP_EOL);
|
|
||||||
//devolver un array con los campos del codigo error, descripción de la falla, clientID y amount
|
|
||||||
$arrayOxxoPayment['oxxo_reference'] = '';
|
|
||||||
$arrayOxxoPayment['url'] = '';
|
|
||||||
$arrayOxxoPayment['error'] = 'errorsinadeudo';
|
|
||||||
$arrayOxxoPayment['failDescription'] = 'Este cliente no tiene adeudos.';
|
|
||||||
$arrayOxxoPayment['clientID'] = $clientID;
|
|
||||||
$arrayOxxoPayment['clientFullName'] = $clientFullName;
|
|
||||||
$arrayOxxoPayment['amount'] = $amount;
|
|
||||||
$arrayOxxoPayment['voucher_image_url'] = '';
|
|
||||||
return $arrayOxxoPayment;
|
return $arrayOxxoPayment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Genera el voucher y lo sube (Paso 2 del flujo asíncrono)
|
||||||
|
*/
|
||||||
|
public function generateOxxoVoucher($arrayOxxoPayment, $uploadToFtp) {
|
||||||
|
if (empty($arrayOxxoPayment['order_id'])) {
|
||||||
|
$this->logger->error("Intentando generar voucher sin order_id");
|
||||||
|
return $arrayOxxoPayment;
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = PluginConfigManager::create()->loadConfig();
|
||||||
|
$ipPuppeteer = $config['ipPuppeteer'];
|
||||||
|
$portPuppeteer = $config['portPuppeteer'];
|
||||||
|
$baseUrl = 'http://'.$ipPuppeteer.':'.$portPuppeteer;
|
||||||
|
$guzzleClient = new Client(['timeout' => 60]);
|
||||||
|
|
||||||
|
$clientFullNameWithoutSpaces = str_replace(' ', '_', $arrayOxxoPayment['clientFullName']);
|
||||||
|
$voucherFileName = 'voucher_'.$clientFullNameWithoutSpaces.'_' . time() . '.jpeg';
|
||||||
|
$output_filename = realpath(__DIR__ . '/../../vouchers_oxxo') . '/'. $voucherFileName;
|
||||||
|
|
||||||
|
$request_data = [
|
||||||
|
'url' => $arrayOxxoPayment['url'],
|
||||||
|
'filename' => $voucherFileName,
|
||||||
|
'clip' => ['x' => 325, 'y' => 30, 'width' => 550, 'height' => 550]
|
||||||
|
];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $guzzleClient->post($baseUrl . '/orders/' . $arrayOxxoPayment['order_id'] . '/generate', [
|
||||||
|
'json' => $request_data,
|
||||||
|
'headers' => ['Accept' => 'image/jpeg, image/png']
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($response->getStatusCode() === 200) {
|
||||||
|
file_put_contents($output_filename, $response->getBody()->getContents());
|
||||||
|
|
||||||
|
$arrayOxxoPayment['voucher_filename'] = $voucherFileName;
|
||||||
|
|
||||||
|
if ($uploadToFtp) {
|
||||||
|
$url_file = $this->minioStorage->uploadFile($output_filename, $voucherFileName);
|
||||||
|
$arrayOxxoPayment['voucher_image_url'] = $url_file;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$guzzleClient->post($baseUrl . '/orders/' . $arrayOxxoPayment['order_id'] . '/complete', [
|
||||||
|
'json' => ['voucher_image_url' => $url_file]
|
||||||
|
]);
|
||||||
|
|
||||||
|
// CLEANUP: Eliminar voucher local tras subida exitosa
|
||||||
|
if (file_exists($output_filename)) {
|
||||||
|
unlink($output_filename);
|
||||||
|
//$this->logger->info("Limpieza: Voucher local eliminado ($voucherFileName)");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$this->logger->warning("No se pudo actualizar URL final: " . $ex->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->logger->error("Error generando voucher (Puppeteer): " . $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $arrayOxxoPayment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mantiene compatibilidad con llamadas anteriores
|
||||||
|
*/
|
||||||
|
private function processSynchronousGeneration($arrayOxxoPayment, $uploadToFtp) {
|
||||||
|
$arrayOxxoPayment = $this->createOxxoOrder($arrayOxxoPayment);
|
||||||
|
if (!empty($arrayOxxoPayment['order_id'])) {
|
||||||
|
$arrayOxxoPayment = $this->generateOxxoVoucher($arrayOxxoPayment, $uploadToFtp);
|
||||||
|
}
|
||||||
|
return $arrayOxxoPayment;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -501,21 +518,18 @@ abstract class AbstractOxxoOperationsFacade
|
|||||||
{
|
{
|
||||||
|
|
||||||
// $log = PluginLogManager::create(); //Initialize Logger
|
// $log = PluginLogManager::create(); //Initialize Logger
|
||||||
// $configManager = PluginConfigManager::create();
|
$configManager = PluginConfigManager::create();
|
||||||
// $config = $configManager->loadConfig();
|
$config = $configManager->loadConfig();
|
||||||
|
|
||||||
// // Configuración de conexión FTP
|
// Configuración de conexión FTP
|
||||||
// $ftp_server = $config['hostServerFTP'];
|
$ftp_server = $config['hostServerFTP'];
|
||||||
// $ftp_username = $config['usernameServerFTP'];
|
$ftp_username = $config['usernameServerFTP'];
|
||||||
// $ftp_password = $config['passServerFTP'];
|
$ftp_password = $config['passServerFTP'];
|
||||||
|
|
||||||
$remote_folder = "/public_html/wp/wp-content/uploads/img/";
|
$remote_folder = "/public_html/wp/wp-content/uploads/img/";
|
||||||
|
|
||||||
|
|
||||||
// Configuración de conexión FTP
|
// Configuración de conexión FTP
|
||||||
$ftp_server = "siip.mx";
|
|
||||||
$ftp_username = "siip0001";
|
|
||||||
$ftp_password = '$spGiT,[wa)n';
|
|
||||||
$remote_file = "/public_html/wp/wp-content/uploads/img/" . $imageFileName;
|
$remote_file = "/public_html/wp/wp-content/uploads/img/" . $imageFileName;
|
||||||
$file_to_upload = __DIR__ . '/' . $imageFileName;
|
$file_to_upload = __DIR__ . '/' . $imageFileName;
|
||||||
$url = 'https://siip.mx/wp/wp-content/uploads/img/' . $imageFileName;
|
$url = 'https://siip.mx/wp/wp-content/uploads/img/' . $imageFileName;
|
||||||
@ -620,9 +634,6 @@ abstract class AbstractOxxoOperationsFacade
|
|||||||
|
|
||||||
$log->appendLog("Subiendo voucher a worpdpress " . PHP_EOL);
|
$log->appendLog("Subiendo voucher a worpdpress " . PHP_EOL);
|
||||||
// Configuración de conexión FTP
|
// Configuración de conexión FTP
|
||||||
// $ftp_server = "siip.mx";
|
|
||||||
// $ftp_username = "siip0001";
|
|
||||||
// $ftp_password = '$spGiT,[wa)n';
|
|
||||||
$remote_file = "/public_html/wp/wp-content/uploads/vouchers_oxxo/" . $imageFileName;
|
$remote_file = "/public_html/wp/wp-content/uploads/vouchers_oxxo/" . $imageFileName;
|
||||||
$file_to_upload = __DIR__ . '/../../vouchers_oxxo/' . $imageFileName;
|
$file_to_upload = __DIR__ . '/../../vouchers_oxxo/' . $imageFileName;
|
||||||
$url = 'https://siip.mx/wp/wp-content/uploads/vouchers_oxxo/' . $imageFileName;
|
$url = 'https://siip.mx/wp/wp-content/uploads/vouchers_oxxo/' . $imageFileName;
|
||||||
@ -642,9 +653,16 @@ abstract class AbstractOxxoOperationsFacade
|
|||||||
$log->appendLog("El archivo ha sido cargado exitosamente." . PHP_EOL);
|
$log->appendLog("El archivo ha sido cargado exitosamente." . PHP_EOL);
|
||||||
$log->appendLog("La URL es: " . $url . PHP_EOL);
|
$log->appendLog("La URL es: " . $url . PHP_EOL);
|
||||||
|
|
||||||
$this->deleteFilesWordpressExceptLastHundred($log, $ftp_conn, $remote_file);
|
// try {
|
||||||
|
// $this->deleteFilesWordpressExceptLastHundred($log, $ftp_conn, $remote_folder);
|
||||||
|
// } catch (\Exception $e) {
|
||||||
|
// $log->appendLog("Error en limpieza de archivos antiguos: " . $e->getMessage() . PHP_EOL);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Cerrar conexión FTP (o dejar abierta si se prefiere, pero mejor cerrar al final si es posible, aunque aquí retornamos directo)
|
||||||
|
// ftp_close($ftp_conn);
|
||||||
// Cerrar conexión FTP
|
// Cerrar conexión FTP
|
||||||
ftp_close($ftp_conn); //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
|
//ftp_close($ftp_conn); //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
|
||||||
return $url; //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
|
return $url; //COMENTAR AQUÍ SI SE BORRAN LOS ARCHIVOS DE WORDPRESS DESCOMENTANDO EL CÓDIGO DE MÁS ABAJO
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -93,10 +93,7 @@ abstract class AbstractStripeOperationsFacade
|
|||||||
$clientId = $pi->metadata->clientId ?? null;
|
$clientId = $pi->metadata->clientId ?? null;
|
||||||
if (!$clientId) return;
|
if (!$clientId) return;
|
||||||
|
|
||||||
$methodId = null;
|
$methodId = $this->findPaymentMethodId('Transferencia bancaria');
|
||||||
foreach ($this->ucrmApi->get('payment-methods') as $m) {
|
|
||||||
if ($m['name'] === 'Transferencia bancaria') { $methodId = $m['id']; break; }
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($methodId) {
|
if ($methodId) {
|
||||||
$this->ucrmApi->post('payments', [
|
$this->ucrmApi->post('payments', [
|
||||||
@ -104,7 +101,7 @@ abstract class AbstractStripeOperationsFacade
|
|||||||
'amount' => abs($data['net_amount']) / 100,
|
'amount' => abs($data['net_amount']) / 100,
|
||||||
'currencyCode' => strtoupper($pi->currency),
|
'currencyCode' => strtoupper($pi->currency),
|
||||||
'methodId' => $methodId,
|
'methodId' => $methodId,
|
||||||
'note' => "Stripe (Saldo Aplicado) - PI: $piId",
|
'note' => "Transferencia Bancaria (Stripe Saldo) - PI: $piId",
|
||||||
'createdDate' => date('c'),
|
'createdDate' => date('c'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@ -113,6 +110,103 @@ abstract class AbstractStripeOperationsFacade
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function registerPaymentFromIntent(array $data): void {
|
||||||
|
$piId = $data['id'] ?? null;
|
||||||
|
if (!$piId) return;
|
||||||
|
|
||||||
|
if (($data['status'] ?? '') !== 'succeeded') {
|
||||||
|
$this->logger->warning("PaymentIntent $piId no está succeeded (status: " . ($data['status']??'unknown') . ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buscar clientId en metadata (prioridad: clientId > ucrm_client_id)
|
||||||
|
$clientId = $data['metadata']['clientId'] ?? $data['metadata']['ucrm_client_id'] ?? null;
|
||||||
|
|
||||||
|
// Fallback: Buscar por Stripe Customer ID si no hay metadata
|
||||||
|
if (!$clientId && !empty($data['customer'])) {
|
||||||
|
$clientId = $this->findClientIdByStripeCustomer($data['customer']);
|
||||||
|
if ($clientId) {
|
||||||
|
$this->logger->info("Cliente encontrado por Stripe ID ({$data['customer']}): $clientId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$clientId) {
|
||||||
|
$this->logger->warning("PaymentIntent $piId no tiene clientId en metadata y no se encontró por Customer ID ({$data['customer']}).");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Intentar detectar Payment Method name basado en tipo
|
||||||
|
$type = $data['payment_method_types'][0] ?? 'card';
|
||||||
|
$methodSearchName = ($type === 'oxxo') ? 'OXXO' : 'Stripe';
|
||||||
|
|
||||||
|
// Buscar ID de metodo en UCRM
|
||||||
|
$methodId = $this->findPaymentMethodId($methodSearchName);
|
||||||
|
if (!$methodId && $methodSearchName === 'OXXO') {
|
||||||
|
$methodId = $this->findPaymentMethodId('Stripe'); // Fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($methodId) {
|
||||||
|
$checkAmount = ($data['amount_received'] ?? $data['amount']) / 100;
|
||||||
|
$this->ucrmApi->post('payments', [
|
||||||
|
'clientId' => (int)$clientId,
|
||||||
|
'amount' => $checkAmount,
|
||||||
|
'currencyCode' => strtoupper($data['currency'] ?? 'MXN'),
|
||||||
|
'methodId' => $methodId,
|
||||||
|
'note' => "Stripe ($methodSearchName) - PI: $piId",
|
||||||
|
'createdDate' => date('c'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->logger->info("Pago registrado en UCRM vía PI Succeeded: $piId, Cliente: $clientId, Monto: $checkAmount");
|
||||||
|
} else {
|
||||||
|
$this->logger->warning("No se encontró método de pago para '$methodSearchName' en UCRM.");
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error("Error al registrar pago desde PaymentIntent: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findClientIdByStripeCustomer(string $stripeCustomerId): ?int {
|
||||||
|
try {
|
||||||
|
// Nota: Esto puede ser lento si hay muchos clientes, pero es un fallback.
|
||||||
|
// Idealmente usaríamos $this->ucrmApi->get('clients', ['customAttributeKey' => 'stripeCustomerId', ...]) si existiera ese filtro.
|
||||||
|
// Como fallback, buscamos en los clientes que tenemos cacheados o hacemos un search.
|
||||||
|
// UCRM API permite filtrar por userIdent? No directamente por atributo custom en GET /clients sin plugin extentions.
|
||||||
|
// PERO podemos usar la API de 'clients' y filtrar en memoria si no son muchos, o confiar en que el usuario ya usó metadata en el futuro.
|
||||||
|
// MEJOR OPCION: Usar el endpoint de attributes si es posible, o iterar.
|
||||||
|
// Dado que no queremos matar el server, limitaremos la búsqueda o asumiremos que el FIX de metadata es el principal.
|
||||||
|
// Sin embargo, para este caso específico, vamos a intentar buscar en los clientes recientes o usar una búsqueda básica.
|
||||||
|
// UCRM API v1.0 GET /clients soporta ?customAttributeId&customAttributeValue
|
||||||
|
|
||||||
|
$attrId = $this->resolveAttributeId('stripeCustomerId');
|
||||||
|
if (!$attrId) return null;
|
||||||
|
|
||||||
|
$clients = $this->ucrmApi->get('clients', [
|
||||||
|
'customAttributeId' => $attrId,
|
||||||
|
'customAttributeValue' => $stripeCustomerId
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!empty($clients) && isset($clients[0]['id'])) {
|
||||||
|
return (int)$clients[0]['id'];
|
||||||
|
}
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error("Error buscando cliente por Stripe ID: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function findPaymentMethodId(string $name): ?int {
|
||||||
|
try {
|
||||||
|
$methods = $this->ucrmApi->get('payment-methods');
|
||||||
|
foreach ($methods as $m) {
|
||||||
|
if (stripos($m['name'], $name) !== false) {
|
||||||
|
return $m['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(\Exception $e) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public function createStripeClient(NotificationData $notificationData, string $tagName, bool $generateSpei = true): void {
|
public function createStripeClient(NotificationData $notificationData, string $tagName, bool $generateSpei = true): void {
|
||||||
$clientId = $notificationData->clientId;
|
$clientId = $notificationData->clientId;
|
||||||
if (!$clientId) return;
|
if (!$clientId) return;
|
||||||
|
|||||||
@ -3,11 +3,13 @@ namespace SmsNotifier\Facade;
|
|||||||
|
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use GuzzleHttp\Client;
|
use GuzzleHttp\Client;
|
||||||
use Imagick;
|
// use Imagick; // Legacy removed
|
||||||
use ImagickException;
|
// use ImagickException; // Legacy removed
|
||||||
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
|
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
|
||||||
use Ubnt\UcrmPluginSdk\Service\PluginLogManager;
|
use Ubnt\UcrmPluginSdk\Service\PluginLogManager;
|
||||||
use Ubnt\UcrmPluginSdk\Service\UcrmApi;
|
use Ubnt\UcrmPluginSdk\Service\UcrmApi;
|
||||||
|
use SmsNotifier\Service\MinioStorageService;
|
||||||
|
use SmsNotifier\Service\Logger;
|
||||||
|
|
||||||
//use SmsNotifier\Service\Logger;
|
//use SmsNotifier\Service\Logger;
|
||||||
|
|
||||||
@ -430,26 +432,117 @@ class ClientCallBellAPI
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
// --- NUEVO FLUJO: Microservicio PDF->IMG + MinIO ---
|
||||||
$image = new Imagick();
|
$url_file = '';
|
||||||
$image->setResolution(300, 300);
|
$rutaImagen = str_replace('.pdf', '.jpg', $rutaArchivo); // Usamos .jpg para la salida del microservicio
|
||||||
$image->readImage($rutaArchivo); // Aquí podría ocurrir un error
|
|
||||||
$image->setImageFormat('png');
|
|
||||||
$rutaImagen = str_replace('.pdf', '.png', $rutaArchivo);
|
|
||||||
$image->writeImage($rutaImagen);
|
|
||||||
$image->destroy();
|
|
||||||
|
|
||||||
$log->appendLog("El archivo PNG se ha generado correctamente en: $rutaImagen" . PHP_EOL);
|
try {
|
||||||
} catch (ImagickException $e) {
|
// 1. Instanciar Logger y MinioService
|
||||||
$log->appendLog("Error al convertir el PDF a PNG con Imagick: " . $e->getMessage() . PHP_EOL);
|
$loggerService = new Logger(); // Servicio de Logging propio del namespace
|
||||||
|
$minioService = new MinioStorageService($loggerService);
|
||||||
|
|
||||||
|
// 2. Configurar Microservicio
|
||||||
|
$ipMicroservice = $config['ipPuppeteer'] ?? 'localhost'; // Reutilizamos IP de Puppeteer
|
||||||
|
$portMicroservice = '8050'; // Puerto definido en docker-compose
|
||||||
|
$microserviceUrl = "http://{$ipMicroservice}:{$portMicroservice}/process";
|
||||||
|
|
||||||
|
$log->appendLog("Procesando PDF con microservicio: $microserviceUrl" . PHP_EOL);
|
||||||
|
|
||||||
|
// 2. DETECTAR METODO DE PAGO (Overlay)
|
||||||
|
$overlayText = '';
|
||||||
|
$note = $payments[0]['note'] ?? '';
|
||||||
|
|
||||||
|
// Si la nota dice OXXO o Transferencia, preparamos el reemplazo
|
||||||
|
if (stripos($note, 'OXXO') !== false) {
|
||||||
|
$overlayText = 'OXXO Pay';
|
||||||
|
} elseif (stripos($note, 'Transferencia') !== false) {
|
||||||
|
$overlayText = 'Transferencia Bancaria';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coordenadas APROXIMADAS para el template default de UCRM (Ajustar si es necesario)
|
||||||
|
// Asumiendo PDF a 200dpi (ancho ~1600px).
|
||||||
|
// "Método" suele estar alineado a la izquierda, valor a la derecha.
|
||||||
|
// X=500, Y=650 (ejemplo). W=800, H=40.
|
||||||
|
$overlayX = 450;
|
||||||
|
$overlayY = 665; // Ajustar probando
|
||||||
|
$overlayW = 1000;
|
||||||
|
$overlayH = 50;
|
||||||
|
|
||||||
|
// 3. Llamar al Microservicio (PDF -> JPG)
|
||||||
|
$multipartData = [
|
||||||
|
[
|
||||||
|
'name' => 'file',
|
||||||
|
'contents' => fopen($rutaArchivo, 'r'),
|
||||||
|
'filename' => basename($rutaArchivo)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'mode',
|
||||||
|
'contents' => 'full'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($overlayText) {
|
||||||
|
$log->appendLog("Aplicando Overlay: $overlayText en ($overlayX, $overlayY)" . PHP_EOL);
|
||||||
|
$multipartData[] = ['name' => 'overlay_text', 'contents' => $overlayText];
|
||||||
|
$multipartData[] = ['name' => 'overlay_x', 'contents' => (string)$overlayX];
|
||||||
|
$multipartData[] = ['name' => 'overlay_y', 'contents' => (string)$overlayY];
|
||||||
|
$multipartData[] = ['name' => 'overlay_w', 'contents' => (string)$overlayW];
|
||||||
|
$multipartData[] = ['name' => 'overlay_h', 'contents' => (string)$overlayH];
|
||||||
|
}
|
||||||
|
|
||||||
|
$guzzleParams = [
|
||||||
|
'multipart' => $multipartData,
|
||||||
|
'timeout' => 30
|
||||||
|
];
|
||||||
|
|
||||||
|
$httpClient = new Client();
|
||||||
|
$responseMs = $httpClient->post($microserviceUrl, $guzzleParams);
|
||||||
|
|
||||||
|
if ($responseMs->getStatusCode() === 200) {
|
||||||
|
$jpgContent = $responseMs->getBody()->getContents();
|
||||||
|
if (file_put_contents($rutaImagen, $jpgContent) !== false) {
|
||||||
|
$log->appendLog("Imagen generada por microservicio guardada en: $rutaImagen" . PHP_EOL);
|
||||||
|
|
||||||
|
// 4. Subir a MinIO
|
||||||
|
$fileNameComprobanteImage = str_replace('.jpg', '_' . time() . '.jpg', basename($rutaImagen));
|
||||||
|
$url_file = $minioService->uploadFile($rutaImagen, $fileNameComprobanteImage);
|
||||||
|
|
||||||
|
if ($url_file) {
|
||||||
|
$log->appendLog("Imagen subida a MinIO: $url_file" . PHP_EOL);
|
||||||
|
|
||||||
|
// 5. LIMPIEZA AUTOMÁTICA (Consistencia con req. de usuario)
|
||||||
|
if (file_exists($rutaArchivo)) {
|
||||||
|
unlink($rutaArchivo);
|
||||||
|
//$log->appendLog("Archivo PDF temporal eliminado." . PHP_EOL);
|
||||||
|
}
|
||||||
|
if (file_exists($rutaImagen)) {
|
||||||
|
unlink($rutaImagen);
|
||||||
|
//$log->appendLog("Archivo JPG temporal eliminado." . PHP_EOL);
|
||||||
|
}
|
||||||
|
$log->appendLog("Archivos temporales (PDF/JPG) eliminados tras subida exitosa." . PHP_EOL);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$log->appendLog("Error: Falló la subida a MinIO." . PHP_EOL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$log->appendLog("Error guardando imagen del microservicio." . PHP_EOL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$log->appendLog("Error microservicio PDF: HTTP " . $responseMs->getStatusCode() . PHP_EOL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$log->appendLog("Excepción en flujo Microservicio/MinIO: " . $e->getMessage() . PHP_EOL);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileNameComprobanteImage = str_replace('.pdf', '.png', $fileNameComprobante);
|
// Legacy FTP eliminado
|
||||||
$url_file = $this->UploadReceiptToWordpressByImageFileName($fileNameComprobanteImage); //Carga del comprobante PDF a Wordpress para su posterior envío
|
// $url_file = $this->UploadReceiptToWordpressByImageFileName($fileNameComprobanteImage);
|
||||||
// $url_file = $this->UploadReceiptToWordpressByImageFileName($fileNameComprobante);//Carga del comprobante PDF a Wordpress para su posterior envío
|
|
||||||
|
|
||||||
$log->appendLog("Se terminó de subir comprobante a wordpress " . PHP_EOL);
|
$log->appendLog("Proceso de obtención de imagen finalizado." . PHP_EOL);
|
||||||
|
|
||||||
//$log->appendLog("Entrando al metodo sendPaymentNotificationWhatsAp" . PHP_EOL);
|
//$log->appendLog("Entrando al metodo sendPaymentNotificationWhatsAp" . PHP_EOL);
|
||||||
$ch = curl_init();
|
$ch = curl_init();
|
||||||
@ -1033,46 +1126,50 @@ class ClientCallBellAPI
|
|||||||
"name" => sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']),
|
"name" => sprintf("%s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']),
|
||||||
|
|
||||||
"custom_fields" => [
|
"custom_fields" => [
|
||||||
"Cliente" => $notificationData->clientData['id'],
|
"Site" => $site,
|
||||||
"Domicilio" => ($notificationData->clientData['fullAddress'] == null) ? '📍❌ Sin domicilio' : '📍 ' . $notificationData->clientData['fullAddress'],
|
"Estado" => ($notificationData->clientData['hasSuspendedService']) ? '🟠 Suspendido' : '🟢 Activo ',
|
||||||
"Nombre" => sprintf("👤 %s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']),
|
|
||||||
"URL" => '🌐 https://sistema.siip.mx/crm/client/' . $notificationData->clientId,
|
"URL" => '🌐 https://sistema.siip.mx/crm/client/' . $notificationData->clientId,
|
||||||
|
"Nombre" => sprintf("👤 %s %s", $notificationData->clientData['firstName'], $notificationData->clientData['lastName']),
|
||||||
|
"Cliente" => $notificationData->clientData['id'],
|
||||||
|
"Fecha Ultima Actualizacion" => '📆🔄️ ' . $fecha_actual_ajustada,
|
||||||
"Saldo Actual" => $saldoTexto,
|
"Saldo Actual" => $saldoTexto,
|
||||||
"Monto Ultimo Pago" => '💲 ' . $payments[0]['amount'],
|
"Monto Ultimo Pago" => '💲 ' . $payments[0]['amount'],
|
||||||
"Estado" => ($notificationData->clientData['hasSuspendedService']) ? '🔴 Suspendido' : '🟢 Activo ',
|
|
||||||
"Resumen" => $resumenClienteJSON,
|
|
||||||
"Fecha Ultimo Pago" => '📆💸 ' . $fecha_ultimoPago_ajustada . ' con ' . $payment_method,
|
|
||||||
"Fecha Ultima Actualizacion" => '📆🔄️ ' . $fecha_actual_ajustada,
|
|
||||||
"Clabe Interbancaria" => $clabeInterbancaria,
|
"Clabe Interbancaria" => $clabeInterbancaria,
|
||||||
"Site" => $site,
|
"Fecha Ultimo Pago" => '📆💸 ' . $fecha_ultimoPago_ajustada . ' con ' . $payment_method,
|
||||||
"Antena/Sectorial" => $antenaSectorial,
|
"Antena/Sectorial" => $antenaSectorial,
|
||||||
"Password Antena" => $passAntenaFinal,
|
"Domicilio" => ($notificationData->clientData['fullAddress'] == null) ? '📍❌ Sin domicilio' : '📍 ' . $notificationData->clientData['fullAddress'],
|
||||||
|
"Resumen" => $resumenClienteJSON,
|
||||||
|
"password-antena" => $passAntenaFinal,
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
$log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL);
|
$log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL);
|
||||||
|
|
||||||
// OPT: Comparación inteligente para evitar patches innecesarios
|
// OPT: Comparación inteligente para evitar patches innecesarios
|
||||||
|
// La respuesta de getContactWhatsapp viene envuelta en 'contact' y usa 'customFields'
|
||||||
|
$contact = $response_getContactCallBell['contact'] ?? [];
|
||||||
|
$contactCustomFields = $contact['customFields'] ?? [];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$response_getContactCallBell['custom_fields']['Cliente'] != $data_CRM['custom_fields']['Cliente']
|
($contactCustomFields['Cliente'] ?? '') != $data_CRM['custom_fields']['Cliente']
|
||||||
|| $response_getContactCallBell['custom_fields']['Domicilio'] != $data_CRM['custom_fields']['Domicilio']
|
|| ($contactCustomFields['Domicilio'] ?? '') != $data_CRM['custom_fields']['Domicilio']
|
||||||
|| $response_getContactCallBell['custom_fields']['Nombre'] != $data_CRM['custom_fields']['Nombre']
|
|| ($contactCustomFields['Nombre'] ?? '') != $data_CRM['custom_fields']['Nombre']
|
||||||
|| $response_getContactCallBell['custom_fields']['URL'] != $data_CRM['custom_fields']['URL']
|
|| ($contactCustomFields['URL'] ?? '') != $data_CRM['custom_fields']['URL']
|
||||||
|| $response_getContactCallBell['custom_fields']['Saldo Actual'] != $data_CRM['custom_fields']['Saldo Actual']
|
|| ($contactCustomFields['Saldo Actual'] ?? '') != $data_CRM['custom_fields']['Saldo Actual']
|
||||||
|| $response_getContactCallBell['custom_fields']['Estado'] != $data_CRM['custom_fields']['Estado']
|
|| ($contactCustomFields['Estado'] ?? '') != $data_CRM['custom_fields']['Estado']
|
||||||
|| $response_getContactCallBell['custom_fields']['Fecha Ultimo Pago'] != $data_CRM['custom_fields']['Fecha Ultimo Pago']
|
|| ($contactCustomFields['Fecha Ultimo Pago'] ?? '') != $data_CRM['custom_fields']['Fecha Ultimo Pago']
|
||||||
|| $response_getContactCallBell['custom_fields']['Monto Ultimo Pago'] != $data_CRM['custom_fields']['Monto Ultimo Pago']
|
|| ($contactCustomFields['Monto Ultimo Pago'] ?? '') != $data_CRM['custom_fields']['Monto Ultimo Pago']
|
||||||
|| ($response_getContactCallBell['custom_fields']['Password Antena'] ?? '') != $data_CRM['custom_fields']['Password Antena']
|
|| ($contactCustomFields['password-antena'] ?? '') != $data_CRM['custom_fields']['password-antena']
|
||||||
|| $response_getContactCallBell['name'] != $data_CRM['name']
|
|| ($contact['name'] ?? '') != $data_CRM['name']
|
||||||
|
|
||||||
) {
|
) {
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data_CRM));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data_CRM));
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
$log->appendLog("Response Patch CallBell: " . $response . PHP_EOL);
|
//$log->appendLog("Response Patch CallBell: " . $response . PHP_EOL);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$log->appendLog("No hay cambios que actualizar " . PHP_EOL);
|
//$log->appendLog("No hay cambios que actualizar " . PHP_EOL);
|
||||||
curl_close($ch);
|
curl_close($ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1118,7 +1215,10 @@ class ClientCallBellAPI
|
|||||||
|
|
||||||
$log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL);
|
$log->appendLog("JSON con los datos a actualizar: " . json_encode($data_CRM) . PHP_EOL);
|
||||||
|
|
||||||
if ($response_getContactCallBell['custom_fields']['Estado'] != $data_CRM['custom_fields']['Estado']) {
|
$contact = $response_getContactCallBell['contact'] ?? [];
|
||||||
|
$contactCustomFields = $contact['customFields'] ?? [];
|
||||||
|
|
||||||
|
if (($contactCustomFields['Estado'] ?? '') != $data_CRM['custom_fields']['Estado']) {
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data_CRM));
|
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data_CRM));
|
||||||
$response = curl_exec($ch);
|
$response = curl_exec($ch);
|
||||||
$log->appendLog("Response Patch CallBell: " . $response . PHP_EOL);
|
$log->appendLog("Response Patch CallBell: " . $response . PHP_EOL);
|
||||||
|
|||||||
@ -29,9 +29,10 @@ class PluginOxxoNotifierFacade extends AbstractOxxoOperationsFacade
|
|||||||
Logger $logger,
|
Logger $logger,
|
||||||
MessageTextFactory $messageTextFactory,
|
MessageTextFactory $messageTextFactory,
|
||||||
SmsNumberProvider $smsNumberProvider,
|
SmsNumberProvider $smsNumberProvider,
|
||||||
OptionsManager $optionsManager
|
OptionsManager $optionsManager,
|
||||||
|
\SmsNotifier\Service\MinioStorageService $minioStorage
|
||||||
) {
|
) {
|
||||||
parent::__construct($logger, $messageTextFactory, $smsNumberProvider);
|
parent::__construct($logger, $messageTextFactory, $smsNumberProvider, $minioStorage);
|
||||||
// load config data
|
// load config data
|
||||||
$this->pluginData = $optionsManager->load();
|
$this->pluginData = $optionsManager->load();
|
||||||
}
|
}
|
||||||
|
|||||||
135
src/Plugin.php
135
src/Plugin.php
@ -162,50 +162,105 @@ class Plugin
|
|||||||
case 'cash_balance.funds_available':
|
case 'cash_balance.funds_available':
|
||||||
$this->logger->info('Evento de Pago de fondos disponibles recibido: ' . json_encode($jsonData) . PHP_EOL);
|
$this->logger->info('Evento de Pago de fondos disponibles recibido: ' . json_encode($jsonData) . PHP_EOL);
|
||||||
break;
|
break;
|
||||||
case 'oxxo.request':
|
case 'payment_intent.succeeded':
|
||||||
$this->logger->info('Evento de solicitud de referencia de OXXO recibido');
|
$this->logger->info('Evento de pago exitoso (Stripe PI) recibido.');
|
||||||
|
if (isset($jsonData['data']['object'])) {
|
||||||
if (! empty($jsonData['amount'])) {
|
$this->pluginNotifierFacade->registerPaymentFromIntent($jsonData['data']['object']);
|
||||||
$this->logger->info('Referencia personalizada, Monto: ' . $jsonData['amount']);
|
|
||||||
$intentos = 0;
|
|
||||||
do {
|
|
||||||
$responseOxxo = $this->pluginOxxoNotifierFacade->createOxxoPaymentIntent($jsonData, $jsonData['amount']);
|
|
||||||
$this->logger->debug('Respuesta OXXO: ' . json_encode($responseOxxo));
|
|
||||||
$intentos++;
|
|
||||||
} while (strpos($responseOxxo['url'] ?? '', 'https') !== 0 && $intentos < 3);
|
|
||||||
} else {
|
|
||||||
$intentos = 0;
|
|
||||||
do {
|
|
||||||
$responseOxxo = $this->pluginOxxoNotifierFacade->createOxxoPaymentIntent($jsonData);
|
|
||||||
$intentos++;
|
|
||||||
} while (strpos($responseOxxo['url'] ?? '', 'https') !== 0 && $intentos < 3);
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case 'oxxo.retrieve':
|
||||||
|
$this->logger->info('Evento de recuperación de orden OXXO recibido');
|
||||||
|
$orderId = $jsonData['order_id'] ?? null;
|
||||||
|
|
||||||
//El array asociativo $responseOxxo es un array asosiativo con los siguientes campos: oxxo_reference, error, failDescription, clientID, amount
|
if ($orderId) {
|
||||||
//Si la respuesta no contiene https, se genera un error
|
$status = $this->pluginOxxoNotifierFacade->getOxxoOrderStatus($orderId);
|
||||||
if (strpos($responseOxxo['url'], 'https') !== 0) {
|
$this->logger->debug("Estado recuperado para Orden #$orderId: " . json_encode($status));
|
||||||
//this->logger->error('Error al crear la referencia de OXXO: ' . $responseOxxo);
|
|
||||||
//crear un json con variable $response que contenga las claves y valores del array $responseOxxo los cuales son: oxxo_reference, error, failDescription, clientID, clientFullName amount
|
|
||||||
$response = '{' .
|
|
||||||
'"url": "' . $responseOxxo['url'] . '",' .
|
|
||||||
'"oxxo_reference": "' . $responseOxxo['oxxo_reference'] . '",' .
|
|
||||||
'"voucher_image_url": "' . $responseOxxo['voucher_image_url'] . '",' .
|
|
||||||
'"error": "' . $responseOxxo['error'] . '",' .
|
|
||||||
'"failDescription": "' . $responseOxxo['failDescription'] . '",' .
|
|
||||||
'"clientID": "' . $responseOxxo['clientID'] . '",' .
|
|
||||||
'"clientFullName": "' . $responseOxxo['clientFullName'] . '",' .
|
|
||||||
'"amount": "' . $responseOxxo['amount'] . '"' .
|
|
||||||
'}';
|
|
||||||
|
|
||||||
echo $response;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
$response = json_encode($responseOxxo);
|
|
||||||
$this->logger->debug('Response enviado: ' . $response);
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
echo $response;
|
echo json_encode($status);
|
||||||
break;
|
} else {
|
||||||
|
$this->logger->warning('Solicitud de oxxo.retrieve sin order_id');
|
||||||
|
echo json_encode(['error' => 'missing_order_id']);
|
||||||
}
|
}
|
||||||
|
return; // Terminar ejecución aquí
|
||||||
|
break;
|
||||||
|
case 'oxxo.request':
|
||||||
|
$this->logger->info('Evento de solicitud de referencia de OXXO recibido (Async Flow)');
|
||||||
|
|
||||||
|
// 1. Obtener datos de Stripe (OXXO Reference, URL, etc.)
|
||||||
|
$stripeResult = $this->pluginOxxoNotifierFacade->createStripeReference($jsonData, $jsonData['amount'] ?? null);
|
||||||
|
|
||||||
|
if ($stripeResult['hasError'] ?? false) {
|
||||||
|
$this->logger->error('Error generando referencia Stripe: ' . json_encode($stripeResult));
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo json_encode([
|
||||||
|
'oxxo_reference' => '',
|
||||||
|
'url' => '',
|
||||||
|
'error' => $stripeResult['data']['error'] ?? 'stripe_error',
|
||||||
|
'status' => 'failed'
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oxxoData = $stripeResult['data'];
|
||||||
|
|
||||||
|
// 2. Crear Orden (Sync) para obtener ID
|
||||||
|
// Ahora pasamos $oxxoData que SI tiene clientID, clientFullName, etc.
|
||||||
|
$responseOxxo = $this->pluginOxxoNotifierFacade->createOxxoOrder($oxxoData);
|
||||||
|
|
||||||
|
$orderId = $responseOxxo['order_id'] ?? null;
|
||||||
|
|
||||||
|
// 3. Preparar respuesta inmediata (Pending)
|
||||||
|
$responseArray = [
|
||||||
|
'oxxo_reference' => $responseOxxo['oxxo_reference'] ?? '',
|
||||||
|
'url' => '', // No hay URL de imagen todavía
|
||||||
|
'stripe_url' => $responseOxxo['url'] ?? '',
|
||||||
|
'voucher_image_url' => '',
|
||||||
|
'order_id' => $orderId,
|
||||||
|
'clientFullName' => $responseOxxo['clientFullName'] ?? '',
|
||||||
|
'clientID' => $responseOxxo['clientID'] ?? '',
|
||||||
|
'amount' => $responseOxxo['amount'] ?? '',
|
||||||
|
'error' => $responseOxxo['error'] ?? '',
|
||||||
|
'status' => 'generating' // Estado esperado por el bot para iniciar polling
|
||||||
|
];
|
||||||
|
|
||||||
|
// 4. Enviar Respuesta y CERRAR Conexión
|
||||||
|
// Limpiamos buffers
|
||||||
|
while (ob_get_level() > 0) {
|
||||||
|
ob_end_clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
header('Connection: close');
|
||||||
|
ignore_user_abort(true); // Permitir que el script siga corriendo
|
||||||
|
|
||||||
|
echo json_encode($responseArray);
|
||||||
|
|
||||||
|
// Forzar envío al cliente
|
||||||
|
if (function_exists('fastcgi_finish_request')) {
|
||||||
|
fastcgi_finish_request();
|
||||||
|
} else {
|
||||||
|
// Fallback para servidores no FastCGI
|
||||||
|
header('Content-Length: ' . strlen(json_encode($responseArray)));
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Trabajo en Pesado (Background)
|
||||||
|
if ($orderId) {
|
||||||
|
$this->logger->info("Iniciando generación background para orden #$orderId");
|
||||||
|
set_time_limit(180); // 3 minutos para Puppeteer
|
||||||
|
sleep(1); // Pequeña pausa para asegurar liberación del socket
|
||||||
|
|
||||||
|
$this->pluginOxxoNotifierFacade->generateOxxoVoucher($responseOxxo, true);
|
||||||
|
|
||||||
|
$this->logger->info("Generación background finalizada para orden #$orderId");
|
||||||
|
} else {
|
||||||
|
$this->logger->error("No se pudo iniciar background job: Falta order_id");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminar proceso hijo
|
||||||
|
exit;
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
95
src/Service/MinioStorageService.php
Normal file
95
src/Service/MinioStorageService.php
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace SmsNotifier\Service;
|
||||||
|
|
||||||
|
use Aws\S3\S3Client;
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
use Ubnt\UcrmPluginSdk\Service\PluginConfigManager;
|
||||||
|
|
||||||
|
class MinioStorageService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var S3Client
|
||||||
|
*/
|
||||||
|
private $s3Client;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $bucket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $publicUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Logger
|
||||||
|
*/
|
||||||
|
private $logger;
|
||||||
|
|
||||||
|
public function __construct(Logger $logger)
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
$this->initializeClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function initializeClient(): void
|
||||||
|
{
|
||||||
|
$config = PluginConfigManager::create()->loadConfig();
|
||||||
|
|
||||||
|
$endpoint = $config['minioEndpoint'] ?? 'http://localhost:9002';
|
||||||
|
$key = $config['minioAccessKey'] ?? 'minioadmin';
|
||||||
|
$secret = $config['minioSecretKey'] ?? 'minioadmin';
|
||||||
|
$this->bucket = $config['minioBucket'] ?? 'vouchers-oxxo';
|
||||||
|
$this->publicUrl = rtrim($config['minioPublicUrl'] ?? 'http://localhost:9002', '/');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->s3Client = new S3Client([
|
||||||
|
'version' => 'latest',
|
||||||
|
'region' => 'us-east-1', // MinIO doesn't really care about region, but SDK requires it
|
||||||
|
'endpoint' => $endpoint,
|
||||||
|
'use_path_style_endpoint' => true,
|
||||||
|
'credentials' => [
|
||||||
|
'key' => $key,
|
||||||
|
'secret' => $secret,
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error("Error initializing S3 Client: " . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uploadFile(string $sourcePath, string $filename): string
|
||||||
|
{
|
||||||
|
if (!$this->s3Client) {
|
||||||
|
$this->logger->error("S3 Client not initialized. Cannot upload.");
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = $this->s3Client->putObject([
|
||||||
|
'Bucket' => $this->bucket,
|
||||||
|
'Key' => $filename,
|
||||||
|
'SourceFile' => $sourcePath,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Construct Public URL
|
||||||
|
// We do NOT use $result['ObjectURL'] because that might point to the internal container IP/Port
|
||||||
|
// We specifically want to use the public domain provided in config.
|
||||||
|
$finalUrl = $this->publicUrl . '/' . $this->bucket . '/' . $filename;
|
||||||
|
|
||||||
|
$this->logger->info("Archivo subido exitosamente a MinIO: $finalUrl");
|
||||||
|
return $finalUrl;
|
||||||
|
|
||||||
|
} catch (AwsException $e) {
|
||||||
|
$this->logger->error("AWS S3 Error uploading file $filename: " . $e->getMessage());
|
||||||
|
return '';
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$this->logger->error("General Error uploading file $filename: " . $e->getMessage());
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -43,8 +43,9 @@ class SmsNumberProvider
|
|||||||
if (!empty($contact['phone'])) {
|
if (!empty($contact['phone'])) {
|
||||||
if (isset($contact['types']) && is_array($contact['types'])) {
|
if (isset($contact['types']) && is_array($contact['types'])) {
|
||||||
foreach ($contact['types'] as $type) {
|
foreach ($contact['types'] as $type) {
|
||||||
if (in_array($type['name'], ['WhatsApp', 'WhatsNotifica'])) {
|
$typeNameLower = trim(strtolower($type['name']));
|
||||||
// Almacena varios números bajo el mismo tipo
|
if (in_array($typeNameLower, ['whatsapp', 'whatsnotifica'])) {
|
||||||
|
// Almacena varios números bajo el mismo tipo normalizado
|
||||||
$arrayPhones[$type['name']][] = $contact['phone'];
|
$arrayPhones[$type['name']][] = $contact['phone'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,8 +58,9 @@ class SmsNumberProvider
|
|||||||
if (!empty($contact['phone'])) {
|
if (!empty($contact['phone'])) {
|
||||||
if (isset($contact['types']) && is_array($contact['types'])) {
|
if (isset($contact['types']) && is_array($contact['types'])) {
|
||||||
foreach ($contact['types'] as $type) {
|
foreach ($contact['types'] as $type) {
|
||||||
if (in_array($type['name'], ['WhatsApp', 'WhatsNotifica', 'WhatsActualiza'])) {
|
$typeNameLower = trim(strtolower($type['name']));
|
||||||
// Almacena varios números bajo el mismo tipo
|
if (in_array($typeNameLower, ['whatsapp', 'whatsnotifica', 'whatsactualiza'])) {
|
||||||
|
// Almacena varios números bajo el mismo tipo normalizado
|
||||||
$arrayPhones[$type['name']][] = $contact['phone'];
|
$arrayPhones[$type['name']][] = $contact['phone'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -121,7 +123,7 @@ class SmsNumberProvider
|
|||||||
$types = $contact['types'] ?? [];
|
$types = $contact['types'] ?? [];
|
||||||
foreach ($types as $type) {
|
foreach ($types as $type) {
|
||||||
//$log->appendLog("Entrando al case client del switch: " . json_encode($type));
|
//$log->appendLog("Entrando al case client del switch: " . json_encode($type));
|
||||||
if ($type['name'] == 'WhatsApp') {
|
if (trim(strtolower($type['name'])) == 'whatsapp') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,7 +135,7 @@ class SmsNumberProvider
|
|||||||
$types = $contact['types'] ?? [];
|
$types = $contact['types'] ?? [];
|
||||||
foreach ($types as $type) {
|
foreach ($types as $type) {
|
||||||
//$log->appendLog("Entrando al case client del switch: " . json_encode($type));
|
//$log->appendLog("Entrando al case client del switch: " . json_encode($type));
|
||||||
if ($type['name'] == 'WhatsApp') {
|
if (trim(strtolower($type['name'])) == 'whatsapp') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,7 +146,7 @@ class SmsNumberProvider
|
|||||||
$types = $contact['types'] ?? [];
|
$types = $contact['types'] ?? [];
|
||||||
foreach ($types as $type) {
|
foreach ($types as $type) {
|
||||||
//$log->appendLog("Entrando al case client del switch: " . json_encode($type));
|
//$log->appendLog("Entrando al case client del switch: " . json_encode($type));
|
||||||
if ($type['name'] == 'WhatsApp') {
|
if (trim(strtolower($type['name'])) == 'whatsapp') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
vendor/autoload.php
vendored
18
vendor/autoload.php
vendored
@ -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 ComposerAutoloaderInitd6442a7ec79f2f43fc97d16bdcdd18ee::getLoader();
|
return ComposerAutoloaderInitd6442a7ec79f2f43fc97d16bdcdd18ee::getLoader();
|
||||||
|
|||||||
4
vendor/aws/aws-crt-php/CODE_OF_CONDUCT.md
vendored
Normal file
4
vendor/aws/aws-crt-php/CODE_OF_CONDUCT.md
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
## Code of Conduct
|
||||||
|
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||||
|
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||||
|
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||||
175
vendor/aws/aws-crt-php/LICENSE
vendored
Normal file
175
vendor/aws/aws-crt-php/LICENSE
vendored
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
1
vendor/aws/aws-crt-php/NOTICE
vendored
Normal file
1
vendor/aws/aws-crt-php/NOTICE
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
117
vendor/aws/aws-crt-php/README.md
vendored
Normal file
117
vendor/aws/aws-crt-php/README.md
vendored
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
# AWS Common Runtime PHP bindings
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
* PHP 5.5+ on UNIX platforms, 7.2+ on Windows
|
||||||
|
* CMake 3.x
|
||||||
|
* GCC 4.4+, clang 3.8+ on UNIX, Visual Studio build tools on Windows
|
||||||
|
* Tests require [Composer](https://getcomposer.org)
|
||||||
|
|
||||||
|
## Installing with Composer and PECL
|
||||||
|
|
||||||
|
The package has two different package published to [composer](https://packagist.org/packages/aws/aws-crt-php) and [PECL](https://pecl.php.net/package/awscrt).
|
||||||
|
|
||||||
|
On UNIX, you can get the package from package manager or build from source:
|
||||||
|
|
||||||
|
```
|
||||||
|
pecl install awscrt
|
||||||
|
composer require aws/aws-crt-php
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows, you need to build from source as instruction written below for the native extension `php_awscrt.dll` . And, follow https://www.php.net/manual/en/install.pecl.windows.php#install.pecl.windows.loading to load extension. After that:
|
||||||
|
|
||||||
|
```
|
||||||
|
composer require aws/aws-crt-php
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building from Github source
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ git clone --recursive https://github.com/awslabs/aws-crt-php.git
|
||||||
|
$ cd aws-crt-php
|
||||||
|
$ phpize
|
||||||
|
$ ./configure
|
||||||
|
$ make
|
||||||
|
$ ./dev-scripts/run_tests.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building on Windows
|
||||||
|
|
||||||
|
### Requirements for Windows
|
||||||
|
|
||||||
|
* Ensure you have the [windows PHP SDK](https://github.com/microsoft/php-sdk-binary-tools) (this example assumes installation of the SDK to C:\php-sdk and that you've checked out the PHP source to php-src within the build directory) and it works well on your machine.
|
||||||
|
|
||||||
|
* Ensure you have "Development package (SDK to develop PHP extensions)" and PHP available from your system path. You can download them from https://windows.php.net/download/. You can check if they are available by running `phpize -v` and `php -v`
|
||||||
|
|
||||||
|
### Instructions
|
||||||
|
|
||||||
|
From Command Prompt (not powershell). The instruction is based on Visual Studio 2019 on 64bit Windows.
|
||||||
|
|
||||||
|
```bat
|
||||||
|
> git clone --recursive https://github.com/awslabs/aws-crt-php.git
|
||||||
|
> git clone https://github.com/microsoft/php-sdk-binary-tools.git C:\php-sdk
|
||||||
|
> C:\php-sdk\phpsdk-vs16-x64.bat
|
||||||
|
|
||||||
|
C:\php-sdk\
|
||||||
|
$ cd <your-path-to-aws-crt-php>
|
||||||
|
|
||||||
|
<your-path-to-aws-crt-php>\
|
||||||
|
$ phpize
|
||||||
|
|
||||||
|
# --with-prefix only required when your php runtime in system path is different than the runtime you wish to use.
|
||||||
|
<your-path-to-aws-crt-php>\
|
||||||
|
$ configure --enable-awscrt=shared --with-prefix=<your-path-to-php-prefix>
|
||||||
|
|
||||||
|
<your-path-to-aws-crt-php>\
|
||||||
|
$ nmake
|
||||||
|
|
||||||
|
<your-path-to-aws-crt-php>\
|
||||||
|
$ nmake generate-php-ini
|
||||||
|
|
||||||
|
# check .\php-win.ini, it now has the full path to php_awscrt.dll that you can manually load to your php runtime, or you can run the following command to run tests and load the required native extension for awscrt.
|
||||||
|
<your-path-to-aws-crt-php>\
|
||||||
|
$ .\dev-scripts\run_tests.bat <your-path-to-php-binary>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: for VS2017, Cmake will default to build for Win32, refer to [here](https://cmake.org/cmake/help/latest/generator/Visual%20Studio%2015%202017.html). If you are building for x64 php, you can set environment variable as follow to let cmake pick x64 compiler.
|
||||||
|
|
||||||
|
```bat
|
||||||
|
set CMAKE_GENERATOR=Visual Studio 15 2017
|
||||||
|
set CMAKE_GENERATOR_PLATFORM=x64
|
||||||
|
```
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
Using [PHPBrew](https://github.com/phpbrew/phpbrew) to build/manage multiple versions of PHP is helpful.
|
||||||
|
|
||||||
|
Note: You must use a debug build of PHP to debug native extensions.
|
||||||
|
See the [PHP Internals Book](https://www.phpinternalsbook.com/php7/build_system/building_php.html) for more info
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# PHP 8 example
|
||||||
|
$ phpbrew install --stdout -j 8 8.0 +default -- CFLAGS=-Wno-error --disable-cgi --enable-debug
|
||||||
|
# PHP 5.5 example
|
||||||
|
$ phpbrew install --stdout -j 8 5.5 +default -openssl -mbstring -- CFLAGS="-w -Wno-error" --enable-debug --with-zlib=/usr/local/opt/zlib
|
||||||
|
$ phpbrew switch php-8.0.6 # or whatever version is current, it'll be at the end of the build output
|
||||||
|
$ phpize
|
||||||
|
$ ./configure
|
||||||
|
$ make CMAKE_BUILD_TYPE=Debug
|
||||||
|
```
|
||||||
|
|
||||||
|
Ensure that the php you launch from your debugger is the result of `which php` , not just
|
||||||
|
the system default php.
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more information.
|
||||||
|
|
||||||
|
## Known OpenSSL related issue (Unix only)
|
||||||
|
|
||||||
|
* When your php loads a different version of openssl than your system openssl version, awscrt may fail to load or weirdly crash. You can find the openssl version php linked via: `php -i | grep 'OpenSSL'`, and awscrt linked from the build log, which will be `Found OpenSSL: * (found version *)`
|
||||||
|
|
||||||
|
The easiest workaround to those issue is to build from source and get aws-lc for awscrt to depend on instead.
|
||||||
|
TO do that, same instructions as [here](#building-from-github-source), but use `USE_OPENSSL=OFF make` instead of `make`
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the Apache-2.0 License.
|
||||||
35
vendor/aws/aws-crt-php/composer.json
vendored
Normal file
35
vendor/aws/aws-crt-php/composer.json
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "aws/aws-crt-php",
|
||||||
|
"homepage": "https://github.com/awslabs/aws-crt-php",
|
||||||
|
"description": "AWS Common Runtime for PHP",
|
||||||
|
"keywords": ["aws","amazon","sdk","crt"],
|
||||||
|
"type": "library",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "AWS SDK Common Runtime Team",
|
||||||
|
"email": "aws-sdk-common-runtime@amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"minimum-stability": "alpha",
|
||||||
|
"require": {
|
||||||
|
"php": ">=5.5"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit":"^4.8.35||^5.6.3||^9.5",
|
||||||
|
"yoast/phpunit-polyfills": "^1.0"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"classmap": [
|
||||||
|
"src/"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"test": "./dev-scripts/run_tests.sh",
|
||||||
|
"test-extension": "@test",
|
||||||
|
"test-win": ".\\dev-scripts\\run_tests.bat"
|
||||||
|
},
|
||||||
|
"license": "Apache-2.0"
|
||||||
|
}
|
||||||
46
vendor/aws/aws-crt-php/format-check.py
vendored
Executable file
46
vendor/aws/aws-crt-php/format-check.py
vendored
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
from subprocess import list2cmdline, run
|
||||||
|
from tempfile import NamedTemporaryFile
|
||||||
|
|
||||||
|
CLANG_FORMAT_VERSION = '18.1.6'
|
||||||
|
|
||||||
|
INCLUDE_REGEX = re.compile(r'^ext/.*\.(c|h|inl)$')
|
||||||
|
EXCLUDE_REGEX = re.compile(r'^$')
|
||||||
|
|
||||||
|
arg_parser = argparse.ArgumentParser(description="Check with clang-format")
|
||||||
|
arg_parser.add_argument('-i', '--inplace-edit', action='store_true',
|
||||||
|
help="Edit files inplace")
|
||||||
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
os.chdir(Path(__file__).parent)
|
||||||
|
|
||||||
|
# create file containing list of all files to format
|
||||||
|
filepaths_file = NamedTemporaryFile(delete=False)
|
||||||
|
for dirpath, dirnames, filenames in os.walk('.'):
|
||||||
|
for filename in filenames:
|
||||||
|
# our regexes expect filepath to use forward slash
|
||||||
|
filepath = Path(dirpath, filename).as_posix()
|
||||||
|
if not INCLUDE_REGEX.match(filepath):
|
||||||
|
continue
|
||||||
|
if EXCLUDE_REGEX.match(filepath):
|
||||||
|
continue
|
||||||
|
|
||||||
|
filepaths_file.write(f"{filepath}\n".encode())
|
||||||
|
filepaths_file.close()
|
||||||
|
|
||||||
|
# use pipx to run clang-format from PyPI
|
||||||
|
# this is a simple way to run the same clang-format version regardless of OS
|
||||||
|
cmd = ['pipx', 'run', f'clang-format=={CLANG_FORMAT_VERSION}',
|
||||||
|
f'--files={filepaths_file.name}']
|
||||||
|
if args.inplace_edit:
|
||||||
|
cmd += ['-i']
|
||||||
|
else:
|
||||||
|
cmd += ['--Werror', '--dry-run']
|
||||||
|
|
||||||
|
print(f"{Path.cwd()}$ {list2cmdline(cmd)}")
|
||||||
|
if run(cmd).returncode:
|
||||||
|
exit(1)
|
||||||
69
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php
vendored
Normal file
69
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/AwsCredentials.php
vendored
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource as NativeResource;
|
||||||
|
use AWS\CRT\Options as Options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a set of AWS credentials
|
||||||
|
*
|
||||||
|
* @param array options:
|
||||||
|
* - string access_key_id - AWS Access Key Id
|
||||||
|
* - string secret_access_key - AWS Secret Access Key
|
||||||
|
* - string session_token - Optional STS session token
|
||||||
|
* - int expiration_timepoint_seconds - Optional time to expire these credentials
|
||||||
|
*/
|
||||||
|
final class AwsCredentials extends NativeResource {
|
||||||
|
|
||||||
|
static function defaults() {
|
||||||
|
return [
|
||||||
|
'access_key_id' => '',
|
||||||
|
'secret_access_key' => '',
|
||||||
|
'session_token' => '',
|
||||||
|
'expiration_timepoint_seconds' => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private $access_key_id;
|
||||||
|
private $secret_access_key;
|
||||||
|
private $session_token;
|
||||||
|
private $expiration_timepoint_seconds = 0;
|
||||||
|
|
||||||
|
public function __get($name) {
|
||||||
|
return $this->$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct(array $options = []) {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$options = new Options($options, self::defaults());
|
||||||
|
$this->access_key_id = $options->access_key_id->asString();
|
||||||
|
$this->secret_access_key = $options->secret_access_key->asString();
|
||||||
|
$this->session_token = $options->session_token ? $options->session_token->asString() : null;
|
||||||
|
$this->expiration_timepoint_seconds = $options->expiration_timepoint_seconds->asInt();
|
||||||
|
|
||||||
|
if (strlen($this->access_key_id) == 0) {
|
||||||
|
throw new \InvalidArgumentException("access_key_id must be provided");
|
||||||
|
}
|
||||||
|
if (strlen($this->secret_access_key) == 0) {
|
||||||
|
throw new \InvalidArgumentException("secret_access_key must be provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
$creds_options = self::$crt->aws_credentials_options_new();
|
||||||
|
self::$crt->aws_credentials_options_set_access_key_id($creds_options, $this->access_key_id);
|
||||||
|
self::$crt->aws_credentials_options_set_secret_access_key($creds_options, $this->secret_access_key);
|
||||||
|
self::$crt->aws_credentials_options_set_session_token($creds_options, $this->session_token);
|
||||||
|
self::$crt->aws_credentials_options_set_expiration_timepoint_seconds($creds_options, $this->expiration_timepoint_seconds);
|
||||||
|
$this->acquire(self::$crt->aws_credentials_new($creds_options));
|
||||||
|
self::$crt->aws_credentials_options_release($creds_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
self::$crt->aws_credentials_release($this->release());
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
}
|
||||||
23
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php
vendored
Normal file
23
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/CredentialsProvider.php
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource as NativeResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for credentials providers
|
||||||
|
*/
|
||||||
|
abstract class CredentialsProvider extends NativeResource {
|
||||||
|
|
||||||
|
function __construct(array $options = []) {
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
self::$crt->credentials_provider_release($this->release());
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
}
|
||||||
43
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php
vendored
Normal file
43
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/Signable.php
vendored
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
use AWS\CRT\IO\InputStream;
|
||||||
|
use AWS\CRT\NativeResource as NativeResource;
|
||||||
|
|
||||||
|
class Signable extends NativeResource {
|
||||||
|
|
||||||
|
public static function fromHttpRequest($http_message) {
|
||||||
|
return new Signable(function() use ($http_message) {
|
||||||
|
return self::$crt->signable_new_from_http_request($http_message->native);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromChunk($chunk_stream, $previous_signature="") {
|
||||||
|
if (!($chunk_stream instanceof InputStream)) {
|
||||||
|
$chunk_stream = new InputStream($chunk_stream);
|
||||||
|
}
|
||||||
|
return new Signable(function() use($chunk_stream, $previous_signature) {
|
||||||
|
return self::$crt->signable_new_from_chunk($chunk_stream->native, $previous_signature);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromCanonicalRequest($canonical_request) {
|
||||||
|
return new Signable(function() use($canonical_request) {
|
||||||
|
return self::$crt->signable_new_from_canonical_request($canonical_request);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function __construct($ctor) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->acquire($ctor());
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
self::$crt->signable_release($this->release());
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
}
|
||||||
15
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php
vendored
Normal file
15
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SignatureType.php
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
class SignatureType {
|
||||||
|
const HTTP_REQUEST_HEADERS = 0;
|
||||||
|
const HTTP_REQUEST_QUERY_PARAMS = 1;
|
||||||
|
const HTTP_REQUEST_CHUNK = 2;
|
||||||
|
const HTTP_REQUEST_EVENT = 3;
|
||||||
|
const CANONICAL_REQUEST_HEADERS = 4;
|
||||||
|
const CANONICAL_REQUEST_QUERY_PARAMS = 5;
|
||||||
|
}
|
||||||
11
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SignedBodyHeaderType.php
vendored
Normal file
11
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SignedBodyHeaderType.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
class SignedBodyHeaderType {
|
||||||
|
const NONE = 0;
|
||||||
|
const X_AMZ_CONTENT_SHA256 = 1;
|
||||||
|
}
|
||||||
22
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/Signing.php
vendored
Normal file
22
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/Signing.php
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource;
|
||||||
|
|
||||||
|
abstract class Signing extends NativeResource {
|
||||||
|
static function signRequestAws($signable, $signing_config, $on_complete) {
|
||||||
|
return self::$crt->sign_request_aws($signable->native, $signing_config->native,
|
||||||
|
function($result, $error_code) use ($on_complete) {
|
||||||
|
$signing_result = SigningResult::fromNative($result);
|
||||||
|
$on_complete($signing_result, $error_code);
|
||||||
|
}, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function testVerifySigV4ASigning($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y) {
|
||||||
|
return self::$crt->test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php
vendored
Normal file
11
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SigningAlgorithm.php
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
class SigningAlgorithm {
|
||||||
|
const SIGv4 = 0;
|
||||||
|
const SIGv4_ASYMMETRIC = 1;
|
||||||
|
}
|
||||||
75
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SigningConfigAWS.php
vendored
Normal file
75
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SigningConfigAWS.php
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource as NativeResource;
|
||||||
|
use AWS\CRT\Options as Options;
|
||||||
|
|
||||||
|
class SigningConfigAWS extends NativeResource {
|
||||||
|
|
||||||
|
public static function defaults() {
|
||||||
|
return [
|
||||||
|
'algorithm' => SigningAlgorithm::SIGv4,
|
||||||
|
'signature_type' => SignatureType::HTTP_REQUEST_HEADERS,
|
||||||
|
'credentials_provider' => null,
|
||||||
|
'region' => null,
|
||||||
|
'service' => null,
|
||||||
|
'use_double_uri_encode' => false,
|
||||||
|
'should_normalize_uri_path' => false,
|
||||||
|
'omit_session_token' => false,
|
||||||
|
'signed_body_value' => null,
|
||||||
|
'signed_body_header_type' => SignedBodyHeaderType::NONE,
|
||||||
|
'expiration_in_seconds' => 0,
|
||||||
|
'date' => time(),
|
||||||
|
'should_sign_header' => null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private $options;
|
||||||
|
|
||||||
|
public function __construct(array $options = []) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->options = $options = new Options($options, self::defaults());
|
||||||
|
$sc = $this->acquire(self::$crt->signing_config_aws_new());
|
||||||
|
self::$crt->signing_config_aws_set_algorithm($sc, $options->algorithm->asInt());
|
||||||
|
self::$crt->signing_config_aws_set_signature_type($sc, $options->signature_type->asInt());
|
||||||
|
if ($credentials_provider = $options->credentials_provider->asObject()) {
|
||||||
|
self::$crt->signing_config_aws_set_credentials_provider(
|
||||||
|
$sc,
|
||||||
|
$credentials_provider->native);
|
||||||
|
}
|
||||||
|
self::$crt->signing_config_aws_set_region(
|
||||||
|
$sc, $options->region->asString());
|
||||||
|
self::$crt->signing_config_aws_set_service(
|
||||||
|
$sc, $options->service->asString());
|
||||||
|
self::$crt->signing_config_aws_set_use_double_uri_encode(
|
||||||
|
$sc, $options->use_double_uri_encode->asBool());
|
||||||
|
self::$crt->signing_config_aws_set_should_normalize_uri_path(
|
||||||
|
$sc, $options->should_normalize_uri_path->asBool());
|
||||||
|
self::$crt->signing_config_aws_set_omit_session_token(
|
||||||
|
$sc, $options->omit_session_token->asBool());
|
||||||
|
self::$crt->signing_config_aws_set_signed_body_value(
|
||||||
|
$sc, $options->signed_body_value->asString());
|
||||||
|
self::$crt->signing_config_aws_set_signed_body_header_type(
|
||||||
|
$sc, $options->signed_body_header_type->asInt());
|
||||||
|
self::$crt->signing_config_aws_set_expiration_in_seconds(
|
||||||
|
$sc, $options->expiration_in_seconds->asInt());
|
||||||
|
self::$crt->signing_config_aws_set_date($sc, $options->date->asInt());
|
||||||
|
if ($should_sign_header = $options->should_sign_header->asCallable()) {
|
||||||
|
self::$crt->signing_config_aws_set_should_sign_header_fn($sc, $should_sign_header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct()
|
||||||
|
{
|
||||||
|
self::$crt->signing_config_aws_release($this->release());
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name) {
|
||||||
|
return $this->options->get($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
33
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php
vendored
Normal file
33
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/SigningResult.php
vendored
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource;
|
||||||
|
use AWS\CRT\HTTP\Request;
|
||||||
|
|
||||||
|
class SigningResult extends NativeResource {
|
||||||
|
protected function __construct($native) {
|
||||||
|
parent::__construct();
|
||||||
|
|
||||||
|
$this->acquire($native);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
// No destruction necessary, SigningResults are transient, just release
|
||||||
|
$this->release();
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function fromNative($ptr) {
|
||||||
|
return new SigningResult($ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function applyToHttpRequest(&$http_request) {
|
||||||
|
self::$crt->signing_result_apply_to_http_request($this->native, $http_request->native);
|
||||||
|
// Update http_request from native
|
||||||
|
$http_request = Request::unmarshall($http_request->toBlob());
|
||||||
|
}
|
||||||
|
}
|
||||||
35
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php
vendored
Normal file
35
vendor/aws/aws-crt-php/src/AWS/CRT/Auth/StaticCredentialsProvider.php
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a static set of AWS credentials
|
||||||
|
*
|
||||||
|
* @param array options:
|
||||||
|
* - string access_key_id - AWS Access Key Id
|
||||||
|
* - string secret_access_key - AWS Secret Access Key
|
||||||
|
* - string session_token - Optional STS session token
|
||||||
|
*/
|
||||||
|
final class StaticCredentialsProvider extends CredentialsProvider {
|
||||||
|
|
||||||
|
private $credentials;
|
||||||
|
|
||||||
|
public function __get($name) {
|
||||||
|
return $this->$name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct(array $options = []) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->credentials = new AwsCredentials($options);
|
||||||
|
|
||||||
|
$provider_options = self::$crt->credentials_provider_static_options_new();
|
||||||
|
self::$crt->credentials_provider_static_options_set_access_key_id($provider_options, $this->credentials->access_key_id);
|
||||||
|
self::$crt->credentials_provider_static_options_set_secret_access_key($provider_options, $this->credentials->secret_access_key);
|
||||||
|
self::$crt->credentials_provider_static_options_set_session_token($provider_options, $this->credentials->session_token);
|
||||||
|
$this->acquire(self::$crt->credentials_provider_static_new($provider_options));
|
||||||
|
self::$crt->credentials_provider_static_options_release($provider_options);
|
||||||
|
}
|
||||||
|
}
|
||||||
358
vendor/aws/aws-crt-php/src/AWS/CRT/CRT.php
vendored
Normal file
358
vendor/aws/aws-crt-php/src/AWS/CRT/CRT.php
vendored
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT;
|
||||||
|
|
||||||
|
use AWS\CRT\Internal\Extension;
|
||||||
|
|
||||||
|
use \RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper for the interface to the CRT. There only ever needs to be one of these, but
|
||||||
|
* additional instances won't cost anything other than their memory.
|
||||||
|
* Creating an instance of any NativeResource will activate the CRT binding. User code
|
||||||
|
* should only need to create one of these if they are only accessing CRT:: static functions.
|
||||||
|
*/
|
||||||
|
final class CRT {
|
||||||
|
|
||||||
|
private static $impl = null;
|
||||||
|
private static $refcount = 0;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
if (is_null(self::$impl)) {
|
||||||
|
try {
|
||||||
|
self::$impl = new Extension();
|
||||||
|
} catch (RuntimeException $rex) {
|
||||||
|
throw new RuntimeException("Unable to initialize AWS CRT via awscrt extension: \n$rex", -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++self::$refcount;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
if (--self::$refcount == 0) {
|
||||||
|
self::$impl = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool whether or not the CRT is currently loaded
|
||||||
|
*/
|
||||||
|
public static function isLoaded() {
|
||||||
|
return !is_null(self::$impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool whether or not the CRT is available via one of the possible backends
|
||||||
|
*/
|
||||||
|
public static function isAvailable() {
|
||||||
|
try {
|
||||||
|
new CRT();
|
||||||
|
return true;
|
||||||
|
} catch (RuntimeException $ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return integer last error code reported within the CRT
|
||||||
|
*/
|
||||||
|
public static function last_error() {
|
||||||
|
return self::$impl->aws_crt_last_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $error Error code from the CRT, usually delivered via callback or {@see last_error}
|
||||||
|
* @return string Human-readable description of the provided error code
|
||||||
|
*/
|
||||||
|
public static function error_str($error) {
|
||||||
|
return self::$impl->aws_crt_error_str((int) $error);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param integer $error Error code from the CRT, usually delivered via callback or {@see last_error}
|
||||||
|
* @return string Name/enum identifier for the provided error code
|
||||||
|
*/
|
||||||
|
public static function error_name($error) {
|
||||||
|
return self::$impl->aws_crt_error_name((int) $error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log_to_stdout() {
|
||||||
|
return self::$impl->aws_crt_log_to_stdout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log_to_stderr() {
|
||||||
|
return self::$impl->aws_crt_log_to_stderr();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log_to_file($filename) {
|
||||||
|
return self::$impl->aws_crt_log_to_file($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log_to_stream($stream) {
|
||||||
|
return self::$impl->aws_crt_log_to_stream($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log_set_level($level) {
|
||||||
|
return self::$impl->aws_crt_log_set_level($level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log_stop() {
|
||||||
|
return self::$impl->aws_crt_log_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log_message($level, $message) {
|
||||||
|
return self::$impl->aws_crt_log_message($level, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return object Pointer to native event_loop_group_options
|
||||||
|
*/
|
||||||
|
function event_loop_group_options_new() {
|
||||||
|
return self::$impl->aws_crt_event_loop_group_options_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $elg_options Pointer to native event_loop_group_options
|
||||||
|
*/
|
||||||
|
function event_loop_group_options_release($elg_options) {
|
||||||
|
self::$impl->aws_crt_event_loop_group_options_release($elg_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $elg_options Pointer to native event_loop_group_options
|
||||||
|
* @param integer $max_threads Maximum number of threads to allow the event loop group to use, default: 0/1 per CPU core
|
||||||
|
*/
|
||||||
|
function event_loop_group_options_set_max_threads($elg_options, $max_threads) {
|
||||||
|
self::$impl->aws_crt_event_loop_group_options_set_max_threads($elg_options, (int)$max_threads);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object Pointer to event_loop_group_options, {@see event_loop_group_options_new}
|
||||||
|
* @return object Pointer to the new event loop group
|
||||||
|
*/
|
||||||
|
function event_loop_group_new($options) {
|
||||||
|
return self::$impl->aws_crt_event_loop_group_new($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param object $elg Pointer to the event loop group to release
|
||||||
|
*/
|
||||||
|
function event_loop_group_release($elg) {
|
||||||
|
self::$impl->aws_crt_event_loop_group_release($elg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return object Pointer to native AWS credentials options
|
||||||
|
*/
|
||||||
|
function aws_credentials_options_new() {
|
||||||
|
return self::$impl->aws_crt_credentials_options_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
function aws_credentials_options_release($options) {
|
||||||
|
self::$impl->aws_crt_credentials_options_release($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aws_credentials_options_set_access_key_id($options, $access_key_id) {
|
||||||
|
self::$impl->aws_crt_credentials_options_set_access_key_id($options, $access_key_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aws_credentials_options_set_secret_access_key($options, $secret_access_key) {
|
||||||
|
self::$impl->aws_crt_credentials_options_set_secret_access_key($options, $secret_access_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aws_credentials_options_set_session_token($options, $session_token) {
|
||||||
|
self::$impl->aws_crt_credentials_options_set_session_token($options, $session_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aws_credentials_options_set_expiration_timepoint_seconds($options, $expiration_timepoint_seconds) {
|
||||||
|
self::$impl->aws_crt_credentials_options_set_expiration_timepoint_seconds($options, $expiration_timepoint_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aws_credentials_new($options) {
|
||||||
|
return self::$impl->aws_crt_credentials_new($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function aws_credentials_release($credentials) {
|
||||||
|
self::$impl->aws_crt_credentials_release($credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
function credentials_provider_release($provider) {
|
||||||
|
self::$impl->aws_crt_credentials_provider_release($provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function credentials_provider_static_options_new() {
|
||||||
|
return self::$impl->aws_crt_credentials_provider_static_options_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
function credentials_provider_static_options_release($options) {
|
||||||
|
self::$impl->aws_crt_credentials_provider_static_options_release($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function credentials_provider_static_options_set_access_key_id($options, $access_key_id) {
|
||||||
|
self::$impl->aws_crt_credentials_provider_static_options_set_access_key_id($options, $access_key_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function credentials_provider_static_options_set_secret_access_key($options, $secret_access_key) {
|
||||||
|
self::$impl->aws_crt_credentials_provider_static_options_set_secret_access_key($options, $secret_access_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
function credentials_provider_static_options_set_session_token($options, $session_token) {
|
||||||
|
self::$impl->aws_crt_credentials_provider_static_options_set_session_token($options, $session_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
function credentials_provider_static_new($options) {
|
||||||
|
return self::$impl->aws_crt_credentials_provider_static_new($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_options_new() {
|
||||||
|
return self::$impl->aws_crt_input_stream_options_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_options_release($options) {
|
||||||
|
self::$impl->aws_crt_input_stream_options_release($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_options_set_user_data($options, $user_data) {
|
||||||
|
self::$impl->aws_crt_input_stream_options_set_user_data($options, $user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_new($options) {
|
||||||
|
return self::$impl->aws_crt_input_stream_new($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_release($stream) {
|
||||||
|
self::$impl->aws_crt_input_stream_release($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_seek($stream, $offset, $basis) {
|
||||||
|
return self::$impl->aws_crt_input_stream_seek($stream, $offset, $basis);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_read($stream, $length) {
|
||||||
|
return self::$impl->aws_crt_input_stream_read($stream, $length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_eof($stream) {
|
||||||
|
return self::$impl->aws_crt_input_stream_eof($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
function input_stream_get_length($stream) {
|
||||||
|
return self::$impl->aws_crt_input_stream_get_length($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
function http_message_new_from_blob($blob) {
|
||||||
|
return self::$impl->aws_crt_http_message_new_from_blob($blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
function http_message_to_blob($message) {
|
||||||
|
return self::$impl->aws_crt_http_message_to_blob($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function http_message_release($message) {
|
||||||
|
self::$impl->aws_crt_http_message_release($message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_new() {
|
||||||
|
return self::$impl->aws_crt_signing_config_aws_new();
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_release($signing_config) {
|
||||||
|
return self::$impl->aws_crt_signing_config_aws_release($signing_config);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_algorithm($signing_config, $algorithm) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_algorithm($signing_config, (int)$algorithm);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_signature_type($signing_config, $signature_type) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_signature_type($signing_config, (int)$signature_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_credentials_provider($signing_config, $credentials_provider) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_credentials_provider($signing_config, $credentials_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_region($signing_config, $region) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_region($signing_config, $region);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_service($signing_config, $service) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_service($signing_config, $service);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_use_double_uri_encode($signing_config, $use_double_uri_encode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_should_normalize_uri_path($signing_config, $should_normalize_uri_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_omit_session_token($signing_config, $omit_session_token) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_omit_session_token($signing_config, $omit_session_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_signed_body_value($signing_config, $signed_body_value) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_signed_body_value($signing_config, $signed_body_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_signed_body_header_type($signing_config, $signed_body_header_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_expiration_in_seconds($signing_config, $expiration_in_seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_date($signing_config, $timestamp) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_date($signing_config, $timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_config_aws_set_should_sign_header_fn($signing_config, $should_sign_header_fn) {
|
||||||
|
self::$impl->aws_crt_signing_config_aws_set_should_sign_header_fn($signing_config, $should_sign_header_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signable_new_from_http_request($http_message) {
|
||||||
|
return self::$impl->aws_crt_signable_new_from_http_request($http_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signable_new_from_chunk($chunk_stream, $previous_signature) {
|
||||||
|
return self::$impl->aws_crt_signable_new_from_chunk($chunk_stream, $previous_signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signable_new_from_canonical_request($canonical_request) {
|
||||||
|
return self::$impl->aws_crt_signable_new_from_canonical_request($canonical_request);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signable_release($signable) {
|
||||||
|
self::$impl->aws_crt_signable_release($signable);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_result_release($signing_result) {
|
||||||
|
self::$impl->aws_crt_signing_result_release($signing_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
function signing_result_apply_to_http_request($signing_result, $http_message) {
|
||||||
|
return self::$impl->aws_crt_signing_result_apply_to_http_request(
|
||||||
|
$signing_result, $http_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sign_request_aws($signable, $signing_config, $on_complete, $user_data) {
|
||||||
|
return self::$impl->aws_crt_sign_request_aws($signable, $signing_config, $on_complete, $user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y) {
|
||||||
|
return self::$impl->aws_crt_test_verify_sigv4a_signing($signable, $signing_config, $expected_canonical_request, $signature, $ecc_key_pub_x, $ecc_key_pub_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function crc32($input, $previous = 0) {
|
||||||
|
return self::$impl->aws_crt_crc32($input, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function crc32c($input, $previous = 0) {
|
||||||
|
return self::$impl->aws_crt_crc32c($input, $previous);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php
vendored
Normal file
50
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Headers.php
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\HTTP;
|
||||||
|
|
||||||
|
use AWS\CRT\Internal\Encoding;
|
||||||
|
|
||||||
|
final class Headers {
|
||||||
|
private $headers;
|
||||||
|
|
||||||
|
public function __construct($headers = []) {
|
||||||
|
$this->headers = $headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function marshall($headers) {
|
||||||
|
$buf = "";
|
||||||
|
foreach ($headers->headers as $header => $value) {
|
||||||
|
$buf .= Encoding::encodeString($header);
|
||||||
|
$buf .= Encoding::encodeString($value);
|
||||||
|
}
|
||||||
|
return $buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unmarshall($buf) {
|
||||||
|
$strings = Encoding::readStrings($buf);
|
||||||
|
$headers = [];
|
||||||
|
for ($idx = 0; $idx < count($strings);) {
|
||||||
|
$headers[$strings[$idx++]] = $strings[$idx++];
|
||||||
|
}
|
||||||
|
return new Headers($headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count() {
|
||||||
|
return count($this->headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($header) {
|
||||||
|
return isset($this->headers[$header]) ? $this->headers[$header] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function set($header, $value) {
|
||||||
|
$this->headers[$header] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray() {
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php
vendored
Normal file
95
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Message.php
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\HTTP;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource;
|
||||||
|
use AWS\CRT\Internal\Encoding;
|
||||||
|
|
||||||
|
abstract class Message extends NativeResource {
|
||||||
|
private $method;
|
||||||
|
private $path;
|
||||||
|
private $query;
|
||||||
|
private $headers;
|
||||||
|
|
||||||
|
public function __construct($method, $path, $query = [], $headers = []) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->method = $method;
|
||||||
|
$this->path = $path;
|
||||||
|
$this->query = $query;
|
||||||
|
$this->headers = new Headers($headers);
|
||||||
|
$this->acquire(self::$crt->http_message_new_from_blob(self::marshall($this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct() {
|
||||||
|
self::$crt->http_message_release($this->release());
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toBlob() {
|
||||||
|
return self::$crt->http_message_to_blob($this->native);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function marshall($msg) {
|
||||||
|
$buf = "";
|
||||||
|
$buf .= Encoding::encodeString($msg->method);
|
||||||
|
$buf .= Encoding::encodeString($msg->pathAndQuery());
|
||||||
|
$buf .= Headers::marshall($msg->headers);
|
||||||
|
return $buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function _unmarshall($buf, $class=Message::class) {
|
||||||
|
$method = Encoding::readString($buf);
|
||||||
|
$path_and_query = Encoding::readString($buf);
|
||||||
|
$parts = explode("?", $path_and_query, 2);
|
||||||
|
$path = isset($parts[0]) ? $parts[0] : "";
|
||||||
|
$query = isset($parts[1]) ? $parts[1] : "";
|
||||||
|
$headers = Headers::unmarshall($buf);
|
||||||
|
|
||||||
|
// Turn query params back into a dictionary
|
||||||
|
if (strlen($query)) {
|
||||||
|
$query = rawurldecode($query);
|
||||||
|
$query = explode("&", $query);
|
||||||
|
$query = array_reduce($query, function($params, $pair) {
|
||||||
|
list($param, $value) = explode("=", $pair, 2);
|
||||||
|
$params[$param] = $value;
|
||||||
|
return $params;
|
||||||
|
}, []);
|
||||||
|
} else {
|
||||||
|
$query = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new $class($method, $path, $query, $headers->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pathAndQuery() {
|
||||||
|
$path = $this->path;
|
||||||
|
$queries = [];
|
||||||
|
foreach ($this->query as $param => $value) {
|
||||||
|
$queries []= urlencode($param) . "=" . urlencode($value);
|
||||||
|
}
|
||||||
|
$query = implode("&", $queries);
|
||||||
|
if (strlen($query)) {
|
||||||
|
$path = implode("?", [$path, $query]);
|
||||||
|
}
|
||||||
|
return $path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function method() {
|
||||||
|
return $this->method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function path() {
|
||||||
|
return $this->path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function query() {
|
||||||
|
return $this->query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function headers() {
|
||||||
|
return $this->headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
32
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php
vendored
Normal file
32
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Request.php
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\HTTP;
|
||||||
|
|
||||||
|
use AWS\CRT\IO\InputStream;
|
||||||
|
|
||||||
|
class Request extends Message {
|
||||||
|
private $body_stream = null;
|
||||||
|
|
||||||
|
public function __construct($method, $path, $query = [], $headers = [], $body_stream = null) {
|
||||||
|
parent::__construct($method, $path, $query, $headers);
|
||||||
|
if (!is_null($body_stream) && !($body_stream instanceof InputStream)) {
|
||||||
|
throw new \InvalidArgumentException('body_stream must be an instance of ' . InputStream::class);
|
||||||
|
}
|
||||||
|
$this->body_stream = $body_stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function marshall($request) {
|
||||||
|
return parent::marshall($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unmarshall($buf) {
|
||||||
|
return parent::_unmarshall($buf, Request::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function body_stream() {
|
||||||
|
return $this->body_stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
27
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php
vendored
Normal file
27
vendor/aws/aws-crt-php/src/AWS/CRT/HTTP/Response.php
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\HTTP;
|
||||||
|
|
||||||
|
class Response extends Message {
|
||||||
|
private $status_code;
|
||||||
|
|
||||||
|
public function __construct($method, $path, $query, $headers, $status_code) {
|
||||||
|
parent::__construct($method, $path, $query, $headers);
|
||||||
|
$this->status_code = $status_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function marshall($response) {
|
||||||
|
return parent::marshall($response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function unmarshall($buf) {
|
||||||
|
return parent::_unmarshall($buf, Response::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function status_code() {
|
||||||
|
return $this->status_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
39
vendor/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php
vendored
Normal file
39
vendor/aws/aws-crt-php/src/AWS/CRT/IO/EventLoopGroup.php
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\IO;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource as NativeResource;
|
||||||
|
use AWS\CRT\Options as Options;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents 1 or more event loops (1 per thread) for doing I/O and background tasks.
|
||||||
|
* Typically, every application has one EventLoopGroup.
|
||||||
|
*
|
||||||
|
* @param array options:
|
||||||
|
* - int num_threads - Number of worker threads in the EventLoopGroup. Defaults to 0/1 per logical core.
|
||||||
|
*/
|
||||||
|
final class EventLoopGroup extends NativeResource {
|
||||||
|
|
||||||
|
static function defaults() {
|
||||||
|
return [
|
||||||
|
'max_threads' => 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct(array $options = []) {
|
||||||
|
parent::__construct();
|
||||||
|
$options = new Options($options, self::defaults());
|
||||||
|
$elg_options = self::$crt->event_loop_group_options_new();
|
||||||
|
self::$crt->event_loop_group_options_set_max_threads($elg_options, $options->getInt('max_threads'));
|
||||||
|
$this->acquire(self::$crt->event_loop_group_new($elg_options));
|
||||||
|
self::$crt->event_loop_group_options_release($elg_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
self::$crt->event_loop_group_release($this->release());
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
}
|
||||||
50
vendor/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php
vendored
Normal file
50
vendor/aws/aws-crt-php/src/AWS/CRT/IO/InputStream.php
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\IO;
|
||||||
|
|
||||||
|
use AWS\CRT\NativeResource as NativeResource;
|
||||||
|
|
||||||
|
final class InputStream extends NativeResource {
|
||||||
|
private $stream = null;
|
||||||
|
|
||||||
|
const SEEK_BEGIN = 0;
|
||||||
|
const SEEK_END = 2;
|
||||||
|
|
||||||
|
public function __construct($stream) {
|
||||||
|
parent::__construct();
|
||||||
|
$this->stream = $stream;
|
||||||
|
$options = self::$crt->input_stream_options_new();
|
||||||
|
// The stream implementation in native just converts the PHP stream into
|
||||||
|
// a native php_stream* and executes operations entirely in native
|
||||||
|
self::$crt->input_stream_options_set_user_data($options, $stream);
|
||||||
|
$this->acquire(self::$crt->input_stream_new($options));
|
||||||
|
self::$crt->input_stream_options_release($options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct() {
|
||||||
|
$this->release();
|
||||||
|
parent::__destruct();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eof() {
|
||||||
|
return self::$crt->input_stream_eof($this->native);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function length() {
|
||||||
|
return self::$crt->input_stream_get_length($this->native);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function read($length = 0) {
|
||||||
|
if ($length == 0) {
|
||||||
|
$length = $this->length();
|
||||||
|
}
|
||||||
|
return self::$crt->input_stream_read($this->native, $length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function seek($offset, $basis) {
|
||||||
|
return self::$crt->input_stream_seek($this->native, $offset, $basis);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
vendor/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php
vendored
Normal file
37
vendor/aws/aws-crt-php/src/AWS/CRT/Internal/Encoding.php
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Internal;
|
||||||
|
|
||||||
|
final class Encoding {
|
||||||
|
public static function readString(&$buffer) {
|
||||||
|
list($len, $str) = self::decodeString($buffer);
|
||||||
|
// Advance by sizeof(length) + strlen(str)
|
||||||
|
$buffer = substr($buffer, 4 + $len);
|
||||||
|
return $str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function readStrings($buffer) {
|
||||||
|
$strings = [];
|
||||||
|
while (strlen($buffer)) {
|
||||||
|
$strings []= self::readString($buffer);
|
||||||
|
}
|
||||||
|
return $strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function decodeString($buffer) {
|
||||||
|
$len = unpack("N", $buffer)[1];
|
||||||
|
$buffer = substr($buffer, 4);
|
||||||
|
$str = unpack("a{$len}", $buffer)[1];
|
||||||
|
return [$len, $str];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function encodeString($str) {
|
||||||
|
if (is_array($str)) {
|
||||||
|
$str = $str[0];
|
||||||
|
}
|
||||||
|
return pack("Na*", strlen($str), $str);
|
||||||
|
}
|
||||||
|
}
|
||||||
29
vendor/aws/aws-crt-php/src/AWS/CRT/Internal/Extension.php
vendored
Normal file
29
vendor/aws/aws-crt-php/src/AWS/CRT/Internal/Extension.php
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT\Internal;
|
||||||
|
|
||||||
|
use \RuntimeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* Forwards calls on to awscrt PHP extension functions
|
||||||
|
*/
|
||||||
|
final class Extension {
|
||||||
|
function __construct() {
|
||||||
|
if (!extension_loaded('awscrt')) {
|
||||||
|
throw new RuntimeException('awscrt extension is not loaded');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forwards any call made on this object to the extension function of the
|
||||||
|
* same name with the supplied arguments. Argument type hinting and checking
|
||||||
|
* occurs at the CRT wrapper.
|
||||||
|
*/
|
||||||
|
function __call($name, $args) {
|
||||||
|
return call_user_func_array($name, $args);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
vendor/aws/aws-crt-php/src/AWS/CRT/Log.php
vendored
Normal file
47
vendor/aws/aws-crt-php/src/AWS/CRT/Log.php
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT;
|
||||||
|
use AWS\CRT\CRT;
|
||||||
|
|
||||||
|
final class Log {
|
||||||
|
const NONE = 0;
|
||||||
|
const FATAL = 1;
|
||||||
|
const ERROR = 2;
|
||||||
|
const WARN = 3;
|
||||||
|
const INFO = 4;
|
||||||
|
const DEBUG = 5;
|
||||||
|
const TRACE = 6;
|
||||||
|
|
||||||
|
public static function toStdout() {
|
||||||
|
CRT::log_to_stdout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toStderr() {
|
||||||
|
CRT::log_to_stderr();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toFile($filename) {
|
||||||
|
CRT::log_to_file($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toStream($stream) {
|
||||||
|
assert(get_resource_type($stream) == "stream");
|
||||||
|
CRT::log_to_stream($stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stop() {
|
||||||
|
CRT::log_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setLogLevel($level) {
|
||||||
|
assert($level >= self::NONE && $level <= self::TRACE);
|
||||||
|
CRT::log_set_level($level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log($level, $message) {
|
||||||
|
CRT::log_message($level, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
vendor/aws/aws-crt-php/src/AWS/CRT/NativeResource.php
vendored
Normal file
42
vendor/aws/aws-crt-php/src/AWS/CRT/NativeResource.php
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT;
|
||||||
|
|
||||||
|
use AWS\CRT\CRT as CRT;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all native resources, tracks all outstanding resources
|
||||||
|
* and provides basic leak checking
|
||||||
|
*/
|
||||||
|
abstract class NativeResource {
|
||||||
|
protected static $crt = null;
|
||||||
|
protected static $resources = [];
|
||||||
|
protected $native = null;
|
||||||
|
|
||||||
|
protected function __construct() {
|
||||||
|
if (is_null(self::$crt)) {
|
||||||
|
self::$crt = new CRT();
|
||||||
|
}
|
||||||
|
|
||||||
|
self::$resources[spl_object_hash($this)] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function acquire($handle) {
|
||||||
|
return $this->native = $handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function release() {
|
||||||
|
$native = $this->native;
|
||||||
|
$this->native = null;
|
||||||
|
return $native;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
// Should have been destroyed and released by derived resource
|
||||||
|
assert($this->native == null);
|
||||||
|
unset(self::$resources[spl_object_hash($this)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
vendor/aws/aws-crt-php/src/AWS/CRT/Options.php
vendored
Normal file
77
vendor/aws/aws-crt-php/src/AWS/CRT/Options.php
vendored
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0.
|
||||||
|
*/
|
||||||
|
namespace AWS\CRT;
|
||||||
|
|
||||||
|
final class OptionValue {
|
||||||
|
private $value;
|
||||||
|
function __construct($value) {
|
||||||
|
$this->value = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asObject() {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asMixed() {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asInt() {
|
||||||
|
return empty($this->value) ? 0 : (int)$this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asBool() {
|
||||||
|
return boolval($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asString() {
|
||||||
|
return !empty($this->value) ? strval($this->value) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asArray() {
|
||||||
|
return is_array($this->value) ? $this->value : (!empty($this->value) ? [$this->value] : []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asCallable() {
|
||||||
|
return is_callable($this->value) ? $this->value : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class Options {
|
||||||
|
private $options;
|
||||||
|
|
||||||
|
public function __construct($opts = [], $defaults = []) {
|
||||||
|
$this->options = array_replace($defaults, empty($opts) ? [] : $opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name) {
|
||||||
|
return $this->get($name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function asArray() {
|
||||||
|
return $this->options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray() {
|
||||||
|
return array_merge_recursive([], $this->options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($name) {
|
||||||
|
return new OptionValue($this->options[$name]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInt($name) {
|
||||||
|
return $this->get($name)->asInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getString($name) {
|
||||||
|
return $this->get($name)->asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBool($name) {
|
||||||
|
return $this->get($name)->asBool();
|
||||||
|
}
|
||||||
|
}
|
||||||
4
vendor/aws/aws-sdk-php/CODE_OF_CONDUCT.md
vendored
Normal file
4
vendor/aws/aws-sdk-php/CODE_OF_CONDUCT.md
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
## Code of Conduct
|
||||||
|
This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct).
|
||||||
|
For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact
|
||||||
|
opensource-codeofconduct@amazon.com with any additional questions or comments.
|
||||||
4
vendor/aws/aws-sdk-php/CRT_INSTRUCTIONS.md
vendored
Normal file
4
vendor/aws/aws-sdk-php/CRT_INSTRUCTIONS.md
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
## Building and enabling the Common Run Time
|
||||||
|
|
||||||
|
1. **Follow instructions on crt repo** – Clone and build the repo as shown [here][https://github.com/awslabs/aws-crt-php].
|
||||||
|
1. **Enable the CRT** – add the following line to your php.ini file `extension=path/to/aws-crt-php/modules/awscrt.so`
|
||||||
141
vendor/aws/aws-sdk-php/LICENSE
vendored
Normal file
141
vendor/aws/aws-sdk-php/LICENSE
vendored
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
# Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
## 1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1
|
||||||
|
through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the
|
||||||
|
License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled
|
||||||
|
by, or are under common control with that entity. For the purposes of this definition, "control" means
|
||||||
|
(i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract
|
||||||
|
or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial
|
||||||
|
ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications, including but not limited to software
|
||||||
|
source code, documentation source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form,
|
||||||
|
including but not limited to compiled object code, generated documentation, and conversions to other media
|
||||||
|
types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License,
|
||||||
|
as indicated by a copyright notice that is included in or attached to the work (an example is provided in the
|
||||||
|
Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from)
|
||||||
|
the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent,
|
||||||
|
as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not
|
||||||
|
include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work
|
||||||
|
and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including the original version of the Work and any
|
||||||
|
modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to
|
||||||
|
Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to
|
||||||
|
submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of
|
||||||
|
electronic, verbal, or written communication sent to the Licensor or its representatives, including but not
|
||||||
|
limited to communication on electronic mailing lists, source code control systems, and issue tracking systems
|
||||||
|
that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise designated in writing by the copyright
|
||||||
|
owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been
|
||||||
|
received by Licensor and subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
## 2. Grant of Copyright License.
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare
|
||||||
|
Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||||
|
Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
## 3. Grant of Patent License.
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent
|
||||||
|
license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such
|
||||||
|
license applies only to those patent claims licensable by such Contributor that are necessarily infringed by
|
||||||
|
their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such
|
||||||
|
Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim
|
||||||
|
or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work
|
||||||
|
constitutes direct or contributory patent infringement, then any patent licenses granted to You under this
|
||||||
|
License for that Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
## 4. Redistribution.
|
||||||
|
|
||||||
|
You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||||
|
|
||||||
|
1. You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
2. You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||||
|
|
||||||
|
3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent,
|
||||||
|
trademark, and attribution notices from the Source form of the Work, excluding those notices that do
|
||||||
|
not pertain to any part of the Derivative Works; and
|
||||||
|
|
||||||
|
4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that
|
||||||
|
You distribute must include a readable copy of the attribution notices contained within such NOTICE
|
||||||
|
file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed as part of the Derivative Works; within
|
||||||
|
the Source form or documentation, if provided along with the Derivative Works; or, within a display
|
||||||
|
generated by the Derivative Works, if and wherever such third-party notices normally appear. The
|
||||||
|
contents of the NOTICE file are for informational purposes only and do not modify the License. You may
|
||||||
|
add Your own attribution notices within Derivative Works that You distribute, alongside or as an
|
||||||
|
addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be
|
||||||
|
construed as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide additional or different license
|
||||||
|
terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative
|
||||||
|
Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the
|
||||||
|
conditions stated in this License.
|
||||||
|
|
||||||
|
## 5. Submission of Contributions.
|
||||||
|
|
||||||
|
Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by
|
||||||
|
You to the Licensor shall be under the terms and conditions of this License, without any additional terms or
|
||||||
|
conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate
|
||||||
|
license agreement you may have executed with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
## 6. Trademarks.
|
||||||
|
|
||||||
|
This License does not grant permission to use the trade names, trademarks, service marks, or product names of
|
||||||
|
the Licensor, except as required for reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
## 7. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor
|
||||||
|
provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
|
||||||
|
or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT,
|
||||||
|
MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of
|
||||||
|
permissions under this License.
|
||||||
|
|
||||||
|
## 8. Limitation of Liability.
|
||||||
|
|
||||||
|
In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless
|
||||||
|
required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any
|
||||||
|
Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential
|
||||||
|
damages of any character arising as a result of this License or out of the use or inability to use the Work
|
||||||
|
(including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||||
|
any and all other commercial damages or losses), even if such Contributor has been advised of the possibility
|
||||||
|
of such damages.
|
||||||
|
|
||||||
|
## 9. Accepting Warranty or Additional Liability.
|
||||||
|
|
||||||
|
While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for,
|
||||||
|
acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole
|
||||||
|
responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold
|
||||||
|
each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
17
vendor/aws/aws-sdk-php/NOTICE
vendored
Normal file
17
vendor/aws/aws-sdk-php/NOTICE
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# AWS SDK for PHP
|
||||||
|
|
||||||
|
<http://aws.amazon.com/php>
|
||||||
|
|
||||||
|
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License").
|
||||||
|
You may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
84
vendor/aws/aws-sdk-php/THIRD-PARTY-LICENSES
vendored
Normal file
84
vendor/aws/aws-sdk-php/THIRD-PARTY-LICENSES
vendored
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
The AWS SDK for PHP includes the following third-party software/licensing:
|
||||||
|
|
||||||
|
|
||||||
|
** Guzzle - https://github.com/guzzle/guzzle
|
||||||
|
|
||||||
|
Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
----------------
|
||||||
|
|
||||||
|
** jmespath.php - https://github.com/mtdowling/jmespath.php
|
||||||
|
|
||||||
|
Copyright (c) 2014 Michael Dowling, https://github.com/mtdowling
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
----------------
|
||||||
|
|
||||||
|
** phpunit-mock-objects -- https://github.com/sebastianbergmann/phpunit-mock-objects
|
||||||
|
|
||||||
|
Copyright (c) 2002-2018, Sebastian Bergmann <sebastian@phpunit.de>.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the name of Sebastian Bergmann nor the names of his
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
73
vendor/aws/aws-sdk-php/composer.json
vendored
Normal file
73
vendor/aws/aws-sdk-php/composer.json
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"name": "aws/aws-sdk-php",
|
||||||
|
"homepage": "http://aws.amazon.com/sdkforphp",
|
||||||
|
"description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
|
||||||
|
"keywords": ["aws","amazon","sdk","s3","ec2","dynamodb","cloud","glacier"],
|
||||||
|
"type": "library",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Amazon Web Services",
|
||||||
|
"homepage": "http://aws.amazon.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"forum": "https://github.com/aws/aws-sdk-php/discussions",
|
||||||
|
"issues": "https://github.com/aws/aws-sdk-php/issues"
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.1",
|
||||||
|
"guzzlehttp/guzzle": "^7.4.5",
|
||||||
|
"guzzlehttp/psr7": "^2.4.5",
|
||||||
|
"guzzlehttp/promises": "^2.0",
|
||||||
|
"mtdowling/jmespath.php": "^2.8.0",
|
||||||
|
"ext-pcre": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-simplexml": "*",
|
||||||
|
"aws/aws-crt-php": "^1.2.3",
|
||||||
|
"psr/http-message": "^1.0 || ^2.0",
|
||||||
|
"symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"composer/composer" : "^2.7.8",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"ext-dom": "*",
|
||||||
|
"ext-sockets": "*",
|
||||||
|
"phpunit/phpunit": "^9.6",
|
||||||
|
"behat/behat": "~3.0",
|
||||||
|
"doctrine/cache": "~1.4",
|
||||||
|
"aws/aws-php-sns-message-validator": "~1.0",
|
||||||
|
"andrewsville/php-token-reflection": "^1.4",
|
||||||
|
"psr/cache": "^2.0 || ^3.0",
|
||||||
|
"psr/simple-cache": "^2.0 || ^3.0",
|
||||||
|
"sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0",
|
||||||
|
"yoast/phpunit-polyfills": "^2.0",
|
||||||
|
"dms/phpunit-arraysubset-asserts": "^0.4.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
|
||||||
|
"ext-curl": "To send requests using cURL",
|
||||||
|
"ext-sockets": "To use client-side monitoring",
|
||||||
|
"ext-pcntl": "To use client-side monitoring",
|
||||||
|
"doctrine/cache": "To use the DoctrineCacheAdapter",
|
||||||
|
"aws/aws-php-sns-message-validator": "To validate incoming SNS notifications"
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Aws\\": "src/"
|
||||||
|
},
|
||||||
|
"files": ["src/functions.php"],
|
||||||
|
"exclude-from-classmap": ["src/data/"]
|
||||||
|
},
|
||||||
|
"autoload-dev": {
|
||||||
|
"psr-4": {
|
||||||
|
"Aws\\Test\\": "tests/"
|
||||||
|
},
|
||||||
|
"classmap": ["build/"]
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "3.0-dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
vendor/aws/aws-sdk-php/src/ACMPCA/ACMPCAClient.php
vendored
Normal file
55
vendor/aws/aws-sdk-php/src/ACMPCA/ACMPCAClient.php
vendored
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\ACMPCA;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AWS Certificate Manager Private Certificate Authority** service.
|
||||||
|
* @method \Aws\Result createCertificateAuthority(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createCertificateAuthorityAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createCertificateAuthorityAuditReport(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createCertificateAuthorityAuditReportAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createPermission(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createPermissionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteCertificateAuthority(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteCertificateAuthorityAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deletePermission(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deletePermissionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deletePolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deletePolicyAsync(array $args = [])
|
||||||
|
* @method \Aws\Result describeCertificateAuthority(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise describeCertificateAuthorityAsync(array $args = [])
|
||||||
|
* @method \Aws\Result describeCertificateAuthorityAuditReport(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise describeCertificateAuthorityAuditReportAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getCertificateAuthorityCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getCertificateAuthorityCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getCertificateAuthorityCsr(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getCertificateAuthorityCsrAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getPolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getPolicyAsync(array $args = [])
|
||||||
|
* @method \Aws\Result importCertificateAuthorityCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise importCertificateAuthorityCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result issueCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise issueCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listCertificateAuthorities(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listCertificateAuthoritiesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listPermissions(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listPermissionsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listTags(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listTagsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result putPolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise putPolicyAsync(array $args = [])
|
||||||
|
* @method \Aws\Result restoreCertificateAuthority(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise restoreCertificateAuthorityAsync(array $args = [])
|
||||||
|
* @method \Aws\Result revokeCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise revokeCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result tagCertificateAuthority(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise tagCertificateAuthorityAsync(array $args = [])
|
||||||
|
* @method \Aws\Result untagCertificateAuthority(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise untagCertificateAuthorityAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateCertificateAuthority(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateCertificateAuthorityAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class ACMPCAClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/ACMPCA/Exception/ACMPCAException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/ACMPCA/Exception/ACMPCAException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\ACMPCA\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AWS Certificate Manager Private Certificate Authority** service.
|
||||||
|
*/
|
||||||
|
class ACMPCAException extends AwsException {}
|
||||||
31
vendor/aws/aws-sdk-php/src/AIOps/AIOpsClient.php
vendored
Normal file
31
vendor/aws/aws-sdk-php/src/AIOps/AIOpsClient.php
vendored
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AIOps;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AWS AI Ops** service.
|
||||||
|
* @method \Aws\Result createInvestigationGroup(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createInvestigationGroupAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteInvestigationGroup(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteInvestigationGroupAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteInvestigationGroupPolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteInvestigationGroupPolicyAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getInvestigationGroup(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getInvestigationGroupAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getInvestigationGroupPolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getInvestigationGroupPolicyAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listInvestigationGroups(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listInvestigationGroupsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listTagsForResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result putInvestigationGroupPolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise putInvestigationGroupPolicyAsync(array $args = [])
|
||||||
|
* @method \Aws\Result tagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result untagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateInvestigationGroup(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateInvestigationGroupAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class AIOpsClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/AIOps/Exception/AIOpsException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/AIOps/Exception/AIOpsException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AIOps\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AWS AI Ops** service.
|
||||||
|
*/
|
||||||
|
class AIOpsException extends AwsException {}
|
||||||
51
vendor/aws/aws-sdk-php/src/ARCRegionSwitch/ARCRegionSwitchClient.php
vendored
Normal file
51
vendor/aws/aws-sdk-php/src/ARCRegionSwitch/ARCRegionSwitchClient.php
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\ARCRegionSwitch;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **ARC - Region switch** service.
|
||||||
|
* @method \Aws\Result approvePlanExecutionStep(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise approvePlanExecutionStepAsync(array $args = [])
|
||||||
|
* @method \Aws\Result cancelPlanExecution(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise cancelPlanExecutionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createPlan(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createPlanAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deletePlan(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deletePlanAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getPlan(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getPlanAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getPlanEvaluationStatus(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getPlanEvaluationStatusAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getPlanExecution(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getPlanExecutionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getPlanInRegion(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getPlanInRegionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listPlanExecutionEvents(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listPlanExecutionEventsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listPlanExecutions(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listPlanExecutionsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listPlans(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listPlansAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listPlansInRegion(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listPlansInRegionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listRoute53HealthChecks(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listRoute53HealthChecksAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listRoute53HealthChecksInRegion(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listRoute53HealthChecksInRegionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listTagsForResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startPlanExecution(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startPlanExecutionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result tagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result untagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updatePlan(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updatePlanAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updatePlanExecution(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updatePlanExecutionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updatePlanExecutionStep(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updatePlanExecutionStepAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class ARCRegionSwitchClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/ARCRegionSwitch/Exception/ARCRegionSwitchException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/ARCRegionSwitch/Exception/ARCRegionSwitchException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\ARCRegionSwitch\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **ARC - Region switch** service.
|
||||||
|
*/
|
||||||
|
class ARCRegionSwitchException extends AwsException {}
|
||||||
39
vendor/aws/aws-sdk-php/src/ARCZonalShift/ARCZonalShiftClient.php
vendored
Normal file
39
vendor/aws/aws-sdk-php/src/ARCZonalShift/ARCZonalShiftClient.php
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\ARCZonalShift;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AWS ARC - Zonal Shift** service.
|
||||||
|
* @method \Aws\Result cancelPracticeRun(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise cancelPracticeRunAsync(array $args = [])
|
||||||
|
* @method \Aws\Result cancelZonalShift(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise cancelZonalShiftAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createPracticeRunConfiguration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createPracticeRunConfigurationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deletePracticeRunConfiguration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deletePracticeRunConfigurationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getAutoshiftObserverNotificationStatus(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAutoshiftObserverNotificationStatusAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getManagedResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getManagedResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listAutoshifts(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listAutoshiftsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listManagedResources(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listManagedResourcesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listZonalShifts(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listZonalShiftsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startPracticeRun(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startPracticeRunAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startZonalShift(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startZonalShiftAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateAutoshiftObserverNotificationStatus(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateAutoshiftObserverNotificationStatusAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updatePracticeRunConfiguration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updatePracticeRunConfigurationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateZonalAutoshiftConfiguration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateZonalAutoshiftConfigurationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateZonalShift(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateZonalShiftAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class ARCZonalShiftClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/ARCZonalShift/Exception/ARCZonalShiftException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/ARCZonalShift/Exception/ARCZonalShiftException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\ARCZonalShift\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AWS ARC - Zonal Shift** service.
|
||||||
|
*/
|
||||||
|
class ARCZonalShiftException extends AwsException {}
|
||||||
157
vendor/aws/aws-sdk-php/src/AbstractConfigurationProvider.php
vendored
Normal file
157
vendor/aws/aws-sdk-php/src/AbstractConfigurationProvider.php
vendored
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws;
|
||||||
|
|
||||||
|
use GuzzleHttp\Promise;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A configuration provider is a function that returns a promise that is
|
||||||
|
* fulfilled with a configuration object. This class provides base functionality
|
||||||
|
* usable by specific configuration provider implementations
|
||||||
|
*/
|
||||||
|
abstract class AbstractConfigurationProvider
|
||||||
|
{
|
||||||
|
const ENV_PROFILE = 'AWS_PROFILE';
|
||||||
|
const ENV_CONFIG_FILE = 'AWS_CONFIG_FILE';
|
||||||
|
|
||||||
|
public static $cacheKey;
|
||||||
|
|
||||||
|
protected static $interfaceClass;
|
||||||
|
protected static $exceptionClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a config provider and saves provided configuration in an
|
||||||
|
* instance of Aws\CacheInterface. Forwards calls when no config found
|
||||||
|
* in cache and updates cache with the results.
|
||||||
|
*
|
||||||
|
* @param callable $provider Configuration provider function to wrap
|
||||||
|
* @param CacheInterface $cache Cache to store configuration
|
||||||
|
* @param string|null $cacheKey (optional) Cache key to use
|
||||||
|
*
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
public static function cache(
|
||||||
|
callable $provider,
|
||||||
|
CacheInterface $cache,
|
||||||
|
$cacheKey = null
|
||||||
|
) {
|
||||||
|
$cacheKey = $cacheKey ?: static::$cacheKey;
|
||||||
|
|
||||||
|
return function () use ($provider, $cache, $cacheKey) {
|
||||||
|
$found = $cache->get($cacheKey);
|
||||||
|
if ($found instanceof static::$interfaceClass) {
|
||||||
|
return Promise\Create::promiseFor($found);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $provider()
|
||||||
|
->then(function ($config) use (
|
||||||
|
$cache,
|
||||||
|
$cacheKey
|
||||||
|
) {
|
||||||
|
$cache->set($cacheKey, $config);
|
||||||
|
return $config;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an aggregate configuration provider that invokes the provided
|
||||||
|
* variadic providers one after the other until a provider returns
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
public static function chain()
|
||||||
|
{
|
||||||
|
$links = func_get_args();
|
||||||
|
if (empty($links)) {
|
||||||
|
throw new \InvalidArgumentException('No providers in chain');
|
||||||
|
}
|
||||||
|
|
||||||
|
return function () use ($links) {
|
||||||
|
/** @var callable $parent */
|
||||||
|
$parent = array_shift($links);
|
||||||
|
$promise = $parent();
|
||||||
|
while ($next = array_shift($links)) {
|
||||||
|
$promise = $promise->otherwise($next);
|
||||||
|
}
|
||||||
|
return $promise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the environment's HOME directory if available.
|
||||||
|
*
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
protected static function getHomeDir()
|
||||||
|
{
|
||||||
|
// On Linux/Unix-like systems, use the HOME environment variable
|
||||||
|
if ($homeDir = getenv('HOME')) {
|
||||||
|
return $homeDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the HOMEDRIVE and HOMEPATH values for Windows hosts
|
||||||
|
$homeDrive = getenv('HOMEDRIVE');
|
||||||
|
$homePath = getenv('HOMEPATH');
|
||||||
|
|
||||||
|
return ($homeDrive && $homePath) ? $homeDrive . $homePath : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets default config file location from environment, falling back to aws
|
||||||
|
* default location
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected static function getDefaultConfigFilename()
|
||||||
|
{
|
||||||
|
if ($filename = getenv(self::ENV_CONFIG_FILE)) {
|
||||||
|
return $filename;
|
||||||
|
}
|
||||||
|
return self::getHomeDir() . '/.aws/config';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps a config provider and caches previously provided configuration.
|
||||||
|
*
|
||||||
|
* @param callable $provider Config provider function to wrap.
|
||||||
|
*
|
||||||
|
* @return callable
|
||||||
|
*/
|
||||||
|
public static function memoize(callable $provider)
|
||||||
|
{
|
||||||
|
return function () use ($provider) {
|
||||||
|
static $result;
|
||||||
|
static $isConstant;
|
||||||
|
|
||||||
|
// Constant config will be returned constantly.
|
||||||
|
if ($isConstant) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the initial promise that will be used as the cached value
|
||||||
|
if (null === $result) {
|
||||||
|
$result = $provider();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return config and set flag that provider is already set
|
||||||
|
return $result
|
||||||
|
->then(function ($config) use (&$isConstant) {
|
||||||
|
$isConstant = true;
|
||||||
|
return $config;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reject promise with standardized exception.
|
||||||
|
*
|
||||||
|
* @param $msg
|
||||||
|
* @return Promise\RejectedPromise
|
||||||
|
*/
|
||||||
|
protected static function reject($msg)
|
||||||
|
{
|
||||||
|
$exceptionClass = static::$exceptionClass;
|
||||||
|
return new Promise\RejectedPromise(new $exceptionClass($msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
83
vendor/aws/aws-sdk-php/src/AccessAnalyzer/AccessAnalyzerClient.php
vendored
Normal file
83
vendor/aws/aws-sdk-php/src/AccessAnalyzer/AccessAnalyzerClient.php
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AccessAnalyzer;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **Access Analyzer** service.
|
||||||
|
* @method \Aws\Result applyArchiveRule(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise applyArchiveRuleAsync(array $args = [])
|
||||||
|
* @method \Aws\Result cancelPolicyGeneration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise cancelPolicyGenerationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result checkAccessNotGranted(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise checkAccessNotGrantedAsync(array $args = [])
|
||||||
|
* @method \Aws\Result checkNoNewAccess(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise checkNoNewAccessAsync(array $args = [])
|
||||||
|
* @method \Aws\Result checkNoPublicAccess(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise checkNoPublicAccessAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createAccessPreview(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createAccessPreviewAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createAnalyzer(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createAnalyzerAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createArchiveRule(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createArchiveRuleAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteAnalyzer(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteAnalyzerAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteArchiveRule(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteArchiveRuleAsync(array $args = [])
|
||||||
|
* @method \Aws\Result generateFindingRecommendation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise generateFindingRecommendationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getAccessPreview(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAccessPreviewAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getAnalyzedResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAnalyzedResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getAnalyzer(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAnalyzerAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getArchiveRule(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getArchiveRuleAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getFinding(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getFindingAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getFindingRecommendation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getFindingRecommendationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getFindingV2(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getFindingV2Async(array $args = [])
|
||||||
|
* @method \Aws\Result getFindingsStatistics(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getFindingsStatisticsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getGeneratedPolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getGeneratedPolicyAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listAccessPreviewFindings(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listAccessPreviewFindingsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listAccessPreviews(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listAccessPreviewsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listAnalyzedResources(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listAnalyzedResourcesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listAnalyzers(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listAnalyzersAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listArchiveRules(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listArchiveRulesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listFindings(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listFindingsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listFindingsV2(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listFindingsV2Async(array $args = [])
|
||||||
|
* @method \Aws\Result listPolicyGenerations(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listPolicyGenerationsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listTagsForResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startPolicyGeneration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startPolicyGenerationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startResourceScan(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startResourceScanAsync(array $args = [])
|
||||||
|
* @method \Aws\Result tagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result untagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateAnalyzer(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateAnalyzerAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateArchiveRule(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateArchiveRuleAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateFindings(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateFindingsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result validatePolicy(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise validatePolicyAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class AccessAnalyzerClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/AccessAnalyzer/Exception/AccessAnalyzerException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/AccessAnalyzer/Exception/AccessAnalyzerException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AccessAnalyzer\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **Access Analyzer** service.
|
||||||
|
*/
|
||||||
|
class AccessAnalyzerException extends AwsException {}
|
||||||
39
vendor/aws/aws-sdk-php/src/Account/AccountClient.php
vendored
Normal file
39
vendor/aws/aws-sdk-php/src/Account/AccountClient.php
vendored
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Account;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AWS Account** service.
|
||||||
|
* @method \Aws\Result acceptPrimaryEmailUpdate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise acceptPrimaryEmailUpdateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteAlternateContact(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteAlternateContactAsync(array $args = [])
|
||||||
|
* @method \Aws\Result disableRegion(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise disableRegionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result enableRegion(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise enableRegionAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getAccountInformation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAccountInformationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getAlternateContact(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAlternateContactAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getContactInformation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getContactInformationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getGovCloudAccountInformation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getGovCloudAccountInformationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getPrimaryEmail(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getPrimaryEmailAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getRegionOptStatus(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getRegionOptStatusAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listRegions(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listRegionsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result putAccountName(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise putAccountNameAsync(array $args = [])
|
||||||
|
* @method \Aws\Result putAlternateContact(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise putAlternateContactAsync(array $args = [])
|
||||||
|
* @method \Aws\Result putContactInformation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise putContactInformationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startPrimaryEmailUpdate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startPrimaryEmailUpdateAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class AccountClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/Account/Exception/AccountException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/Account/Exception/AccountException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Account\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AWS Account** service.
|
||||||
|
*/
|
||||||
|
class AccountException extends AwsException {}
|
||||||
42
vendor/aws/aws-sdk-php/src/Acm/AcmClient.php
vendored
Normal file
42
vendor/aws/aws-sdk-php/src/Acm/AcmClient.php
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Acm;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AWS Certificate Manager** service.
|
||||||
|
*
|
||||||
|
* @method \Aws\Result addTagsToCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise addTagsToCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result describeCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise describeCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result exportCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise exportCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getAccountConfiguration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAccountConfigurationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result importCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise importCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listCertificates(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listCertificatesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listTagsForCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listTagsForCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result putAccountConfiguration(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise putAccountConfigurationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result removeTagsFromCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise removeTagsFromCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result renewCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise renewCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result requestCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise requestCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result resendValidationEmail(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise resendValidationEmailAsync(array $args = [])
|
||||||
|
* @method \Aws\Result revokeCertificate(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise revokeCertificateAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateCertificateOptions(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateCertificateOptionsAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class AcmClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/Acm/Exception/AcmException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/Acm/Exception/AcmException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Acm\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AWS Certificate Manager** service.
|
||||||
|
*/
|
||||||
|
class AcmException extends AwsException {}
|
||||||
83
vendor/aws/aws-sdk-php/src/Amplify/AmplifyClient.php
vendored
Normal file
83
vendor/aws/aws-sdk-php/src/Amplify/AmplifyClient.php
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Amplify;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AWS Amplify** service.
|
||||||
|
* @method \Aws\Result createApp(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createAppAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createBackendEnvironment(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createBackendEnvironmentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createBranch(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createBranchAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createDeployment(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createDeploymentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createDomainAssociation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createDomainAssociationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createWebhook(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createWebhookAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteApp(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteAppAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteBackendEnvironment(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteBackendEnvironmentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteBranch(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteBranchAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteDomainAssociation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteDomainAssociationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteWebhook(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteWebhookAsync(array $args = [])
|
||||||
|
* @method \Aws\Result generateAccessLogs(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise generateAccessLogsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getApp(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getAppAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getArtifactUrl(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getArtifactUrlAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBackendEnvironment(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBackendEnvironmentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBranch(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBranchAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getDomainAssociation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getDomainAssociationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getWebhook(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getWebhookAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listApps(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listAppsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listArtifacts(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listArtifactsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listBackendEnvironments(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listBackendEnvironmentsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listBranches(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listBranchesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listDomainAssociations(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listDomainAssociationsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listJobs(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listJobsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listTagsForResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listWebhooks(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listWebhooksAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startDeployment(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startDeploymentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result stopJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise stopJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result tagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result untagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateApp(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateAppAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateBranch(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateBranchAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateDomainAssociation(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateDomainAssociationAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateWebhook(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateWebhookAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class AmplifyClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/Amplify/Exception/AmplifyException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/Amplify/Exception/AmplifyException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Amplify\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AWS Amplify** service.
|
||||||
|
*/
|
||||||
|
class AmplifyException extends AwsException {}
|
||||||
71
vendor/aws/aws-sdk-php/src/AmplifyBackend/AmplifyBackendClient.php
vendored
Normal file
71
vendor/aws/aws-sdk-php/src/AmplifyBackend/AmplifyBackendClient.php
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AmplifyBackend;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AmplifyBackend** service.
|
||||||
|
* @method \Aws\Result cloneBackend(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise cloneBackendAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createBackend(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createBackendAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createBackendAPI(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createBackendAPIAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createBackendAuth(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createBackendAuthAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createBackendConfig(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createBackendConfigAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createBackendStorage(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createBackendStorageAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createToken(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createTokenAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteBackend(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteBackendAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteBackendAPI(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteBackendAPIAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteBackendAuth(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteBackendAuthAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteBackendStorage(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteBackendStorageAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteToken(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteTokenAsync(array $args = [])
|
||||||
|
* @method \Aws\Result generateBackendAPIModels(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise generateBackendAPIModelsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBackend(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBackendAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBackendAPI(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBackendAPIAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBackendAPIModels(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBackendAPIModelsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBackendAuth(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBackendAuthAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBackendJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBackendJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getBackendStorage(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getBackendStorageAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getChallengeToken(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getChallengeTokenAsync(array $args = [])
|
||||||
|
* @method \Aws\Result importBackendAuth(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise importBackendAuthAsync(array $args = [])
|
||||||
|
* @method \Aws\Result importBackendStorage(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise importBackendStorageAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listBackendJobs(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listBackendJobsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listS3Buckets(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listS3BucketsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result removeAllBackends(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise removeAllBackendsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result removeBackendConfig(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise removeBackendConfigAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateBackendAPI(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateBackendAPIAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateBackendAuth(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateBackendAuthAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateBackendConfig(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateBackendConfigAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateBackendJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateBackendJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateBackendStorage(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateBackendStorageAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class AmplifyBackendClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/AmplifyBackend/Exception/AmplifyBackendException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/AmplifyBackend/Exception/AmplifyBackendException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AmplifyBackend\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AmplifyBackend** service.
|
||||||
|
*/
|
||||||
|
class AmplifyBackendException extends AwsException {}
|
||||||
65
vendor/aws/aws-sdk-php/src/AmplifyUIBuilder/AmplifyUIBuilderClient.php
vendored
Normal file
65
vendor/aws/aws-sdk-php/src/AmplifyUIBuilder/AmplifyUIBuilderClient.php
vendored
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AmplifyUIBuilder;
|
||||||
|
|
||||||
|
use Aws\AwsClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This client is used to interact with the **AWS Amplify UI Builder** service.
|
||||||
|
* @method \Aws\Result createComponent(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createComponentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createForm(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createFormAsync(array $args = [])
|
||||||
|
* @method \Aws\Result createTheme(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise createThemeAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteComponent(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteComponentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteForm(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteFormAsync(array $args = [])
|
||||||
|
* @method \Aws\Result deleteTheme(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise deleteThemeAsync(array $args = [])
|
||||||
|
* @method \Aws\Result exchangeCodeForToken(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise exchangeCodeForTokenAsync(array $args = [])
|
||||||
|
* @method \Aws\Result exportComponents(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise exportComponentsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result exportForms(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise exportFormsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result exportThemes(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise exportThemesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getCodegenJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getCodegenJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getComponent(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getComponentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getForm(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getFormAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getMetadata(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getMetadataAsync(array $args = [])
|
||||||
|
* @method \Aws\Result getTheme(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise getThemeAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listCodegenJobs(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listCodegenJobsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listComponents(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listComponentsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listForms(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listFormsAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listTagsForResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listTagsForResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result listThemes(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise listThemesAsync(array $args = [])
|
||||||
|
* @method \Aws\Result putMetadataFlag(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise putMetadataFlagAsync(array $args = [])
|
||||||
|
* @method \Aws\Result refreshToken(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise refreshTokenAsync(array $args = [])
|
||||||
|
* @method \Aws\Result startCodegenJob(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise startCodegenJobAsync(array $args = [])
|
||||||
|
* @method \Aws\Result tagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise tagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result untagResource(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise untagResourceAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateComponent(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateComponentAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateForm(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateFormAsync(array $args = [])
|
||||||
|
* @method \Aws\Result updateTheme(array $args = [])
|
||||||
|
* @method \GuzzleHttp\Promise\Promise updateThemeAsync(array $args = [])
|
||||||
|
*/
|
||||||
|
class AmplifyUIBuilderClient extends AwsClient {}
|
||||||
9
vendor/aws/aws-sdk-php/src/AmplifyUIBuilder/Exception/AmplifyUIBuilderException.php
vendored
Normal file
9
vendor/aws/aws-sdk-php/src/AmplifyUIBuilder/Exception/AmplifyUIBuilderException.php
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\AmplifyUIBuilder\Exception;
|
||||||
|
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an error interacting with the **AWS Amplify UI Builder** service.
|
||||||
|
*/
|
||||||
|
class AmplifyUIBuilderException extends AwsException {}
|
||||||
89
vendor/aws/aws-sdk-php/src/Api/AbstractModel.php
vendored
Normal file
89
vendor/aws/aws-sdk-php/src/Api/AbstractModel.php
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class that is used by most API shapes
|
||||||
|
*/
|
||||||
|
abstract class AbstractModel implements \ArrayAccess
|
||||||
|
{
|
||||||
|
/** @var array */
|
||||||
|
protected $definition;
|
||||||
|
|
||||||
|
/** @var ShapeMap */
|
||||||
|
protected $shapeMap;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
protected $contextParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $definition Service description
|
||||||
|
* @param ShapeMap $shapeMap Shapemap used for creating shapes
|
||||||
|
*/
|
||||||
|
public function __construct(array $definition, ShapeMap $shapeMap)
|
||||||
|
{
|
||||||
|
$this->definition = $definition;
|
||||||
|
$this->shapeMap = $shapeMap;
|
||||||
|
if (isset($definition['contextParam'])) {
|
||||||
|
$this->contextParam = $definition['contextParam'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return $this->definition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed|null
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetGet($offset)
|
||||||
|
{
|
||||||
|
return isset($this->definition[$offset])
|
||||||
|
? $this->definition[$offset] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetSet($offset, $value)
|
||||||
|
{
|
||||||
|
$this->definition[$offset] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetExists($offset)
|
||||||
|
{
|
||||||
|
return isset($this->definition[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function offsetUnset($offset)
|
||||||
|
{
|
||||||
|
unset($this->definition[$offset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function shapeAt($key)
|
||||||
|
{
|
||||||
|
if (!isset($this->definition[$key])) {
|
||||||
|
throw new \InvalidArgumentException('Expected shape definition at '
|
||||||
|
. $key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->shapeFor($this->definition[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function shapeFor(array $definition)
|
||||||
|
{
|
||||||
|
return isset($definition['shape'])
|
||||||
|
? $this->shapeMap->resolve($definition)
|
||||||
|
: Shape::create($definition, $this->shapeMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
244
vendor/aws/aws-sdk-php/src/Api/ApiProvider.php
vendored
Normal file
244
vendor/aws/aws-sdk-php/src/Api/ApiProvider.php
vendored
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api;
|
||||||
|
|
||||||
|
use Aws\Exception\UnresolvedApiException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API providers.
|
||||||
|
*
|
||||||
|
* An API provider is a function that accepts a type, service, and version and
|
||||||
|
* returns an array of API data on success or NULL if no API data can be created
|
||||||
|
* for the provided arguments.
|
||||||
|
*
|
||||||
|
* You can wrap your calls to an API provider with the
|
||||||
|
* {@see ApiProvider::resolve} method to ensure that API data is created. If the
|
||||||
|
* API data is not created, then the resolve() method will throw a
|
||||||
|
* {@see Aws\Exception\UnresolvedApiException}.
|
||||||
|
*
|
||||||
|
* use Aws\Api\ApiProvider;
|
||||||
|
* $provider = ApiProvider::defaultProvider();
|
||||||
|
* // Returns an array or NULL.
|
||||||
|
* $data = $provider('api', 's3', '2006-03-01');
|
||||||
|
* // Returns an array or throws.
|
||||||
|
* $data = ApiProvider::resolve($provider, 'api', 'elasticfood', '2020-01-01');
|
||||||
|
*
|
||||||
|
* You can compose multiple providers into a single provider using
|
||||||
|
* {@see Aws\or_chain}. This method accepts providers as arguments and
|
||||||
|
* returns a new function that will invoke each provider until a non-null value
|
||||||
|
* is returned.
|
||||||
|
*
|
||||||
|
* $a = ApiProvider::filesystem(sys_get_temp_dir() . '/aws-beta-models');
|
||||||
|
* $b = ApiProvider::manifest();
|
||||||
|
*
|
||||||
|
* $c = \Aws\or_chain($a, $b);
|
||||||
|
* $data = $c('api', 'betaservice', '2015-08-08'); // $a handles this.
|
||||||
|
* $data = $c('api', 's3', '2006-03-01'); // $b handles this.
|
||||||
|
* $data = $c('api', 'invalid', '2014-12-15'); // Neither handles this.
|
||||||
|
*/
|
||||||
|
class ApiProvider
|
||||||
|
{
|
||||||
|
/** @var array A map of public API type names to their file suffix. */
|
||||||
|
private static $typeMap = [
|
||||||
|
'api' => 'api-2',
|
||||||
|
'paginator' => 'paginators-1',
|
||||||
|
'waiter' => 'waiters-2',
|
||||||
|
'docs' => 'docs-2',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var array API manifest */
|
||||||
|
private $manifest;
|
||||||
|
|
||||||
|
/** @var string The directory containing service models. */
|
||||||
|
private $modelsDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves an API provider and ensures a non-null return value.
|
||||||
|
*
|
||||||
|
* @param callable $provider Provider function to invoke.
|
||||||
|
* @param string $type Type of data ('api', 'waiter', 'paginator').
|
||||||
|
* @param string $service Service name.
|
||||||
|
* @param string $version API version.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @throws UnresolvedApiException
|
||||||
|
*/
|
||||||
|
public static function resolve(callable $provider, $type, $service, $version)
|
||||||
|
{
|
||||||
|
// Execute the provider and return the result, if there is one.
|
||||||
|
$result = $provider($type, $service, $version);
|
||||||
|
if (is_array($result)) {
|
||||||
|
if (!isset($result['metadata']['serviceIdentifier'])) {
|
||||||
|
$result['metadata']['serviceIdentifier'] = $service;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw an exception with a message depending on the inputs.
|
||||||
|
if (!isset(self::$typeMap[$type])) {
|
||||||
|
$msg = "The type must be one of: " . implode(', ', self::$typeMap);
|
||||||
|
} elseif ($service) {
|
||||||
|
$msg = "The {$service} service does not have version: {$version}.";
|
||||||
|
} else {
|
||||||
|
$msg = "You must specify a service name to retrieve its API data.";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnresolvedApiException($msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default SDK API provider.
|
||||||
|
*
|
||||||
|
* This provider loads pre-built manifest data from the `data` directory.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function defaultProvider()
|
||||||
|
{
|
||||||
|
return new self(__DIR__ . '/../data', \Aws\manifest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads API data after resolving the version to the latest, compatible,
|
||||||
|
* available version based on the provided manifest data.
|
||||||
|
*
|
||||||
|
* Manifest data is essentially an associative array of service names to
|
||||||
|
* associative arrays of API version aliases.
|
||||||
|
*
|
||||||
|
* [
|
||||||
|
* ...
|
||||||
|
* 'ec2' => [
|
||||||
|
* 'latest' => '2014-10-01',
|
||||||
|
* '2014-10-01' => '2014-10-01',
|
||||||
|
* '2014-09-01' => '2014-10-01',
|
||||||
|
* '2014-06-15' => '2014-10-01',
|
||||||
|
* ...
|
||||||
|
* ],
|
||||||
|
* 'ecs' => [...],
|
||||||
|
* 'elasticache' => [...],
|
||||||
|
* ...
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* @param string $dir Directory containing service models.
|
||||||
|
* @param array $manifest The API version manifest data.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public static function manifest($dir, array $manifest)
|
||||||
|
{
|
||||||
|
return new self($dir, $manifest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads API data from the specified directory.
|
||||||
|
*
|
||||||
|
* If "latest" is specified as the version, this provider must glob the
|
||||||
|
* directory to find which is the latest available version.
|
||||||
|
*
|
||||||
|
* @param string $dir Directory containing service models.
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
* @throws \InvalidArgumentException if the provided `$dir` is invalid.
|
||||||
|
*/
|
||||||
|
public static function filesystem($dir)
|
||||||
|
{
|
||||||
|
return new self($dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a list of valid versions for the specified service.
|
||||||
|
*
|
||||||
|
* @param string $service Service name
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getVersions($service)
|
||||||
|
{
|
||||||
|
if (!isset($this->manifest)) {
|
||||||
|
$this->buildVersionsList($service);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->manifest[$service]['versions'])) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values(array_unique($this->manifest[$service]['versions']));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the provider.
|
||||||
|
*
|
||||||
|
* @param string $type Type of data ('api', 'waiter', 'paginator').
|
||||||
|
* @param string $service Service name.
|
||||||
|
* @param string $version API version.
|
||||||
|
*
|
||||||
|
* @return array|null
|
||||||
|
*/
|
||||||
|
public function __invoke($type, $service, $version)
|
||||||
|
{
|
||||||
|
// Resolve the type or return null.
|
||||||
|
if (isset(self::$typeMap[$type])) {
|
||||||
|
$type = self::$typeMap[$type];
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve the version or return null.
|
||||||
|
if (!isset($this->manifest)) {
|
||||||
|
$this->buildVersionsList($service);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($this->manifest[$service]['versions'][$version])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = $this->manifest[$service]['versions'][$version];
|
||||||
|
$path = "{$this->modelsDir}/{$service}/{$version}/{$type}.json";
|
||||||
|
|
||||||
|
try {
|
||||||
|
return \Aws\load_compiled_json($path);
|
||||||
|
} catch (\InvalidArgumentException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $modelsDir Directory containing service models.
|
||||||
|
* @param array $manifest The API version manifest data.
|
||||||
|
*/
|
||||||
|
private function __construct($modelsDir, ?array $manifest = null)
|
||||||
|
{
|
||||||
|
$this->manifest = $manifest;
|
||||||
|
$this->modelsDir = rtrim($modelsDir, '/');
|
||||||
|
if (!is_dir($this->modelsDir)) {
|
||||||
|
throw new \InvalidArgumentException(
|
||||||
|
"The specified models directory, {$modelsDir}, was not found."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the versions list for the specified service by globbing the dir.
|
||||||
|
*/
|
||||||
|
private function buildVersionsList($service)
|
||||||
|
{
|
||||||
|
$dir = "{$this->modelsDir}/{$service}/";
|
||||||
|
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get versions, remove . and .., and sort in descending order.
|
||||||
|
$results = array_diff(scandir($dir, SCANDIR_SORT_DESCENDING), ['..', '.']);
|
||||||
|
|
||||||
|
if (!$results) {
|
||||||
|
$this->manifest[$service] = ['versions' => []];
|
||||||
|
} else {
|
||||||
|
$this->manifest[$service] = [
|
||||||
|
'versions' => [
|
||||||
|
'latest' => $results[0]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
$this->manifest[$service]['versions'] += array_combine($results, $results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
134
vendor/aws/aws-sdk-php/src/Api/DateTimeResult.php
vendored
Normal file
134
vendor/aws/aws-sdk-php/src/Api/DateTimeResult.php
vendored
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aws\Api;
|
||||||
|
|
||||||
|
use Aws\Api\Parser\Exception\ParserException;
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DateTime overrides that make DateTime work more seamlessly as a string,
|
||||||
|
* with JSON documents, and with JMESPath.
|
||||||
|
*/
|
||||||
|
class DateTimeResult extends \DateTime implements \JsonSerializable
|
||||||
|
{
|
||||||
|
private const ISO8601_NANOSECOND_REGEX = '/^(.*\.\d{6})(\d{1,3})(Z|[+-]\d{2}:\d{2})?$/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new DateTimeResult from a unix timestamp.
|
||||||
|
* The Unix epoch (or Unix time or POSIX time or Unix
|
||||||
|
* timestamp) is the number of seconds that have elapsed since
|
||||||
|
* January 1, 1970 (midnight UTC/GMT).
|
||||||
|
*
|
||||||
|
* @return DateTimeResult
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromEpoch($unixTimestamp)
|
||||||
|
{
|
||||||
|
if (!is_numeric($unixTimestamp)) {
|
||||||
|
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromEpoch');
|
||||||
|
}
|
||||||
|
|
||||||
|
// PHP 5.5 does not support sub-second precision
|
||||||
|
if (\PHP_VERSION_ID < 56000) {
|
||||||
|
return new self(gmdate('c', $unixTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
$decimalSeparator = isset(localeconv()['decimal_point']) ? localeconv()['decimal_point'] : ".";
|
||||||
|
$formatString = "U" . $decimalSeparator . "u";
|
||||||
|
$dateTime = DateTime::createFromFormat(
|
||||||
|
$formatString,
|
||||||
|
sprintf('%0.6f', $unixTimestamp),
|
||||||
|
new DateTimeZone('UTC')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (false === $dateTime) {
|
||||||
|
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromEpoch');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new self(
|
||||||
|
$dateTime->format('Y-m-d H:i:s.u'),
|
||||||
|
new DateTimeZone('UTC')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return DateTimeResult
|
||||||
|
*/
|
||||||
|
public static function fromISO8601($iso8601Timestamp)
|
||||||
|
{
|
||||||
|
if (is_numeric($iso8601Timestamp) || !is_string($iso8601Timestamp)) {
|
||||||
|
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromISO8601');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prior to 8.0.10, nanosecond precision is not supported
|
||||||
|
// Reduces to microsecond precision if nanosecond precision is detected
|
||||||
|
if (PHP_VERSION_ID < 80010
|
||||||
|
&& preg_match(self::ISO8601_NANOSECOND_REGEX, $iso8601Timestamp, $matches)
|
||||||
|
) {
|
||||||
|
$iso8601Timestamp = $matches[1] . ($matches[3] ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DateTimeResult($iso8601Timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new DateTimeResult from an unknown timestamp.
|
||||||
|
*
|
||||||
|
* @return DateTimeResult
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function fromTimestamp($timestamp, $expectedFormat = null)
|
||||||
|
{
|
||||||
|
if (empty($timestamp)) {
|
||||||
|
return self::fromEpoch(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(is_string($timestamp) || is_numeric($timestamp))) {
|
||||||
|
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromTimestamp');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($expectedFormat == 'iso8601') {
|
||||||
|
try {
|
||||||
|
return self::fromISO8601($timestamp);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return self::fromEpoch($timestamp);
|
||||||
|
}
|
||||||
|
} else if ($expectedFormat == 'unixTimestamp') {
|
||||||
|
try {
|
||||||
|
return self::fromEpoch($timestamp);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
return self::fromISO8601($timestamp);
|
||||||
|
}
|
||||||
|
} else if (\Aws\is_valid_epoch($timestamp)) {
|
||||||
|
return self::fromEpoch($timestamp);
|
||||||
|
}
|
||||||
|
return self::fromISO8601($timestamp);
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
throw new ParserException('Invalid timestamp value passed to DateTimeResult::fromTimestamp');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the DateTimeResult as an ISO 8601 date string.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function __toString()
|
||||||
|
{
|
||||||
|
return $this->format('c');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the date as an ISO 8601 date when serializing as JSON.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function jsonSerialize()
|
||||||
|
{
|
||||||
|
return (string) $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
139
vendor/aws/aws-sdk-php/src/Api/DocModel.php
vendored
Normal file
139
vendor/aws/aws-sdk-php/src/Api/DocModel.php
vendored
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the documentation strings for a given service-version and
|
||||||
|
* provides methods for extracting the desired parts related to a service,
|
||||||
|
* operation, error, or shape (i.e., parameter).
|
||||||
|
*/
|
||||||
|
class DocModel
|
||||||
|
{
|
||||||
|
/** @var array */
|
||||||
|
private $docs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $docs
|
||||||
|
*
|
||||||
|
* @throws \RuntimeException
|
||||||
|
*/
|
||||||
|
public function __construct(array $docs)
|
||||||
|
{
|
||||||
|
if (!extension_loaded('tidy')) {
|
||||||
|
throw new \RuntimeException('The "tidy" PHP extension is required.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->docs = $docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the doc model to an array.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function toArray()
|
||||||
|
{
|
||||||
|
return $this->docs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves documentation about the service.
|
||||||
|
*
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getServiceDocs()
|
||||||
|
{
|
||||||
|
return isset($this->docs['service']) ? $this->docs['service'] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves documentation about an operation.
|
||||||
|
*
|
||||||
|
* @param string $operation Name of the operation
|
||||||
|
*
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getOperationDocs($operation)
|
||||||
|
{
|
||||||
|
return isset($this->docs['operations'][$operation])
|
||||||
|
? $this->docs['operations'][$operation]
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves documentation about an error.
|
||||||
|
*
|
||||||
|
* @param string $error Name of the error
|
||||||
|
*
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getErrorDocs($error)
|
||||||
|
{
|
||||||
|
return isset($this->docs['shapes'][$error]['base'])
|
||||||
|
? $this->docs['shapes'][$error]['base']
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves documentation about a shape, specific to the context.
|
||||||
|
*
|
||||||
|
* @param string $shapeName Name of the shape.
|
||||||
|
* @param string $parentName Name of the parent/context shape.
|
||||||
|
* @param string $ref Name used by the context to reference the shape.
|
||||||
|
*
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public function getShapeDocs($shapeName, $parentName, $ref)
|
||||||
|
{
|
||||||
|
if (!isset($this->docs['shapes'][$shapeName])) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = '';
|
||||||
|
$d = $this->docs['shapes'][$shapeName];
|
||||||
|
if (isset($d['refs']["{$parentName}\${$ref}"])) {
|
||||||
|
$result = $d['refs']["{$parentName}\${$ref}"];
|
||||||
|
} elseif (isset($d['base'])) {
|
||||||
|
$result = $d['base'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($d['append'])) {
|
||||||
|
if (!isset($d['excludeAppend'])
|
||||||
|
|| !in_array($parentName, $d['excludeAppend'])
|
||||||
|
) {
|
||||||
|
$result .= $d['append'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($d['appendOnly'])
|
||||||
|
&& in_array($parentName, $d['appendOnly']['shapes'])
|
||||||
|
) {
|
||||||
|
$result .= $d['appendOnly']['message'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->clean($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function clean($content)
|
||||||
|
{
|
||||||
|
if (!$content) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$tidy = new \tidy();
|
||||||
|
$tidy->parseString($content, [
|
||||||
|
'indent' => true,
|
||||||
|
'doctype' => 'omit',
|
||||||
|
'output-html' => true,
|
||||||
|
'show-body-only' => true,
|
||||||
|
'drop-empty-paras' => true,
|
||||||
|
'clean' => true,
|
||||||
|
'drop-proprietary-attributes' => true,
|
||||||
|
'hide-comments' => true,
|
||||||
|
'logical-emphasis' => true
|
||||||
|
]);
|
||||||
|
$tidy->cleanRepair();
|
||||||
|
|
||||||
|
return (string) $content;
|
||||||
|
}
|
||||||
|
}
|
||||||
99
vendor/aws/aws-sdk-php/src/Api/ErrorParser/AbstractErrorParser.php
vendored
Normal file
99
vendor/aws/aws-sdk-php/src/Api/ErrorParser/AbstractErrorParser.php
vendored
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\ErrorParser;
|
||||||
|
|
||||||
|
use Aws\Api\Parser\MetadataParserTrait;
|
||||||
|
use Aws\Api\Parser\PayloadParserTrait;
|
||||||
|
use Aws\Api\Service;
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Aws\CommandInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
abstract class AbstractErrorParser
|
||||||
|
{
|
||||||
|
use MetadataParserTrait;
|
||||||
|
use PayloadParserTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Service
|
||||||
|
*/
|
||||||
|
protected $api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Service $api
|
||||||
|
*/
|
||||||
|
public function __construct(?Service $api = null)
|
||||||
|
{
|
||||||
|
$this->api = $api;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function payload(
|
||||||
|
ResponseInterface $response,
|
||||||
|
StructureShape $member
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function extractPayload(
|
||||||
|
StructureShape $member,
|
||||||
|
ResponseInterface $response
|
||||||
|
) {
|
||||||
|
if ($member instanceof StructureShape) {
|
||||||
|
// Structure members parse top-level data into a specific key.
|
||||||
|
return $this->payload($response, $member);
|
||||||
|
} else {
|
||||||
|
// Streaming data is just the stream from the response body.
|
||||||
|
return $response->getBody();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function populateShape(
|
||||||
|
array &$data,
|
||||||
|
ResponseInterface $response,
|
||||||
|
?CommandInterface $command = null
|
||||||
|
) {
|
||||||
|
$data['body'] = [];
|
||||||
|
|
||||||
|
if (!empty($command) && !empty($this->api)) {
|
||||||
|
|
||||||
|
// If modeled error code is indicated, check for known error shape
|
||||||
|
if (!empty($data['code'])) {
|
||||||
|
|
||||||
|
$errors = $this->api->getOperation($command->getName())->getErrors();
|
||||||
|
foreach ($errors as $key => $error) {
|
||||||
|
|
||||||
|
// If error code matches a known error shape, populate the body
|
||||||
|
if ($this->errorCodeMatches($data, $error)) {
|
||||||
|
$modeledError = $error;
|
||||||
|
$data['body'] = $this->extractPayload(
|
||||||
|
$modeledError,
|
||||||
|
$response
|
||||||
|
);
|
||||||
|
$data['error_shape'] = $modeledError;
|
||||||
|
|
||||||
|
foreach ($error->getMembers() as $name => $member) {
|
||||||
|
switch ($member['location']) {
|
||||||
|
case 'header':
|
||||||
|
$this->extractHeader($name, $member, $response, $data['body']);
|
||||||
|
break;
|
||||||
|
case 'headers':
|
||||||
|
$this->extractHeaders($name, $member, $response, $data['body']);
|
||||||
|
break;
|
||||||
|
case 'statusCode':
|
||||||
|
$this->extractStatus($name, $response, $data['body']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function errorCodeMatches(array $data, $error): bool
|
||||||
|
{
|
||||||
|
return $data['code'] == $error['name']
|
||||||
|
|| (isset($error['error']['code']) && $data['code'] === $error['error']['code']);
|
||||||
|
}
|
||||||
|
}
|
||||||
144
vendor/aws/aws-sdk-php/src/Api/ErrorParser/JsonParserTrait.php
vendored
Normal file
144
vendor/aws/aws-sdk-php/src/Api/ErrorParser/JsonParserTrait.php
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\ErrorParser;
|
||||||
|
|
||||||
|
use Aws\Api\Parser\PayloadParserTrait;
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides basic JSON error parsing functionality.
|
||||||
|
*/
|
||||||
|
trait JsonParserTrait
|
||||||
|
{
|
||||||
|
use PayloadParserTrait;
|
||||||
|
|
||||||
|
private function genericHandler(ResponseInterface $response): array
|
||||||
|
{
|
||||||
|
$code = (string) $response->getStatusCode();
|
||||||
|
$error_code = null;
|
||||||
|
$error_type = null;
|
||||||
|
|
||||||
|
// Parse error code and type for query compatible services
|
||||||
|
if ($this->api
|
||||||
|
&& !is_null($this->api->getMetadata('awsQueryCompatible'))
|
||||||
|
&& $response->hasHeader('x-amzn-query-error')
|
||||||
|
) {
|
||||||
|
$awsQueryError = $this->parseAwsQueryCompatibleHeader($response);
|
||||||
|
if ($awsQueryError) {
|
||||||
|
$error_code = $awsQueryError['code'];
|
||||||
|
$error_type = $awsQueryError['type'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse error code from X-Amzn-Errortype header
|
||||||
|
if (!$error_code && $response->hasHeader('X-Amzn-Errortype')) {
|
||||||
|
$error_code = $this->extractErrorCode(
|
||||||
|
$response->getHeaderLine('X-Amzn-Errortype')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parsedBody = null;
|
||||||
|
$body = $response->getBody();
|
||||||
|
if (!$body->isSeekable() || $body->getSize()) {
|
||||||
|
$parsedBody = $this->parseJson((string) $body, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse error code from response body
|
||||||
|
if (!$error_code && $parsedBody) {
|
||||||
|
$error_code = $this->parseErrorFromBody($parsedBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($error_type)) {
|
||||||
|
$error_type = $code[0] == '4' ? 'client' : 'server';
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'request_id' => $response->getHeaderLine('x-amzn-requestid'),
|
||||||
|
'code' => $error_code ?? null,
|
||||||
|
'message' => null,
|
||||||
|
'type' => $error_type,
|
||||||
|
'parsed' => $parsedBody
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse AWS Query Compatible error from header
|
||||||
|
*
|
||||||
|
* @param ResponseInterface $response
|
||||||
|
* @return array|null Returns ['code' => string, 'type' => string] or null
|
||||||
|
*/
|
||||||
|
private function parseAwsQueryCompatibleHeader(ResponseInterface $response): ?array
|
||||||
|
{
|
||||||
|
$queryError = $response->getHeaderLine('x-amzn-query-error');
|
||||||
|
$parts = explode(';', $queryError);
|
||||||
|
|
||||||
|
if (count($parts) === 2 && $parts[0] && $parts[1]) {
|
||||||
|
return [
|
||||||
|
'code' => $parts[0],
|
||||||
|
'type' => $parts[1]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse error code from response body
|
||||||
|
*
|
||||||
|
* @param array|null $parsedBody
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
private function parseErrorFromBody(?array $parsedBody): ?string
|
||||||
|
{
|
||||||
|
if (!$parsedBody
|
||||||
|
|| (!isset($parsedBody['code']) && !isset($parsedBody['__type']))
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error_code = $parsedBody['code'] ?? $parsedBody['__type'];
|
||||||
|
return $this->extractErrorCode($error_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract error code from raw error string containing # and/or : delimiters
|
||||||
|
*
|
||||||
|
* @param string $rawErrorCode
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function extractErrorCode(string $rawErrorCode): string
|
||||||
|
{
|
||||||
|
// Handle format with both # and uri (e.g., "namespace#http://foo-bar")
|
||||||
|
if (str_contains($rawErrorCode, ':') && str_contains($rawErrorCode, '#')) {
|
||||||
|
$start = strpos($rawErrorCode, '#') + 1;
|
||||||
|
$end = strpos($rawErrorCode, ':', $start);
|
||||||
|
return substr($rawErrorCode, $start, $end - $start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle format with uri only : (e.g., "ErrorCode:http://foo-bar.com/baz")
|
||||||
|
if (str_contains($rawErrorCode, ':')) {
|
||||||
|
return substr($rawErrorCode, 0, strpos($rawErrorCode, ':'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle format with only # (e.g., "namespace#ErrorCode")
|
||||||
|
if (str_contains($rawErrorCode, '#')) {
|
||||||
|
return substr($rawErrorCode, strpos($rawErrorCode, '#') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rawErrorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function payload(
|
||||||
|
ResponseInterface $response,
|
||||||
|
StructureShape $member
|
||||||
|
) {
|
||||||
|
$body = $response->getBody();
|
||||||
|
if (!$body->isSeekable() || $body->getSize()) {
|
||||||
|
$jsonBody = $this->parseJson($body, $response);
|
||||||
|
} else {
|
||||||
|
$jsonBody = (string) $body;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->parser->parse($member, $jsonBody);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
vendor/aws/aws-sdk-php/src/Api/ErrorParser/JsonRpcErrorParser.php
vendored
Normal file
47
vendor/aws/aws-sdk-php/src/Api/ErrorParser/JsonRpcErrorParser.php
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\ErrorParser;
|
||||||
|
|
||||||
|
use Aws\Api\Parser\JsonParser;
|
||||||
|
use Aws\Api\Service;
|
||||||
|
use Aws\CommandInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parsers JSON-RPC errors.
|
||||||
|
*/
|
||||||
|
class JsonRpcErrorParser extends AbstractErrorParser
|
||||||
|
{
|
||||||
|
use JsonParserTrait;
|
||||||
|
|
||||||
|
private $parser;
|
||||||
|
|
||||||
|
public function __construct(?Service $api = null, ?JsonParser $parser = null)
|
||||||
|
{
|
||||||
|
parent::__construct($api);
|
||||||
|
$this->parser = $parser ?: new JsonParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(
|
||||||
|
ResponseInterface $response,
|
||||||
|
?CommandInterface $command = null
|
||||||
|
) {
|
||||||
|
$data = $this->genericHandler($response);
|
||||||
|
|
||||||
|
// Make the casing consistent across services.
|
||||||
|
if ($data['parsed']) {
|
||||||
|
$data['parsed'] = array_change_key_case($data['parsed']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($data['parsed']['__type'])) {
|
||||||
|
if (!isset($data['code'])) {
|
||||||
|
$parts = explode('#', $data['parsed']['__type']);
|
||||||
|
$data['code'] = isset($parts[1]) ? $parts[1] : $parts[0];
|
||||||
|
}
|
||||||
|
$data['message'] = $data['parsed']['message'] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->populateShape($data, $response, $command);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
vendor/aws/aws-sdk-php/src/Api/ErrorParser/RestJsonErrorParser.php
vendored
Normal file
49
vendor/aws/aws-sdk-php/src/Api/ErrorParser/RestJsonErrorParser.php
vendored
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\ErrorParser;
|
||||||
|
|
||||||
|
use Aws\Api\Parser\JsonParser;
|
||||||
|
use Aws\Api\Service;
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Aws\CommandInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses JSON-REST errors.
|
||||||
|
*/
|
||||||
|
class RestJsonErrorParser extends AbstractErrorParser
|
||||||
|
{
|
||||||
|
use JsonParserTrait;
|
||||||
|
|
||||||
|
private $parser;
|
||||||
|
|
||||||
|
public function __construct(?Service $api = null, ?JsonParser $parser = null)
|
||||||
|
{
|
||||||
|
parent::__construct($api);
|
||||||
|
$this->parser = $parser ?: new JsonParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(
|
||||||
|
ResponseInterface $response,
|
||||||
|
?CommandInterface $command = null
|
||||||
|
) {
|
||||||
|
$data = $this->genericHandler($response);
|
||||||
|
|
||||||
|
// Merge in error data from the JSON body
|
||||||
|
if ($json = $data['parsed']) {
|
||||||
|
$data = array_replace($json, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct error type from services like Amazon Glacier
|
||||||
|
if (!empty($data['type'])) {
|
||||||
|
$data['type'] = strtolower($data['type']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve error message directly
|
||||||
|
$data['message'] = $data['parsed']['message']
|
||||||
|
?? ($data['parsed']['Message'] ?? null);
|
||||||
|
|
||||||
|
$this->populateShape($data, $response, $command);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
111
vendor/aws/aws-sdk-php/src/Api/ErrorParser/XmlErrorParser.php
vendored
Normal file
111
vendor/aws/aws-sdk-php/src/Api/ErrorParser/XmlErrorParser.php
vendored
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\ErrorParser;
|
||||||
|
|
||||||
|
use Aws\Api\Parser\PayloadParserTrait;
|
||||||
|
use Aws\Api\Parser\XmlParser;
|
||||||
|
use Aws\Api\Service;
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Aws\CommandInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses XML errors.
|
||||||
|
*/
|
||||||
|
class XmlErrorParser extends AbstractErrorParser
|
||||||
|
{
|
||||||
|
use PayloadParserTrait;
|
||||||
|
|
||||||
|
protected $parser;
|
||||||
|
|
||||||
|
public function __construct(?Service $api = null, ?XmlParser $parser = null)
|
||||||
|
{
|
||||||
|
parent::__construct($api);
|
||||||
|
$this->parser = $parser ?: new XmlParser();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(
|
||||||
|
ResponseInterface $response,
|
||||||
|
?CommandInterface $command = null
|
||||||
|
) {
|
||||||
|
$code = (string) $response->getStatusCode();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'type' => $code[0] == '4' ? 'client' : 'server',
|
||||||
|
'request_id' => null,
|
||||||
|
'code' => null,
|
||||||
|
'message' => null,
|
||||||
|
'parsed' => null
|
||||||
|
];
|
||||||
|
|
||||||
|
$body = $response->getBody();
|
||||||
|
if ($body->getSize() > 0) {
|
||||||
|
$this->parseBody($this->parseXml($body, $response), $data);
|
||||||
|
} else {
|
||||||
|
$this->parseHeaders($response, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->populateShape($data, $response, $command);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseHeaders(ResponseInterface $response, array &$data)
|
||||||
|
{
|
||||||
|
if ($response->getStatusCode() == '404') {
|
||||||
|
$data['code'] = 'NotFound';
|
||||||
|
}
|
||||||
|
|
||||||
|
$data['message'] = $response->getStatusCode() . ' '
|
||||||
|
. $response->getReasonPhrase();
|
||||||
|
|
||||||
|
if ($requestId = $response->getHeaderLine('x-amz-request-id')) {
|
||||||
|
$data['request_id'] = $requestId;
|
||||||
|
$data['message'] .= " (Request-ID: $requestId)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseBody(\SimpleXMLElement $body, array &$data)
|
||||||
|
{
|
||||||
|
$data['parsed'] = $body;
|
||||||
|
$prefix = $this->registerNamespacePrefix($body);
|
||||||
|
|
||||||
|
if ($tempXml = $body->xpath("//{$prefix}Code[1]")) {
|
||||||
|
$data['code'] = (string) $tempXml[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($tempXml = $body->xpath("//{$prefix}Message[1]")) {
|
||||||
|
$data['message'] = (string) $tempXml[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$tempXml = $body->xpath("//{$prefix}RequestId[1]");
|
||||||
|
if (isset($tempXml[0])) {
|
||||||
|
$data['request_id'] = (string)$tempXml[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function registerNamespacePrefix(\SimpleXMLElement $element)
|
||||||
|
{
|
||||||
|
$namespaces = $element->getDocNamespaces();
|
||||||
|
if (!isset($namespaces[''])) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Account for the default namespace being defined and PHP not
|
||||||
|
// being able to handle it :(.
|
||||||
|
$element->registerXPathNamespace('ns', $namespaces['']);
|
||||||
|
return 'ns:';
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function payload(
|
||||||
|
ResponseInterface $response,
|
||||||
|
StructureShape $member
|
||||||
|
) {
|
||||||
|
$xmlBody = $this->parseXml($response->getBody(), $response);
|
||||||
|
$prefix = $this->registerNamespacePrefix($xmlBody);
|
||||||
|
$errorBody = $xmlBody->xpath("//{$prefix}Error");
|
||||||
|
|
||||||
|
if (is_array($errorBody) && !empty($errorBody[0])) {
|
||||||
|
return $this->parser->parse($member, $errorBody[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
vendor/aws/aws-sdk-php/src/Api/ListShape.php
vendored
Normal file
35
vendor/aws/aws-sdk-php/src/Api/ListShape.php
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a list shape.
|
||||||
|
*/
|
||||||
|
class ListShape extends Shape
|
||||||
|
{
|
||||||
|
private $member;
|
||||||
|
|
||||||
|
public function __construct(array $definition, ShapeMap $shapeMap)
|
||||||
|
{
|
||||||
|
$definition['type'] = 'list';
|
||||||
|
parent::__construct($definition, $shapeMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Shape
|
||||||
|
* @throws \RuntimeException if no member is specified
|
||||||
|
*/
|
||||||
|
public function getMember()
|
||||||
|
{
|
||||||
|
if (!$this->member) {
|
||||||
|
if (!isset($this->definition['member'])) {
|
||||||
|
throw new \RuntimeException('No member attribute specified');
|
||||||
|
}
|
||||||
|
$this->member = Shape::create(
|
||||||
|
$this->definition['member'],
|
||||||
|
$this->shapeMap
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->member;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
vendor/aws/aws-sdk-php/src/Api/MapShape.php
vendored
Normal file
54
vendor/aws/aws-sdk-php/src/Api/MapShape.php
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a map shape.
|
||||||
|
*/
|
||||||
|
class MapShape extends Shape
|
||||||
|
{
|
||||||
|
/** @var Shape */
|
||||||
|
private $value;
|
||||||
|
|
||||||
|
/** @var Shape */
|
||||||
|
private $key;
|
||||||
|
|
||||||
|
public function __construct(array $definition, ShapeMap $shapeMap)
|
||||||
|
{
|
||||||
|
$definition['type'] = 'map';
|
||||||
|
parent::__construct($definition, $shapeMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Shape
|
||||||
|
* @throws \RuntimeException if no value is specified
|
||||||
|
*/
|
||||||
|
public function getValue()
|
||||||
|
{
|
||||||
|
if (!$this->value) {
|
||||||
|
if (!isset($this->definition['value'])) {
|
||||||
|
throw new \RuntimeException('No value specified');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->value = Shape::create(
|
||||||
|
$this->definition['value'],
|
||||||
|
$this->shapeMap
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Shape
|
||||||
|
*/
|
||||||
|
public function getKey()
|
||||||
|
{
|
||||||
|
if (!$this->key) {
|
||||||
|
$this->key = isset($this->definition['key'])
|
||||||
|
? Shape::create($this->definition['key'], $this->shapeMap)
|
||||||
|
: new Shape(['type' => 'string'], $this->shapeMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
}
|
||||||
158
vendor/aws/aws-sdk-php/src/Api/Operation.php
vendored
Normal file
158
vendor/aws/aws-sdk-php/src/Api/Operation.php
vendored
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an API operation.
|
||||||
|
*/
|
||||||
|
class Operation extends AbstractModel
|
||||||
|
{
|
||||||
|
private $input;
|
||||||
|
private $output;
|
||||||
|
private $errors;
|
||||||
|
private $staticContextParams = [];
|
||||||
|
private $contextParams;
|
||||||
|
private $operationContextParams = [];
|
||||||
|
|
||||||
|
public function __construct(array $definition, ShapeMap $shapeMap)
|
||||||
|
{
|
||||||
|
$definition['type'] = 'structure';
|
||||||
|
|
||||||
|
if (!isset($definition['http']['method'])) {
|
||||||
|
$definition['http']['method'] = 'POST';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($definition['http']['requestUri'])) {
|
||||||
|
$definition['http']['requestUri'] = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($definition['staticContextParams'])) {
|
||||||
|
$this->staticContextParams = $definition['staticContextParams'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($definition['operationContextParams'])) {
|
||||||
|
$this->operationContextParams = $definition['operationContextParams'];
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($definition, $shapeMap);
|
||||||
|
$this->contextParams = $this->setContextParams();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an associative array of the HTTP attribute of the operation:
|
||||||
|
*
|
||||||
|
* - method: HTTP method of the operation
|
||||||
|
* - requestUri: URI of the request (can include URI template placeholders)
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getHttp()
|
||||||
|
{
|
||||||
|
return $this->definition['http'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the input shape of the operation.
|
||||||
|
*
|
||||||
|
* @return StructureShape
|
||||||
|
*/
|
||||||
|
public function getInput()
|
||||||
|
{
|
||||||
|
if (!$this->input) {
|
||||||
|
if ($input = $this['input']) {
|
||||||
|
$this->input = $this->shapeFor($input);
|
||||||
|
} else {
|
||||||
|
$this->input = new StructureShape([], $this->shapeMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->input;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the output shape of the operation.
|
||||||
|
*
|
||||||
|
* @return StructureShape
|
||||||
|
*/
|
||||||
|
public function getOutput()
|
||||||
|
{
|
||||||
|
if (!$this->output) {
|
||||||
|
if ($output = $this['output']) {
|
||||||
|
$this->output = $this->shapeFor($output);
|
||||||
|
} else {
|
||||||
|
$this->output = new StructureShape([], $this->shapeMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an array of operation error shapes.
|
||||||
|
*
|
||||||
|
* @return Shape[]
|
||||||
|
*/
|
||||||
|
public function getErrors()
|
||||||
|
{
|
||||||
|
if ($this->errors === null) {
|
||||||
|
if ($errors = $this['errors']) {
|
||||||
|
foreach ($errors as $key => $error) {
|
||||||
|
$errors[$key] = $this->shapeFor($error);
|
||||||
|
}
|
||||||
|
$this->errors = $errors;
|
||||||
|
} else {
|
||||||
|
$this->errors = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets static modeled static values used for
|
||||||
|
* endpoint resolution.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getStaticContextParams()
|
||||||
|
{
|
||||||
|
return $this->staticContextParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets definition of modeled dynamic values used
|
||||||
|
* for endpoint resolution
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getContextParams()
|
||||||
|
{
|
||||||
|
return $this->contextParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets definition of modeled dynamic values used
|
||||||
|
* for endpoint resolution
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getOperationContextParams(): array
|
||||||
|
{
|
||||||
|
return $this->operationContextParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setContextParams()
|
||||||
|
{
|
||||||
|
$members = $this->getInput()->getMembers();
|
||||||
|
$contextParams = [];
|
||||||
|
|
||||||
|
foreach($members as $name => $shape) {
|
||||||
|
if (!empty($contextParam = $shape->getContextParam())) {
|
||||||
|
$contextParams[$contextParam['name']] = [
|
||||||
|
'shape' => $name,
|
||||||
|
'type' => $shape->getType()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $contextParams;
|
||||||
|
}
|
||||||
|
}
|
||||||
46
vendor/aws/aws-sdk-php/src/Api/Parser/AbstractParser.php
vendored
Normal file
46
vendor/aws/aws-sdk-php/src/Api/Parser/AbstractParser.php
vendored
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\Parser;
|
||||||
|
|
||||||
|
use Aws\Api\Service;
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Aws\CommandInterface;
|
||||||
|
use Aws\ResultInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
abstract class AbstractParser
|
||||||
|
{
|
||||||
|
/** @var \Aws\Api\Service Representation of the service API*/
|
||||||
|
protected $api;
|
||||||
|
|
||||||
|
/** @var callable */
|
||||||
|
protected $parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Service $api Service description.
|
||||||
|
*/
|
||||||
|
public function __construct(Service $api)
|
||||||
|
{
|
||||||
|
$this->api = $api;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CommandInterface $command Command that was executed.
|
||||||
|
* @param ResponseInterface $response Response that was received.
|
||||||
|
*
|
||||||
|
* @return ResultInterface
|
||||||
|
*/
|
||||||
|
abstract public function __invoke(
|
||||||
|
CommandInterface $command,
|
||||||
|
ResponseInterface $response
|
||||||
|
);
|
||||||
|
|
||||||
|
abstract public function parseMemberFromStream(
|
||||||
|
StreamInterface $stream,
|
||||||
|
StructureShape $member,
|
||||||
|
$response
|
||||||
|
);
|
||||||
|
}
|
||||||
216
vendor/aws/aws-sdk-php/src/Api/Parser/AbstractRestParser.php
vendored
Normal file
216
vendor/aws/aws-sdk-php/src/Api/Parser/AbstractRestParser.php
vendored
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\Parser;
|
||||||
|
|
||||||
|
use Aws\Api\DateTimeResult;
|
||||||
|
use Aws\Api\Shape;
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Aws\Result;
|
||||||
|
use Aws\CommandInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
abstract class AbstractRestParser extends AbstractParser
|
||||||
|
{
|
||||||
|
use PayloadParserTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a payload from a response.
|
||||||
|
*
|
||||||
|
* @param ResponseInterface $response Response to parse.
|
||||||
|
* @param StructureShape $member Member to parse
|
||||||
|
* @param array $result Result value
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
abstract protected function payload(
|
||||||
|
ResponseInterface $response,
|
||||||
|
StructureShape $member,
|
||||||
|
array &$result
|
||||||
|
);
|
||||||
|
|
||||||
|
public function __invoke(
|
||||||
|
CommandInterface $command,
|
||||||
|
ResponseInterface $response
|
||||||
|
) {
|
||||||
|
$output = $this->api->getOperation($command->getName())->getOutput();
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
if ($payload = $output['payload']) {
|
||||||
|
$this->extractPayload($payload, $output, $response, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($output->getMembers() as $name => $member) {
|
||||||
|
switch ($member['location']) {
|
||||||
|
case 'header':
|
||||||
|
$this->extractHeader($name, $member, $response, $result);
|
||||||
|
break;
|
||||||
|
case 'headers':
|
||||||
|
$this->extractHeaders($name, $member, $response, $result);
|
||||||
|
break;
|
||||||
|
case 'statusCode':
|
||||||
|
$this->extractStatus($name, $response, $result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$body = $response->getBody();
|
||||||
|
if (!$payload
|
||||||
|
&& (!$body->isSeekable() || $body->getSize())
|
||||||
|
&& count($output->getMembers()) > 0
|
||||||
|
) {
|
||||||
|
// if no payload was found, then parse the contents of the body
|
||||||
|
$this->payload($response, $output, $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Result($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function extractPayload(
|
||||||
|
$payload,
|
||||||
|
StructureShape $output,
|
||||||
|
ResponseInterface $response,
|
||||||
|
array &$result
|
||||||
|
) {
|
||||||
|
$member = $output->getMember($payload);
|
||||||
|
$body = $response->getBody();
|
||||||
|
|
||||||
|
if (!empty($member['eventstream'])) {
|
||||||
|
$result[$payload] = new EventParsingIterator(
|
||||||
|
$body,
|
||||||
|
$member,
|
||||||
|
$this
|
||||||
|
);
|
||||||
|
} elseif ($member instanceof StructureShape) {
|
||||||
|
//Unions must have at least one member set to a non-null value
|
||||||
|
// If the body is empty, we can assume it is unset
|
||||||
|
if (!empty($member['union']) && ($body->isSeekable() && !$body->getSize())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[$payload] = [];
|
||||||
|
$this->payload($response, $member, $result[$payload]);
|
||||||
|
} else {
|
||||||
|
// Always set the payload to the body stream, regardless of content
|
||||||
|
$result[$payload] = $body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a single header from the response into the result.
|
||||||
|
*/
|
||||||
|
private function extractHeader(
|
||||||
|
$name,
|
||||||
|
Shape $shape,
|
||||||
|
ResponseInterface $response,
|
||||||
|
&$result
|
||||||
|
) {
|
||||||
|
$value = $response->getHeaderLine($shape['locationName'] ?: $name);
|
||||||
|
// Empty headers should not be deserialized
|
||||||
|
if ($value === null || $value === '') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($shape->getType()) {
|
||||||
|
case 'float':
|
||||||
|
case 'double':
|
||||||
|
$value = match ($value) {
|
||||||
|
'NaN', 'Infinity', '-Infinity' => $value,
|
||||||
|
default => (float) $value
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 'long':
|
||||||
|
case 'integer':
|
||||||
|
$value = (int) $value;
|
||||||
|
break;
|
||||||
|
case 'boolean':
|
||||||
|
$value = filter_var($value, FILTER_VALIDATE_BOOLEAN);
|
||||||
|
break;
|
||||||
|
case 'blob':
|
||||||
|
$value = base64_decode($value);
|
||||||
|
break;
|
||||||
|
case 'timestamp':
|
||||||
|
try {
|
||||||
|
$value = DateTimeResult::fromTimestamp(
|
||||||
|
$value,
|
||||||
|
!empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// If the value cannot be parsed, then do not add it to the
|
||||||
|
// output structure.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 'string':
|
||||||
|
try {
|
||||||
|
if ($shape['jsonvalue']) {
|
||||||
|
$value = $this->parseJson(base64_decode($value), $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If value is not set, do not add to output structure.
|
||||||
|
if (!isset($value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
//If the value cannot be parsed, then do not add it to the
|
||||||
|
//output structure.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 'list':
|
||||||
|
$listMember = $shape->getMember();
|
||||||
|
$type = $listMember->getType();
|
||||||
|
|
||||||
|
// Only boolean lists require special handling
|
||||||
|
// other types can be returned as-is
|
||||||
|
if ($type !== 'boolean') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = array_map('trim', explode(',', $value));
|
||||||
|
$value = array_map(
|
||||||
|
static fn($item) => filter_var($item, FILTER_VALIDATE_BOOLEAN),
|
||||||
|
$items
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract a map of headers with an optional prefix from the response.
|
||||||
|
*/
|
||||||
|
private function extractHeaders(
|
||||||
|
$name,
|
||||||
|
Shape $shape,
|
||||||
|
ResponseInterface $response,
|
||||||
|
&$result
|
||||||
|
) {
|
||||||
|
// Check if the headers are prefixed by a location name
|
||||||
|
$result[$name] = [];
|
||||||
|
$prefix = $shape['locationName'];
|
||||||
|
$prefixLen = $prefix !== null ? strlen($prefix) : 0;
|
||||||
|
|
||||||
|
foreach ($response->getHeaders() as $k => $values) {
|
||||||
|
if (!$prefixLen) {
|
||||||
|
$result[$name][$k] = implode(', ', $values);
|
||||||
|
} elseif (stripos($k, $prefix) === 0) {
|
||||||
|
$result[$name][substr($k, $prefixLen)] = implode(', ', $values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places the status code of the response into the result array.
|
||||||
|
*/
|
||||||
|
private function extractStatus(
|
||||||
|
$name,
|
||||||
|
ResponseInterface $response,
|
||||||
|
array &$result
|
||||||
|
) {
|
||||||
|
$result[$name] = (int) $response->getStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
54
vendor/aws/aws-sdk-php/src/Api/Parser/Crc32ValidatingParser.php
vendored
Normal file
54
vendor/aws/aws-sdk-php/src/Api/Parser/Crc32ValidatingParser.php
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\Parser;
|
||||||
|
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Aws\CommandInterface;
|
||||||
|
use Aws\Exception\AwsException;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
use GuzzleHttp\Psr7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal Decorates a parser and validates the x-amz-crc32 header.
|
||||||
|
*/
|
||||||
|
class Crc32ValidatingParser extends AbstractParser
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @param callable $parser Parser to wrap.
|
||||||
|
*/
|
||||||
|
public function __construct(callable $parser)
|
||||||
|
{
|
||||||
|
$this->parser = $parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __invoke(
|
||||||
|
CommandInterface $command,
|
||||||
|
ResponseInterface $response
|
||||||
|
) {
|
||||||
|
if ($expected = $response->getHeaderLine('x-amz-crc32')) {
|
||||||
|
$hash = hexdec(Psr7\Utils::hash($response->getBody(), 'crc32b'));
|
||||||
|
if ($expected != $hash) {
|
||||||
|
throw new AwsException(
|
||||||
|
"crc32 mismatch. Expected {$expected}, found {$hash}.",
|
||||||
|
$command,
|
||||||
|
[
|
||||||
|
'code' => 'ClientChecksumMismatch',
|
||||||
|
'connection_error' => true,
|
||||||
|
'response' => $response
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$fn = $this->parser;
|
||||||
|
return $fn($command, $response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parseMemberFromStream(
|
||||||
|
StreamInterface $stream,
|
||||||
|
StructureShape $member,
|
||||||
|
$response
|
||||||
|
) {
|
||||||
|
return $this->parser->parseMemberFromStream($stream, $member, $response);
|
||||||
|
}
|
||||||
|
}
|
||||||
347
vendor/aws/aws-sdk-php/src/Api/Parser/DecodingEventStreamIterator.php
vendored
Normal file
347
vendor/aws/aws-sdk-php/src/Api/Parser/DecodingEventStreamIterator.php
vendored
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aws\Api\Parser;
|
||||||
|
|
||||||
|
use \Iterator;
|
||||||
|
use Aws\Api\DateTimeResult;
|
||||||
|
use GuzzleHttp\Psr7;
|
||||||
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
use Aws\Api\Parser\Exception\ParserException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal Implements a decoder for a binary encoded event stream that will
|
||||||
|
* decode, validate, and provide individual events from the stream.
|
||||||
|
*/
|
||||||
|
class DecodingEventStreamIterator implements Iterator
|
||||||
|
{
|
||||||
|
const HEADERS = 'headers';
|
||||||
|
const PAYLOAD = 'payload';
|
||||||
|
|
||||||
|
const LENGTH_TOTAL = 'total_length';
|
||||||
|
const LENGTH_HEADERS = 'headers_length';
|
||||||
|
|
||||||
|
const CRC_PRELUDE = 'prelude_crc';
|
||||||
|
|
||||||
|
const BYTES_PRELUDE = 12;
|
||||||
|
const BYTES_TRAILING = 4;
|
||||||
|
|
||||||
|
private static $preludeFormat = [
|
||||||
|
self::LENGTH_TOTAL => 'decodeUint32',
|
||||||
|
self::LENGTH_HEADERS => 'decodeUint32',
|
||||||
|
self::CRC_PRELUDE => 'decodeUint32',
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $lengthFormatMap = [
|
||||||
|
1 => 'decodeUint8',
|
||||||
|
2 => 'decodeUint16',
|
||||||
|
4 => 'decodeUint32',
|
||||||
|
8 => 'decodeUint64',
|
||||||
|
];
|
||||||
|
|
||||||
|
private static $headerTypeMap = [
|
||||||
|
0 => 'decodeBooleanTrue',
|
||||||
|
1 => 'decodeBooleanFalse',
|
||||||
|
2 => 'decodeInt8',
|
||||||
|
3 => 'decodeInt16',
|
||||||
|
4 => 'decodeInt32',
|
||||||
|
5 => 'decodeInt64',
|
||||||
|
6 => 'decodeBytes',
|
||||||
|
7 => 'decodeString',
|
||||||
|
8 => 'decodeTimestamp',
|
||||||
|
9 => 'decodeUuid',
|
||||||
|
];
|
||||||
|
|
||||||
|
/** @var StreamInterface Stream of eventstream shape to parse. */
|
||||||
|
protected $stream;
|
||||||
|
|
||||||
|
/** @var array Currently parsed event. */
|
||||||
|
protected $currentEvent;
|
||||||
|
|
||||||
|
/** @var int Current in-order event key. */
|
||||||
|
protected $key;
|
||||||
|
|
||||||
|
/** @var resource|\HashContext CRC32 hash context for event validation */
|
||||||
|
protected $hashContext;
|
||||||
|
|
||||||
|
/** @var int $currentPosition */
|
||||||
|
protected $currentPosition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DecodingEventStreamIterator constructor.
|
||||||
|
*
|
||||||
|
* @param StreamInterface $stream
|
||||||
|
*/
|
||||||
|
public function __construct(StreamInterface $stream)
|
||||||
|
{
|
||||||
|
$this->stream = $stream;
|
||||||
|
$this->rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parseHeaders($headerBytes)
|
||||||
|
{
|
||||||
|
$headers = [];
|
||||||
|
$bytesRead = 0;
|
||||||
|
|
||||||
|
while ($bytesRead < $headerBytes) {
|
||||||
|
list($key, $numBytes) = $this->decodeString(1);
|
||||||
|
$bytesRead += $numBytes;
|
||||||
|
|
||||||
|
list($type, $numBytes) = $this->decodeUint8();
|
||||||
|
$bytesRead += $numBytes;
|
||||||
|
|
||||||
|
$f = self::$headerTypeMap[$type];
|
||||||
|
list($value, $numBytes) = $this->{$f}();
|
||||||
|
$bytesRead += $numBytes;
|
||||||
|
|
||||||
|
if (isset($headers[$key])) {
|
||||||
|
throw new ParserException('Duplicate key in event headers.');
|
||||||
|
}
|
||||||
|
$headers[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$headers, $bytesRead];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function parsePrelude()
|
||||||
|
{
|
||||||
|
$prelude = [];
|
||||||
|
$bytesRead = 0;
|
||||||
|
|
||||||
|
$calculatedCrc = null;
|
||||||
|
foreach (self::$preludeFormat as $key => $decodeFunction) {
|
||||||
|
if ($key === self::CRC_PRELUDE) {
|
||||||
|
$hashCopy = hash_copy($this->hashContext);
|
||||||
|
$calculatedCrc = hash_final($this->hashContext, true);
|
||||||
|
$this->hashContext = $hashCopy;
|
||||||
|
}
|
||||||
|
list($value, $numBytes) = $this->{$decodeFunction}();
|
||||||
|
$bytesRead += $numBytes;
|
||||||
|
|
||||||
|
$prelude[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unpack('N', $calculatedCrc)[1] !== $prelude[self::CRC_PRELUDE]) {
|
||||||
|
throw new ParserException('Prelude checksum mismatch.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$prelude, $bytesRead];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method decodes an event from the stream.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function parseEvent()
|
||||||
|
{
|
||||||
|
$event = [];
|
||||||
|
|
||||||
|
if ($this->stream->tell() < $this->stream->getSize()) {
|
||||||
|
$this->hashContext = hash_init('crc32b');
|
||||||
|
|
||||||
|
$bytesLeft = $this->stream->getSize() - $this->stream->tell();
|
||||||
|
list($prelude, $numBytes) = $this->parsePrelude();
|
||||||
|
if ($prelude[self::LENGTH_TOTAL] > $bytesLeft) {
|
||||||
|
throw new ParserException('Message length too long.');
|
||||||
|
}
|
||||||
|
$bytesLeft -= $numBytes;
|
||||||
|
|
||||||
|
if ($prelude[self::LENGTH_HEADERS] > $bytesLeft) {
|
||||||
|
throw new ParserException('Headers length too long.');
|
||||||
|
}
|
||||||
|
|
||||||
|
list(
|
||||||
|
$event[self::HEADERS],
|
||||||
|
$numBytes
|
||||||
|
) = $this->parseHeaders($prelude[self::LENGTH_HEADERS]);
|
||||||
|
|
||||||
|
$event[self::PAYLOAD] = Psr7\Utils::streamFor(
|
||||||
|
$this->readAndHashBytes(
|
||||||
|
$prelude[self::LENGTH_TOTAL] - self::BYTES_PRELUDE
|
||||||
|
- $numBytes - self::BYTES_TRAILING
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$calculatedCrc = hash_final($this->hashContext, true);
|
||||||
|
$messageCrc = $this->stream->read(4);
|
||||||
|
if ($calculatedCrc !== $messageCrc) {
|
||||||
|
throw new ParserException('Message checksum mismatch.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $event;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterator Functionality
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
return $this->currentEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function key()
|
||||||
|
{
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$this->currentPosition = $this->stream->tell();
|
||||||
|
if ($this->valid()) {
|
||||||
|
$this->key++;
|
||||||
|
$this->currentEvent = $this->parseEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function rewind()
|
||||||
|
{
|
||||||
|
$this->stream->rewind();
|
||||||
|
$this->key = 0;
|
||||||
|
$this->currentPosition = 0;
|
||||||
|
$this->currentEvent = $this->parseEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
return $this->currentPosition < $this->stream->getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decoding Utilities
|
||||||
|
|
||||||
|
protected function readAndHashBytes($num)
|
||||||
|
{
|
||||||
|
$bytes = $this->stream->read($num);
|
||||||
|
hash_update($this->hashContext, $bytes);
|
||||||
|
return $bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeBooleanTrue()
|
||||||
|
{
|
||||||
|
return [true, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeBooleanFalse()
|
||||||
|
{
|
||||||
|
return [false, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function uintToInt($val, $size)
|
||||||
|
{
|
||||||
|
$signedCap = pow(2, $size - 1);
|
||||||
|
if ($val > $signedCap) {
|
||||||
|
$val -= (2 * $signedCap);
|
||||||
|
}
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeInt8()
|
||||||
|
{
|
||||||
|
$val = (int)unpack('C', $this->readAndHashBytes(1))[1];
|
||||||
|
return [$this->uintToInt($val, 8), 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeUint8()
|
||||||
|
{
|
||||||
|
return [unpack('C', $this->readAndHashBytes(1))[1], 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeInt16()
|
||||||
|
{
|
||||||
|
$val = (int)unpack('n', $this->readAndHashBytes(2))[1];
|
||||||
|
return [$this->uintToInt($val, 16), 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeUint16()
|
||||||
|
{
|
||||||
|
return [unpack('n', $this->readAndHashBytes(2))[1], 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeInt32()
|
||||||
|
{
|
||||||
|
$val = (int)unpack('N', $this->readAndHashBytes(4))[1];
|
||||||
|
return [$this->uintToInt($val, 32), 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeUint32()
|
||||||
|
{
|
||||||
|
return [unpack('N', $this->readAndHashBytes(4))[1], 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeInt64()
|
||||||
|
{
|
||||||
|
$val = $this->unpackInt64($this->readAndHashBytes(8))[1];
|
||||||
|
return [$this->uintToInt($val, 64), 8];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeUint64()
|
||||||
|
{
|
||||||
|
return [$this->unpackInt64($this->readAndHashBytes(8))[1], 8];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function unpackInt64($bytes)
|
||||||
|
{
|
||||||
|
return unpack('J', $bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeBytes($lengthBytes=2)
|
||||||
|
{
|
||||||
|
if (!isset(self::$lengthFormatMap[$lengthBytes])) {
|
||||||
|
throw new ParserException('Undefined variable length format.');
|
||||||
|
}
|
||||||
|
$f = self::$lengthFormatMap[$lengthBytes];
|
||||||
|
list($len, $bytes) = $this->{$f}();
|
||||||
|
return [$this->readAndHashBytes($len), $len + $bytes];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeString($lengthBytes=2)
|
||||||
|
{
|
||||||
|
if (!isset(self::$lengthFormatMap[$lengthBytes])) {
|
||||||
|
throw new ParserException('Undefined variable length format.');
|
||||||
|
}
|
||||||
|
$f = self::$lengthFormatMap[$lengthBytes];
|
||||||
|
list($len, $bytes) = $this->{$f}();
|
||||||
|
return [$this->readAndHashBytes($len), $len + $bytes];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeTimestamp()
|
||||||
|
{
|
||||||
|
list($val, $bytes) = $this->decodeInt64();
|
||||||
|
return [
|
||||||
|
DateTimeResult::createFromFormat('U.u', $val / 1000),
|
||||||
|
$bytes
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decodeUuid()
|
||||||
|
{
|
||||||
|
$val = unpack('H32', $this->readAndHashBytes(16))[1];
|
||||||
|
return [
|
||||||
|
substr($val, 0, 8) . '-'
|
||||||
|
. substr($val, 8, 4) . '-'
|
||||||
|
. substr($val, 12, 4) . '-'
|
||||||
|
. substr($val, 16, 4) . '-'
|
||||||
|
. substr($val, 20, 12),
|
||||||
|
16
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
211
vendor/aws/aws-sdk-php/src/Api/Parser/EventParsingIterator.php
vendored
Normal file
211
vendor/aws/aws-sdk-php/src/Api/Parser/EventParsingIterator.php
vendored
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Aws\Api\Parser;
|
||||||
|
|
||||||
|
use \Iterator;
|
||||||
|
use Aws\Exception\EventStreamDataException;
|
||||||
|
use Aws\Api\Parser\Exception\ParserException;
|
||||||
|
use Aws\Api\StructureShape;
|
||||||
|
use Psr\Http\Message\StreamInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal Implements a decoder for a binary encoded event stream that will
|
||||||
|
* decode, validate, and provide individual events from the stream.
|
||||||
|
*/
|
||||||
|
class EventParsingIterator implements Iterator
|
||||||
|
{
|
||||||
|
/** @var StreamInterface */
|
||||||
|
private $decodingIterator;
|
||||||
|
|
||||||
|
/** @var StructureShape */
|
||||||
|
private $shape;
|
||||||
|
|
||||||
|
/** @var AbstractParser */
|
||||||
|
private $parser;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
StreamInterface $stream,
|
||||||
|
StructureShape $shape,
|
||||||
|
AbstractParser $parser
|
||||||
|
) {
|
||||||
|
$this->decodingIterator = $this->chooseDecodingIterator($stream);
|
||||||
|
$this->shape = $shape;
|
||||||
|
$this->parser = $parser;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method choose a decoding iterator implementation based on if the stream
|
||||||
|
* is seekable or not.
|
||||||
|
*
|
||||||
|
* @param $stream
|
||||||
|
*
|
||||||
|
* @return Iterator
|
||||||
|
*/
|
||||||
|
private function chooseDecodingIterator($stream)
|
||||||
|
{
|
||||||
|
if ($stream->isSeekable()) {
|
||||||
|
return new DecodingEventStreamIterator($stream);
|
||||||
|
} else {
|
||||||
|
return new NonSeekableStreamDecodingEventStreamIterator($stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function current()
|
||||||
|
{
|
||||||
|
return $this->parseEvent($this->decodingIterator->current());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function key()
|
||||||
|
{
|
||||||
|
return $this->decodingIterator->key();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function next()
|
||||||
|
{
|
||||||
|
$this->decodingIterator->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function rewind()
|
||||||
|
{
|
||||||
|
$this->decodingIterator->rewind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
#[\ReturnTypeWillChange]
|
||||||
|
public function valid()
|
||||||
|
{
|
||||||
|
return $this->decodingIterator->valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseEvent(array $event)
|
||||||
|
{
|
||||||
|
if (!empty($event['headers'][':message-type'])) {
|
||||||
|
if ($event['headers'][':message-type'] === 'error') {
|
||||||
|
return $this->parseError($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($event['headers'][':message-type'] === 'exception') {
|
||||||
|
return $this->parseException($event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($event['headers'][':message-type'] !== 'event') {
|
||||||
|
throw new ParserException('Failed to parse unknown message type.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$eventType = $event['headers'][':event-type'] ?? null;
|
||||||
|
if (empty($eventType)) {
|
||||||
|
throw new ParserException('Failed to parse without event type.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$eventPayload = $event['payload'];
|
||||||
|
if ($eventType === 'initial-response') {
|
||||||
|
return $this->parseInitialResponseEvent($eventPayload);
|
||||||
|
}
|
||||||
|
|
||||||
|
$eventShape = $this->shape->getMember($eventType);
|
||||||
|
|
||||||
|
return [
|
||||||
|
$eventType => array_merge(
|
||||||
|
$this->parseEventHeaders($event['headers'], $eventShape),
|
||||||
|
$this->parseEventPayload($eventPayload, $eventShape)
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $headers
|
||||||
|
* @param $eventShape
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function parseEventHeaders($headers, $eventShape): array
|
||||||
|
{
|
||||||
|
$parsedHeaders = [];
|
||||||
|
foreach ($eventShape->getMembers() as $memberName => $memberProps) {
|
||||||
|
if (isset($memberProps['eventheader'])) {
|
||||||
|
$parsedHeaders[$memberName] = $headers[$memberName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parsedHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $payload
|
||||||
|
* @param $eventShape
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
private function parseEventPayload($payload, $eventShape): array
|
||||||
|
{
|
||||||
|
$parsedPayload = [];
|
||||||
|
foreach ($eventShape->getMembers() as $memberName => $memberProps) {
|
||||||
|
$memberShape = $eventShape->getMember($memberName);
|
||||||
|
if (isset($memberProps['eventpayload'])) {
|
||||||
|
if ($memberShape->getType() === 'blob') {
|
||||||
|
$parsedPayload[$memberName] = $payload;
|
||||||
|
} else {
|
||||||
|
$parsedPayload[$memberName] = $this->parser->parseMemberFromStream(
|
||||||
|
$payload,
|
||||||
|
$memberShape,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($parsedPayload) && !empty($payload->getContents())) {
|
||||||
|
/**
|
||||||
|
* If we did not find a member with an eventpayload trait, then we should deserialize the payload
|
||||||
|
* using the event's shape.
|
||||||
|
*/
|
||||||
|
$parsedPayload = $this->parser->parseMemberFromStream($payload, $eventShape, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parsedPayload;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseError(array $event)
|
||||||
|
{
|
||||||
|
throw new EventStreamDataException(
|
||||||
|
$event['headers'][':error-code'],
|
||||||
|
$event['headers'][':error-message']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseException(array $event) {
|
||||||
|
$payload = $event['payload']?->getContents();
|
||||||
|
$parsedPayload = json_decode($payload, true);
|
||||||
|
|
||||||
|
throw new EventStreamDataException(
|
||||||
|
$event['headers'][':exception-type'] ?? 'Unknown',
|
||||||
|
$parsedPayload['message'] ?? $payload,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseInitialResponseEvent($payload): array
|
||||||
|
{
|
||||||
|
return ['initial-response' => json_decode($payload, true)];
|
||||||
|
}
|
||||||
|
}
|
||||||
56
vendor/aws/aws-sdk-php/src/Api/Parser/Exception/ParserException.php
vendored
Normal file
56
vendor/aws/aws-sdk-php/src/Api/Parser/Exception/ParserException.php
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\Parser\Exception;
|
||||||
|
|
||||||
|
use Aws\HasMonitoringEventsTrait;
|
||||||
|
use Aws\MonitoringEventsInterface;
|
||||||
|
use Aws\ResponseContainerInterface;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
|
||||||
|
class ParserException extends \RuntimeException implements
|
||||||
|
MonitoringEventsInterface,
|
||||||
|
ResponseContainerInterface
|
||||||
|
{
|
||||||
|
use HasMonitoringEventsTrait;
|
||||||
|
|
||||||
|
private $errorCode;
|
||||||
|
private $requestId;
|
||||||
|
private $response;
|
||||||
|
|
||||||
|
public function __construct($message = '', $code = 0, $previous = null, array $context = [])
|
||||||
|
{
|
||||||
|
$this->errorCode = isset($context['error_code']) ? $context['error_code'] : null;
|
||||||
|
$this->requestId = isset($context['request_id']) ? $context['request_id'] : null;
|
||||||
|
$this->response = isset($context['response']) ? $context['response'] : null;
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the error code, if any.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getErrorCode()
|
||||||
|
{
|
||||||
|
return $this->errorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the request ID, if any.
|
||||||
|
*
|
||||||
|
* @return string|null
|
||||||
|
*/
|
||||||
|
public function getRequestId()
|
||||||
|
{
|
||||||
|
return $this->requestId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the received HTTP response if any.
|
||||||
|
*
|
||||||
|
* @return ResponseInterface|null
|
||||||
|
*/
|
||||||
|
public function getResponse()
|
||||||
|
{
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
}
|
||||||
74
vendor/aws/aws-sdk-php/src/Api/Parser/JsonParser.php
vendored
Normal file
74
vendor/aws/aws-sdk-php/src/Api/Parser/JsonParser.php
vendored
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
namespace Aws\Api\Parser;
|
||||||
|
|
||||||
|
use Aws\Api\DateTimeResult;
|
||||||
|
use Aws\Api\Shape;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal Implements standard JSON parsing.
|
||||||
|
*/
|
||||||
|
class JsonParser
|
||||||
|
{
|
||||||
|
public function parse(Shape $shape, $value)
|
||||||
|
{
|
||||||
|
if ($value === null) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($shape['type']) {
|
||||||
|
case 'structure':
|
||||||
|
if (isset($shape['document']) && $shape['document']) {
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
$target = [];
|
||||||
|
foreach ($shape->getMembers() as $name => $member) {
|
||||||
|
$locationName = $member['locationName'] ?: $name;
|
||||||
|
if (isset($value[$locationName])) {
|
||||||
|
$target[$name] = $this->parse($member, $value[$locationName]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isset($shape['union'])
|
||||||
|
&& $shape['union']
|
||||||
|
&& is_array($value)
|
||||||
|
&& empty($target)
|
||||||
|
) {
|
||||||
|
foreach ($value as $key => $val) {
|
||||||
|
$target['Unknown'][$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $target;
|
||||||
|
|
||||||
|
case 'list':
|
||||||
|
$member = $shape->getMember();
|
||||||
|
$target = [];
|
||||||
|
foreach ($value as $v) {
|
||||||
|
$target[] = $this->parse($member, $v);
|
||||||
|
}
|
||||||
|
return $target;
|
||||||
|
|
||||||
|
case 'map':
|
||||||
|
$values = $shape->getValue();
|
||||||
|
$target = [];
|
||||||
|
foreach ($value as $k => $v) {
|
||||||
|
// null map values should not be deserialized
|
||||||
|
if (!is_null($v)) {
|
||||||
|
$target[$k] = $this->parse($values, $v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $target;
|
||||||
|
|
||||||
|
case 'timestamp':
|
||||||
|
return DateTimeResult::fromTimestamp(
|
||||||
|
$value,
|
||||||
|
!empty($shape['timestampFormat']) ? $shape['timestampFormat'] : null
|
||||||
|
);
|
||||||
|
|
||||||
|
case 'blob':
|
||||||
|
return base64_decode($value);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user