diff --git a/adn/00_bitacora.md b/adn/00_bitacora.md index acc63a9c..39946ea2 100644 --- a/adn/00_bitacora.md +++ b/adn/00_bitacora.md @@ -1,15 +1,16 @@ -# Índice de Bitácoras del Proyecto srv-NS8 +# Índice de Bitácoras del Proyecto srv-ns8 El registro detallado de eventos se ha segmentado por fecha para mejor organización. | Fecha | Eventos Clave | Resumen de Actividad | | :--- | :--- | :--- | +| [**19/02/2026**](../bitacoras/2026-02-19.md) | Registro Procedimientos, Backup Proxmox. | Implementación del sistema de procedimientos y lanzamiento del primer ciclo de backup automatizado (Ruby). | | [**18/02/2026**](../bitacoras/2026-02-18.md) | Recuperación Proxmox, DASU, Alta Nodos. | Recuperación Proxmox SSH, implementación VPN Tailscale, alta usuarios DC y carga calendario Posgrado. | | [**16/02/2026**](../bitacoras/2026-02-16.md) | Hardening SSH, Expansión Grid. | Hardening masivo de SSH en el Grid y expansión del relevamiento a nuevos nodos LXC/VM. | | [**15/02/2026**](../bitacoras/2026-02-15.md) | Tailscale Server. | Implementación de Tailscale y RustDesk como solución estratégica de acceso remoto. | | [**11/02/2026**](../bitacoras/2026-02-11.md) | Servicios Base (Nginx, SSL). | Configuración de servicios base, establecimiento de protocolos de seguridad y red híbrida. | -| [**08/02/2026**](../bitacoras/2026-02-08.md) | Solución Licencia FENIX. | Resolución del incidente de apagado automático en `srvv-FENIX` por causa de licencia. | -| [**07/02/2026**](../bitacoras/2026-02-07.md) | Incidentes apagado srvv-FENIX. | Investigación forense intensiva ante apagados recurrentes de `srvv-FENIX`. | +| [**08/02/2026**](../bitacoras/2026-02-08.md) | Solución Licencia FENIX. | Resolución del incidente de apagado automático en `srvv-fenix` por causa de licencia. | +| [**07/02/2026**](../bitacoras/2026-02-07.md) | Incidentes apagado srvv-fenix. | Investigación forense intensiva ante apagados recurrentes de `srvv-fenix`. | | [**14/01/2026**](../bitacoras/2026-01-14.md) | Gestión Digital CD (Video). | Gestión y publicación de grabaciones de Consejo Directivo en YouTube. | > **Nota**: Los archivos fuente se encuentran en el directorio `/bitacoras`. diff --git a/adn/01_ontologia.md b/adn/01_ontologia.md index 9712b1d5..0f0c26d3 100644 --- a/adn/01_ontologia.md +++ b/adn/01_ontologia.md @@ -1,117 +1,95 @@ -# 01 - Ontología del Sistema: srv-NS8 +# 01 - Ontología del Sistema: srv-ns8 -Este documento define la identidad, propósito y componentes principales del servidor `srv-NS8`. +Este documento define la identidad, propósito y componentes principales del servidor `srv-ns8`. -## Identidad -- **Nombre**: `srv-NS8` -- **Hostname**: `srv-NS8` +## Responsable +**Lic. Ricardo MONLA** +*Departamento Servidores* +Dirección de TIC +Facultad Regional La Rioja +**Universidad Tecnológica Nacional** + +--- + +## Identidad del Sistema +- **Nombre**: `srv-ns8` +- **Hostname**: `srv-ns8` - **Rol Principal**: Workstation / Híbrido (Docker Host + VirtualBox Hypervisor). - **Sistema Operativo**: Debian GNU/Linux 12 (bookworm). -- **Kernel**: 6.1.0-28-amd64. -- **Ubicación de Red**: `10.0.10.8/24`. +- **IP**: `10.0.10.8/24`. -## Nodos de la Red (Grid) +--- -| Nodo | IP / Ubicación | Descripción / Rol | +## Nodos de la Red (Árbol de Dependencia) + +### 🖥️ srv-ns8 (Physical / Hybrid) +- **CPU**: AMD Ryzen (16 hilos) | **RAM**: 15 GiB +| Nodo | IP | Rol | | :--- | :--- | :--- | -| **[srv-NS8](../nodos/srv-NS8.md)** | `10.0.10.8` | Workstation / Híbrido | -| **[srv-pmox1](../nodos/srv-pmox1.md)** | `10.0.10.201` | Nodo Proxmox de Virtualización | -| **[srv-pmox2](../nodos/srv-pmox2.md)** | `10.0.10.202` | Nodo Proxmox de Virtualización | -| **[srv-pmox3](../nodos/srv-pmox3.md)** | `10.0.10.203` | Nodo Proxmox de Virtualización (High RAM) | -| **[srvv-SITIO](../nodos/srvv-SITIO.md)** | `10.0.10.18` `190.114.205.20` | VM Ubuntu / Docker Host | -| **[srvv-SITIO0](../nodos/srvv-SITIO0.md)** | `10.0.10.119` | VM Debian 12 (`srvv-SCERO`) | -| **[srvv-DTIC](../nodos/srvv-DTIC.md)** | `10.0.10.4` | VM Debian 12 / Docker Host | -| **[srvv-DOCs](../nodos/srvv-DOCs.md)** | `10.0.10.14` | VM Debian 12 / Docker Host | -| **[srvv-KOHA](../nodos/srvv-KOHA.md)** | `10.0.10.130` | VM Debian 11 / Librería | -| **[srvv-UPTIME](../nodos/srvv-UPTIME.md)** | `10.0.10.9` | LXC Debian 12 / Monitorización (⚠️ Disk 77%) | -| **[srvv-DATA](../nodos/srvv-DATA.md)** | `10.0.10.13` | LXC Debian 12 / Datos | -| **[srvv-SITIO2](../nodos/srvv-SITIO2.md)** | `10.0.10.19` | LXC Debian 12 / Web Secundario (Acceso `root`) | -| **[srv-xen01](../nodos/srv-xen01.md)** | `10.0.10.23` | **Citrix XenServer 7.0** / Hypervisor (4 Cores Xeon) | -| **[cam-hikvision-24](../nodos/cam-hikvision-24.md)** | `10.0.10.24` | Disp. Hikvision / Cámara o DVR (Detectado vía HTTP) | -| **[srvv-DNS](../nodos/srvv-DNS.md)** | `10.0.10.2` | VM Debian 12 / Servidor DNS | +| **[srv-ns8](../nodos/srv-ns8.md)** | `10.0.10.8` | **Gateway / Workstation** | -## Nodos Externos / Satélites +### ☁️ Cluster Proxmox -| Nodo | Ubicación | Descripción / Rol | -| :--- | :--- | :--- | -| **[pc-DASU0](../nodos/pc-DASU0.md)** | Oficina DASUTEN | Win10 Físico / Acceso Usuarias (Tailscale `100.65.62.44`) | -| **[pcv-DASU1](../nodos/pcv-DASU1.md)** | Facultad (`srv-pmox2`) | Win10 VM / Sistema DASU (Tailscale `100.100.145.51`) | -| **[srvv-MAURIK](../nodos/srvv-MAURIK.md)** | *Desconocida* | Windows Server / DC `utnlarioja.intranet` | - -## Incidentes Recientes (Trazabilidad) -| ID | Nodo | Resumen | Estado | +#### **[srv-pmox1](../nodos/srv-pmox1.md)** (`10.0.10.201`) +*Proxmox VE 8.2.2 | i5-6500 (4C) | 16GB RAM* +| VMID | Nodo | IP | Rol | | :--- | :--- | :--- | :--- | -| **[260218_1940](../incidentes/260218_1940_cronograma_posgrado.md)** | srv-NS8 | Extracción Cronograma Posgrado 2026 | ✅ Carga Exitosa | -| **[260218_1005](../incidentes/260218_1005_proxmox-ssh-cluster.md)** | srv-pmox* | Reparación Trust Cluster Proxmox (SSH) | ✅ Resuelto | -| **[260218_0829](../incidentes/260218_0829_conectividad-dasu.md)** | pc-DASU0 | Bypass AnyDesk via Tailscale/RustDesk | ✅ Implementado | -| **[260207_2100](../incidentes/260207_2100_srvv-fenix-recurrence.md)** | srv-pmox3 | Investigación Forense srvv-FENIX (Recurrencia) | ✅ Licencia OK | +| 101 | **[srvv-sitio](../nodos/srvv-sitio.md)** | `10.0.10.18` | VM Ubuntu / Docker Host | +| 102 | **[srvv-sitio0](../nodos/srvv-sitio0.md)** | `10.0.10.119` | VM Debian 12 | +| 103 | **[srvv-dtic](../nodos/srvv-dtic.md)** | `10.0.10.4` | VM Debian / Servicios | +| 104 | **[srvv-docs](../nodos/srvv-docs.md)** | `10.0.10.14` | VM Debian / Docs | +| 112 | **[srvv-dns](../nodos/srvv-dns.md)** | `10.0.10.2` | VM Debian / Servidor DNS | +#### **[srv-pmox2](../nodos/srv-pmox2.md)** (`10.0.10.202`) +*Proxmox VE (Estable) | i5-6500 (4C) | 16GB RAM* +| VMID | Nodo | IP | Rol | +| :--- | :--- | :--- | :--- | +| 105 | **[srvv-koha](../nodos/srvv-koha.md)** | `10.0.10.130` | VM Librería | +| 108 | **[pcv-dasu2](../nodos/pcv-dasu2.md)** | *DHCP* | Win10 VM / Sistema DASU | +| - | **[pcv-dasu1](../nodos/pcv-dasu1.md)** | *Tailscale* | Win10 VM / Sistema DASU | +#### **[srv-pmox3](../nodos/srv-pmox3.md)** (`10.0.10.203`) +*Proxmox VE (Estable) | AMD A10-9700 (4C+6G) | 64GB RAM* +| VMID | Nodo | IP | Rol | +| :--- | :--- | :--- | :--- | +| 111 | **[srvv-fenix](../nodos/srvv-fenix.md)** | *Interna* | Sistema Académico Legacy | +| 106 | **[srvv-uptime](../nodos/srvv-uptime.md)** | `10.0.10.9` | LXC Monitorización | +| 107 | **[srvv-data](../nodos/srvv-data.md)** | `10.0.10.13` | LXC Datos | +| 113 | **[srvv-sitio2](../nodos/srvv-sitio2.md)** | `10.0.10.19` | LXC Web Secundario | +### 🏔️ Citrix XenServer +#### **[srv-xen01](../nodos/srv-xen01.md)** (`10.0.10.23`) +*Citrix XenServer 7.0.0 | Xeon E3-1230 (4C) | Hypervisor Legacy* +| VMID | Nodo | IP | Rol | +| :--- | :--- | :--- | :--- | +| - | **[srvv-sysacadweb](../nodos/srvv-sysacadweb.md)** | *Interna* | Web SysACAD | +| - | **[srvv-maurik](../nodos/srvv-maurik.md)** | *Desconocida* | Domain Controller | +### 🛰️ Nodos Externos / Satélites +| Nodo | Ubicación | Descripción | +| :--- | :--- | :--- | +| **[cam-hikvision-24](../nodos/cam-hikvision-24.md)** | `10.0.10.24` | Cámara / DVR | +| **[pc-dasu0](../nodos/pc-dasu0.md)** | Oficina DASUTEN | Win10 Físico (Ryzen 5) | - -## Hardware -- **CPU**: AMD Ryzen (16 hilos). -- **RAM**: 15 GiB Total. -- **Almacenamiento**: 438 GB (Root partition). +--- ## Servicios Críticos (ADN Detectado) ### 1. Virtualización (Prioridad Alta) - **Motor**: VirtualBox. -- **Carga**: VM `PCV_DTIC-RRHH_W732`. -- **Directiva**: **CRÍTICO / PERMANENTE**. Debe priorizarse el uso de RAM para esta VM. -- **Estado**: Ejecutándose (`Ssl`). +- **Carga**: VM `pcv-dtic-rrhh-w732`. -### 2. Contenedores Docker (En Optimización) -- **Motor**: Docker + Docker Compose. -- **Objetivo**: Optimizar despliegue y consumo de recursos. -- **Estado de Armonía**: ✅ **Consistente**. - - **Configuración Centralizada**: `dtic-srv-NS8/servicios/`. - - **Servicios Activos**: - - `portainer` (Gestión) - - **`nginx` (Nativo - Proxy Reverso)** - - `bitacoras` (App + DB) - - `sysacad` (App + Nginx interno) - - **`homepage` (Dashboard Unificado)** - - **Protección de Recursos**: Límites de RAM aplicados. - -### 3. Acceso Remoto Seguro (Capa de Invisibilidad) -- **Capa de Red**: Tailscale (VPN Mesh). - - **IP Tailscale**: `100.88.252.26`. - - **Propósito**: Acceso cifrado a servicios internos y administración SSH sin exposición a la WAN. -- **Capa Gráfica**: RustDesk (Nativo). - - **Propósito**: Soporte remoto visual optimizado sobre el túnel de Tailscale. - -### 4. Puntos de Acceso (URLs) -| Servicio | URL Pública (SSL) | URL Interna (Tailscale) | Descripción | -| :--- | :--- | :--- | :--- | -| **Portal Principal** | `https://ns8.frlr.utn.edu.ar` | `https://100.88.252.26` | **Dashboard Unificado (Homepage)** | -| **Portainer** | `https://ns8.frlr.utn.edu.ar/portainer/` | `http://100.88.252.26:9000` | Gestión de Contenedores | -| **SysACAD** | `https://ns8.frlr.utn.edu.ar/sysacad/` | `http://100.88.252.26:8080` | Sistema Académico | -| **Bitácoras** | `https://ns8.frlr.utn.edu.ar/bitacoras/` | `http://100.88.252.26:5173` | Sistema de Bitácoras | - -### 4. Topología de Red (Híbrida / Policy Routing) -El servidor opera con una arquitectura de red avanzada que combina velocidad en LAN y visibilidad en WAN mediante **Policy Based Routing**. - -- **Interfaz Física**: `enp38s0` -- **Direcciones IP**: - 1. **Privada (Principal/Salida)**: `10.0.10.8/24` (Gateway: `10.0.10.1`). Priorizada para navegación rápida del servidor. - 2. **Pública (Entrada)**: `190.114.205.18/24` (Gateway: `190.114.205.1`). Habilitada para acceso externo seguro. -- **Mecanismo de Enrutamiento**: - - Se utiliza una tabla de rutas secundaria (`190`) y una regla de política (`ip rule`) para asegurar que todo tráfico que entra por la IP pública responda por el Gateway público, evitando asimetría. - - **Optimización VPN (Tailscale)**: El tráfico saliente de la VPN utiliza el Gateway prioritario `10.0.10.1`, garantizando que el acceso remoto sea a través de la red de mayor velocidad disponible en el host. -- **Seguridad de Red**: - - **Protocolo "Hombre Muerto"**: Implementado en scripts de configuración para revertir cambios automáticamente en caso de pérdida de conexión. - - **SSL/TLS**: Terminación SSL en Nginx Nativo (Puerto 443) para todo el tráfico entrante. - - **Capa de VPN**: Tailscale actúa como capa de autenticación y cifrado adicional. - -## Propósito -Servidor híbrido que garantiza la operatividad continua de la VM administrativa de RRHH, mientras aloja servicios de desarrollo DTIC gestionados por Nginx Nativo y Docker. - -## Estado Actual -- **Estado General**: Operativo. VM y Servicios Docker ejecutándose simultáneamente. -- **Uso de Recursos**: ~7.5GB RAM Estimada (4GB VM + ~3.5GB Docker Max). Equilibrado. +### 2. Contenedores Docker (srv-ns8) +- **Estado**: ✅ **Consistente**. +- **Servicios Activos**: + - `nginx` (Proxy Reverso) + - `homepage` (Dashboard Unificado: `https://ns8.frlr.utn.edu.ar`) + - `bitacoras` + - `portainer` +### 3. Acceso Remoto Seguro +- **Tailscale**: `100.88.252.26` (Mesh VPN). +- **RustDesk**: Soporte remoto visual. +## Topología de Red +- **Híbrida**: `10.0.10.8` (LAN) + `190.114.205.18` (WAN) con Policy Routing. diff --git a/adn/02_protocolo.md b/adn/02_protocolo.md index 47f0a9a0..4feb277f 100644 --- a/adn/02_protocolo.md +++ b/adn/02_protocolo.md @@ -1,15 +1,15 @@ # 02 - Protocolo del Proyecto: Normas y Directivas -Este documento establece las reglas fundamentales para la interacción, documentación y desarrollo en el proyecto `srv-NS8`. +Este documento establece las reglas fundamentales para la interacción, documentación y desarrollo en el proyecto `srv-ns8`. -## 1. Idioma +## 1. Idioma y Nomenclatura - **Directiva**: **Todo el contenido debe estar en español.** +- **Nomenclatura de Nodos**: Estrictamente **minúsculas** en nombres de archivo y referencias (ej: `srv-ns8`, `pc-dasu0`, `srvv-maurik`). - **Alcance**: - Interacciones con el asistente (chat). - Documentación (archivos `.md`). - Mensajes de Commit (Git). - Comentarios en el código (scripts, configs). - - Nombres de archivos y directorios (preferentemente, salvo estándares técnicos estrictos). ## 2. Formato de Documentación - **Estilo**: Markdown estándar. @@ -17,27 +17,40 @@ Este documento establece las reglas fundamentales para la interacción, document ## 3. Armonía y Auto-optimización - **Principio**: La documentación (ADN) debe mantenerse como un todo coherente y libre de contradicciones. +- **Alcance Global**: Esta directiva aplica a **TODOS** los directorios del proyecto, incluyendo `adn/`, `bitacoras/`, `nodos/`, y `procedimientos/`. - **Directiva**: - - **Consistencia**: No deben existir discrepancias entre diferentes hebras (archivos `.md`). Si se actualiza una definición en `01_ontologia.md`, debe reflejarse en los protocolos y bitácoras correspondientes. + - **Consistencia**: No deben existir discrepancias entre diferentes hebras. Si se actualiza una definición en `01_ontologia.md`, debe reflejarse en los protocolos y bitácoras correspondientes. + - **Trazabilidad**: Los IDs y estados deben ser consistentes a través del tiempo. - **Auto-corrección**: Al detectar una inconsistencia, es prioritario resolverla para restaurar la armonía del sistema documental. -## 4. Estructura de Registro (Centralizada) -- **Principio**: **Bitácora Única**. - - `adn/00_bitacora.md` es la **Fuente de Verdad Histórica** del Grid completo. - - Se prohíben bitácoras dispersas en archivos individuales. -- **Formato**: Tabla Markdown con columnas: `| Hora | Nodo | Detalle |`. - - **Hora**: `HH:MM` (Hora Local). - - **Nodo**: Hostname del equipo afectado (e.g. `srv-pmox1`, `srvv-SITIO`). - - **Detalle**: Descripción consisa. Uso de Emojis para estado visual (✅, ⚠️, ❌, 🔧). +## 4. Estructura de Bitácora (Flujo Diario) +- **Principio**: **Orden Inverso Cronológico** (Lo más nuevo SIEMPRE ARRIBA). +- **Archivo Diario**: `bitacoras/YYYY-MM-DD.md`. +- **Secciones Obligatorias**: + +### 4.1 Control de Gestión +- **Pendientes**: Tabla de tareas por hacer (ID | NODO | DETALLE). +- **En Proceso**: Tabla de tareas activas (ID | NODO | DETALLE). +- **Resumen de Actividades**: + - **Formato**: Tabla (NODO | RESUMEN INTEGRAL). + - **Estilo**: **Narrativa Sintética e Integral**. SIN TÍTULOS NI ESTADOS en el texto. Solo la historia consolidada del día para ese nodo. + - **Regla**: **Una sola fila por Nodo**. + +### 4.2 Actividades Detalladas +- **Subdivisión**: Encabezados por Nodo (`### srv-ns8`). +- **Formato**: Tabla detallada (Tema | Detalle | Ini | Fin). +- **Estilo**: **Narrativa Generosa y Técnica**. Aquí se explican los "qué", "cómo" y "por qué". +- **Estados**: Uso de iconos (✅, 🧹, 🔧) para visualización rápida. + +### 4.3 Footer de Mantenimiento (IA) +- Al final de cada bitácora, incluir el bloque de comentarios HTML con las **Premisas de Trabajo** (Orden inverso, Nomenclatura, Flujo de Carga: Detalle -> Resumen). ## 5. Documentación de Nodos (Snapshots) -- **Ubicación**: `adn/nodos/.md`. +- **Ubicación**: `nodos/.md` (Raíz del proyecto). - **Contenido**: Representa el **Estado Actual** (Snapshot) del nodo. -- **Actualización**: Solo se modifica cuando cambia la configuración o estado del nodo (no se usa como log histórico). +- **Actualización**: Solo se modifica cuando cambia la configuración o estado del nodo. No duplicar información dinámica de la bitácora. - - -## 5. Protocolo de Seguridad de Red (Hombre Muerto) +## 6. Protocolo de Seguridad de Red (Hombre Muerto) - **Problemática**: La administración remota del servidor implica el riesgo de desconexión total ante cambios erróneos en la configuración de red. - **Directiva**: **Toda modificación de red debe incluir un mecanismo de reversión automática.** - **Implementación**: @@ -48,22 +61,22 @@ Este documento establece las reglas fundamentales para la interacción, document 3. **Si no hay confirmación**: Revertir cambios inmediatamente y restaurar estado anterior. 4. **Si hay confirmación**: Hacer cambios persistentes. -## 6. Referencia de Estados (Bitácora) -Para optimizar espacio horizontal, la columna `Estado` utiliza los siguientes iconos: +## 7. Referencia de Estados (Bitácora Detallada) +Para optimizar espacio horizontal en tablas de detalle: | Icono | Significado | Descripción | | :---: | :--- | :--- | | ✅ | **Completado** | Tarea finalizada o problema solucionado exitosamente. | | ⏳ | **En Proceso** | Tarea iniciada pero pendiente de cierre. | +| 🟢 | **Operativo** | Servicio funcionando correctamente tras intervención. | +| 🔧 | **Mantenimiento** | Acción técnica de configuración o ajuste. | | 🧪 | **Verificado** | Validación técnica o prueba superada. | | ⚠️ | **Alerta** | Problema detectado, riesgo o atención requerida. | -| 📍 | **Definido** | Hito establecido o prioridad fijada sin ejecución inmediata. | +| 📍 | **Definido** | Hito establecido o prioridad fijada. | -## 7. Resguardo del Repositorio (Safeguard) +## 8. Resguardo del Repositorio (Safeguard) - **Objetivo**: Asegurar la integridad y el historial de cambios del proyecto. - **Directiva**: - **Frecuencia**: Al finalizar una tarea significativa o conjunto de tareas relacionadas (hito). - **Alcance**: Todo cambio en `adn/`, `servicios/config`, `scripts/` y documentación `docs/`. - **Formato Mensaje**: `[Categoría] Descripción breve del cambio`. - - Categorías: `Feat` (Nueva funcionalidad), `Fix` (Corrección), `Docs` (Documentación), `Refactor` (Mejora de código/estructura), `Chore` (Mantenimiento). - diff --git a/bitacoras/2026-01-14.md b/bitacoras/2026-01-14.md index 8e4d5253..5db909f9 100644 --- a/bitacoras/2026-01-14.md +++ b/bitacoras/2026-01-14.md @@ -1,5 +1,33 @@ -# Bitácora 14/01/2026 - Gestión Digital CD +# Bitácora de Operaciones - 14/01/2026 -| Hora | Nodo | Detalle | +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | | :--- | :--- | :--- | -| 22:00 | srv-NS8 | ✅ **Gestión Digital**: Publicación de grabación Consejo Directivo (30/12). Zoom -> YouTube (Oculto). Entregado enlace a C. GATICA / E. RUEDA. | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-ns8](#srv-ns8) | ✅ **Gestión Digital** (🕒 22:00)
Procesamiento y publicación segura de material audiovisual institucional (Consejo Directivo). | + +--- + +## 📂 Actividades Detalladas + +### srv-ns8 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Institucional | ✅ **Consejo Directivo**: Publicación de grabación (30/12) en canal YouTube (Oculto). Enlace de acceso seguro entregado a Secretarías correspondientes. | 21:30 | 22:00 | + +--- + + diff --git a/bitacoras/2026-02-07.md b/bitacoras/2026-02-07.md index 01a9b4a6..61e42126 100644 --- a/bitacoras/2026-02-07.md +++ b/bitacoras/2026-02-07.md @@ -1,6 +1,34 @@ -# Bitácora 07/02/2026 - Incidente srvv-FENIX +# Bitácora de Operaciones - 07/02/2026 -| Hora | Nodo | Detalle | +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | | :--- | :--- | :--- | -| 21:00 | srv-pmox3 | ⚠️ **Alerta Crítica**: [srvv-FENIX apagado recurrente](../incidentes/260207_2100_srvv-fenix-recurrence.md). Reporte W. KRUPP. Inicio de Investigación Forense. | -| 18:00 | srv-pmox3 | ⚠️ **Incidente**: [srvv-FENIX apagado](../incidentes/260207_1800_srvv-fenix-shutdown.md). Reporte de Wilfredo KRUPP. VM Stopped. Se inicia remotamente. | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-pmox3](#srv-pmox3) | ⚠️ **Alerta e Investigación** (🕒 21:00)
Inicio de protocolo de incidente ante reportes de apagado no programado de la VM crítica `srvv-fenix`. Se estableció monitoreo y análisis forense. | + +--- + +## 📂 Actividades Detalladas + +### srv-pmox3 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Incidente | ⚠️ **Alerta Crítica**: [srvv-fenix apagado recurrente](../incidentes/260207_2100_srvv-fenix-recurrence.md). Reporte W. Krupp. Se declara incidente mayor e inicia investigación. | 20:30 | 21:00 | +| Incidente | ⚠️ **Reporte Inicial**: [srvv-fenix apagado](../incidentes/260207_1800_srvv-fenix-shutdown.md). Primer reporte de caída. Se procede al encendido remoto para restaurar servicio. | 18:00 | 18:05 | + +--- + + diff --git a/bitacoras/2026-02-08.md b/bitacoras/2026-02-08.md index 60144d4f..091c4db2 100644 --- a/bitacoras/2026-02-08.md +++ b/bitacoras/2026-02-08.md @@ -1,6 +1,34 @@ -# Bitácora 08/02/2026 - Resolución FENIX +# Bitácora de Operaciones - 08/02/2026 -| Hora | Nodo | Detalle | +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | | :--- | :--- | :--- | -| 10:00 | srv-pmox3 | ✅ **Solución srvv-FENIX**: Se identifica causa raíz: Licencia de Windows Server expirada (Shutdown auto). Se aplica `slmgr -rearm` (180 días). | -| 09:00 | srv-pmox3 | ⏳ **Investigación**: Se retoma análisis de logs. | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-pmox3](#srv-pmox3) | ✅ **Resolución de Incidente** (🕒 10:00)
Solución definitiva a los apagados recurrentes de la VM `srvv-fenix`. Se identificó el vencimiento de la licencia Windows Server como causa raíz y se aplicó mitigación mediante rearme de licencia. | + +--- + +## 📂 Actividades Detalladas + +### srv-pmox3 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Incidente | ✅ **Solución Definitiva**: Diagnóstico confirmado (Shutdown automático por expiración de activación). Se ejecutó `slmgr -rearm` extendiendo la validez por 180 días. | 09:30 | 10:00 | +| Investigación | ⏳ **Análisis Forense**: Revisión profunda de logs de sistema (Event Viewer) para descartar fallos de hardware o hipervisor. | 09:00 | 09:30 | + +--- + + diff --git a/bitacoras/2026-02-11.md b/bitacoras/2026-02-11.md index e019cea4..45abff1f 100644 --- a/bitacoras/2026-02-11.md +++ b/bitacoras/2026-02-11.md @@ -1,23 +1,51 @@ -# Bitácora 11/02/2026 - Configuración Inicial de Servicios +# Bitácora de Operaciones - 11/02/2026 -| Hora | Nodo | Detalle | +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | | :--- | :--- | :--- | -| 23:25 | srv-NS8 | ✅ **Configuración SSL y Reverse Proxy**: **Exitoso**. Certificado Let's Encrypt instalado para `ns8.frlr.utn.edu.ar`. Nginx configurado como Reverse Proxy para servir `/portainer/`, `/sysacad/`, `/bitacoras/` bajo HTTPS (Puerto 443). | -| 23:15 | srv-NS8 | ✅ **Configuración Red Híbrida**: **Exitoso**. Se ejecuta `configurar_red_hibrida.sh`. El servidor mantiene gateway `10.x` para salida, pero responde correctamente a la IP pública `190.x` mediante Policy Routing. | -| 23:10 | srv-NS8 | ✅ **Protocolo de Seguridad**: Se incorpora la **Directiva 5: Protocolo de Seguridad de Red (Hombre Muerto)** en `adn/02_protocolo.md` (Reversión automática). | -| 23:00 | srv-NS8 | ✅ **Instalación Nginx Nativo**: **Completado**. El usuario ejecutó `instalar_nginx_simple.sh`. Nginx está activo en el Host (Puerto 80). | -| 22:55 | srv-NS8 | ✅ **Resolución Conflicto Puerto**: Se reconfigura SysACAD para usar puertos 8080/8443, liberando el puerto 80 del host. | -| 22:50 | srv-NS8 | ✅ **Saneamiento y Simplificación**: Se eliminan scripts de migración de IP complejos por riesgo innecesario. Se consolida `scripts/instalar_nginx_simple.sh`. | -| 22:45 | srv-NS8 | ✅ **Cambio de Estrategia: Nginx Nativo**: Se decide eliminar el contenedor `proxy` (Docker) y reemplazarlo por **Nginx Nativo** en el host (`10.0.10.8`). | -| 22:15 | srv-NS8 | ✅ **Documentación de Red**: Se detalla la **Topología de Red** en `adn/01_ontologia.md`. | -| 22:10 | srv-NS8 | ✅ **Mantenimiento**: Se actualiza **Portainer** a la última versión disponible (detectada 2.33.7). | -| 22:05 | srv-NS8 | ✅ **Documentación de Accesos**: Se incorpora la tabla de **Puntos de Acceso (URLs)** en `adn/01_ontologia.md`. | -| 22:00 | srv-NS8 | ✅ **Reactivación de Servicios**: Se levantan exitosamente `portainer`, `proxy`, `bitacoras` y `sysacad`. | -| 21:50 | srv-NS8 | 🧪 **Validación de Servicios**: Pruebas de configuración (`docker compose config`) exitosas. Límites de memoria confirmados correctos. | -| 21:40 | srv-NS8 | ✅ **Optimización de Recursos**: Se completa la migración de archivos e incluyen `.env`. Se aplican límites de memoria RAM a los servicios Docker. | -| 21:35 | srv-NS8 | ✅ **Centralización de Servicios**: Se mueven las configuraciones de servicios a `dtic-srv-NS8/servicios/`. | -| 21:22 | srv-NS8 | 📍 **Definición de Prioridades**: Se establece la VM `PCV_DTIC-RRHH_W732` como servicio **Crítico/Permanente**. | -| 21:15 | srv-NS8 | ✅ **Relevamiento Técnico**: Se detectan redes Docker sin contenedores activos. VM VirtualBox consume ~4GB RAM. | -| 21:07 | srv-NS8 | ✅ **Protocolo de Armonía**: Se incorpora la directiva de **Armonía y Auto-optimización** en `adn/02_protocolo.md`. | -| 21:05 | srv-NS8 | ✅ **Establecimiento de Protocolo**: Se define el **español** como idioma obligatorio. Se crea `adn/02_protocolo.md`. | -| 21:01 | srv-NS8 | ✅ **Inicio del Relevamiento**: Inicialización del repositorio y estructura de directorios `adn`, `docs`, `scripts`. | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-ns8](#srv-ns8) | ✅ **Fundación del Grid y Servicios Base** (🕒 23:25)
Jornada fundacional donde se estableció la arquitectura híbrida de red (Policy Routing), se desplegó Nginx Nativo como Reverse Proxy con seguridad SSL (Let's Encrypt), se definieron los protocolos centrales del ADN (Ontología, Seguridad, Idioma) y se centralizaron las configuraciones de servicios. | + +--- + +## 📂 Actividades Detalladas + +### srv-ns8 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Infraestructura | ✅ **SSL y Reverse Proxy**: Implementación exitosa de Certbot (Let's Encrypt) para `ns8.frlr.utn.edu.ar`. Configuración de Nginx para servir `/portainer/`, `/sysacad/`, `/bitacoras/` bajo HTTPS (443). | 23:05 | 23:25 | +| Red | ✅ **Configuración Red Híbrida**: Ejecución de `configurar_red_hibrida.sh`. Establecimiento de Policy Routing para mantener gateway LAN `10.x` mientras se responde a IP Pública `190.x`. | 23:00 | 23:15 | +| ADN | ✅ **Protocolo de Seguridad**: Definición e incorporación de la **Directiva 5: Protocolo de Seguridad de Red (Hombre Muerto)** en `adn/02_protocolo.md` para garantizar reversibilidad. | 23:00 | 23:10 | +| Despliegue | ✅ **Nginx Nativo**: Instalación de Nginx en el host (Puerto 80) tras decidir eliminar la capa de contenedor `proxy`. | 22:50 | 23:00 | +| Configuración | ✅ **Resolución de Conflictos**: Reconfiguración de SysACAD en puertos 8080/8443 para liberar el puerto 80 del host. | 22:45 | 22:55 | +| Saneamiento | ✅ **Simplificación**: Eliminación de scripts de migración complejos y consolidación de herramientas de instalación (`instalar_nginx_simple.sh`). | 22:40 | 22:50 | +| Estrategia | ✅ **Cambio Arquitectónico**: Decisión de migrar de Proxy Docker a Nginx Nativo para simplificar la gestión de red del host. | 22:30 | 22:45 | +| ADN | ✅ **Documentación de Red**: Detalle formal de la **Topología de Red** en `adn/01_ontologia.md`. | 22:10 | 22:15 | +| Mantenimiento | ✅ **Update Portainer**: Actualización del orquestador a la versión 2.33.7. | 22:05 | 22:10 | +| ADN | ✅ **Documentación de Accesos**: Registro de la tabla de **Puntos de Acceso (URLs)** en `adn/01_ontologia.md`. | 22:00 | 22:05 | +| Servicios | ✅ **Reactivación**: Puesta en marcha exitosa de servicios críticos (`portainer`, `sysacad`, `bitacoras`). | 21:50 | 22:00 | +| Control | 🧪 **Validación**: Pruebas de configuración (`docker compose config`) y verificación de límites de memoria RAM. | 21:40 | 21:50 | +| Optimización | ✅ **Recursos**: Aplicación de límites de memoria (Hard Limits) a contenedores Docker y migración de variables de entorno (`.env`). | 21:30 | 21:40 | +| Estructura | ✅ **Centralización**: Migración de configuraciones de servicios al directorio `dtic-srv-ns8/servicios/`. | 21:25 | 21:35 | +| Prioridades | 📍 **Definición Crítica**: Catalogación de la VM `pcv-dtic-rrhh-w732` como servicio de Prioridad Máxima. | 21:20 | 21:22 | +| Relevamiento | ✅ **Diagnóstico Inicial**: Detección de redes Docker huérfanas y consumo de RAM por VirtualBox (~4GB). | 21:10 | 21:15 | +| ADN | ✅ **Protocolo de Armonía**: Definición de la directiva de **Auto-optimización** en `adn/02_protocolo.md`. | 21:05 | 21:07 | +| ADN | ✅ **Establecimiento de Protocolo**: Definición del **español** como idioma oficial y creación de `adn/02_protocolo.md`. | 21:01 | 21:05 | +| Inicio | ✅ **Génesis**: Inicialización del repositorio git y estructura de directorios base (`adn`, `docs`, `scripts`). | 21:00 | 21:01 | + +--- + + diff --git a/bitacoras/2026-02-15.md b/bitacoras/2026-02-15.md index b0bd1fa4..4999aebb 100644 --- a/bitacoras/2026-02-15.md +++ b/bitacoras/2026-02-15.md @@ -1,7 +1,35 @@ -# Bitácora 15/02/2026 - Implementación Tailscale y Sincronización +# Bitácora de Operaciones - 15/02/2026 -| Hora | Nodo | Detalle | +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | | :--- | :--- | :--- | -| 21:55 | srv-NS8 | ✅ **Consolidación ADN**: Se actualiza `01_ontologia.md` con la nueva arquitectura de acceso remoto (Tailscale + RustDesk) y manual de conexión. | -| 21:35 | srv-NS8 | ✅ **Implementación Acceso Remoto**: **Exitoso**. Se instala Tailscale (IP `100.88.252.26`) y se verifica RustDesk nativo. Se establece solución de doble capa (Red VPN + GUI). | -| 20:50 | srv-NS8 | ✅ **Sincronización Inicial Repo**: **Exitoso**. Se crea `.gitignore` para excluir datos volátiles y se realiza el primer commit masivo de ADN, Scripts y Servicios. | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-ns8](#srv-ns8) | ✅ **Acceso Remoto y Sincronización** (🕒 21:55)
Establecimiento de la arquitectura de conectividad remota oficial mediante la implementación de Tailscale (VPN Mesh) y RustDesk (Soporte Visual), documentando el estándar en el ADN. Adicionalmente, se consolidó el repositorio con la primera sincronización masiva y configuración de exclusiones (`.gitignore`). | + +--- + +## 📂 Actividades Detalladas + +### srv-ns8 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| ADN | ✅ **Consolidación**: Actualización de `01_ontologia.md` reflejando la nueva arquitectura híbrida y manuales de conexión. | 21:35 | 21:55 | +| Conectividad | ✅ **Tailscale + RustDesk**: Instalación y configuración exitosa de Tailscale (IP `100.88.252.26`) como capa de red segura y verificación de RustDesk para soporte visual. | 20:50 | 21:35 | +| Repositorio | ✅ **Sincronización Inicial**: Creación de políticas de exclusión (`.gitignore`) para datos volátiles y ejecución del primer commit masivo de activos (ADN, Scripts, Servicios). | 20:30 | 20:50 | + +--- + + diff --git a/bitacoras/2026-02-16.md b/bitacoras/2026-02-16.md index 04fdfffa..8cd33e26 100644 --- a/bitacoras/2026-02-16.md +++ b/bitacoras/2026-02-16.md @@ -1,25 +1,109 @@ -# Bitácora 16/02/2026 - Hardening SSH y Expansión de Grid +# Bitácora de Operaciones - 16/02/2026 -| Hora | Nodo | Detalle | +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | | :--- | :--- | :--- | -| 23:15 | Grid | 🔒 **Seguridad**: Hardening Completo. `PermitRootLogin no` en `srvv-SITIO` y `srvv-SITIO2`. | -| 23:05 | Grid | 🔒 **Seguridad**: Hardening aplicado. `PermitRootLogin no` en Proxmox Nodes. Clave SSH local protegida con Passphrase. | -| 22:45 | srvv-UPTIME | 🔧 **Mantenimiento**: Limpieza de Logs y Reducción de Historial. Uso de disco bajó de 86% a 77% (+350MB libres). | -| 22:35 | srvv-SITIO2 | ✅ **Expansión de Grid**: **Conexión Exitosa**. LXC Debian 12 (`10.0.10.19`). Acceso configurado vía `root`. Documentado en `adn/nodos/srvv-SITIO2.md`. | -| 22:30 | srvv-DATA | ✅ **Expansión de Grid**: **Conexión Exitosa**. LXC Debian 12 (`10.0.10.13`). Documentado en `adn/nodos/srvv-DATA.md`. | -| 22:30 | srvv-UPTIME | ⚠️ **Alerta**: **Disco 86% Lleno**. LXC Debian 12 (`10.0.10.9`). Documentado en `adn/nodos/srvv-UPTIME.md`. | -| 22:25 | srvv-KOHA | ✅ **Expansión de Grid**: **Conexión Exitosa**. VM Debian 11. Documentado en `adn/nodos/srvv-KOHA.md`. | -| 22:15 | srvv-DOCs | ✅ **Expansión de Grid**: **Conexión Exitosa**. VM Debian (`10.0.10.14`). Docker Host. Documentado en `adn/nodos/srvv-DOCs.md`. | -| 22:15 | srvv-DTIC | ✅ **Expansión de Grid**: **Conexión Exitosa**. VM Debian (`10.0.10.4`). Docker Host. Documentado en `adn/nodos/srvv-DTIC.md`. | -| 22:05 | srvv-SITIO0 | ✅ **Expansión de Grid**: **Conexión Exitosa** (Script `alta_nodo.sh`). VM Debian 12 (`10.0.10.119`). Docker detectado (requiere permisos de grupo para `rmonla`). Documentado en `adn/nodos/srvv-SITIO0.md`. | -| 21:55 | srvv-SITIO | ✅ **Expansión de Grid**: **Conexión Exitosa**. VM Ubuntu (`10.0.10.18`). Detectada IP Pública directa. Docker instalado pero sin contenedores activos. Documentado en `adn/nodos/srvv-SITIO.md`. | -| 21:50 | srv-pmox3 | ✅ **Expansión de Grid**: **Conexión Exitosa**. Nodo de Alta Capacidad (64GB RAM). Aloja `srvv-FENIX` (32GB) y varios LXC. Documentado en `adn/nodos/srv-pmox3.md`. | -| 21:45 | srv-pmox2 | ✅ **Expansión de Grid**: **Conexión Exitosa**. Servidor i5-6500 (16GB RAM). Aloja servicios `KOHA` y `DASU`. Documentado en `adn/nodos/srv-pmox2.md`. | -| 21:30 | srv-pmox1 | ✅ **Reversión SSL**: Se elimina certificado expirado y se reactiva `pve-ssl.pem` (Self-Signed). Acceso port 8006 recuperado (con advertencia de navegador). | -| 21:25 | srv-NS8 | ✅ **Actualización Protocolo**: Se define en `adn/02_protocolo.md` la estrategia de **Bitácora Centralizada** + **Documentación de Nodo** actualizada. | -| 21:10 | srv-pmox1 | ⚠️ **Diagnóstico SSL**: Se confirma que el nodo usa un certificado custom `/etc/pve/local/pveproxy-ssl.pem` (Let's Encrypt) que expiró el 21/12/2025. El certificado default (`pve-ssl.pem`) es válido hasta 2027 pero está ignorado. | -| 15:40 | srv-pmox1 | ⚠️ **Alerta de Recursos**: Se detecta **Sobreasignación de RAM**. VMs asignadas suman ~24GB sobre 16GB físicos. Riesgo de degradación por swapping/ballooning. | -| 15:35 | srv-pmox1 | ✅ **Documentación de Nodo**: Se crea `adn/nodos/srv-pmox1.md` detallando Specs (i5-6500, 16GB RAM) y Cargas de Trabajo (5 VMs activas). Se integra en `adn/01_ontologia.md`. | -| 15:30 | srv-pmox1 | ✅ **Expansión de Grid**: **Conexión Exitosa**. Se establece acceso SSH sin clave (`id_rsa`) al nodo `10.0.10.201`. Se recaba información de hardware y servicios. | -| 14:10 | srv-NS8 | ✅ **Optimización Dashboard**: **Exitoso**. Reorganización de `homepage` en 3 columnas (Infra, Gestión, Apps) mediante ajuste de `settings.yaml`. Corrección de widgets Portainer (Auth) y Uptime Kuma (URL). | -| 13:00 | srv-NS8 | ✅ **Implementación Homepage**: **Exitoso**. Despliegue de `gethomepage` en `servicios/homepage`. Integración con Proxmox API, Portainer y logs. Sustitución de página default Nginx por Dashboard dinámico. | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-ns8](#srv-ns8) | ✅ **Gestión y Dashboard** (🕒 21:25)
Implementación del Dashboard Unificado (`homepage`) con integración total de servicios e infraestructura. Actualización formal del ADN definiendo la estrategia de documentación centralizada. | +| [srv-pmox1](#srv-pmox1) | ✅ **Recuperación y Hardening** (🕒 23:05)
Incorporación al Grid con acceso SSH sin contraseña, diagnóstico de recursos (RAM crítica) y resolución de bloqueo SSL mediante reversión a certificados self-signed. Se aplicó hardening de seguridad (Root Login/Passphrase). | +| [srvv-uptime](#srvv-uptime) | ✅ **Mantenimiento Preventivo** (🕒 22:45)
Resolución de alerta de almacenamiento (86%) mediante limpieza de logs y reducción de historial. | +| [srvv-sitio](#srvv-sitio) | ✅ **Expansión de Grid** (🕒 23:15)
Conexión exitosa, documentación de nodo y hardening de seguridad SSH. | +| [srvv-sitio2](#srvv-sitio2) | ✅ **Expansión de Grid** (🕒 23:15)
Conexión exitosa, documentación de nodo y hardening de seguridad SSH. | +| [srvv-sitio0](#srvv-sitio0) | ✅ **Expansión de Grid** (🕒 22:05)
Alta mediante script `alta_nodo.sh`, detección de Docker y documentación. | +| [srvv-data](#srvv-data) | ✅ **Expansión de Grid** (🕒 22:30)
Conexión exitosa y documentación de nodo LXC Debian. | +| [srvv-koha](#srvv-koha) | ✅ **Expansión de Grid** (🕒 22:25)
Conexión exitosa y documentación de nodo VM Debian. | +| [srvv-docs](#srvv-docs) | ✅ **Expansión de Grid** (🕒 22:15)
Conexión exitosa y documentación de nodo Docker Host. | +| [srvv-dtic](#srvv-dtic) | ✅ **Expansión de Grid** (🕒 22:15)
Conexión exitosa y documentación de nodo Docker Host. | +| [srv-pmox3](#srv-pmox3) | ✅ **Expansión de Grid** (🕒 21:50)
Conexión exitosa y documentación del nodo de Alta Capacidad (64GB RAM). | +| [srv-pmox2](#srv-pmox2) | ✅ **Expansión de Grid** (🕒 21:45)
Conexión exitosa y documentación del nodo hospedador de KOHA/DASU. | + +--- + +## 📂 Actividades Detalladas + +### srv-ns8 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| ADN | ✅ **Actualización Protocolo**: Definición en `adn/02_protocolo.md` de la estrategia de **Bitácora Centralizada** + **Documentación de Nodo**. | 21:00 | 21:25 | +| Dashboard | ✅ **Optimización**: Reorganización de `homepage` en 3 columnas (Infra, Gestión, Apps) y corrección de widgets (Portainer Auth, Uptime Kuma). | 13:30 | 14:10 | +| Despliegue | ✅ **Implementación Homepage**: Despliegue exitoso de `gethomepage` en `servicios/homepage` con integración a Proxmox API. | 12:00 | 13:00 | + +### srv-pmox1 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Seguridad | 🔒 **Hardening**: Deshabilitación de `PermitRootLogin` y protección de clave privada con Passphrase local. | 22:50 | 23:05 | +| SSL | ✅ **Reversión Certificados**: Restauración de `pve-ssl.pem` (Self-Signed) tras expirar certificado Let's Encrypt custom. Acceso GUI recuperado. | 21:15 | 21:30 | +| Diagnóstico | ⚠️ **Análisis SSL**: Detección de certificado expirado el 21/12/2025 en `/etc/pve/local/pveproxy-ssl.pem`. | 21:00 | 21:10 | +| Recursos | ⚠️ **Alerta RAM**: Sobreasignación detectada (24GB asignados vs 16GB físicos). Riesgo de swapping/ballooning. | 15:35 | 15:40 | +| ADN | ✅ **Documentación**: Creación de `nodos/srv-pmox1.md` detallando Specs y Cargas de Trabajo (5 VMs). | 15:30 | 15:35 | +| Acceso | ✅ **Conexión SSH**: Establecimiento de confianza (`id_rsa`) y relevamiento inicial de hardware. | 15:00 | 15:30 | + +### srvv-uptime +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Mantenimiento | 🔧 **Limpieza**: Reducción de logs de sistema y journal. Espacio libre aumentado (+350MB). | 22:35 | 22:45 | +| Recursos | ⚠️ **Alerta Disco**: Notificación de uso de disco al 86% en nodo de monitoreo. | 22:25 | 22:30 | + +### srvv-sitio +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Seguridad | 🔒 **Hardening**: Deshabilitación de `PermitRootLogin`. | 23:00 | 23:15 | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa (Ubuntu). Detección de IP Pública directa. Documentación creada. | 21:50 | 21:55 | + +### srvv-sitio2 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Seguridad | 🔒 **Hardening**: Deshabilitación de `PermitRootLogin`. | 23:00 | 23:15 | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa (Debian 12). Documentación creada. | 22:30 | 22:35 | + +### srvv-sitio0 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Expansión | ✅ **Alta Automática**: Ejecución exitosa de `alta_nodo.sh`. Detección de Docker y permisos de usuario. | 22:00 | 22:05 | + +### srvv-data +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa (LXC Debian). Documentación creada. | 22:25 | 22:30 | + +### srvv-koha +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa (VM Debian). Documentación creada. | 22:20 | 22:25 | + +### srvv-docs +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa (VM Debian). Documentación creada. | 22:10 | 22:15 | + +### srvv-dtic +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa (VM Debian). Documentación creada. | 22:10 | 22:15 | + +### srv-pmox3 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa. Relevamiento de hardware (Alta Capacidad). Documentación creada. | 21:45 | 21:50 | + +### srv-pmox2 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Expansión | ✅ **Alta de Nodo**: Conexión SSH exitosa. Identificación de servicios críticos (KOHA/DASU). Documentación creada. | 21:40 | 21:45 | + +--- + + diff --git a/bitacoras/2026-02-18.md b/bitacoras/2026-02-18.md index 647cb439..c7bed1c3 100644 --- a/bitacoras/2026-02-18.md +++ b/bitacoras/2026-02-18.md @@ -1,16 +1,64 @@ -# Bitácora 18/02/2026 - Alta de Nodos Externos y Reparación Proxmox +# Bitácora de Operaciones - 18/02/2026 -| Hora | Nodo | Detalle | +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | | :--- | :--- | :--- | -| 19:50 | srv-NS8 | ✅ **Carga Masiva Calendar**: Importación exitosa de 84 eventos de Posgrado 2026 en el calendario `.26 - POSG.EMIA`. Se incluyeron enlaces de Zoom, ID de reunión y descripción institucional. | -| 19:45 | srv-NS8 | ✅ **Procesamiento de Documentos**: Extracción automática de cronograma de clases desde PDF. Datos estructurados en [cronograma_posgrado.md](../incidentes/260218_1940_cronograma_posgrado.md). | -| 19:40 | srvv-MAURIK | ✅ **Gestión de Usuarios**: Alta de usuario corporativo `chuergo` en dominio `utnlarioja.intranet`. Credenciales entregadas a Cristian GATICA. | -| 19:10 | srv-NS8 | ✅ **Gestión Digital**: Solicitud Ing. Martín HEREDIA. Gestión de videos Asamblea Universitaria. | -| 16:45 | pc-DASU0 | ✅ **Soporte Usuario**: Se asiste a Romina MOLINA. Conexión exitosa vía RustDesk/Tailscale. | -| 14:00 | srv-NS8 | ✅ **Conectividad DASU**: [Bypass Exitoso AnyDesk](../incidentes/260218_0829_conectividad-dasu.md). Instalación de Tailscale en `pc-DASU0` y `pcv-DASU1`. | -| 11:00 | srv-pmox* | ✅ **Incidencia Crítica Resuelta**: [Cluster Proxmox SSH](../incidentes/260218_1005_proxmox-ssh-cluster.md). Restauración de confianza y certificados. | -| 00:55 | Grid | ✅ **Documentación ONTO**: Se actualiza `01_ontologia.md` y se crean fichas para `srv-xen01` y `cam-hikvision-24`. | -| 00:45 | cam-hikvision-24 | ⚠️ **Sonda de Campo**: **Detección HTTP**. IP `10.0.10.24`. Puerto 80 abierto (Hikvision Login), SSH cerrado. Rol: Cámara/DVR. | -| 00:35 | srv-xen01 | ✅ **Sonda de Campo**: **Corrección de Rol**. IP `10.0.10.23`. Identificado como **Citrix XenServer 7.0** (previamente catalogado como Debian). Evidencia forense de procesos Xen y Open vSwitch. | -| 00:10 | Grid | 🔒 **Protocolo de Seguridad**: Implementación de **Candado JIT** (`scripts/candado.rb`). Autorización temporal (5 min) basada en desafío de passphrase SSH. El Agente requiere token activo para operar sondas. | -| 00:00 | Grid | 🔧 **Automatización**: Despliegue de `scripts/alta_nodo.rb` (Ruby). Sonda de relevamiento autónoma con detección de roles y soporte SSH legacy. | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-ns8](#srv-ns8) | ✅ **Gestión y Desarrollo** (🕒 19:50)
Jornada multifacética abarcando soporte crítico (Conectividad DASU, Cluster Proxmox SSH), gestión académica (Carga masiva Calendar, Procesamiento PDF) y desarrollo de herramientas de automatización (`candado.rb`, `alta_nodo.rb`). | +| [srvv-maurik](#srvv-maurik) | ✅ **Gestión de Identidad** (🕒 19:40)
Alta de usuarios corporativos en el dominio `utnlarioja.intranet`. | +| [pc-dasu0](#pc-dasu0) | ✅ **Soporte Remoto** (🕒 16:45)
Asistencia exitosa a usuario final mediante la nueva infraestructura Tailscale/RustDesk. | +| [cam-hikvision-24](#cam-hikvision-24) | ⚠️ **Sonda de Campo** (🕒 00:45)
Identificación de dispositivo de videovigilancia con puerto 80 abierto. | +| [srv-xen01](#srv-xen01) | ✅ **Corrección Ontológica** (🕒 00:35)
Reclasificación del nodo como Citrix XenServer 7.0 tras evidencia forense. | + +--- + +## 📂 Actividades Detalladas + +### srv-ns8 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Académica | ✅ **Carga Masiva Calendar**: Importación exitosa de 84 eventos de Posgrado 2026 en el calendario `.26 - POSG.EMIA` con metadatos completos (Zoom, ID). | 19:30 | 19:50 | +| Gestión | ✅ **Procesamiento de Documentos**: Extracción automática de cronograma de clases desde PDF y estructuración en [cronograma_posgrado.md](../incidentes/260218_1940_cronograma_posgrado.md). | 19:40 | 19:45 | +| Institucional | ✅ **Gestión Digital**: Procesamiento y gestión de videos de la Asamblea Universitaria (Solicitud Ing. Heredia). | 19:00 | 19:10 | +| Conectividad | ✅ **Conectividad DASU**: [Bypass Exitoso AnyDesk](../incidentes/260218_0829_conectividad-dasu.md). Instalación de Tailscale en `pc-dasu0` y `pcv-dasu1` para garantizar acceso. | 13:00 | 14:00 | +| Infraestructura | ✅ **Incidencia Crítica Resuelta**: [Cluster Proxmox SSH](../incidentes/260218_1005_proxmox-ssh-cluster.md). Restauración de confianza y certificados entre nodos del cluster. | 10:00 | 11:00 | +| ADN | ✅ **Documentación ONTO**: Actualización integral de `01_ontologia.md` con nuevos activos detectados (`srv-xen01`, `cam-hikvision-24`). | 00:50 | 00:55 | +| Seguridad | 🔒 **Protocolo JIT**: Implementación de **Candado JIT** (`scripts/candado.rb`) para autorización temporal basada en desafío de passphrase. | 00:00 | 00:10 | +| Automatización | 🔧 **Scripting**: Despliegue de `scripts/alta_nodo.rb` (Ruby) para relevamiento autónomo de nodos. | 23:30 | 00:00 | + +### srvv-maurik +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Usuarios | ✅ **Gestión de Usuarios**: Alta de usuario corporativo `chuergo` en dominio. Credenciales entregadas. | 19:30 | 19:40 | + +### pc-dasu0 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Soporte | ✅ **Asistencia Usuario**: Conexión y soporte exitoso a Romina MOLINA vía RustDesk/Tailscale. | 16:30 | 16:45 | + +### cam-hikvision-24 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Relevamiento | ⚠️ **Sonda de Campo**: Detección HTTP en IP `10.0.10.24`. Puerto 80 abierto (Hikvision Login). Identificado como DVR/Cámara. | 00:40 | 00:45 | + +### srv-xen01 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Relevamiento | ✅ **Sonda de Campo**: Identificación positiva como **Citrix XenServer 7.0** (Open vSwitch detectado), corrigiendo catalogación previa. | 00:30 | 00:35 | + +--- + + diff --git a/bitacoras/2026-02-19.md b/bitacoras/2026-02-19.md new file mode 100644 index 00000000..c1bfc6df --- /dev/null +++ b/bitacoras/2026-02-19.md @@ -0,0 +1,109 @@ +# Bitácora de Operaciones - 19/02/2026 + +## Control de Gestión + +### 🚩 Pendientes +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### ⏳ En Proceso +| ID | NODO | DETALLE | +| :--- | :--- | :--- | + +### 📝 Resumen de Actividades +| NODO | RESUMEN INTEGRAL | +| :--- | :--- | +| [srv-ns8](#srv-ns8) | Jornada de estandarización y despliegue (23:15). Se aplicó la política de nomenclatura lowercase en todo el grid, se establecieron los cimientos del ADN, se implementó TinyFileManager con seguridad Nginx y roles, se saneó el workspace y se procesaron los relevamientos de activos AIDA64. | +| [srv-pmox2](#srv-pmox2) | Recuperación definitiva de la conectividad (22:30) asegurando la persistencia del Gateway en la configuración de red y habilitando el entorno para la automatización de scripts. | +| [srvv-sysacadweb](#srvv-sysacadweb) | Corrección documental y operativa (19:45), rectificando la especificación del SO (Win2008 R2) tras el análisis de activos y registrando el estado del nodo. | +| [pcv-dasu2](#pcv-dasu2) | Normalización de identidad (10:55) completando el cambio de hostname y su actualización en la ontología del sistema. | +| [srvv-maurik](#srvv-maurik) | Verificación de hardware (10:05) actualización de ficha técnica con datos de relevamiento y health check de servicios de dominio. | +| [pcv-dasu1](#pcv-dasu1) | Aseguramiento de datos críticos (09:54) mediante ejecución exitosa del procedimiento de backup de estación de trabajo. | +| [srv-pmox3](#srv-pmox3) | Ejecución correcta del ciclo de respaldos nocturnos automatizados en almacenamiento ZFS (03:02). | +| [srv-pmox1](#srv-pmox1) | Validación operativa del nuevo script de automatización Ruby con el primer backup exitoso (02:00). | + +--- + +## 📂 Actividades Detalladas + +### srv-ns8 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| ADN | ✅ **Nomenclatura**: Renombrado masivo de archivos y referencias a minúsculas (`srv-ns8`, `srvv-maurik`, etc.) para cumplir estándar. | 23:00 | 23:15 | +| Activos | ✅ **Integración AIDA64**: Procesamiento de reportes, actualización de fichas (`MAURIK`, `SYSACADWEB`) y unificación de `pc-dasu0`. | 22:35 | 22:45 | +| Saneamiento | 🧹 **Limpieza de Workspace**: Eliminación de directorios `servicios/hfs` y `servicios/filebrowser` para mantener higiene del repositorio. | 21:30 | 21:35 | +| Personalización | ✅ **Identidad TFM**: Configuración de Título "NS8 - TFM" y ACLs: `rmonla` (Admin), `utnlarioja` (Lectura). | 20:55 | 21:00 | +| Configuración | ✅ **Storage TFM**: Mapeo de volumen de datos a disco físico `/mnt/ns8Disco2/DTIC_APPs/`. | 20:25 | 20:40 | +| Despliegue | ✅ **Nginx Proxy**: Exposición del servicio TFM bajo ruta segura `/tfm` con autenticación integrada. | 20:05 | 20:20 | +| Investigación | ✅ **Selección de Software**: Análisis de alternativas para File Server, eligiendo TinyFileManager por agilidad PHP. | 15:30 | 20:00 | +| Scripts | ✅ **Automatización Ruby**: Desarrollo del script `mantenimiento_backups.rb` para ciclo de vida de snapshots. | 01:25 | 02:00 | +| ADN | ✅ **Estandarización**: Creación de `TEMPLATE_PROCEDIMIENTO.md` y estructura de `procedimientos/`. | 00:45 | 01:10 | + +

⬆️ Volver arriba

+ +### srv-pmox2 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Red | ✅ **Persistencia de Gateway**: Inyección de `gateway 10.0.10.8` en configuración de interfaces para garantizar conectividad post-reboot. | 22:20 | 22:30 | +| Backup | ✅ **Ciclo de Respaldo**: Ejecución exitosa del script de backup tras recuperar conectividad. | 02:33 | 02:45 | +| S.O. | ✅ **Runtime Ruby**: Instalación de dependencias para permitir la ejecución de scripts de mantenimiento. | 02:22 | 02:33 | +| Red | ✅ **Resolución de Incidente**: Diagnóstico y corrección manual de ruta por defecto perdida ("Network unreachable"). | 02:22 | 02:33 | + +

⬆️ Volver arriba

+ +### srvv-sysacadweb +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Control | ✅ **Validación Operativa**: Confirmación de arranque correcto de servicios IIS y base de datos tras snapshot. | 19:40 | 19:45 | +| ADN | ✅ **Snapshot Documental**: Registro formal del estado del nodo en la estructura `nodos/`. | 19:34 | 19:40 | +| Backup | ✅ **Respaldo Completo**: Ciclo de backup de VM completado sin errores. | 09:23 | 19:34 | + +

⬆️ Volver arriba

+ +### pcv-dasu2 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Identidad | ✅ **Cambio de Hostname**: Renombrado de `pcv-dasu3` a `pcv-dasu2` para alinear con nomenclatura del Grid (Ontología). | 10:00 | 10:55 | + +

⬆️ Volver arriba

+ +### srvv-maurik +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Control | ✅ **Health Check**: Verificación de servicios de Dominio (AD DS) y resolución DNS post-backup. | 10:01 | 10:05 | +| Backup | ✅ **Ciclo de Respaldo**: Ejecución de backup programado. | 09:23 | 10:01 | + +

⬆️ Volver arriba

+ +### pcv-dasu1 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Backup | ✅ **Respaldo Crítico**: Backup de seguridad de la estación de trabajo principal de DASU. | 09:43 | 09:54 | + +

⬆️ Volver arriba

+ +### srv-pmox3 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Backup | ✅ **Automatización Nocturna**: Ejecución programada del ciclo de respaldos en ZFS. | 02:08 | 03:02 | + +

⬆️ Volver arriba

+ +### srv-pmox1 +| Tema | Detalle | Ini | Fin | +| :--- | :--- | :--- | :--- | +| Backup | ✅ **Automatización Nocturna**: Primer ejecución válida del nuevo sistema de backups en Ruby. | 01:44 | 02:00 | + +

⬆️ Volver arriba

+ +--- + + diff --git a/nodos/pc-DASU0.md b/nodos/pc-dasu0.md similarity index 69% rename from nodos/pc-DASU0.md rename to nodos/pc-dasu0.md index 0ecb74f7..026e05f2 100644 --- a/nodos/pc-DASU0.md +++ b/nodos/pc-dasu0.md @@ -1,7 +1,7 @@ -# Nodo: pc-DASU0 +# Nodo: pc-dasu0 ## Información General -- **Hostname**: `pc-DASU0` (Prev: `UTNLR32120`) +- **Hostname**: `pc-dasu0` (Prev: `UTNLR32120`) - **Patrimonio**: `32120` - **Ubicación**: Oficina DASUTEN (Externa a Facultad) - **Tipo**: PC Física @@ -12,8 +12,13 @@ ## Credenciales de Gestión (Tailscale Admin) - **Cuenta Maestra**: `pcdasu0@frlr.utn.edu.ar` - **Pass (Ref)**: `UTN$larioja00` -- **Propósito**: Esta cuenta gestiona la red Tailscale que une a `pc-DASU0` con `pcv-DASU1`. +- **Propósito**: Esta cuenta gestiona la red Tailscale que une a `pc-dasu0` con `pcv-dasu1`. ## Servicios - **RustDesk**: ID `398 699 016` (Acceso Remoto Principal). Password: `UTNlarioja00` +20: +21: ## Hardware (AIDA64 27/03/2025) +22: - **CPU**: HexaCore AMD Ryzen 5 4600G @ 4.30GHz +23: - **RAM**: 8 GB (DDR4-3200) +24: - **Placa Base**: Asus Prime A320M-K diff --git a/nodos/pcv-DASU1.md b/nodos/pcv-dasu1.md similarity index 85% rename from nodos/pcv-DASU1.md rename to nodos/pcv-dasu1.md index 0968672a..d4b6345b 100644 --- a/nodos/pcv-DASU1.md +++ b/nodos/pcv-dasu1.md @@ -1,7 +1,7 @@ -# Nodo: pcv-DASU1 +# Nodo: pcv-dasu1 ## Información General -- **Hostname**: `pcv-DASU1` (Prev: `pcvDASU2`) +- **Hostname**: `pcv-dasu1` (Prev: `pcvDASU2`) - **Ubicación**: Interna (Facultad / srv-pmox2) - **Tipo**: Máquina Virtual (VM) - **Rol**: Estación de Trabajo Objetivo (Hosting del Sistema DASU) @@ -14,4 +14,4 @@ - **RustDesk**: ID `290 015 364` (Acceso Remoto Principal). Password: `UTNlarioja00` ## Estrategia de Acceso -Este nodo debe tener Tailscale instalado y logueado con la cuenta `pcdasu0@frlr.utn.edu.ar` (o validado en la misma red) para recibir conexiones directas desde `pc-DASU0`. +Este nodo debe tener Tailscale instalado y logueado con la cuenta `pcdasu0@frlr.utn.edu.ar` (o validado en la misma red) para recibir conexiones directas desde `pc-dasu0`. diff --git a/nodos/pcv-dasu2.md b/nodos/pcv-dasu2.md new file mode 100644 index 00000000..8f6a0819 --- /dev/null +++ b/nodos/pcv-dasu2.md @@ -0,0 +1,17 @@ +# Ficha de Nodo: pcv-dasu2 + +| Atributo | Valor | +| :--- | :--- | +| **Hostname** | `pcv-dasu2` | +| **IP / Ubicación** | Facultad (`srv-pmox2`) | +| **Tailscale IP** | *Pendiente (Consultar pcv-dasu3 previa)* | +| **Sistema Operativo** | Windows 10 VM | +| **Rol Principal** | Sistema DASU / Atención al Usuario | +| **Estado** | 🟢 Online | + +## Descripción +Máquina virtual encargada del procesamiento de datos de DASUTEN. Recientemente renombrada de `pcv-dasu3` a `pcv-dasu2` para estandarización del Grid. + +## Intervenciones Recientes +- **19/02/2026**: Cambio de hostname exitoso (10:00 - 10:55). +- **19/02/2026**: Backup automatizado completado. diff --git a/nodos/srv-NS8.md b/nodos/srv-ns8.md similarity index 87% rename from nodos/srv-NS8.md rename to nodos/srv-ns8.md index 1d07e5ed..611e8d0f 100644 --- a/nodos/srv-NS8.md +++ b/nodos/srv-ns8.md @@ -1,8 +1,8 @@ -# Ficha de Nodo: srv-NS8 (Host Principal) +# Ficha de Nodo: srv-ns8 (Host Principal) | Atributo | Valor | | :--- | :--- | -| **Hostname** | `srv-NS8` | +| **Hostname** | `srv-ns8` | | **IP LAN** | `10.0.10.8` | | **IP Pública** | `190.114.205.18` | | **IP Tailscale** | `100.88.252.26` | @@ -16,7 +16,7 @@ - **Disco**: 500GB NVMe (Root) + Almacenamiento externo conectado. ## Servicios Críticos -1. **VirtualBox**: Aloja la VM `PCV_DTIC-RRHH_W732` (Vital para el funcionamiento del departamento). +1. **VirtualBox**: Aloja la VM `pcv-dtic-rrhh-w732` (Vital para el funcionamiento del departamento). 2. **Docker**: Despliegue de servicios DTIC (Nginx, Portainer, SysACAD, Homepage). 3. **Red Híbrida**: Configuración de doble Gateway con Policy Routing. diff --git a/nodos/srv-pmox1.md b/nodos/srv-pmox1.md index ae7f1939..723e1620 100644 --- a/nodos/srv-pmox1.md +++ b/nodos/srv-pmox1.md @@ -18,11 +18,11 @@ | VMID | Nombre | Estado | Memoria (MB) | Disco (GB) | | :--- | :--- | :--- | :--- | :--- | -| 101 | srvv-SITIO | Running | 5120 | 32.00 | -| 102 | srvv-SITIO0 | Running | 3072 | 50.00 | -| 103 | srvv-DTIC | Running | 8192 | 50.00 | -| 104 | srvv-DOCs | Running | 4096 | 50.00 | -| 112 | srvv-DNS | Running | 4096 | 10.00 | +| 101 | srvv-sitio | Running | 5120 | 32.00 | +| 102 | srvv-sitio0 | Running | 3072 | 50.00 | +| 103 | srvv-dtic | Running | 8192 | 50.00 | +| 104 | srvv-docs | Running | 4096 | 50.00 | +| 112 | srvv-dns | Running | 4096 | 10.00 | ## Análisis de Salud - **⚠️ Sobreasignación de RAM**: La suma de la memoria asignada a las VMs activas (~24 GB) excede la memoria física del host (16 GB). El sistema depende fuertemente de KSM (Kernel Samepage Merging) o Ballooning, lo que podría degradar el rendimiento bajo carga. diff --git a/nodos/srv-pmox2.md b/nodos/srv-pmox2.md index ff87b13b..ab2a8f50 100644 --- a/nodos/srv-pmox2.md +++ b/nodos/srv-pmox2.md @@ -15,7 +15,7 @@ | VMID | Nombre | Estado | Memoria (MB) | Disco (GB) | | :--- | :--- | :--- | :--- | :--- | -| 105 | srvv-KOHA | Running | 2048 | 32.00 | +| 105 | srvv-koha | Running | 2048 | 32.00 | | 108 | pcv-DASU2 | Running | 4096 | 50.00 | | 109 | pcv-DASU3 | Running | 4080 | 50.00 | | 110 | pcv-SERVIIO | Running | 4096 | 32.00 | diff --git a/nodos/srv-pmox3.md b/nodos/srv-pmox3.md index 09929cd8..c56a5671 100644 --- a/nodos/srv-pmox3.md +++ b/nodos/srv-pmox3.md @@ -17,17 +17,17 @@ | VMID | Nombre | Estado | Memoria (MB) | Disco (GB) | | :--- | :--- | :--- | :--- | :--- | | 100 | docker | Stopped | 4096 | 10.00 | -| 111 | srvv-FENIX | Running | 32768 | 100.00 | +| 111 | srvv-fenix | Running | 32768 | 100.00 | | 114 | srvv-N8N | Stopped | 4096 | 10.00 | ### Contenedores (LXC) | VMID | Nombre | Estado | | :--- | :--- | :--- | -| 106 | srvv-UPTIME | Running | -| 107 | srvv-DATA | Running | -| 113 | srvv-SITIO2 | Running | +| 106 | srvv-uptime | Running | +| 107 | srvv-data | Running | +| 113 | srvv-sitio2 | Running | | 115 | srvv-N8N | Stopped | ## Análisis de Salud -- **Carga Principal**: `srvv-FENIX` consume 32GB de RAM (50% del host). +- **Carga Principal**: `srvv-fenix` consume 32GB de RAM (50% del host). - **Recursos**: Host holgado con ~20GB de RAM libres. diff --git a/nodos/srvv-DATA.md b/nodos/srvv-data.md similarity index 89% rename from nodos/srvv-DATA.md rename to nodos/srvv-data.md index bc74f7d0..87407e93 100644 --- a/nodos/srvv-DATA.md +++ b/nodos/srvv-data.md @@ -1,7 +1,7 @@ -# Nodo: srvv-DATA +# Nodo: srvv-data ## Información General -- **Hostname**: `srvv-DATA` +- **Hostname**: `srvv-data` - **IP**: `10.0.10.13` - **Rol**: Base de Datos / Almacenamiento - **Estado**: 🟢 Online diff --git a/nodos/srvv-DNS.md b/nodos/srvv-dns.md similarity index 93% rename from nodos/srvv-DNS.md rename to nodos/srvv-dns.md index 225d3d3c..d001abde 100644 --- a/nodos/srvv-DNS.md +++ b/nodos/srvv-dns.md @@ -1,7 +1,7 @@ -# Nodo: srvv-DNS +# Nodo: srvv-dns ## Información General -- **Hostname**: `srvv-DNS` +- **Hostname**: `srvv-dns` - **IP**: `10.0.10.2` - **Rol**: Servidor DNS (Presunto) - **Estado**: 🟢 Online diff --git a/nodos/srvv-DOCs.md b/nodos/srvv-docs.md similarity index 91% rename from nodos/srvv-DOCs.md rename to nodos/srvv-docs.md index e8ed648f..344688a5 100644 --- a/nodos/srvv-DOCs.md +++ b/nodos/srvv-docs.md @@ -1,7 +1,7 @@ -# Nodo: srvv-DOCs +# Nodo: srvv-docs ## Información General -- **Hostname**: `srvv-DOCs` +- **Hostname**: `srvv-docs` - **IP**: `10.0.10.14` - **Rol**: Docker Host / Documentación - **Estado**: 🟢 Online diff --git a/nodos/srvv-DTIC.md b/nodos/srvv-dtic.md similarity index 91% rename from nodos/srvv-DTIC.md rename to nodos/srvv-dtic.md index fccb30bf..c007473c 100644 --- a/nodos/srvv-DTIC.md +++ b/nodos/srvv-dtic.md @@ -1,7 +1,7 @@ -# Nodo: srvv-DTIC +# Nodo: srvv-dtic ## Información General -- **Hostname**: `srvv-DTIC` +- **Hostname**: `srvv-dtic` - **IP**: `10.0.10.4` - **Rol**: Docker Host / Servicios Internos - **Estado**: 🟢 Online diff --git a/nodos/srvv-KOHA.md b/nodos/srvv-koha.md similarity index 90% rename from nodos/srvv-KOHA.md rename to nodos/srvv-koha.md index 6330f114..2a796572 100644 --- a/nodos/srvv-KOHA.md +++ b/nodos/srvv-koha.md @@ -1,7 +1,7 @@ -# Nodo: srvv-KOHA +# Nodo: srvv-koha ## Información General -- **Hostname**: `srvv-KOHA` +- **Hostname**: `srvv-koha` - **IP**: `10.0.10.130` - **Rol**: VM / Librería - **Estado**: 🟢 Online diff --git a/nodos/srvv-MAURIK.md b/nodos/srvv-maurik.md similarity index 60% rename from nodos/srvv-MAURIK.md rename to nodos/srvv-maurik.md index d6a29099..d51137fc 100644 --- a/nodos/srvv-MAURIK.md +++ b/nodos/srvv-maurik.md @@ -1,10 +1,10 @@ -# Ficha de Nodo: srvv-MAURIK +# Ficha de Nodo: srvv-maurik | Atributo | Valor | | :--- | :--- | -| **Hostname** | `srvv-MAURIK` | -| **IP / Ubicación** | *Pendiente de Relevamiento* | -| **Sistema Operativo** | Windows Server | +| **Hostname** | `srvv-maurik` | +| **IP / Ubicación** | `srv-xen01` (Citrix XenServer) | +| **Sistema Operativo** | Windows Server 2019 Standard (1809) | | **Rol Principal** | Controlador de Dominio (Domain Controller) | | **Dominio** | `utnlarioja.intranet` | | **Estado** | Operativo | @@ -15,6 +15,11 @@ Servidor encargado de la gestión de identidades y autenticación para la red ad ## Servicios Detectados - **Active Directory Domain Services (AD DS)**: Gestión de usuarios y computadoras. - **DNS**: Resolución de nombres interna. +19: +20: ## Hardware (AIDA64 19/02/2026) +21: - **CPU**: QuadCore Intel Xeon E3-1230 @ 3.40GHz (Virtual) +22: - **RAM**: 10 GB +23: - **Placa Base**: XenSource Virtual Motherboard ## Intervenciones Recientes - **18/02/2026**: Alta de usuario `chuergo` (Electromecánica). diff --git a/nodos/srvv-SITIO.md b/nodos/srvv-sitio.md similarity index 93% rename from nodos/srvv-SITIO.md rename to nodos/srvv-sitio.md index 41fbfa9c..cfb61569 100644 --- a/nodos/srvv-SITIO.md +++ b/nodos/srvv-sitio.md @@ -1,7 +1,7 @@ -# Nodo: srvv-SITIO +# Nodo: srvv-sitio ## Información General -- **Hostname**: `srvv-SITIO` +- **Hostname**: `srvv-sitio` - **IP Privada**: `10.0.10.18` - **IP Pública**: `190.114.205.20` - **Rol**: Servidor Web / Docker Host (VM en `srv-pmox1`) diff --git a/nodos/srvv-SITIO0.md b/nodos/srvv-sitio0.md similarity index 96% rename from nodos/srvv-SITIO0.md rename to nodos/srvv-sitio0.md index c3661139..e72155da 100644 --- a/nodos/srvv-SITIO0.md +++ b/nodos/srvv-sitio0.md @@ -1,4 +1,4 @@ -# Nodo: srvv-SITIO0 +# Nodo: srvv-sitio0 ## Información General - **Hostname**: `srvv-SCERO` diff --git a/nodos/srvv-SITIO2.md b/nodos/srvv-sitio2.md similarity index 91% rename from nodos/srvv-SITIO2.md rename to nodos/srvv-sitio2.md index dd6cc0de..616998e7 100644 --- a/nodos/srvv-SITIO2.md +++ b/nodos/srvv-sitio2.md @@ -1,7 +1,7 @@ -# Nodo: srvv-SITIO2 +# Nodo: srvv-sitio2 ## Información General -- **Hostname**: `srvv-SITIO2` +- **Hostname**: `srvv-sitio2` - **IP**: `10.0.10.19` - **Rol**: Servidor Web Secundario (LXC) - **Estado**: 🟢 Online diff --git a/nodos/srvv-sysacadweb.md b/nodos/srvv-sysacadweb.md new file mode 100644 index 00000000..dc9ae36f --- /dev/null +++ b/nodos/srvv-sysacadweb.md @@ -0,0 +1,21 @@ +# Ficha de Nodo: srvv-sysacadweb + +| Atributo | Valor | +| :--- | :--- | +| **Hostname** | `srvv-sysacadweb` | +| **IP / Ubicación** | Facultad (`srv-xen01`) | +| **Sistema Operativo** | Windows Web Server 2008 R2 (SP1) | +| **Rol Principal** | Servidor Web SysACAD | +| **Estado** | 🟢 Online | + +## Descripción +Nodo encargado de servir la interfaz web del sistema académico SysACAD. Alojado en el cluster Legacy (Citrix XenServer). + +## Intervenciones Recientes +- **19/02/2026**: Backup automatizado completado exitosamente (09:23 - 19:34). +- **19/02/2026**: Alta formal en el sistema de snapshots ADN. +17: +18: ## Hardware (AIDA64 19/02/2026) +19: - **CPU**: QuadCore Intel Xeon E3-1230 @ 3.50GHz (Virtual) +20: - **RAM**: 4 GB +21: - **Placa Base**: XenSource Virtual Motherboard diff --git a/nodos/srvv-UPTIME.md b/nodos/srvv-uptime.md similarity index 91% rename from nodos/srvv-UPTIME.md rename to nodos/srvv-uptime.md index 6b53e1cb..a12ed722 100644 --- a/nodos/srvv-UPTIME.md +++ b/nodos/srvv-uptime.md @@ -1,7 +1,7 @@ -# Nodo: srvv-UPTIME +# Nodo: srvv-uptime ## Información General -- **Hostname**: `srvv-UPTIME` +- **Hostname**: `srvv-uptime` - **IP**: `10.0.10.9` - **Rol**: Monitorización (Uptime Kuma) - **Estado**: 🟢 Online diff --git a/procedimientos/01_backup_proxmox.md b/procedimientos/01_backup_proxmox.md new file mode 100644 index 00000000..8c41458e --- /dev/null +++ b/procedimientos/01_backup_proxmox.md @@ -0,0 +1,47 @@ +# [PROC-01] - Backup de Nodos y VMs (Proxmox VE) + +## 1. Identificación y Objetivo +- **ID**: `PROC-01` +- **Responsable**: Administrador del Grid +- **Objetivo**: Asegurar la integridad de todos los sistemas (físicos y virtuales) mediante backups periódicos en Proxmox, garantizando la alta disponibilidad tras el reinicio automático. +- **Frecuencia**: Semanal / Antes de cambios críticos. + +## 2. Alcance y Prerrequisitos +- **Nodos Afectados**: + - Host Físicos: `srv-pmox1`, `srv-pmox2`, `srv-pmox3`. + - VMs/CTs: Todos los que inicien con `srvv-XXXX`. +- **Sistemas**: Linux (Host) y Universal (VM Guests). +- **Prerrequisitos**: + - [ ] Unidad de destino `zfsdisco1` operativa y montada. + - [ ] Espacio suficiente en `zfsdisco1`. + - [ ] Permisos de `Datastore.AllocateSpace` y `VM.Backup`. + +## 3. Flujo de Tareas (Ejecución) + +| Paso | Tarea | Estado | Notas | +| :--- | :--- | :---: | :--- | +| 1 | Ejecutar `scripts/mantenimiento_backups.rb` | 📍 | Automatiza el ciclo por VM (Ruby) | +| 2 | Limpieza Granular (Ciclo Interno) | ⏳ | Elimina backups > 6 días **por VM** | +| 3 | Backup Secuencial | ⏳ | Ejecuta `vzdump` tras limpiar cada VM | +| 4 | Identificar Nodos y VMs activas | ✅ | Filtrado por patrón `srvv-` y Linux | +| 5 | Verificar reinicio automático de servicios | ⏳ | Comprobar Uptime post-ciclo | + +## 4. Verificación y Validación +- [ ] Tarea en Proxmox finalizada con estado `OK`. +- [ ] Archivos `.vma.zst` presentes en el storage de destino. +- [ ] Acceso SSH recuperado tras el reinicio automático. +- **Resultado Esperado**: ✅ Sistemas respaldados y servicios operativos (Uptime < 5 min desde el fin del backup). + +## 5. Plan de Reversión (Hombre Muerto) +> [!IMPORTANT] +> Si una VM no inicia automáticamente tras el backup. + +1. **Gatillo de Reversión**: VM en estado `stopped` por más de 10 minutos post-backup. +2. **Acciones**: + - Iniciar manualmente via CLI: `qm start `. + - Revisar logs en `/var/log/pve/tasks/`. + - Si el disco está bloqueado: `qm unlock `. +3. **Verificación post-reversión**: Confirmar ping a la IP del servicio afectado. + +--- +*Documento generado bajo el ADN del proyecto srv-ns8.* diff --git a/procedimientos/TEMPLATE_PROCEDIMIENTO.md b/procedimientos/TEMPLATE_PROCEDIMIENTO.md new file mode 100644 index 00000000..0313aea4 --- /dev/null +++ b/procedimientos/TEMPLATE_PROCEDIMIENTO.md @@ -0,0 +1,42 @@ +# [PROC-XX] - [Título del Procedimiento] + +## 1. Identificación y Objetivo +- **ID**: `PROC-XX` +- **Responsable**: Asistente/Usuario +- **Objetivo**: [Describir qué se busca lograr con este procedimiento] +- **Frecuencia**: [Manual / Automática / Bajo Demanda] + +## 2. Alcance y Prerrequisitos +- **Nodos Afectados**: [Listado de hostnames, ej: srv-pmox1, srvv-sitio] +- **Sistemas**: [Linux / Windows / Docker] +- **Prerrequisitos**: + - [ ] Acceso Root/Sudo. + - [ ] Backup previo de datos críticos. + - [ ] [Herramienta necesaria] instalada. + +## 3. Flujo de Tareas (Ejecución) +Este flujo debe seguirse secuencialmente. Utilizar iconos de estado según el `adn/02_protocolo.md`. + +| Paso | Tarea | Estado | Notas | +| :--- | :--- | :---: | :--- | +| 1 | [Preparación inicial] | 📍 | | +| 2 | [Ejecución core] | ⏳ | | +| 3 | [Post-proceso] | ⏳ | | + +## 4. Verificación y Validación +- [ ] [Prueba técnica 1] +- [ ] [Confirmación visual/logs] +- **Resultado Esperado**: ✅ [Descripción del estado de éxito] + +## 5. Plan de Reversión (Hombre Muerto) +> [!IMPORTANT] +> En caso de fallo crítico o pérdida de conectividad, seguir estos pasos inmediatamente. + +1. **Gatillo de Reversión**: [Ej: Error en el paso X, No hay respuesta tras 5 min] +2. **Acciones**: + - [Acción 1 para restaurar estado] + - [Acción 2 para restaurar estado] +3. **Verificación post-reversión**: [Confirmar retorno a la estabilidad] + +--- +*Documento generado bajo el ADN del proyecto srv-ns8.* diff --git a/scripts/mantenimiento_backups.rb b/scripts/mantenimiento_backups.rb new file mode 100755 index 00000000..31dc67d0 --- /dev/null +++ b/scripts/mantenimiento_backups.rb @@ -0,0 +1,100 @@ +#!/usr/bin/env ruby +# [PROC-01] - Mantenimiento de Backups Proxmox (Ruby Edition) +# Lógica: Granular por VMID, Retención 6 días, Destino zfsDISCO1 + +require 'date' +require 'fileutils' + +STORAGE_NAME = "zfsDISCO1" +# NOTA: En Proxmox, la ruta suele ser /mnt/pve/zfsDISCO1 o similar. +# Ajustamos a la ruta montada del storage. +BASE_PATH = "/mnt/pve/#{STORAGE_NAME}/dump" +RETENTION_DAYS = 6 +VM_PATTERN = /^srv[v]?-/ + +def log(message, type = "INFO") + timestamp = Time.now.strftime("%Y-%m-%d %H:%M:%S") + puts "[#{timestamp}] [#{type}] #{message}" +end + +def get_vmid_list + # Obtener IDs de VMs (QEMU) y Contenedores (LXC) + ids = [] + + # QEMU VMs + `qm list`.each_line.with_index do |line, idx| + next if idx == 0 # Cabecera + parts = line.split + vmid = parts[0] + name = parts[1] + ids << vmid if name =~ VM_PATTERN + end + + # LXC Containers + `pct list`.each_line.with_index do |line, idx| + next if idx == 0 + parts = line.split + vmid = parts[0] + name = parts[2] # El nombre suele ser la 3er columna en pct list + ids << vmid if name =~ VM_PATTERN + end + + ids.uniq +end + +def prune_old_backups(vmid) + log("Iniciando fase de limpieza para VMID: #{vmid}...") + return unless Dir.exist?(BASE_PATH) + + # Patrón de archivos de Proxmox: vzdump-[qemu|lxc]--.* + # Buscamos archivos de este VMID específico + files = Dir.glob("#{BASE_PATH}/vzdump-*-#{vmid}-*") + + files.each do |file| + mtime = File.mtime(file) + age_days = (Date.today - mtime.to_date).to_i + + if age_days > RETENTION_DAYS + log("Eliminando backup antiguo: #{File.basename(file)} (Antigüedad: #{age_days} días)", "WARN") + begin + FileUtils.rm(file) + rescue => e + log("Error al eliminar #{file}: #{e.message}", "ERROR") + end + end + end +end + +def run_backup(vmid) + log("Iniciando backup para VMID: #{vmid} hacia #{STORAGE_NAME}...") + # Usamos --mode stop para asegurar reinicio automático y consistencia + cmd = "vzdump #{vmid} --storage #{STORAGE_NAME} --mode stop --compress zstd" + + log("Ejecutando: #{cmd}") + success = system(cmd) + + if success + log("Backup completado exitosamente para VMID: #{vmid}", "SUCCESS") + else + log("FALLO en el backup para VMID: #{vmid}", "ERROR") + end +end + +# --- EJECUCIÓN PRINCIPAL --- +log("=== INICIO DE CICLO DE MANTENIMIENTO DE BACKUPS ===") + +unless Dir.exist?(BASE_PATH) + log("Error: No se encuentra la ruta del storage #{BASE_PATH}. ¿Está montado?", "ERROR") + exit 1 +end + +vmids = get_vmid_list +log("Nodos detectados para procesar: #{vmids.join(', ')}") + +vmids.each do |vmid| + prune_old_backups(vmid) + run_backup(vmid) + puts "-" * 40 +end + +log("=== FIN DE CICLO DE MANTENIMIENTO ===") diff --git a/servicios/nginx/conf.d/ns8.conf b/servicios/nginx/conf.d/ns8.conf index d60e4224..d32ecb4c 100644 --- a/servicios/nginx/conf.d/ns8.conf +++ b/servicios/nginx/conf.d/ns8.conf @@ -42,6 +42,15 @@ server { proxy_set_header Connection "upgrade"; } + # TinyFileManager + location /tfm/ { + proxy_pass http://127.0.0.1:8082/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/ns8.frlr.utn.edu.ar/privkey.pem; # managed by Certbot diff --git a/servicios/tfm/docker-compose.yml b/servicios/tfm/docker-compose.yml new file mode 100644 index 00000000..00eac52b --- /dev/null +++ b/servicios/tfm/docker-compose.yml @@ -0,0 +1,13 @@ +services: + tfm: + image: tinyfilemanager/tinyfilemanager:master + container_name: srvv-TFM + restart: always + ports: + - "8082:80" + volumes: + - /mnt/ns8Disco2/DTIC_APPs/:/var/www/html/data + - ./index.php:/var/www/html/index.php + - ./translation.json:/var/www/html/translation.json + # Persist config if needed, or mount specific config.php + # - ./config.php:/var/www/html/config.php diff --git a/servicios/tfm/index.php b/servicios/tfm/index.php new file mode 100644 index 00000000..f7fc05e0 --- /dev/null +++ b/servicios/tfm/index.php @@ -0,0 +1,5807 @@ + 'Password', 'Username2' => 'Password2', ...) +// Generate secure password hash - https://tinyfilemanager.github.io/docs/pwd.html +$auth_users = array( + 'rmonla' => '$2y$10$UfZGPTOglFaCpkRrYyWESeBtkgI8jIR24pAYS/TkuDlehWZaCOQtu', //lhsurnm77NS8 + 'utnlarioja' => '$2y$10$ttPlWYT1jgGI.WJhEiWpgeBzYlqHb5s4k30Yq.T5LoY2Q3YhuUEqG', //utnlarioja +); + +// Readonly users +// e.g. array('users', 'guest', ...) +$readonly_users = array( + 'utnlarioja' +); + +// Global readonly, including when auth is not being used +$global_readonly = false; + +// user specific directories +// array('Username' => 'Directory path', 'Username2' => 'Directory path', ...) +$directories_users = array(); + +// Enable highlight.js (https://highlightjs.org/) on view's page +$use_highlightjs = true; + +// highlight.js style +// for dark theme use 'ir-black' +$highlightjs_style = 'vs'; + +// Enable ace.js (https://ace.c9.io/) on view's page +$edit_files = true; + +// Default timezone for date() and time() +// Doc - http://php.net/manual/en/timezones.php +$default_timezone = 'Etc/UTC'; // UTC + +// Root path for file manager +// use absolute path of directory i.e: '/var/www/folder' or $_SERVER['DOCUMENT_ROOT'].'/folder' +//make sure update $root_url in next section +$root_path = $_SERVER['DOCUMENT_ROOT'] . '/data'; + +// Root url for links in file manager.Relative to $http_host. Variants: '', 'path/to/subfolder' +// Will not working if $root_path will be outside of server document root +$root_url = ''; + +// Server hostname. Can set manually if wrong +// $_SERVER['HTTP_HOST'].'/folder' +$http_host = $_SERVER['HTTP_HOST']; + +// input encoding for iconv +$iconv_input_encoding = 'UTF-8'; + +// date() format for file modification date +// Doc - https://www.php.net/manual/en/function.date.php +$datetime_format = 'm/d/Y g:i A'; + +// Path display mode when viewing file information +// 'full' => show full path +// 'relative' => show path relative to root_path +// 'host' => show path on the host +$path_display_mode = 'full'; + +// Allowed file extensions for create and rename files +// e.g. 'txt,html,css,js' +$allowed_file_extensions = ''; + +// Allowed file extensions for upload files +// e.g. 'gif,png,jpg,html,txt' +$allowed_upload_extensions = ''; + +// Favicon path. This can be either a full url to an .PNG image, or a path based on the document root. +// full path, e.g http://example.com/favicon.png +// local path, e.g images/icons/favicon.png +$favicon_path = ''; + +// Files and folders to excluded from listing +// e.g. array('myfile.html', 'personal-folder', '*.php', '/path/to/folder', ...) +$exclude_items = array(); + +// Online office Docs Viewer +// Available rules are 'google', 'microsoft' or false +// Google => View documents using Google Docs Viewer +// Microsoft => View documents using Microsoft Web Apps Viewer +// false => disable online doc viewer +$online_viewer = 'google'; + +// Sticky Nav bar +// true => enable sticky header +// false => disable sticky header +$sticky_navbar = true; + +// Maximum file upload size +// Increase the following values in php.ini to work properly +// memory_limit, upload_max_filesize, post_max_size +$max_upload_size_bytes = 5000000000; // size 5,000,000,000 bytes (~5GB) + +// chunk size used for upload +// eg. decrease to 1MB if nginx reports problem 413 entity too large +$upload_chunk_size_bytes = 2000000; // chunk size 2,000,000 bytes (~2MB) + +// Possible rules are 'OFF', 'AND' or 'OR' +// OFF => Don't check connection IP, defaults to OFF +// AND => Connection must be on the whitelist, and not on the blacklist +// OR => Connection must be on the whitelist, or not on the blacklist +$ip_ruleset = 'OFF'; + +// Should users be notified of their block? +$ip_silent = true; + +// IP-addresses, both ipv4 and ipv6 +$ip_whitelist = array( + '127.0.0.1', // local ipv4 + '::1' // local ipv6 +); + +// IP-addresses, both ipv4 and ipv6 +$ip_blacklist = array( + '0.0.0.0', // non-routable meta ipv4 + '::' // non-routable meta ipv6 +); + +// if User has the external config file, try to use it to override the default config above [config.php] +// sample config - https://tinyfilemanager.github.io/config-sample.txt +$config_file = __DIR__ . '/config.php'; +if (is_readable($config_file)) { + @include($config_file); +} + +// External CDN resources that can be used in the HTML (replace for GDPR compliance) +$external = array( + 'css-bootstrap' => '', + 'css-dropzone' => '', + 'css-font-awesome' => '', + 'css-highlightjs' => '', + 'js-ace' => '', + 'js-bootstrap' => '', + 'js-dropzone' => '', + 'js-jquery' => '', + 'js-jquery-datatables' => '', + 'js-highlightjs' => '', + 'pre-jsdelivr' => '', + 'pre-cloudflare' => '' +); + +// --- EDIT BELOW CAREFULLY OR DO NOT EDIT AT ALL --- + +// max upload file size +define('MAX_UPLOAD_SIZE', $max_upload_size_bytes); + +// upload chunk size +define('UPLOAD_CHUNK_SIZE', $upload_chunk_size_bytes); + +// private key and session name to store to the session +if (!defined('FM_SESSION_ID')) { + define('FM_SESSION_ID', 'filemanager'); +} + +// Configuration +$cfg = new FM_Config(); + +// Default language +$lang = isset($cfg->data['lang']) ? $cfg->data['lang'] : 'es'; + +// Show or hide files and folders that starts with a dot +$show_hidden_files = isset($cfg->data['show_hidden']) ? $cfg->data['show_hidden'] : true; + +// PHP error reporting - false = Turns off Errors, true = Turns on Errors +$report_errors = isset($cfg->data['error_reporting']) ? $cfg->data['error_reporting'] : true; + +// Hide Permissions and Owner cols in file-listing +$hide_Cols = isset($cfg->data['hide_Cols']) ? $cfg->data['hide_Cols'] : true; + +// Theme +$theme = isset($cfg->data['theme']) ? $cfg->data['theme'] : 'light'; + +define('FM_THEME', $theme); + +//available languages +$lang_list = array( + 'en' => 'English' +); + +if ($report_errors == true) { + @ini_set('error_reporting', E_ALL); + @ini_set('display_errors', 1); +} else { + @ini_set('error_reporting', E_ALL); + @ini_set('display_errors', 0); +} + +// if fm included +if (defined('FM_EMBED')) { + $use_auth = false; + $sticky_navbar = false; +} else { + @set_time_limit(600); + + date_default_timezone_set($default_timezone); + + ini_set('default_charset', 'UTF-8'); + if (version_compare(PHP_VERSION, '5.6.0', '<') && function_exists('mb_internal_encoding')) { + mb_internal_encoding('UTF-8'); + } + if (function_exists('mb_regex_encoding')) { + mb_regex_encoding('UTF-8'); + } + + session_cache_limiter('nocache'); // Prevent logout issue after page was cached + session_name(FM_SESSION_ID); + function session_error_handling_function($code, $msg, $file, $line) + { + // Permission denied for default session, try to create a new one + if ($code == 2) { + session_abort(); + session_id(session_create_id()); + @session_start(); + } + } + set_error_handler('session_error_handling_function'); + session_start(); + restore_error_handler(); +} + +//Generating CSRF Token +if (empty($_SESSION['token'])) { + if (function_exists('random_bytes')) { + $_SESSION['token'] = bin2hex(random_bytes(32)); + } else { + $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32)); + } +} + +if (empty($auth_users)) { + $use_auth = false; +} + +$is_https = isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) == 'on' || $_SERVER['HTTPS'] == 1) + || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'; + +// update $root_url based on user specific directories +if (isset($_SESSION[FM_SESSION_ID]['logged']) && !empty($directories_users[$_SESSION[FM_SESSION_ID]['logged']])) { + $wd = fm_clean_path(dirname($_SERVER['PHP_SELF'])); + $root_url = $root_url . $wd . DIRECTORY_SEPARATOR . $directories_users[$_SESSION[FM_SESSION_ID]['logged']]; +} +// clean $root_url +$root_url = fm_clean_path($root_url); + +// abs path for site +// abs path for site +defined('FM_ROOT_URL') || define('FM_ROOT_URL', 'https://ns8.frlr.utn.edu.ar/tfm'); +defined('FM_SELF_URL') || define('FM_SELF_URL', 'https://ns8.frlr.utn.edu.ar/tfm/'); + +// logout +if (isset($_GET['logout'])) { + unset($_SESSION[FM_SESSION_ID]['logged']); + unset($_SESSION['token']); + fm_redirect(FM_SELF_URL); +} + +// Validate connection IP +if ($ip_ruleset != 'OFF') { + function getClientIP() + { + if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) { + return $_SERVER["HTTP_CF_CONNECTING_IP"]; + } else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { + return $_SERVER["HTTP_X_FORWARDED_FOR"]; + } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { + return $_SERVER['REMOTE_ADDR']; + } else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { + return $_SERVER['HTTP_CLIENT_IP']; + } + return ''; + } + + $clientIp = getClientIP(); + $proceed = false; + $whitelisted = in_array($clientIp, $ip_whitelist); + $blacklisted = in_array($clientIp, $ip_blacklist); + + if ($ip_ruleset == 'AND') { + if ($whitelisted == true && $blacklisted == false) { + $proceed = true; + } + } else + if ($ip_ruleset == 'OR') { + if ($whitelisted == true || $blacklisted == false) { + $proceed = true; + } + } + + if ($proceed == false) { + trigger_error('User connection denied from: ' . $clientIp, E_USER_WARNING); + + if ($ip_silent == false) { + fm_set_msg(lng('Access denied. IP restriction applicable'), 'error'); + fm_show_header_login(); + fm_show_message(); + } + exit(); + } +} + +// Checking if the user is logged in or not. If not, it will show the login form. +if ($use_auth) { + if (isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']])) { + // Logged + } elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'], $_POST['token'])) { + // Logging In + sleep(1); + if (function_exists('password_verify')) { + if (isset($auth_users[$_POST['fm_usr']]) && isset($_POST['fm_pwd']) && password_verify($_POST['fm_pwd'], $auth_users[$_POST['fm_usr']]) && verifyToken($_POST['token'])) { + $_SESSION[FM_SESSION_ID]['logged'] = $_POST['fm_usr']; + fm_set_msg(lng('You are logged in')); + fm_redirect(FM_SELF_URL); + } else { + unset($_SESSION[FM_SESSION_ID]['logged']); + fm_set_msg(lng('Login failed. Invalid username or password'), 'error'); + fm_redirect(FM_SELF_URL); + } + } else { + fm_set_msg(lng('password_hash not supported, Upgrade PHP version'), 'error'); + ; + } + } else { + // Form + unset($_SESSION[FM_SESSION_ID]['logged']); + fm_show_header_login(); + ?> +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + " . lng('Root path') . " \"{$root_path}\" " . lng('not found!') . " "; + exit; +} + +defined('FM_SHOW_HIDDEN') || define('FM_SHOW_HIDDEN', $show_hidden_files); +defined('FM_ROOT_PATH') || define('FM_ROOT_PATH', $root_path); +defined('FM_LANG') || define('FM_LANG', $lang); +defined('FM_FILE_EXTENSION') || define('FM_FILE_EXTENSION', $allowed_file_extensions); +defined('FM_UPLOAD_EXTENSION') || define('FM_UPLOAD_EXTENSION', $allowed_upload_extensions); +defined('FM_EXCLUDE_ITEMS') || define('FM_EXCLUDE_ITEMS', (version_compare(PHP_VERSION, '7.0.0', '<') ? serialize($exclude_items) : $exclude_items)); +defined('FM_DOC_VIEWER') || define('FM_DOC_VIEWER', $online_viewer); +define('FM_READONLY', $global_readonly || ($use_auth && !empty($readonly_users) && isset($_SESSION[FM_SESSION_ID]['logged']) && in_array($_SESSION[FM_SESSION_ID]['logged'], $readonly_users))); +define('FM_IS_WIN', DIRECTORY_SEPARATOR == '\\'); + +// always use ?p= +if (!isset($_GET['p']) && empty($_FILES)) { + fm_redirect(FM_SELF_URL . '?p='); +} + +// get path +$p = isset($_GET['p']) ? $_GET['p'] : (isset($_POST['p']) ? $_POST['p'] : ''); + +// clean path +$p = fm_clean_path($p); + +// for ajax request - save +$input = file_get_contents('php://input'); +$_POST = (strpos($input, 'ajax') != FALSE && strpos($input, 'save') != FALSE) ? json_decode($input, true) : $_POST; + +// instead globals vars +define('FM_PATH', $p); +define('FM_USE_AUTH', $use_auth); +define('FM_EDIT_FILE', $edit_files); +defined('FM_ICONV_INPUT_ENC') || define('FM_ICONV_INPUT_ENC', $iconv_input_encoding); +defined('FM_USE_HIGHLIGHTJS') || define('FM_USE_HIGHLIGHTJS', $use_highlightjs); +defined('FM_HIGHLIGHTJS_STYLE') || define('FM_HIGHLIGHTJS_STYLE', $highlightjs_style); +defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format); + +unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style); + +/*************************** ACTIONS ***************************/ + +// Handle all AJAX Request +if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH) && isset($_POST['ajax'], $_POST['token'])) { + if (!verifyToken($_POST['token'])) { + header('HTTP/1.0 401 Unauthorized'); + die("Invalid Token."); + } + + //search : get list of files from the current folder + if (isset($_POST['type']) && $_POST['type'] == "search") { + $dir = $_POST['path'] == "." ? '' : $_POST['path']; + $response = scan(fm_clean_path($dir), $_POST['content']); + echo json_encode($response); + exit(); + } + + if (FM_READONLY) { + exit(); + } + + // save editor file + if (isset($_POST['type']) && $_POST['type'] == "save") { + // get current path + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + // check path + if (!is_dir($path)) { + fm_redirect(FM_SELF_URL . '?p='); + } + $file = $_GET['edit']; + $file = fm_clean_path($file); + $file = str_replace('/', '', $file); + if ($file == '' || !is_file($path . '/' . $file)) { + fm_set_msg(lng('File not found'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + header('X-XSS-Protection:0'); + $file_path = $path . '/' . $file; + + $writedata = $_POST['content']; + $fd = fopen($file_path, "w"); + $write_results = @fwrite($fd, $writedata); + fclose($fd); + if ($write_results === false) { + header("HTTP/1.1 500 Internal Server Error"); + die("Could Not Write File! - Check Permissions / Ownership"); + } + die(true); + } + + // backup files + if (isset($_POST['type']) && $_POST['type'] == "backup" && !empty($_POST['file'])) { + $fileName = fm_clean_path($_POST['file']); + $fullPath = FM_ROOT_PATH . '/'; + if (!empty($_POST['path'])) { + $relativeDirPath = fm_clean_path($_POST['path']); + $fullPath .= "{$relativeDirPath}/"; + } + $date = date("dMy-His"); + $newFileName = "{$fileName}-{$date}.bak"; + $fullyQualifiedFileName = $fullPath . $fileName; + try { + if (!file_exists($fullyQualifiedFileName)) { + throw new Exception("File {$fileName} not found"); + } + if (copy($fullyQualifiedFileName, $fullPath . $newFileName)) { + echo "Backup {$newFileName} created"; + } else { + throw new Exception("Could not copy file {$fileName}"); + } + } catch (Exception $e) { + echo $e->getMessage(); + } + } + + // Save Config + if (isset($_POST['type']) && $_POST['type'] == "settings") { + global $cfg, $lang, $report_errors, $show_hidden_files, $lang_list, $hide_Cols, $theme; + $newLng = $_POST['js-language']; + fm_get_translations([]); + if (!array_key_exists($newLng, $lang_list)) { + $newLng = 'en'; + } + + $erp = isset($_POST['js-error-report']) && $_POST['js-error-report'] == "true" ? true : false; + $shf = isset($_POST['js-show-hidden']) && $_POST['js-show-hidden'] == "true" ? true : false; + $hco = isset($_POST['js-hide-cols']) && $_POST['js-hide-cols'] == "true" ? true : false; + $te3 = $_POST['js-theme-3']; + + if ($cfg->data['lang'] != $newLng) { + $cfg->data['lang'] = $newLng; + $lang = $newLng; + } + if ($cfg->data['error_reporting'] != $erp) { + $cfg->data['error_reporting'] = $erp; + $report_errors = $erp; + } + if ($cfg->data['show_hidden'] != $shf) { + $cfg->data['show_hidden'] = $shf; + $show_hidden_files = $shf; + } + if ($cfg->data['show_hidden'] != $shf) { + $cfg->data['show_hidden'] = $shf; + $show_hidden_files = $shf; + } + if ($cfg->data['hide_Cols'] != $hco) { + $cfg->data['hide_Cols'] = $hco; + $hide_Cols = $hco; + } + if ($cfg->data['theme'] != $te3) { + $cfg->data['theme'] = $te3; + $theme = $te3; + } + $cfg->save(); + echo true; + } + + // new password hash + if (isset($_POST['type']) && $_POST['type'] == "pwdhash") { + $res = isset($_POST['inputPassword2']) && !empty($_POST['inputPassword2']) ? password_hash($_POST['inputPassword2'], PASSWORD_DEFAULT) : ''; + echo $res; + } + + //upload using url + if (isset($_POST['type']) && $_POST['type'] == "upload" && !empty($_REQUEST["uploadurl"])) { + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + function event_callback($message) + { + global $callback; + echo json_encode($message); + } + + function get_file_path() + { + global $path, $fileinfo, $temp_file; + return $path . "/" . basename($fileinfo->name); + } + + $url = !empty($_REQUEST["uploadurl"]) && preg_match("|^http(s)?://.+$|", stripslashes($_REQUEST["uploadurl"])) ? stripslashes($_REQUEST["uploadurl"]) : null; + + //prevent 127.* domain and known ports + $domain = parse_url($url, PHP_URL_HOST); + $port = parse_url($url, PHP_URL_PORT); + $knownPorts = [22, 23, 25, 3306]; + + if (preg_match("/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i", $domain) || in_array($port, $knownPorts)) { + $err = array("message" => "URL is not allowed"); + event_callback(array("fail" => $err)); + exit(); + } + + $use_curl = false; + $temp_file = tempnam(sys_get_temp_dir(), "upload-"); + $fileinfo = new stdClass(); + $fileinfo->name = trim(urldecode(basename($url)), ".\x00..\x20"); + + $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; + $ext = strtolower(pathinfo($fileinfo->name, PATHINFO_EXTENSION)); + $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; + + $err = false; + + if (!$isFileAllowed) { + $err = array("message" => "File extension is not allowed"); + event_callback(array("fail" => $err)); + exit(); + } + + if (!$url) { + $success = false; + } else if ($use_curl) { + @$fp = fopen($temp_file, "w"); + @$ch = curl_init($url); + curl_setopt($ch, CURLOPT_NOPROGRESS, false); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_FILE, $fp); + @$success = curl_exec($ch); + $curl_info = curl_getinfo($ch); + if (!$success) { + $err = array("message" => curl_error($ch)); + } + @curl_close($ch); + fclose($fp); + $fileinfo->size = $curl_info["size_download"]; + $fileinfo->type = $curl_info["content_type"]; + } else { + $ctx = stream_context_create(); + @$success = copy($url, $temp_file, $ctx); + if (!$success) { + $err = error_get_last(); + } + } + + if ($success) { + $success = rename($temp_file, strtok(get_file_path(), '?')); + } + + if ($success) { + event_callback(array("done" => $fileinfo)); + } else { + unlink($temp_file); + if (!$err) { + $err = array("message" => "Invalid url parameter"); + } + event_callback(array("fail" => $err)); + } + } + exit(); +} + +// Delete file / folder +if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) { + $del = str_replace('/', '', fm_clean_path($_GET['del'])); + if ($del != '' && $del != '..' && $del != '.' && verifyToken($_POST['token'])) { + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + $is_dir = is_dir($path . '/' . $del); + if (fm_rdelete($path . '/' . $del)) { + $msg = $is_dir ? lng('Folder') . ' %s ' . lng('Deleted') : lng('File') . ' %s ' . lng('Deleted'); + fm_set_msg(sprintf($msg, fm_enc($del))); + } else { + $msg = $is_dir ? lng('Folder') . ' %s ' . lng('not deleted') : lng('File') . ' %s ' . lng('not deleted'); + fm_set_msg(sprintf($msg, fm_enc($del)), 'error'); + } + } else { + fm_set_msg(lng('Invalid file or folder name'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Create a new file/folder +if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READONLY) { + $type = urldecode($_POST['newfile']); + $new = str_replace('/', '', fm_clean_path(strip_tags($_POST['newfilename']))); + if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.' && verifyToken($_POST['token'])) { + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + if ($type == "file") { + if (!file_exists($path . '/' . $new)) { + if (fm_is_valid_ext($new)) { + @fopen($path . '/' . $new, 'w') or die('Cannot open file: ' . $new); + fm_set_msg(sprintf(lng('File') . ' %s ' . lng('Created'), fm_enc($new))); + } else { + fm_set_msg(lng('File extension is not allowed'), 'error'); + } + } else { + fm_set_msg(sprintf(lng('File') . ' %s ' . lng('already exists'), fm_enc($new)), 'alert'); + } + } else { + if (fm_mkdir($path . '/' . $new, false) === true) { + fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('Created'), $new)); + } elseif (fm_mkdir($path . '/' . $new, false) === $path . '/' . $new) { + fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('already exists'), fm_enc($new)), 'alert'); + } else { + fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('not created'), fm_enc($new)), 'error'); + } + } + } else { + fm_set_msg(lng('Invalid characters in file or folder name'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Copy folder / file +if (isset($_GET['copy'], $_GET['finish']) && !FM_READONLY) { + // from + $copy = urldecode($_GET['copy']); + $copy = fm_clean_path($copy); + // empty path + if ($copy == '') { + fm_set_msg(lng('Source path not defined'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + // abs path from + $from = FM_ROOT_PATH . '/' . $copy; + // abs path to + $dest = FM_ROOT_PATH; + if (FM_PATH != '') { + $dest .= '/' . FM_PATH; + } + $dest .= '/' . basename($from); + // move? + $move = isset($_GET['move']); + $move = fm_clean_path(urldecode($move)); + // copy/move/duplicate + if ($from != $dest) { + $msg_from = trim(FM_PATH . '/' . basename($from), '/'); + if ($move) { // Move and to != from so just perform move + $rename = fm_rename($from, $dest); + if ($rename) { + fm_set_msg(sprintf(lng('Moved from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from))); + } elseif ($rename === null) { + fm_set_msg(lng('File or folder with this path already exists'), 'alert'); + } else { + fm_set_msg(sprintf(lng('Error while moving from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); + } + } else { // Not move and to != from so copy with original name + if (fm_rcopy($from, $dest)) { + fm_set_msg(sprintf(lng('Copied from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from))); + } else { + fm_set_msg(sprintf(lng('Error while copying from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); + } + } + } else { + if (!$move) { //Not move and to = from so duplicate + $msg_from = trim(FM_PATH . '/' . basename($from), '/'); + $fn_parts = pathinfo($from); + $extension_suffix = ''; + if (!is_dir($from)) { + $extension_suffix = '.' . $fn_parts['extension']; + } + //Create new name for duplicate + $fn_duplicate = $fn_parts['dirname'] . '/' . $fn_parts['filename'] . '-' . date('YmdHis') . $extension_suffix; + $loop_count = 0; + $max_loop = 1000; + // Check if a file with the duplicate name already exists, if so, make new name (edge case...) + while (file_exists($fn_duplicate) & $loop_count < $max_loop) { + $fn_parts = pathinfo($fn_duplicate); + $fn_duplicate = $fn_parts['dirname'] . '/' . $fn_parts['filename'] . '-copy' . $extension_suffix; + $loop_count++; + } + if (fm_rcopy($from, $fn_duplicate, False)) { + fm_set_msg(sprintf('Copied from %s to %s', fm_enc($copy), fm_enc($fn_duplicate))); + } else { + fm_set_msg(sprintf('Error while copying from %s to %s', fm_enc($copy), fm_enc($fn_duplicate)), 'error'); + } + } else { + fm_set_msg(lng('Paths must be not equal'), 'alert'); + } + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Mass copy files/ folders +if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token']) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng('Invalid Token.'), 'error'); + die("Invalid Token."); + } + + // from + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + // to + $copy_to_path = FM_ROOT_PATH; + $copy_to = fm_clean_path($_POST['copy_to']); + if ($copy_to != '') { + $copy_to_path .= '/' . $copy_to; + } + if ($path == $copy_to_path) { + fm_set_msg(lng('Paths must be not equal'), 'alert'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + if (!is_dir($copy_to_path)) { + if (!fm_mkdir($copy_to_path, true)) { + fm_set_msg('Unable to create destination folder', 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + } + // move? + $move = isset($_POST['move']); + // copy/move + $errors = 0; + $files = $_POST['file']; + if (is_array($files) && count($files)) { + foreach ($files as $f) { + if ($f != '') { + $f = fm_clean_path($f); + // abs path from + $from = $path . '/' . $f; + // abs path to + $dest = $copy_to_path . '/' . $f; + // do + if ($move) { + $rename = fm_rename($from, $dest); + if ($rename === false) { + $errors++; + } + } else { + if (!fm_rcopy($from, $dest)) { + $errors++; + } + } + } + } + if ($errors == 0) { + $msg = $move ? 'Selected files and folders moved' : 'Selected files and folders copied'; + fm_set_msg($msg); + } else { + $msg = $move ? 'Error while moving items' : 'Error while copying items'; + fm_set_msg($msg, 'error'); + } + } else { + fm_set_msg(lng('Nothing selected'), 'alert'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Rename +if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_READONLY) { + if (!verifyToken($_POST['token'])) { + fm_set_msg("Invalid Token.", 'error'); + die("Invalid Token."); + } + // old name + $old = urldecode($_POST['rename_from']); + $old = fm_clean_path($old); + $old = str_replace('/', '', $old); + // new name + $new = urldecode($_POST['rename_to']); + $new = fm_clean_path(strip_tags($new)); + $new = str_replace('/', '', $new); + // path + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + // rename + if (fm_isvalid_filename($new) && $old != '' && $new != '') { + if (fm_rename($path . '/' . $old, $path . '/' . $new)) { + fm_set_msg(sprintf(lng('Renamed from') . ' %s ' . lng('to') . ' %s', fm_enc($old), fm_enc($new))); + } else { + fm_set_msg(sprintf(lng('Error while renaming from') . ' %s ' . lng('to') . ' %s', fm_enc($old), fm_enc($new)), 'error'); + } + } else { + fm_set_msg(lng('Invalid characters in file name'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Download +if (isset($_GET['dl'], $_POST['token'])) { + // Verify the token to ensure it's valid + if (!verifyToken($_POST['token'])) { + fm_set_msg("Invalid Token.", 'error'); + exit; + } + + // Clean the download file path + $dl = urldecode($_GET['dl']); + $dl = fm_clean_path($dl); + $dl = str_replace('/', '', $dl); // Prevent directory traversal attacks + + // Define the file path + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + // Check if the file exists and is valid + if ($dl != '' && is_file($path . '/' . $dl)) { + // Close the session to prevent session locking + if (session_status() === PHP_SESSION_ACTIVE) { + session_write_close(); + } + + // Call the download function + fm_download_file($path . '/' . $dl, $dl, 1024); // Download with a buffer size of 1024 bytes + exit; + } else { + // Handle the case where the file is not found + fm_set_msg(lng('File not found'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } +} + +// Upload +if (!empty($_FILES) && !FM_READONLY) { + if (isset($_POST['token'])) { + if (!verifyToken($_POST['token'])) { + $response = array('status' => 'error', 'info' => "Invalid Token."); + echo json_encode($response); + exit(); + } + } else { + $response = array('status' => 'error', 'info' => "Token Missing."); + echo json_encode($response); + exit(); + } + + $chunkIndex = $_POST['dzchunkindex']; + $chunkTotal = $_POST['dztotalchunkcount']; + $fullPathInput = fm_clean_path($_REQUEST['fullpath']); + + $f = $_FILES; + $path = FM_ROOT_PATH; + $ds = DIRECTORY_SEPARATOR; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + $errors = 0; + $uploads = 0; + $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; + $response = array( + 'status' => 'error', + 'info' => 'Oops! Try again' + ); + + $filename = $f['file']['name']; + $tmp_name = $f['file']['tmp_name']; + $ext = pathinfo($filename, PATHINFO_FILENAME) != '' ? strtolower(pathinfo($filename, PATHINFO_EXTENSION)) : ''; + $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; + + if (!fm_isvalid_filename($filename) && !fm_isvalid_filename($fullPathInput)) { + $response = array( + 'status' => 'error', + 'info' => "Invalid File name!", + ); + echo json_encode($response); + exit(); + } + + $targetPath = $path . $ds; + if (is_writable($targetPath)) { + $fullPath = $path . '/' . $fullPathInput; + $folder = substr($fullPath, 0, strrpos($fullPath, "/")); + + if (!is_dir($folder)) { + $old = umask(0); + mkdir($folder, 0777, true); + umask($old); + } + + if (empty($f['file']['error']) && !empty($tmp_name) && $tmp_name != 'none' && $isFileAllowed) { + if ($chunkTotal) { + $out = @fopen("{$fullPath}.part", $chunkIndex == 0 ? "wb" : "ab"); + if ($out) { + $in = @fopen($tmp_name, "rb"); + if ($in) { + if (PHP_VERSION_ID < 80009) { + // workaround https://bugs.php.net/bug.php?id=81145 + do { + for (; ; ) { + $buff = fread($in, 4096); + if ($buff === false || $buff === '') { + break; + } + fwrite($out, $buff); + } + } while (!feof($in)); + } else { + stream_copy_to_stream($in, $out); + } + $response = array( + 'status' => 'success', + 'info' => "file upload successful" + ); + } else { + $response = array( + 'status' => 'error', + 'info' => "failed to open output stream", + 'errorDetails' => error_get_last() + ); + } + @fclose($in); + @fclose($out); + @unlink($tmp_name); + + $response = array( + 'status' => 'success', + 'info' => "file upload successful" + ); + } else { + $response = array( + 'status' => 'error', + 'info' => "failed to open output stream" + ); + } + + if ($chunkIndex == $chunkTotal - 1) { + if (file_exists($fullPath)) { + $ext_1 = $ext ? '.' . $ext : ''; + $fullPathTarget = $path . '/' . basename($fullPathInput, $ext_1) . '_' . date('ymdHis') . $ext_1; + } else { + $fullPathTarget = $fullPath; + } + rename("{$fullPath}.part", $fullPathTarget); + } + } else if (move_uploaded_file($tmp_name, $fullPath)) { + // Be sure that the file has been uploaded + if (file_exists($fullPath)) { + $response = array( + 'status' => 'success', + 'info' => "file upload successful" + ); + } else { + $response = array( + 'status' => 'error', + 'info' => 'Couldn\'t upload the requested file.' + ); + } + } else { + $response = array( + 'status' => 'error', + 'info' => "Error while uploading files. Uploaded files $uploads", + ); + } + } + } else { + $response = array( + 'status' => 'error', + 'info' => 'The specified folder for upload isn\'t writeable.' + ); + } + // Return the response + echo json_encode($response); + exit(); +} + +// Mass deleting +if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + $errors = 0; + $files = $_POST['file']; + if (is_array($files) && count($files)) { + foreach ($files as $f) { + if ($f != '') { + $new_path = $path . '/' . $f; + if (!fm_rdelete($new_path)) { + $errors++; + } + } + } + if ($errors == 0) { + fm_set_msg(lng('Selected files and folder deleted')); + } else { + fm_set_msg(lng('Error while deleting items'), 'error'); + } + } else { + fm_set_msg(lng('Nothing selected'), 'alert'); + } + + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Pack files zip, tar +if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $path = FM_ROOT_PATH; + $ext = 'zip'; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + //set pack type + $ext = isset($_POST['tar']) ? 'tar' : 'zip'; + + if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { + fm_set_msg(lng('Operations with archives are not available'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + + $files = $_POST['file']; + $sanitized_files = array(); + + // clean path + foreach ($files as $file) { + array_push($sanitized_files, fm_clean_path($file)); + } + + $files = $sanitized_files; + + if (!empty($files)) { + chdir($path); + + if (count($files) == 1) { + $one_file = reset($files); + $one_file = basename($one_file); + $zipname = $one_file . '_' . date('ymd_His') . '.' . $ext; + } else { + $zipname = 'archive_' . date('ymd_His') . '.' . $ext; + } + + if ($ext == 'zip') { + $zipper = new FM_Zipper(); + $res = $zipper->create($zipname, $files); + } elseif ($ext == 'tar') { + $tar = new FM_Zipper_Tar(); + $res = $tar->create($zipname, $files); + } + + if ($res) { + fm_set_msg(sprintf(lng('Archive') . ' %s ' . lng('Created'), fm_enc($zipname))); + } else { + fm_set_msg(lng('Archive not created'), 'error'); + } + } else { + fm_set_msg(lng('Nothing selected'), 'alert'); + } + + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Unpack zip, tar +if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $unzip = urldecode($_POST['unzip']); + $unzip = fm_clean_path($unzip); + $unzip = str_replace('/', '', $unzip); + $isValid = false; + + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + if ($unzip != '' && is_file($path . '/' . $unzip)) { + $zip_path = $path . '/' . $unzip; + $ext = pathinfo($zip_path, PATHINFO_EXTENSION); + $isValid = true; + } else { + fm_set_msg(lng('File not found'), 'error'); + } + + if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { + fm_set_msg(lng('Operations with archives are not available'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + + if ($isValid) { + //to folder + $tofolder = ''; + if (isset($_POST['tofolder'])) { + $tofolder = pathinfo($zip_path, PATHINFO_FILENAME); + if (fm_mkdir($path . '/' . $tofolder, true)) { + $path .= '/' . $tofolder; + } + } + + if ($ext == "zip") { + $zipper = new FM_Zipper(); + $res = $zipper->unzip($zip_path, $path); + } elseif ($ext == "tar") { + try { + $gzipper = new PharData($zip_path); + if (@$gzipper->extractTo($path, null, true)) { + $res = true; + } else { + $res = false; + } + } catch (Exception $e) { + //TODO:: need to handle the error + $res = true; + } + } + + if ($res) { + fm_set_msg(lng('Archive unpacked')); + } else { + fm_set_msg(lng('Archive not unpacked'), 'error'); + } + } else { + fm_set_msg(lng('File not found'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Change Perms (not for Windows) +if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + $file = $_POST['chmod']; + $file = fm_clean_path($file); + $file = str_replace('/', '', $file); + if ($file == '' || (!is_file($path . '/' . $file) && !is_dir($path . '/' . $file))) { + fm_set_msg(lng('File not found'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + + $mode = 0; + if (!empty($_POST['ur'])) { + $mode |= 0400; + } + if (!empty($_POST['uw'])) { + $mode |= 0200; + } + if (!empty($_POST['ux'])) { + $mode |= 0100; + } + if (!empty($_POST['gr'])) { + $mode |= 0040; + } + if (!empty($_POST['gw'])) { + $mode |= 0020; + } + if (!empty($_POST['gx'])) { + $mode |= 0010; + } + if (!empty($_POST['or'])) { + $mode |= 0004; + } + if (!empty($_POST['ow'])) { + $mode |= 0002; + } + if (!empty($_POST['ox'])) { + $mode |= 0001; + } + + if (@chmod($path . '/' . $file, $mode)) { + fm_set_msg(lng('Permissions changed')); + } else { + fm_set_msg(lng('Permissions not changed'), 'error'); + } + + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +/*************************** ACTIONS ***************************/ + +// get current path +$path = FM_ROOT_PATH; +if (FM_PATH != '') { + $path .= '/' . FM_PATH; +} + +// check path +if (!is_dir($path)) { + fm_redirect(FM_SELF_URL . '?p='); +} + +// get parent folder +$parent = fm_get_parent_path(FM_PATH); + +$objects = is_readable($path) ? scandir($path) : array(); +$folders = array(); +$files = array(); +$current_path = array_slice(explode("/", $path), -1)[0]; +if (is_array($objects) && fm_is_exclude_items($current_path, $path)) { + foreach ($objects as $file) { + if ($file == '.' || $file == '..') { + continue; + } + if (!FM_SHOW_HIDDEN && substr($file, 0, 1) === '.') { + continue; + } + $new_path = $path . '/' . $file; + if (@is_file($new_path) && fm_is_exclude_items($file, $new_path)) { + $files[] = $file; + } elseif (@is_dir($new_path) && $file != '.' && $file != '..' && fm_is_exclude_items($file, $new_path)) { + $folders[] = $file; + } + } +} + +if (!empty($files)) { + natcasesort($files); +} +if (!empty($folders)) { + natcasesort($folders); +} + +// upload form +if (isset($_GET['upload']) && !FM_READONLY) { + fm_show_header(); // HEADER + fm_show_nav_path(FM_PATH); // current path + //get the allowed file extensions + function getUploadExt() + { + $extArr = explode(',', FM_UPLOAD_EXTENSION); + if (FM_UPLOAD_EXTENSION && $extArr) { + array_walk($extArr, function (&$x) { + $x = ".$x"; + }); + return implode(',', $extArr); + } + return ''; + } + ?> + +
+ +
+
+ +
+
+

+ + + : +

+ +
+ + + +
+ +
+
+ + +
+
+
+ + + +
+
+
+
+
+
+
+ + + ' . PHP_EOL; + } + ?> +

: + , ', $copy_files) ?> +

+

: +
+ + / +

+

+ +

+

+   + + +

+ +
+
+
+ +
+

Copying

+

+ Source path:
+ Destination folder: +

+

+ Copy   + Move   + + Cancel +

+

+
    + +
  • ..
  • + +
  • + +
  • + +
+
+ + +
+
+
+ + + +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ /> +
+
+
+ +
+ +
+
+ /> +
+
+
+ +
+ +
+
+ /> +
+
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+ + * + . +
+
+
+
+ + +
+
+
+ + + +
+
+
+
+

+

+ Tiny File Manager

+

+

Author: PRAŚATH MANİ

+

Mail Us: ccpprogrammers [at] gmail [dot] com

+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
    +
  • : +
  • + +
  • : +
  • +
  • : +
  • +
  • : +
  • +
  • :
  • + +
  • :
  • +
  • : +
  • +
  • : + +
  • +
  • : + % +
  • + ' . lng('Image size') . ': ' . (isset($image_size[0]) ? $image_size[0] : '0') . ' x ' . (isset($image_size[1]) ? $image_size[1] : '0') . ''; + } + // Text info + if ($is_text) { + $is_utf8 = fm_is_utf8($content); + if (function_exists('iconv')) { + if (!$is_utf8) { + $content = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $content); + } + } + echo '
  • ' . lng('Charset') . ': ' . ($is_utf8 ? 'utf-8' : '8 bit') . '
  • '; + } + ?> +
+
+
+ +   +
+ + + Delete + +
+ +
+ + + +
+
+ + + + +
+ + + + + + + + +
+
+ '; + } else if ($online_viewer == 'microsoft') { + echo ''; + } + } elseif ($is_zip) { + // ZIP content + if ($filenames !== false) { + echo ''; + foreach ($filenames as $fn) { + if ($fn['folder']) { + echo '' . fm_enc($fn['name']) . '
'; + } else { + echo $fn['name'] . ' (' . fm_get_filesize($fn['filesize']) . ')
'; + } + } + echo '
'; + } else { + echo '

' . lng('Error while fetching archive info') . '

'; + } + } elseif ($is_image) { + // Image content + if (in_array($ext, array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'ico', 'svg', 'webp', 'avif'))) { + echo '

'; + } + } elseif ($is_audio) { + // Audio content + echo '

'; + } elseif ($is_video) { + // Video content + echo '
'; + } elseif ($is_text) { + if (FM_USE_HIGHLIGHTJS) { + // highlight + $hljs_classes = array( + 'shtml' => 'xml', + 'htaccess' => 'apache', + 'phtml' => 'php', + 'lock' => 'json', + 'svg' => 'xml', + ); + $hljs_class = isset($hljs_classes[$ext]) ? 'lang-' . $hljs_classes[$ext] : 'lang-' . $ext; + if (empty($ext) || in_array(strtolower($file), fm_get_text_names()) || preg_match('#\.min\.(css|js)$#i', $file)) { + $hljs_class = 'nohighlight'; + } + $content = '
' . fm_enc($content) . '
'; + } elseif (in_array($ext, array('php', 'php4', 'php5', 'phtml', 'phps'))) { + // php highlight + $content = highlight_string($content, true); + } else { + $content = '
' . fm_enc($content) . '
'; + } + echo $content; + } + ?> +
+
+
+ ' . $file . ''; + header('X-XSS-Protection:0'); + fm_show_header(); // HEADER + fm_show_nav_path(FM_PATH); // current path + + $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ? '/' . FM_PATH : '') . '/' . $file); + $file_path = $path . '/' . $file; + + // normal editer + $isNormalEditor = true; + if (isset($_GET['env'])) { + if ($_GET['env'] == "ace") { + $isNormalEditor = false; + } + } + + // Save File + if (isset($_POST['savedata'])) { + $writedata = $_POST['savedata']; + $fd = fopen($file_path, "w"); + @fwrite($fd, $writedata); + fclose($fd); + fm_set_msg(lng('File Saved Successfully')); + } + + $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); + $mime_type = fm_get_mime_type($file_path); + $filesize = filesize($file_path); + $is_text = false; + $content = ''; // for text + + if (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0, 4) == 'text' || in_array($mime_type, fm_get_text_mimes())) { + $is_text = true; + $content = file_get_contents($file_path); + } + + ?> +
+
+
+ +
+
+
+ + + + + + + + + + + +
+
+
+ ' . htmlspecialchars($content) . ''; + echo ''; + } elseif ($is_text) { + echo '
' . htmlspecialchars($content) . '
'; + } else { + fm_set_msg(lng('FILE EXTENSION HAS NOT SUPPORTED'), 'error'); + } + ?> +
+ +
+
+
+ +
+
+

+ + :
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

+ +   + +

+
+
+
+
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + '?'); + $group = array('name' => '?'); + if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) { + try { + $owner_id = fileowner($path . '/' . $f); + if ($owner_id != 0) { + $owner_info = posix_getpwuid($owner_id); + if ($owner_info) { + $owner = $owner_info; + } + } + $group_id = filegroup($path . '/' . $f); + $group_info = posix_getgrgid($group_id); + if ($group_info) { + $group = $group_info; + } + } catch (Exception $e) { + error_log("exception:" . $e->getMessage()); + } + } + ?> + + + + + + + + + + + + + + '?'); + $group = array('name' => '?'); + if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) { + try { + $owner_id = fileowner($path . '/' . $f); + if ($owner_id != 0) { + $owner_info = posix_getpwuid($owner_id); + if ($owner_info) { + $owner = $owner_info; + } + } + $group_id = filegroup($path . '/' . $f); + $group_info = posix_getgrgid($group_id); + if ($group_info) { + $group = $group_info; + } + } catch (Exception $e) { + error_log("exception:" . $e->getMessage()); + } + } + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
..
+
+ + +
+
> +
+ + ' . readlink($path . '/' . $f) . '' : '') ?> +
+
"> + + + + + + + + + + + + +
+
+ + +
+
> +
+ + + + + + + + + ' . readlink($path . '/' . $f) . '' : '') ?> +
+
"> + + + + + + + + + + + +
+ +
+ ' . fm_get_filesize($all_files_size) . '' ?> + ' . $num_files . '' ?> + ' . $num_folders . '' ?> +
+
+ + +
+ +"; + return; + } + + echo "$external[$key]"; +} + +/** + * Verify CSRF TOKEN and remove after certified + * @param string $token + * @return bool + */ +function verifyToken($token) +{ + if (hash_equals($_SESSION['token'], $token)) { + return true; + } + return false; +} + +/** + * Delete file or folder (recursively) + * @param string $path + * @return bool + */ +function fm_rdelete($path) +{ + if (is_link($path)) { + return unlink($path); + } elseif (is_dir($path)) { + $objects = scandir($path); + $ok = true; + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (!fm_rdelete($path . '/' . $file)) { + $ok = false; + } + } + } + } + return ($ok) ? rmdir($path) : false; + } elseif (is_file($path)) { + return unlink($path); + } + return false; +} + +/** + * Recursive chmod + * @param string $path + * @param int $filemode + * @param int $dirmode + * @return bool + * @todo Will use in mass chmod + */ +function fm_rchmod($path, $filemode, $dirmode) +{ + if (is_dir($path)) { + if (!chmod($path, $dirmode)) { + return false; + } + $objects = scandir($path); + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (!fm_rchmod($path . '/' . $file, $filemode, $dirmode)) { + return false; + } + } + } + } + return true; + } elseif (is_link($path)) { + return true; + } elseif (is_file($path)) { + return chmod($path, $filemode); + } + return false; +} + +/** + * Check the file extension which is allowed or not + * @param string $filename + * @return bool + */ +function fm_is_valid_ext($filename) +{ + $allowed = (FM_FILE_EXTENSION) ? explode(',', FM_FILE_EXTENSION) : false; + + $ext = pathinfo($filename, PATHINFO_EXTENSION); + $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; + + return ($isFileAllowed) ? true : false; +} + +/** + * Safely rename + * @param string $old + * @param string $new + * @return bool|null + */ +function fm_rename($old, $new) +{ + $isFileAllowed = fm_is_valid_ext($new); + + if (!is_dir($old)) { + if (!$isFileAllowed) + return false; + } + + return (!file_exists($new) && file_exists($old)) ? rename($old, $new) : null; +} + +/** + * Copy file or folder (recursively). + * @param string $path + * @param string $dest + * @param bool $upd Update files + * @param bool $force Create folder with same names instead file + * @return bool + */ +function fm_rcopy($path, $dest, $upd = true, $force = true) +{ + if (!is_dir($path) && !is_file($path)) { + return false; + } + + if (is_dir($path)) { + if (!fm_mkdir($dest, $force)) { + return false; + } + + $objects = array_diff(scandir($path), ['.', '..']); + + foreach ($objects as $file) { + if (!fm_rcopy("$path/$file", "$dest/$file", $upd, $force)) { + return false; + } + } + + return true; + } + + // Handle file copying + return fm_copy($path, $dest, $upd); +} + + +/** + * Safely create folder + * @param string $dir + * @param bool $force + * @return bool + */ +function fm_mkdir($dir, $force) +{ + if (file_exists($dir)) { + if (is_dir($dir)) { + return $dir; + } elseif (!$force) { + return false; + } + unlink($dir); + } + return mkdir($dir, 0777, true); +} + +/** + * Safely copy file + * @param string $f1 + * @param string $f2 + * @param bool $upd Indicates if file should be updated with new content + * @return bool + */ +function fm_copy($f1, $f2, $upd) +{ + $time1 = filemtime($f1); + if (file_exists($f2)) { + $time2 = filemtime($f2); + if ($time2 >= $time1 && $upd) { + return false; + } + } + $ok = copy($f1, $f2); + if ($ok) { + touch($f2, $time1); + } + return $ok; +} + +/** + * Get mime type + * @param string $file_path + * @return mixed|string + */ +function fm_get_mime_type($file_path) +{ + if (function_exists('finfo_open')) { + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mime = finfo_file($finfo, $file_path); + finfo_close($finfo); + return $mime; + } elseif (function_exists('mime_content_type')) { + return mime_content_type($file_path); + } elseif (!stristr(ini_get('disable_functions'), 'shell_exec')) { + $file = escapeshellarg($file_path); + $mime = shell_exec('file -bi ' . $file); + return $mime; + } else { + return '--'; + } +} + +/** + * HTTP Redirect + * @param string $url + * @param int $code + */ +function fm_redirect($url, $code = 302) +{ + header('Location: ' . $url, true, $code); + exit; +} + +/** + * Path traversal prevention and clean the url + * It replaces (consecutive) occurrences of / and \\ with whatever is in DIRECTORY_SEPARATOR, and processes /. and /.. fine. + * @param $path + * @return string + */ +function get_absolute_path($path) +{ + $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); + $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); + $absolutes = array(); + foreach ($parts as $part) { + if ('.' == $part) + continue; + if ('..' == $part) { + array_pop($absolutes); + } else { + $absolutes[] = $part; + } + } + return implode(DIRECTORY_SEPARATOR, $absolutes); +} + +/** + * Clean path + * @param string $path + * @return string + */ +function fm_clean_path($path, $trim = true) +{ + $path = $trim ? trim($path) : $path; + $path = trim($path, '\\/'); + $path = str_replace(array('../', '..\\'), '', $path); + $path = get_absolute_path($path); + if ($path == '..') { + $path = ''; + } + return str_replace('\\', '/', $path); +} + +/** + * Get parent path + * @param string $path + * @return bool|string + */ +function fm_get_parent_path($path) +{ + $path = fm_clean_path($path); + if ($path != '') { + $array = explode('/', $path); + if (count($array) > 1) { + $array = array_slice($array, 0, -1); + return implode('/', $array); + } + return ''; + } + return false; +} + +function fm_get_display_path($file_path) +{ + global $path_display_mode, $root_path, $root_url; + switch ($path_display_mode) { + case 'relative': + return array( + 'label' => 'Path', + 'path' => fm_enc(fm_convert_win(str_replace($root_path, '', $file_path))) + ); + case 'host': + $relative_path = str_replace($root_path, '', $file_path); + return array( + 'label' => 'Host Path', + 'path' => fm_enc(fm_convert_win('/' . $root_url . '/' . ltrim(str_replace('\\', '/', $relative_path), '/'))) + ); + case 'full': + default: + return array( + 'label' => 'Full Path', + 'path' => fm_enc(fm_convert_win($file_path)) + ); + } +} + +/** + * Check file is in exclude list + * @param string $name The name of the file/folder + * @param string $path The full path of the file/folder + * @return bool + */ +function fm_is_exclude_items($name, $path) +{ + $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + if (isset($exclude_items) and sizeof($exclude_items)) { + unset($exclude_items); + } + + $exclude_items = FM_EXCLUDE_ITEMS; + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + $exclude_items = unserialize($exclude_items); + } + if (!in_array($name, $exclude_items) && !in_array("*.$ext", $exclude_items) && !in_array($path, $exclude_items)) { + return true; + } + return false; +} + +/** + * get language translations from json file + * @param int $tr + * @return array + */ +function fm_get_translations($tr) +{ + try { + $content = @file_get_contents('translation.json'); + if ($content !== FALSE) { + $lng = json_decode($content, TRUE); + global $lang_list; + foreach ($lng["language"] as $key => $value) { + $code = $value["code"]; + $lang_list[$code] = $value["name"]; + if ($tr) + $tr[$code] = $value["translation"]; + } + return $tr; + } + } catch (Exception $e) { + echo $e; + } +} + +/** + * @param string $file + * Recover all file sizes larger than > 2GB. + * Works on php 32bits and 64bits and supports linux + * @return int|string + */ +function fm_get_size($file) +{ + static $iswin = null; + static $isdarwin = null; + static $exec_works = null; + + // Set static variables once + if ($iswin === null) { + $iswin = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + $isdarwin = strtoupper(PHP_OS) === 'DARWIN'; + $exec_works = function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') === 'EXEC'; + } + + // Attempt shell command if exec is available + if ($exec_works) { + $arg = escapeshellarg($file); + $cmd = $iswin ? "for %F in (\"$file\") do @echo %~zF" : ($isdarwin ? "stat -f%z $arg" : "stat -c%s $arg"); + @exec($cmd, $output); + + if (!empty($output) && ctype_digit($size = trim(implode("\n", $output)))) { + return $size; + } + } + + // Attempt Windows COM interface for Windows systems + if ($iswin && class_exists('COM')) { + try { + $fsobj = new COM('Scripting.FileSystemObject'); + $f = $fsobj->GetFile(realpath($file)); + if (ctype_digit($size = $f->Size)) { + return $size; + } + } catch (Exception $e) { + // COM failed, fallback to filesize + } + } + + // Default to PHP's filesize function + return filesize($file); +} + + +/** + * Get nice filesize + * @param int $size + * @return string + */ +function fm_get_filesize($size) +{ + $size = (float) $size; + $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + $power = ($size > 0) ? floor(log($size, 1024)) : 0; + $power = ($power > (count($units) - 1)) ? (count($units) - 1) : $power; + return sprintf('%s %s', round($size / pow(1024, $power), 2), $units[$power]); +} + +/** + * Get info about zip archive + * @param string $path + * @return array|bool + */ +function fm_get_zif_info($path, $ext) +{ + if ($ext == 'zip' && function_exists('zip_open')) { + $arch = @zip_open($path); + if ($arch) { + $filenames = array(); + while ($zip_entry = @zip_read($arch)) { + $zip_name = @zip_entry_name($zip_entry); + $zip_folder = substr($zip_name, -1) == '/'; + $filenames[] = array( + 'name' => $zip_name, + 'filesize' => @zip_entry_filesize($zip_entry), + 'compressed_size' => @zip_entry_compressedsize($zip_entry), + 'folder' => $zip_folder + //'compression_method' => zip_entry_compressionmethod($zip_entry), + ); + } + @zip_close($arch); + return $filenames; + } + } elseif ($ext == 'tar' && class_exists('PharData')) { + $archive = new PharData($path); + $filenames = array(); + foreach (new RecursiveIteratorIterator($archive) as $file) { + $parent_info = $file->getPathInfo(); + $zip_name = str_replace("phar://" . $path, '', $file->getPathName()); + $zip_name = substr($zip_name, ($pos = strpos($zip_name, '/')) !== false ? $pos + 1 : 0); + $zip_folder = $parent_info->getFileName(); + $zip_info = new SplFileInfo($file); + $filenames[] = array( + 'name' => $zip_name, + 'filesize' => $zip_info->getSize(), + 'compressed_size' => $file->getCompressedSize(), + 'folder' => $zip_folder + ); + } + return $filenames; + } + return false; +} + +/** + * Encode html entities + * @param string $text + * @return string + */ +function fm_enc($text) +{ + return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); +} + +/** + * Prevent XSS attacks + * @param string $text + * @return string + */ +function fm_isvalid_filename($text) +{ + return (strpbrk($text, '/?%*:|"<>') === FALSE) ? true : false; +} + +/** + * Save message in session + * @param string $msg + * @param string $status + */ +function fm_set_msg($msg, $status = 'ok') +{ + $_SESSION[FM_SESSION_ID]['message'] = $msg; + $_SESSION[FM_SESSION_ID]['status'] = $status; +} + +/** + * Check if string is in UTF-8 + * @param string $string + * @return int + */ +function fm_is_utf8($string) +{ + return preg_match('//u', $string); +} + +/** + * Convert file name to UTF-8 in Windows + * @param string $filename + * @return string + */ +function fm_convert_win($filename) +{ + if (FM_IS_WIN && function_exists('iconv')) { + $filename = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $filename); + } + return $filename; +} + +/** + * @param $obj + * @return array + */ +function fm_object_to_array($obj) +{ + if (!is_object($obj) && !is_array($obj)) { + return $obj; + } + if (is_object($obj)) { + $obj = get_object_vars($obj); + } + return array_map('fm_object_to_array', $obj); +} + +/** + * Get CSS classname for file + * @param string $path + * @return string + */ +function fm_get_file_icon_class($path) +{ + // get extension + $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + + switch ($ext) { + case 'ico': + case 'gif': + case 'jpg': + case 'jpeg': + case 'jpc': + case 'jp2': + case 'jpx': + case 'xbm': + case 'wbmp': + case 'png': + case 'bmp': + case 'tif': + case 'tiff': + case 'webp': + case 'avif': + case 'svg': + $img = 'fa fa-picture-o'; + break; + case 'passwd': + case 'ftpquota': + case 'sql': + case 'js': + case 'ts': + case 'jsx': + case 'tsx': + case 'hbs': + case 'json': + case 'sh': + case 'config': + case 'twig': + case 'tpl': + case 'md': + case 'gitignore': + case 'c': + case 'cpp': + case 'cs': + case 'py': + case 'rs': + case 'map': + case 'lock': + case 'dtd': + case 'ps1': + $img = 'fa fa-file-code-o'; + break; + case 'txt': + case 'ini': + case 'conf': + case 'log': + case 'htaccess': + case 'yaml': + case 'yml': + case 'toml': + case 'tmp': + case 'top': + case 'bot': + case 'dat': + case 'bak': + case 'htpasswd': + case 'pl': + $img = 'fa fa-file-text-o'; + break; + case 'css': + case 'less': + case 'sass': + case 'scss': + $img = 'fa fa-css3'; + break; + case 'bz2': + case 'tbz2': + case 'tbz': + case 'zip': + case 'rar': + case 'gz': + case 'tgz': + case 'tar': + case '7z': + case 'xz': + case 'txz': + case 'zst': + case 'tzst': + $img = 'fa fa-file-archive-o'; + break; + case 'php': + case 'php4': + case 'php5': + case 'phps': + case 'phtml': + $img = 'fa fa-code'; + break; + case 'htm': + case 'html': + case 'shtml': + case 'xhtml': + $img = 'fa fa-html5'; + break; + case 'xml': + case 'xsl': + $img = 'fa fa-file-excel-o'; + break; + case 'wav': + case 'mp3': + case 'mp2': + case 'm4a': + case 'aac': + case 'ogg': + case 'oga': + case 'wma': + case 'mka': + case 'flac': + case 'ac3': + case 'tds': + $img = 'fa fa-music'; + break; + case 'm3u': + case 'm3u8': + case 'pls': + case 'cue': + case 'xspf': + $img = 'fa fa-headphones'; + break; + case 'avi': + case 'mpg': + case 'mpeg': + case 'mp4': + case 'm4v': + case 'flv': + case 'f4v': + case 'ogm': + case 'ogv': + case 'mov': + case 'mkv': + case '3gp': + case 'asf': + case 'wmv': + case 'webm': + $img = 'fa fa-file-video-o'; + break; + case 'eml': + case 'msg': + $img = 'fa fa-envelope-o'; + break; + case 'xls': + case 'xlsx': + case 'ods': + $img = 'fa fa-file-excel-o'; + break; + case 'csv': + $img = 'fa fa-file-text-o'; + break; + case 'bak': + case 'swp': + $img = 'fa fa-clipboard'; + break; + case 'doc': + case 'docx': + case 'odt': + $img = 'fa fa-file-word-o'; + break; + case 'ppt': + case 'pptx': + $img = 'fa fa-file-powerpoint-o'; + break; + case 'ttf': + case 'ttc': + case 'otf': + case 'woff': + case 'woff2': + case 'eot': + case 'fon': + $img = 'fa fa-font'; + break; + case 'pdf': + $img = 'fa fa-file-pdf-o'; + break; + case 'psd': + case 'ai': + case 'eps': + case 'fla': + case 'swf': + $img = 'fa fa-file-image-o'; + break; + case 'exe': + case 'msi': + $img = 'fa fa-file-o'; + break; + case 'bat': + $img = 'fa fa-terminal'; + break; + default: + $img = 'fa fa-info-circle'; + } + + return $img; +} + +/** + * Get image files extensions + * @return array + */ +function fm_get_image_exts() +{ + return array('ico', 'gif', 'jpg', 'jpeg', 'jpc', 'jp2', 'jpx', 'xbm', 'wbmp', 'png', 'bmp', 'tif', 'tiff', 'psd', 'svg', 'webp', 'avif'); +} + +/** + * Get video files extensions + * @return array + */ +function fm_get_video_exts() +{ + return array('avi', 'webm', 'wmv', 'mp4', 'm4v', 'ogm', 'ogv', 'mov', 'mkv'); +} + +/** + * Get audio files extensions + * @return array + */ +function fm_get_audio_exts() +{ + return array('wav', 'mp3', 'ogg', 'm4a'); +} + +/** + * Get text file extensions + * @return array + */ +function fm_get_text_exts() +{ + return array( + 'txt', + 'css', + 'ini', + 'conf', + 'log', + 'htaccess', + 'passwd', + 'ftpquota', + 'sql', + 'js', + 'ts', + 'jsx', + 'tsx', + 'mjs', + 'json', + 'sh', + 'config', + 'php', + 'php4', + 'php5', + 'phps', + 'phtml', + 'htm', + 'html', + 'shtml', + 'xhtml', + 'xml', + 'xsl', + 'm3u', + 'm3u8', + 'pls', + 'cue', + 'bash', + 'vue', + 'eml', + 'msg', + 'csv', + 'bat', + 'twig', + 'tpl', + 'md', + 'gitignore', + 'less', + 'sass', + 'scss', + 'c', + 'cpp', + 'cs', + 'py', + 'go', + 'zsh', + 'swift', + 'map', + 'lock', + 'dtd', + 'svg', + 'asp', + 'aspx', + 'asx', + 'asmx', + 'ashx', + 'jsp', + 'jspx', + 'cgi', + 'dockerfile', + 'ruby', + 'yml', + 'yaml', + 'toml', + 'vhost', + 'scpt', + 'applescript', + 'csx', + 'cshtml', + 'c++', + 'coffee', + 'cfm', + 'rb', + 'graphql', + 'mustache', + 'jinja', + 'http', + 'handlebars', + 'java', + 'es', + 'es6', + 'markdown', + 'wiki', + 'tmp', + 'top', + 'bot', + 'dat', + 'bak', + 'htpasswd', + 'pl', + 'ps1' + ); +} + +/** + * Get mime types of text files + * @return array + */ +function fm_get_text_mimes() +{ + return array( + 'application/xml', + 'application/javascript', + 'application/x-javascript', + 'image/svg+xml', + 'message/rfc822', + 'application/json', + ); +} + +/** + * Get file names of text files w/o extensions + * @return array + */ +function fm_get_text_names() +{ + return array( + 'license', + 'readme', + 'authors', + 'contributors', + 'changelog', + ); +} + +/** + * Get online docs viewer supported files extensions + * @return array + */ +function fm_get_onlineViewer_exts() +{ + return array('doc', 'docx', 'xls', 'xlsx', 'pdf', 'ppt', 'pptx', 'ai', 'psd', 'dxf', 'xps', 'rar', 'odt', 'ods'); +} + +/** + * It returns the mime type of a file based on its extension. + * @param extension The file extension of the file you want to get the mime type for. + * @return string|string[] The mime type of the file. + */ +function fm_get_file_mimes($extension) +{ + $fileTypes['swf'] = 'application/x-shockwave-flash'; + $fileTypes['pdf'] = 'application/pdf'; + $fileTypes['exe'] = 'application/octet-stream'; + $fileTypes['zip'] = 'application/zip'; + $fileTypes['doc'] = 'application/msword'; + $fileTypes['xls'] = 'application/vnd.ms-excel'; + $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; + $fileTypes['gif'] = 'image/gif'; + $fileTypes['png'] = 'image/png'; + $fileTypes['jpeg'] = 'image/jpg'; + $fileTypes['jpg'] = 'image/jpg'; + $fileTypes['webp'] = 'image/webp'; + $fileTypes['avif'] = 'image/avif'; + $fileTypes['rar'] = 'application/rar'; + + $fileTypes['ra'] = 'audio/x-pn-realaudio'; + $fileTypes['ram'] = 'audio/x-pn-realaudio'; + $fileTypes['ogg'] = 'audio/x-pn-realaudio'; + + $fileTypes['wav'] = 'video/x-msvideo'; + $fileTypes['wmv'] = 'video/x-msvideo'; + $fileTypes['avi'] = 'video/x-msvideo'; + $fileTypes['asf'] = 'video/x-msvideo'; + $fileTypes['divx'] = 'video/x-msvideo'; + + $fileTypes['mp3'] = 'audio/mpeg'; + $fileTypes['mp4'] = 'video/mp4'; + $fileTypes['mpeg'] = 'video/mpeg'; + $fileTypes['mpg'] = 'video/mpeg'; + $fileTypes['mpe'] = 'video/mpeg'; + $fileTypes['mov'] = 'video/quicktime'; + $fileTypes['swf'] = 'video/quicktime'; + $fileTypes['3gp'] = 'video/quicktime'; + $fileTypes['m4a'] = 'video/quicktime'; + $fileTypes['aac'] = 'video/quicktime'; + $fileTypes['m3u'] = 'video/quicktime'; + + $fileTypes['php'] = ['application/x-php']; + $fileTypes['html'] = ['text/html']; + $fileTypes['txt'] = ['text/plain']; + //Unknown mime-types should be 'application/octet-stream' + if (empty($fileTypes[$extension])) { + $fileTypes[$extension] = ['application/octet-stream']; + } + return $fileTypes[$extension]; +} + +/** + * This function scans the files and folder recursively, and return matching files + * @param string $dir + * @param string $filter + * @return array|null + */ +function scan($dir = '', $filter = '') +{ + $path = FM_ROOT_PATH . '/' . $dir; + if ($path) { + $ite = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); + $rii = new RegexIterator($ite, "/(" . $filter . ")/i"); + + $files = array(); + foreach ($rii as $file) { + if (!$file->isDir()) { + $fileName = $file->getFilename(); + $location = str_replace(FM_ROOT_PATH, '', $file->getPath()); + $files[] = array( + "name" => $fileName, + "type" => "file", + "path" => $location, + ); + } + } + return $files; + } +} + +/** + * Parameters: downloadFile(File Location, File Name, + * max speed, is streaming + * If streaming - videos will show as videos, images as images + * instead of download prompt + * https://stackoverflow.com/a/13821992/1164642 + */ +function fm_download_file($fileLocation, $fileName, $chunkSize = 1024) +{ + if (connection_status() != 0) + return (false); + $extension = pathinfo($fileName, PATHINFO_EXTENSION); + + $contentType = fm_get_file_mimes($extension); + + if (is_array($contentType)) { + $contentType = implode(' ', $contentType); + } + + $size = filesize($fileLocation); + + if ($size == 0) { + fm_set_msg(lng('Zero byte file! Aborting download'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + + return (false); + } + + @ini_set('magic_quotes_runtime', 0); + $fp = fopen("$fileLocation", "rb"); + + if ($fp === false) { + fm_set_msg(lng('Cannot open file! Aborting download'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + return (false); + } + + // headers + header('Content-Description: File Transfer'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + header("Content-Transfer-Encoding: binary"); + header("Content-Type: $contentType"); + + $contentDisposition = 'attachment'; + + if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { + $fileName = preg_replace('/\./', '%2e', $fileName, substr_count($fileName, '.') - 1); + header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); + } else { + header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); + } + + header("Accept-Ranges: bytes"); + $range = 0; + + if (isset($_SERVER['HTTP_RANGE'])) { + list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']); + str_replace($range, "-", $range); + $size2 = $size - 1; + $new_length = $size - $range; + header("HTTP/1.1 206 Partial Content"); + header("Content-Length: $new_length"); + header("Content-Range: bytes $range$size2/$size"); + } else { + $size2 = $size - 1; + header("Content-Range: bytes 0-$size2/$size"); + header("Content-Length: " . $size); + } + $fileLocation = realpath($fileLocation); + while (ob_get_level()) + ob_end_clean(); + readfile($fileLocation); + + fclose($fp); + + return ((connection_status() == 0) and !connection_aborted()); +} + +/** + * Class to work with zip files (using ZipArchive) + */ +class FM_Zipper +{ + private $zip; + + public function __construct() + { + $this->zip = new ZipArchive(); + } + + /** + * Create archive with name $filename and files $files (RELATIVE PATHS!) + * @param string $filename + * @param array|string $files + * @return bool + */ + public function create($filename, $files) + { + $res = $this->zip->open($filename, ZipArchive::CREATE); + if ($res !== true) { + return false; + } + if (is_array($files)) { + foreach ($files as $f) { + $f = fm_clean_path($f); + if (!$this->addFileOrDir($f)) { + $this->zip->close(); + return false; + } + } + $this->zip->close(); + return true; + } else { + if ($this->addFileOrDir($files)) { + $this->zip->close(); + return true; + } + return false; + } + } + + /** + * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) + * @param string $filename + * @param string $path + * @return bool + */ + public function unzip($filename, $path) + { + $res = $this->zip->open($filename); + if ($res !== true) { + return false; + } + if ($this->zip->extractTo($path)) { + $this->zip->close(); + return true; + } + return false; + } + + /** + * Add file/folder to archive + * @param string $filename + * @return bool + */ + private function addFileOrDir($filename) + { + if (is_file($filename)) { + return $this->zip->addFile($filename); + } elseif (is_dir($filename)) { + return $this->addDir($filename); + } + return false; + } + + /** + * Add folder recursively + * @param string $path + * @return bool + */ + private function addDir($path) + { + if (!$this->zip->addEmptyDir($path)) { + return false; + } + $objects = scandir($path); + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (is_dir($path . '/' . $file)) { + if (!$this->addDir($path . '/' . $file)) { + return false; + } + } elseif (is_file($path . '/' . $file)) { + if (!$this->zip->addFile($path . '/' . $file)) { + return false; + } + } + } + } + return true; + } + return false; + } +} + +/** + * Class to work with Tar files (using PharData) + */ +class FM_Zipper_Tar +{ + private $tar; + + public function __construct() + { + $this->tar = null; + } + + /** + * Create archive with name $filename and files $files (RELATIVE PATHS!) + * @param string $filename + * @param array|string $files + * @return bool + */ + public function create($filename, $files) + { + $this->tar = new PharData($filename); + if (is_array($files)) { + foreach ($files as $f) { + $f = fm_clean_path($f); + if (!$this->addFileOrDir($f)) { + return false; + } + } + return true; + } else { + if ($this->addFileOrDir($files)) { + return true; + } + return false; + } + } + + /** + * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) + * @param string $filename + * @param string $path + * @return bool + */ + public function unzip($filename, $path) + { + $res = $this->tar->open($filename); + if ($res !== true) { + return false; + } + if ($this->tar->extractTo($path)) { + return true; + } + return false; + } + + /** + * Add file/folder to archive + * @param string $filename + * @return bool + */ + private function addFileOrDir($filename) + { + if (is_file($filename)) { + try { + $this->tar->addFile($filename); + return true; + } catch (Exception $e) { + return false; + } + } elseif (is_dir($filename)) { + return $this->addDir($filename); + } + return false; + } + + /** + * Add folder recursively + * @param string $path + * @return bool + */ + private function addDir($path) + { + $objects = scandir($path); + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (is_dir($path . '/' . $file)) { + if (!$this->addDir($path . '/' . $file)) { + return false; + } + } elseif (is_file($path . '/' . $file)) { + try { + $this->tar->addFile($path . '/' . $file); + } catch (Exception $e) { + return false; + } + } + } + } + return true; + } + return false; + } +} + +/** + * Save Configuration + */ +class FM_Config +{ + var $data; + + function __construct() + { + global $root_path, $root_url, $CONFIG; + $fm_url = $root_url . $_SERVER["PHP_SELF"]; + $this->data = array( + 'lang' => 'en', + 'error_reporting' => true, + 'show_hidden' => true + ); + $data = false; + if (strlen($CONFIG)) { + $data = fm_object_to_array(json_decode($CONFIG)); + } else { + $msg = 'Tiny File Manager
Error: Cannot load configuration'; + if (substr($fm_url, -1) == '/') { + $fm_url = rtrim($fm_url, '/'); + $msg .= '
'; + $msg .= '
Seems like you have a trailing slash on the URL.'; + $msg .= '
Try this link: ' . $fm_url . ''; + } + die($msg); + } + if (is_array($data) && count($data)) + $this->data = $data; + else + $this->save(); + } + + function save() + { + global $config_file; + $fm_file = is_readable($config_file) ? $config_file : __FILE__; + $var_name = '$CONFIG'; + $var_value = var_export(json_encode($this->data), true); + $config_string = " + + ' . $_SESSION[FM_SESSION_ID]['message'] . '

'; + unset($_SESSION[FM_SESSION_ID]['message']); + unset($_SESSION[FM_SESSION_ID]['status']); + } +} + +/** + * Show page header in Login Form + */ +function fm_show_header_login() +{ + header("Content-Type: text/html; charset=utf-8"); + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); + header("Pragma: no-cache"); + + global $favicon_path; + ?> + + "> + + + + + + + + + '; + } ?> + <?php echo fm_enc(APP_TITLE) ?> + + + + + + "> +
+ + +
+ + + + + + + + + + + + + + + + + + '; + } ?> + <?php echo fm_enc(APP_TITLE) ?> | + <?php echo (isset($_GET['view']) ? $_GET['view'] : ((isset($_GET['edit'])) ? $_GET['edit'] : "H3K")); ?> + + + + + + + + + + + + + + + + "> +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/servicios/tfm/index_original.php b/servicios/tfm/index_original.php new file mode 100644 index 00000000..642f0730 --- /dev/null +++ b/servicios/tfm/index_original.php @@ -0,0 +1,5613 @@ + 'Password', 'Username2' => 'Password2', ...) +// Generate secure password hash - https://tinyfilemanager.github.io/docs/pwd.html +$auth_users = array( + 'admin' => '$2y$10$/K.hjNr84lLNDt8fTXjoI.DBp6PpeyoJ.mGwrrLuCZfAwfSAGqhOW', //admin@123 + 'user' => '$2y$10$Fg6Dz8oH9fPoZ2jJan5tZuv6Z4Kp7avtQ9bDfrdRntXtPeiMAZyGO' //12345 +); + +// Readonly users +// e.g. array('users', 'guest', ...) +$readonly_users = array( + 'user' +); + +// Global readonly, including when auth is not being used +$global_readonly = false; + +// user specific directories +// array('Username' => 'Directory path', 'Username2' => 'Directory path', ...) +$directories_users = array(); + +// Enable highlight.js (https://highlightjs.org/) on view's page +$use_highlightjs = true; + +// highlight.js style +// for dark theme use 'ir-black' +$highlightjs_style = 'vs'; + +// Enable ace.js (https://ace.c9.io/) on view's page +$edit_files = true; + +// Default timezone for date() and time() +// Doc - http://php.net/manual/en/timezones.php +$default_timezone = 'Etc/UTC'; // UTC + +// Root path for file manager +// use absolute path of directory i.e: '/var/www/folder' or $_SERVER['DOCUMENT_ROOT'].'/folder' +//make sure update $root_url in next section +$root_path = $_SERVER['DOCUMENT_ROOT']; + +// Root url for links in file manager.Relative to $http_host. Variants: '', 'path/to/subfolder' +// Will not working if $root_path will be outside of server document root +$root_url = ''; + +// Server hostname. Can set manually if wrong +// $_SERVER['HTTP_HOST'].'/folder' +$http_host = $_SERVER['HTTP_HOST']; + +// input encoding for iconv +$iconv_input_encoding = 'UTF-8'; + +// date() format for file modification date +// Doc - https://www.php.net/manual/en/function.date.php +$datetime_format = 'm/d/Y g:i A'; + +// Path display mode when viewing file information +// 'full' => show full path +// 'relative' => show path relative to root_path +// 'host' => show path on the host +$path_display_mode = 'full'; + +// Allowed file extensions for create and rename files +// e.g. 'txt,html,css,js' +$allowed_file_extensions = ''; + +// Allowed file extensions for upload files +// e.g. 'gif,png,jpg,html,txt' +$allowed_upload_extensions = ''; + +// Favicon path. This can be either a full url to an .PNG image, or a path based on the document root. +// full path, e.g http://example.com/favicon.png +// local path, e.g images/icons/favicon.png +$favicon_path = ''; + +// Files and folders to excluded from listing +// e.g. array('myfile.html', 'personal-folder', '*.php', '/path/to/folder', ...) +$exclude_items = array(); + +// Online office Docs Viewer +// Available rules are 'google', 'microsoft' or false +// Google => View documents using Google Docs Viewer +// Microsoft => View documents using Microsoft Web Apps Viewer +// false => disable online doc viewer +$online_viewer = 'google'; + +// Sticky Nav bar +// true => enable sticky header +// false => disable sticky header +$sticky_navbar = true; + +// Maximum file upload size +// Increase the following values in php.ini to work properly +// memory_limit, upload_max_filesize, post_max_size +$max_upload_size_bytes = 5000000000; // size 5,000,000,000 bytes (~5GB) + +// chunk size used for upload +// eg. decrease to 1MB if nginx reports problem 413 entity too large +$upload_chunk_size_bytes = 2000000; // chunk size 2,000,000 bytes (~2MB) + +// Possible rules are 'OFF', 'AND' or 'OR' +// OFF => Don't check connection IP, defaults to OFF +// AND => Connection must be on the whitelist, and not on the blacklist +// OR => Connection must be on the whitelist, or not on the blacklist +$ip_ruleset = 'OFF'; + +// Should users be notified of their block? +$ip_silent = true; + +// IP-addresses, both ipv4 and ipv6 +$ip_whitelist = array( + '127.0.0.1', // local ipv4 + '::1' // local ipv6 +); + +// IP-addresses, both ipv4 and ipv6 +$ip_blacklist = array( + '0.0.0.0', // non-routable meta ipv4 + '::' // non-routable meta ipv6 +); + +// if User has the external config file, try to use it to override the default config above [config.php] +// sample config - https://tinyfilemanager.github.io/config-sample.txt +$config_file = __DIR__ . '/config.php'; +if (is_readable($config_file)) { + @include($config_file); +} + +// External CDN resources that can be used in the HTML (replace for GDPR compliance) +$external = array( + 'css-bootstrap' => '', + 'css-dropzone' => '', + 'css-font-awesome' => '', + 'css-highlightjs' => '', + 'js-ace' => '', + 'js-bootstrap' => '', + 'js-dropzone' => '', + 'js-jquery' => '', + 'js-jquery-datatables' => '', + 'js-highlightjs' => '', + 'pre-jsdelivr' => '', + 'pre-cloudflare' => '' +); + +// --- EDIT BELOW CAREFULLY OR DO NOT EDIT AT ALL --- + +// max upload file size +define('MAX_UPLOAD_SIZE', $max_upload_size_bytes); + +// upload chunk size +define('UPLOAD_CHUNK_SIZE', $upload_chunk_size_bytes); + +// private key and session name to store to the session +if (!defined('FM_SESSION_ID')) { + define('FM_SESSION_ID', 'filemanager'); +} + +// Configuration +$cfg = new FM_Config(); + +// Default language +$lang = isset($cfg->data['lang']) ? $cfg->data['lang'] : 'en'; + +// Show or hide files and folders that starts with a dot +$show_hidden_files = isset($cfg->data['show_hidden']) ? $cfg->data['show_hidden'] : true; + +// PHP error reporting - false = Turns off Errors, true = Turns on Errors +$report_errors = isset($cfg->data['error_reporting']) ? $cfg->data['error_reporting'] : true; + +// Hide Permissions and Owner cols in file-listing +$hide_Cols = isset($cfg->data['hide_Cols']) ? $cfg->data['hide_Cols'] : true; + +// Theme +$theme = isset($cfg->data['theme']) ? $cfg->data['theme'] : 'light'; + +define('FM_THEME', $theme); + +//available languages +$lang_list = array( + 'en' => 'English' +); + +if ($report_errors == true) { + @ini_set('error_reporting', E_ALL); + @ini_set('display_errors', 1); +} else { + @ini_set('error_reporting', E_ALL); + @ini_set('display_errors', 0); +} + +// if fm included +if (defined('FM_EMBED')) { + $use_auth = false; + $sticky_navbar = false; +} else { + @set_time_limit(600); + + date_default_timezone_set($default_timezone); + + ini_set('default_charset', 'UTF-8'); + if (version_compare(PHP_VERSION, '5.6.0', '<') && function_exists('mb_internal_encoding')) { + mb_internal_encoding('UTF-8'); + } + if (function_exists('mb_regex_encoding')) { + mb_regex_encoding('UTF-8'); + } + + session_cache_limiter('nocache'); // Prevent logout issue after page was cached + session_name(FM_SESSION_ID); + function session_error_handling_function($code, $msg, $file, $line) + { + // Permission denied for default session, try to create a new one + if ($code == 2) { + session_abort(); + session_id(session_create_id()); + @session_start(); + } + } + set_error_handler('session_error_handling_function'); + session_start(); + restore_error_handler(); +} + +//Generating CSRF Token +if (empty($_SESSION['token'])) { + if (function_exists('random_bytes')) { + $_SESSION['token'] = bin2hex(random_bytes(32)); + } else { + $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32)); + } +} + +if (empty($auth_users)) { + $use_auth = false; +} + +$is_https = isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) == 'on' || $_SERVER['HTTPS'] == 1) + || isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'; + +// update $root_url based on user specific directories +if (isset($_SESSION[FM_SESSION_ID]['logged']) && !empty($directories_users[$_SESSION[FM_SESSION_ID]['logged']])) { + $wd = fm_clean_path(dirname($_SERVER['PHP_SELF'])); + $root_url = $root_url . $wd . DIRECTORY_SEPARATOR . $directories_users[$_SESSION[FM_SESSION_ID]['logged']]; +} +// clean $root_url +$root_url = fm_clean_path($root_url); + +// abs path for site +defined('FM_ROOT_URL') || define('FM_ROOT_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . (!empty($root_url) ? '/' . $root_url : '')); +defined('FM_SELF_URL') || define('FM_SELF_URL', ($is_https ? 'https' : 'http') . '://' . $http_host . $_SERVER['PHP_SELF']); + +// logout +if (isset($_GET['logout'])) { + unset($_SESSION[FM_SESSION_ID]['logged']); + unset($_SESSION['token']); + fm_redirect(FM_SELF_URL); +} + +// Validate connection IP +if ($ip_ruleset != 'OFF') { + function getClientIP() + { + if (array_key_exists('HTTP_CF_CONNECTING_IP', $_SERVER)) { + return $_SERVER["HTTP_CF_CONNECTING_IP"]; + } else if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) { + return $_SERVER["HTTP_X_FORWARDED_FOR"]; + } else if (array_key_exists('REMOTE_ADDR', $_SERVER)) { + return $_SERVER['REMOTE_ADDR']; + } else if (array_key_exists('HTTP_CLIENT_IP', $_SERVER)) { + return $_SERVER['HTTP_CLIENT_IP']; + } + return ''; + } + + $clientIp = getClientIP(); + $proceed = false; + $whitelisted = in_array($clientIp, $ip_whitelist); + $blacklisted = in_array($clientIp, $ip_blacklist); + + if ($ip_ruleset == 'AND') { + if ($whitelisted == true && $blacklisted == false) { + $proceed = true; + } + } else + if ($ip_ruleset == 'OR') { + if ($whitelisted == true || $blacklisted == false) { + $proceed = true; + } + } + + if ($proceed == false) { + trigger_error('User connection denied from: ' . $clientIp, E_USER_WARNING); + + if ($ip_silent == false) { + fm_set_msg(lng('Access denied. IP restriction applicable'), 'error'); + fm_show_header_login(); + fm_show_message(); + } + exit(); + } +} + +// Checking if the user is logged in or not. If not, it will show the login form. +if ($use_auth) { + if (isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']])) { + // Logged + } elseif (isset($_POST['fm_usr'], $_POST['fm_pwd'], $_POST['token'])) { + // Logging In + sleep(1); + if (function_exists('password_verify')) { + if (isset($auth_users[$_POST['fm_usr']]) && isset($_POST['fm_pwd']) && password_verify($_POST['fm_pwd'], $auth_users[$_POST['fm_usr']]) && verifyToken($_POST['token'])) { + $_SESSION[FM_SESSION_ID]['logged'] = $_POST['fm_usr']; + fm_set_msg(lng('You are logged in')); + fm_redirect(FM_SELF_URL); + } else { + unset($_SESSION[FM_SESSION_ID]['logged']); + fm_set_msg(lng('Login failed. Invalid username or password'), 'error'); + fm_redirect(FM_SELF_URL); + } + } else { + fm_set_msg(lng('password_hash not supported, Upgrade PHP version'), 'error');; + } + } else { + // Form + unset($_SESSION[FM_SESSION_ID]['logged']); + fm_show_header_login(); +?> +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ + " . lng('Root path') . " \"{$root_path}\" " . lng('not found!') . " "; + exit; +} + +defined('FM_SHOW_HIDDEN') || define('FM_SHOW_HIDDEN', $show_hidden_files); +defined('FM_ROOT_PATH') || define('FM_ROOT_PATH', $root_path); +defined('FM_LANG') || define('FM_LANG', $lang); +defined('FM_FILE_EXTENSION') || define('FM_FILE_EXTENSION', $allowed_file_extensions); +defined('FM_UPLOAD_EXTENSION') || define('FM_UPLOAD_EXTENSION', $allowed_upload_extensions); +defined('FM_EXCLUDE_ITEMS') || define('FM_EXCLUDE_ITEMS', (version_compare(PHP_VERSION, '7.0.0', '<') ? serialize($exclude_items) : $exclude_items)); +defined('FM_DOC_VIEWER') || define('FM_DOC_VIEWER', $online_viewer); +define('FM_READONLY', $global_readonly || ($use_auth && !empty($readonly_users) && isset($_SESSION[FM_SESSION_ID]['logged']) && in_array($_SESSION[FM_SESSION_ID]['logged'], $readonly_users))); +define('FM_IS_WIN', DIRECTORY_SEPARATOR == '\\'); + +// always use ?p= +if (!isset($_GET['p']) && empty($_FILES)) { + fm_redirect(FM_SELF_URL . '?p='); +} + +// get path +$p = isset($_GET['p']) ? $_GET['p'] : (isset($_POST['p']) ? $_POST['p'] : ''); + +// clean path +$p = fm_clean_path($p); + +// for ajax request - save +$input = file_get_contents('php://input'); +$_POST = (strpos($input, 'ajax') != FALSE && strpos($input, 'save') != FALSE) ? json_decode($input, true) : $_POST; + +// instead globals vars +define('FM_PATH', $p); +define('FM_USE_AUTH', $use_auth); +define('FM_EDIT_FILE', $edit_files); +defined('FM_ICONV_INPUT_ENC') || define('FM_ICONV_INPUT_ENC', $iconv_input_encoding); +defined('FM_USE_HIGHLIGHTJS') || define('FM_USE_HIGHLIGHTJS', $use_highlightjs); +defined('FM_HIGHLIGHTJS_STYLE') || define('FM_HIGHLIGHTJS_STYLE', $highlightjs_style); +defined('FM_DATETIME_FORMAT') || define('FM_DATETIME_FORMAT', $datetime_format); + +unset($p, $use_auth, $iconv_input_encoding, $use_highlightjs, $highlightjs_style); + +/*************************** ACTIONS ***************************/ + +// Handle all AJAX Request +if ((isset($_SESSION[FM_SESSION_ID]['logged'], $auth_users[$_SESSION[FM_SESSION_ID]['logged']]) || !FM_USE_AUTH) && isset($_POST['ajax'], $_POST['token'])) { + if (!verifyToken($_POST['token'])) { + header('HTTP/1.0 401 Unauthorized'); + die("Invalid Token."); + } + + //search : get list of files from the current folder + if (isset($_POST['type']) && $_POST['type'] == "search") { + $dir = $_POST['path'] == "." ? '' : $_POST['path']; + $response = scan(fm_clean_path($dir), $_POST['content']); + echo json_encode($response); + exit(); + } + + if(FM_READONLY){ + exit(); + } + + // save editor file + if (isset($_POST['type']) && $_POST['type'] == "save") { + // get current path + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + // check path + if (!is_dir($path)) { + fm_redirect(FM_SELF_URL . '?p='); + } + $file = $_GET['edit']; + $file = fm_clean_path($file); + $file = str_replace('/', '', $file); + if ($file == '' || !is_file($path . '/' . $file)) { + fm_set_msg(lng('File not found'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + header('X-XSS-Protection:0'); + $file_path = $path . '/' . $file; + + $writedata = $_POST['content']; + $fd = fopen($file_path, "w"); + $write_results = @fwrite($fd, $writedata); + fclose($fd); + if ($write_results === false) { + header("HTTP/1.1 500 Internal Server Error"); + die("Could Not Write File! - Check Permissions / Ownership"); + } + die(true); + } + + // backup files + if (isset($_POST['type']) && $_POST['type'] == "backup" && !empty($_POST['file'])) { + $fileName = fm_clean_path($_POST['file']); + $fullPath = FM_ROOT_PATH . '/'; + if (!empty($_POST['path'])) { + $relativeDirPath = fm_clean_path($_POST['path']); + $fullPath .= "{$relativeDirPath}/"; + } + $date = date("dMy-His"); + $newFileName = "{$fileName}-{$date}.bak"; + $fullyQualifiedFileName = $fullPath . $fileName; + try { + if (!file_exists($fullyQualifiedFileName)) { + throw new Exception("File {$fileName} not found"); + } + if (copy($fullyQualifiedFileName, $fullPath . $newFileName)) { + echo "Backup {$newFileName} created"; + } else { + throw new Exception("Could not copy file {$fileName}"); + } + } catch (Exception $e) { + echo $e->getMessage(); + } + } + + // Save Config + if (isset($_POST['type']) && $_POST['type'] == "settings") { + global $cfg, $lang, $report_errors, $show_hidden_files, $lang_list, $hide_Cols, $theme; + $newLng = $_POST['js-language']; + fm_get_translations([]); + if (!array_key_exists($newLng, $lang_list)) { + $newLng = 'en'; + } + + $erp = isset($_POST['js-error-report']) && $_POST['js-error-report'] == "true" ? true : false; + $shf = isset($_POST['js-show-hidden']) && $_POST['js-show-hidden'] == "true" ? true : false; + $hco = isset($_POST['js-hide-cols']) && $_POST['js-hide-cols'] == "true" ? true : false; + $te3 = $_POST['js-theme-3']; + + if ($cfg->data['lang'] != $newLng) { + $cfg->data['lang'] = $newLng; + $lang = $newLng; + } + if ($cfg->data['error_reporting'] != $erp) { + $cfg->data['error_reporting'] = $erp; + $report_errors = $erp; + } + if ($cfg->data['show_hidden'] != $shf) { + $cfg->data['show_hidden'] = $shf; + $show_hidden_files = $shf; + } + if ($cfg->data['show_hidden'] != $shf) { + $cfg->data['show_hidden'] = $shf; + $show_hidden_files = $shf; + } + if ($cfg->data['hide_Cols'] != $hco) { + $cfg->data['hide_Cols'] = $hco; + $hide_Cols = $hco; + } + if ($cfg->data['theme'] != $te3) { + $cfg->data['theme'] = $te3; + $theme = $te3; + } + $cfg->save(); + echo true; + } + + // new password hash + if (isset($_POST['type']) && $_POST['type'] == "pwdhash") { + $res = isset($_POST['inputPassword2']) && !empty($_POST['inputPassword2']) ? password_hash($_POST['inputPassword2'], PASSWORD_DEFAULT) : ''; + echo $res; + } + + //upload using url + if (isset($_POST['type']) && $_POST['type'] == "upload" && !empty($_REQUEST["uploadurl"])) { + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + function event_callback($message) + { + global $callback; + echo json_encode($message); + } + + function get_file_path() + { + global $path, $fileinfo, $temp_file; + return $path . "/" . basename($fileinfo->name); + } + + $url = !empty($_REQUEST["uploadurl"]) && preg_match("|^http(s)?://.+$|", stripslashes($_REQUEST["uploadurl"])) ? stripslashes($_REQUEST["uploadurl"]) : null; + + //prevent 127.* domain and known ports + $domain = parse_url($url, PHP_URL_HOST); + $port = parse_url($url, PHP_URL_PORT); + $knownPorts = [22, 23, 25, 3306]; + + if (preg_match("/^localhost$|^127(?:\.[0-9]+){0,2}\.[0-9]+$|^(?:0*\:)*?:?0*1$/i", $domain) || in_array($port, $knownPorts)) { + $err = array("message" => "URL is not allowed"); + event_callback(array("fail" => $err)); + exit(); + } + + $use_curl = false; + $temp_file = tempnam(sys_get_temp_dir(), "upload-"); + $fileinfo = new stdClass(); + $fileinfo->name = trim(urldecode(basename($url)), ".\x00..\x20"); + + $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; + $ext = strtolower(pathinfo($fileinfo->name, PATHINFO_EXTENSION)); + $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; + + $err = false; + + if (!$isFileAllowed) { + $err = array("message" => "File extension is not allowed"); + event_callback(array("fail" => $err)); + exit(); + } + + if (!$url) { + $success = false; + } else if ($use_curl) { + @$fp = fopen($temp_file, "w"); + @$ch = curl_init($url); + curl_setopt($ch, CURLOPT_NOPROGRESS, false); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_FILE, $fp); + @$success = curl_exec($ch); + $curl_info = curl_getinfo($ch); + if (!$success) { + $err = array("message" => curl_error($ch)); + } + @curl_close($ch); + fclose($fp); + $fileinfo->size = $curl_info["size_download"]; + $fileinfo->type = $curl_info["content_type"]; + } else { + $ctx = stream_context_create(); + @$success = copy($url, $temp_file, $ctx); + if (!$success) { + $err = error_get_last(); + } + } + + if ($success) { + $success = rename($temp_file, strtok(get_file_path(), '?')); + } + + if ($success) { + event_callback(array("done" => $fileinfo)); + } else { + unlink($temp_file); + if (!$err) { + $err = array("message" => "Invalid url parameter"); + } + event_callback(array("fail" => $err)); + } + } + exit(); +} + +// Delete file / folder +if (isset($_GET['del'], $_POST['token']) && !FM_READONLY) { + $del = str_replace('/', '', fm_clean_path($_GET['del'])); + if ($del != '' && $del != '..' && $del != '.' && verifyToken($_POST['token'])) { + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + $is_dir = is_dir($path . '/' . $del); + if (fm_rdelete($path . '/' . $del)) { + $msg = $is_dir ? lng('Folder') . ' %s ' . lng('Deleted') : lng('File') . ' %s ' . lng('Deleted'); + fm_set_msg(sprintf($msg, fm_enc($del))); + } else { + $msg = $is_dir ? lng('Folder') . ' %s ' . lng('not deleted') : lng('File') . ' %s ' . lng('not deleted'); + fm_set_msg(sprintf($msg, fm_enc($del)), 'error'); + } + } else { + fm_set_msg(lng('Invalid file or folder name'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Create a new file/folder +if (isset($_POST['newfilename'], $_POST['newfile'], $_POST['token']) && !FM_READONLY) { + $type = urldecode($_POST['newfile']); + $new = str_replace('/', '', fm_clean_path(strip_tags($_POST['newfilename']))); + if (fm_isvalid_filename($new) && $new != '' && $new != '..' && $new != '.' && verifyToken($_POST['token'])) { + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + if ($type == "file") { + if (!file_exists($path . '/' . $new)) { + if (fm_is_valid_ext($new)) { + @fopen($path . '/' . $new, 'w') or die('Cannot open file: ' . $new); + fm_set_msg(sprintf(lng('File') . ' %s ' . lng('Created'), fm_enc($new))); + } else { + fm_set_msg(lng('File extension is not allowed'), 'error'); + } + } else { + fm_set_msg(sprintf(lng('File') . ' %s ' . lng('already exists'), fm_enc($new)), 'alert'); + } + } else { + if (fm_mkdir($path . '/' . $new, false) === true) { + fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('Created'), $new)); + } elseif (fm_mkdir($path . '/' . $new, false) === $path . '/' . $new) { + fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('already exists'), fm_enc($new)), 'alert'); + } else { + fm_set_msg(sprintf(lng('Folder') . ' %s ' . lng('not created'), fm_enc($new)), 'error'); + } + } + } else { + fm_set_msg(lng('Invalid characters in file or folder name'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Copy folder / file +if (isset($_GET['copy'], $_GET['finish']) && !FM_READONLY) { + // from + $copy = urldecode($_GET['copy']); + $copy = fm_clean_path($copy); + // empty path + if ($copy == '') { + fm_set_msg(lng('Source path not defined'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + // abs path from + $from = FM_ROOT_PATH . '/' . $copy; + // abs path to + $dest = FM_ROOT_PATH; + if (FM_PATH != '') { + $dest .= '/' . FM_PATH; + } + $dest .= '/' . basename($from); + // move? + $move = isset($_GET['move']); + $move = fm_clean_path(urldecode($move)); + // copy/move/duplicate + if ($from != $dest) { + $msg_from = trim(FM_PATH . '/' . basename($from), '/'); + if ($move) { // Move and to != from so just perform move + $rename = fm_rename($from, $dest); + if ($rename) { + fm_set_msg(sprintf(lng('Moved from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from))); + } elseif ($rename === null) { + fm_set_msg(lng('File or folder with this path already exists'), 'alert'); + } else { + fm_set_msg(sprintf(lng('Error while moving from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); + } + } else { // Not move and to != from so copy with original name + if (fm_rcopy($from, $dest)) { + fm_set_msg(sprintf(lng('Copied from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from))); + } else { + fm_set_msg(sprintf(lng('Error while copying from') . ' %s ' . lng('to') . ' %s', fm_enc($copy), fm_enc($msg_from)), 'error'); + } + } + } else { + if (!$move) { //Not move and to = from so duplicate + $msg_from = trim(FM_PATH . '/' . basename($from), '/'); + $fn_parts = pathinfo($from); + $extension_suffix = ''; + if (!is_dir($from)) { + $extension_suffix = '.' . $fn_parts['extension']; + } + //Create new name for duplicate + $fn_duplicate = $fn_parts['dirname'] . '/' . $fn_parts['filename'] . '-' . date('YmdHis') . $extension_suffix; + $loop_count = 0; + $max_loop = 1000; + // Check if a file with the duplicate name already exists, if so, make new name (edge case...) + while (file_exists($fn_duplicate) & $loop_count < $max_loop) { + $fn_parts = pathinfo($fn_duplicate); + $fn_duplicate = $fn_parts['dirname'] . '/' . $fn_parts['filename'] . '-copy' . $extension_suffix; + $loop_count++; + } + if (fm_rcopy($from, $fn_duplicate, False)) { + fm_set_msg(sprintf('Copied from %s to %s', fm_enc($copy), fm_enc($fn_duplicate))); + } else { + fm_set_msg(sprintf('Error while copying from %s to %s', fm_enc($copy), fm_enc($fn_duplicate)), 'error'); + } + } else { + fm_set_msg(lng('Paths must be not equal'), 'alert'); + } + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Mass copy files/ folders +if (isset($_POST['file'], $_POST['copy_to'], $_POST['finish'], $_POST['token']) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng('Invalid Token.'), 'error'); + die("Invalid Token."); + } + + // from + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + // to + $copy_to_path = FM_ROOT_PATH; + $copy_to = fm_clean_path($_POST['copy_to']); + if ($copy_to != '') { + $copy_to_path .= '/' . $copy_to; + } + if ($path == $copy_to_path) { + fm_set_msg(lng('Paths must be not equal'), 'alert'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + if (!is_dir($copy_to_path)) { + if (!fm_mkdir($copy_to_path, true)) { + fm_set_msg('Unable to create destination folder', 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + } + // move? + $move = isset($_POST['move']); + // copy/move + $errors = 0; + $files = $_POST['file']; + if (is_array($files) && count($files)) { + foreach ($files as $f) { + if ($f != '') { + $f = fm_clean_path($f); + // abs path from + $from = $path . '/' . $f; + // abs path to + $dest = $copy_to_path . '/' . $f; + // do + if ($move) { + $rename = fm_rename($from, $dest); + if ($rename === false) { + $errors++; + } + } else { + if (!fm_rcopy($from, $dest)) { + $errors++; + } + } + } + } + if ($errors == 0) { + $msg = $move ? 'Selected files and folders moved' : 'Selected files and folders copied'; + fm_set_msg($msg); + } else { + $msg = $move ? 'Error while moving items' : 'Error while copying items'; + fm_set_msg($msg, 'error'); + } + } else { + fm_set_msg(lng('Nothing selected'), 'alert'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Rename +if (isset($_POST['rename_from'], $_POST['rename_to'], $_POST['token']) && !FM_READONLY) { + if (!verifyToken($_POST['token'])) { + fm_set_msg("Invalid Token.", 'error'); + die("Invalid Token."); + } + // old name + $old = urldecode($_POST['rename_from']); + $old = fm_clean_path($old); + $old = str_replace('/', '', $old); + // new name + $new = urldecode($_POST['rename_to']); + $new = fm_clean_path(strip_tags($new)); + $new = str_replace('/', '', $new); + // path + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + // rename + if (fm_isvalid_filename($new) && $old != '' && $new != '') { + if (fm_rename($path . '/' . $old, $path . '/' . $new)) { + fm_set_msg(sprintf(lng('Renamed from') . ' %s ' . lng('to') . ' %s', fm_enc($old), fm_enc($new))); + } else { + fm_set_msg(sprintf(lng('Error while renaming from') . ' %s ' . lng('to') . ' %s', fm_enc($old), fm_enc($new)), 'error'); + } + } else { + fm_set_msg(lng('Invalid characters in file name'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Download +if (isset($_GET['dl'], $_POST['token'])) { + // Verify the token to ensure it's valid + if (!verifyToken($_POST['token'])) { + fm_set_msg("Invalid Token.", 'error'); + exit; + } + + // Clean the download file path + $dl = urldecode($_GET['dl']); + $dl = fm_clean_path($dl); + $dl = str_replace('/', '', $dl); // Prevent directory traversal attacks + + // Define the file path + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + // Check if the file exists and is valid + if ($dl != '' && is_file($path . '/' . $dl)) { + // Close the session to prevent session locking + if (session_status() === PHP_SESSION_ACTIVE) { + session_write_close(); + } + + // Call the download function + fm_download_file($path . '/' . $dl, $dl, 1024); // Download with a buffer size of 1024 bytes + exit; + } else { + // Handle the case where the file is not found + fm_set_msg(lng('File not found'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } +} + +// Upload +if (!empty($_FILES) && !FM_READONLY) { + if (isset($_POST['token'])) { + if (!verifyToken($_POST['token'])) { + $response = array('status' => 'error', 'info' => "Invalid Token."); + echo json_encode($response); + exit(); + } + } else { + $response = array('status' => 'error', 'info' => "Token Missing."); + echo json_encode($response); + exit(); + } + + $chunkIndex = $_POST['dzchunkindex']; + $chunkTotal = $_POST['dztotalchunkcount']; + $fullPathInput = fm_clean_path($_REQUEST['fullpath']); + + $f = $_FILES; + $path = FM_ROOT_PATH; + $ds = DIRECTORY_SEPARATOR; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + $errors = 0; + $uploads = 0; + $allowed = (FM_UPLOAD_EXTENSION) ? explode(',', FM_UPLOAD_EXTENSION) : false; + $response = array( + 'status' => 'error', + 'info' => 'Oops! Try again' + ); + + $filename = $f['file']['name']; + $tmp_name = $f['file']['tmp_name']; + $ext = pathinfo($filename, PATHINFO_FILENAME) != '' ? strtolower(pathinfo($filename, PATHINFO_EXTENSION)) : ''; + $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; + + if (!fm_isvalid_filename($filename) && !fm_isvalid_filename($fullPathInput)) { + $response = array( + 'status' => 'error', + 'info' => "Invalid File name!", + ); + echo json_encode($response); + exit(); + } + + $targetPath = $path . $ds; + if (is_writable($targetPath)) { + $fullPath = $path . '/' . $fullPathInput; + $folder = substr($fullPath, 0, strrpos($fullPath, "/")); + + if (!is_dir($folder)) { + $old = umask(0); + mkdir($folder, 0777, true); + umask($old); + } + + if (empty($f['file']['error']) && !empty($tmp_name) && $tmp_name != 'none' && $isFileAllowed) { + if ($chunkTotal) { + $out = @fopen("{$fullPath}.part", $chunkIndex == 0 ? "wb" : "ab"); + if ($out) { + $in = @fopen($tmp_name, "rb"); + if ($in) { + if (PHP_VERSION_ID < 80009) { + // workaround https://bugs.php.net/bug.php?id=81145 + do { + for (;;) { + $buff = fread($in, 4096); + if ($buff === false || $buff === '') { + break; + } + fwrite($out, $buff); + } + } while (!feof($in)); + } else { + stream_copy_to_stream($in, $out); + } + $response = array( + 'status' => 'success', + 'info' => "file upload successful" + ); + } else { + $response = array( + 'status' => 'error', + 'info' => "failed to open output stream", + 'errorDetails' => error_get_last() + ); + } + @fclose($in); + @fclose($out); + @unlink($tmp_name); + + $response = array( + 'status' => 'success', + 'info' => "file upload successful" + ); + } else { + $response = array( + 'status' => 'error', + 'info' => "failed to open output stream" + ); + } + + if ($chunkIndex == $chunkTotal - 1) { + if (file_exists($fullPath)) { + $ext_1 = $ext ? '.' . $ext : ''; + $fullPathTarget = $path . '/' . basename($fullPathInput, $ext_1) . '_' . date('ymdHis') . $ext_1; + } else { + $fullPathTarget = $fullPath; + } + rename("{$fullPath}.part", $fullPathTarget); + } + } else if (move_uploaded_file($tmp_name, $fullPath)) { + // Be sure that the file has been uploaded + if (file_exists($fullPath)) { + $response = array( + 'status' => 'success', + 'info' => "file upload successful" + ); + } else { + $response = array( + 'status' => 'error', + 'info' => 'Couldn\'t upload the requested file.' + ); + } + } else { + $response = array( + 'status' => 'error', + 'info' => "Error while uploading files. Uploaded files $uploads", + ); + } + } + } else { + $response = array( + 'status' => 'error', + 'info' => 'The specified folder for upload isn\'t writeable.' + ); + } + // Return the response + echo json_encode($response); + exit(); +} + +// Mass deleting +if (isset($_POST['group'], $_POST['delete'], $_POST['token']) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + $errors = 0; + $files = $_POST['file']; + if (is_array($files) && count($files)) { + foreach ($files as $f) { + if ($f != '') { + $new_path = $path . '/' . $f; + if (!fm_rdelete($new_path)) { + $errors++; + } + } + } + if ($errors == 0) { + fm_set_msg(lng('Selected files and folder deleted')); + } else { + fm_set_msg(lng('Error while deleting items'), 'error'); + } + } else { + fm_set_msg(lng('Nothing selected'), 'alert'); + } + + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Pack files zip, tar +if (isset($_POST['group'], $_POST['token']) && (isset($_POST['zip']) || isset($_POST['tar'])) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $path = FM_ROOT_PATH; + $ext = 'zip'; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + //set pack type + $ext = isset($_POST['tar']) ? 'tar' : 'zip'; + + if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { + fm_set_msg(lng('Operations with archives are not available'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + + $files = $_POST['file']; + $sanitized_files = array(); + + // clean path + foreach ($files as $file) { + array_push($sanitized_files, fm_clean_path($file)); + } + + $files = $sanitized_files; + + if (!empty($files)) { + chdir($path); + + if (count($files) == 1) { + $one_file = reset($files); + $one_file = basename($one_file); + $zipname = $one_file . '_' . date('ymd_His') . '.' . $ext; + } else { + $zipname = 'archive_' . date('ymd_His') . '.' . $ext; + } + + if ($ext == 'zip') { + $zipper = new FM_Zipper(); + $res = $zipper->create($zipname, $files); + } elseif ($ext == 'tar') { + $tar = new FM_Zipper_Tar(); + $res = $tar->create($zipname, $files); + } + + if ($res) { + fm_set_msg(sprintf(lng('Archive') . ' %s ' . lng('Created'), fm_enc($zipname))); + } else { + fm_set_msg(lng('Archive not created'), 'error'); + } + } else { + fm_set_msg(lng('Nothing selected'), 'alert'); + } + + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Unpack zip, tar +if (isset($_POST['unzip'], $_POST['token']) && !FM_READONLY) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $unzip = urldecode($_POST['unzip']); + $unzip = fm_clean_path($unzip); + $unzip = str_replace('/', '', $unzip); + $isValid = false; + + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + if ($unzip != '' && is_file($path . '/' . $unzip)) { + $zip_path = $path . '/' . $unzip; + $ext = pathinfo($zip_path, PATHINFO_EXTENSION); + $isValid = true; + } else { + fm_set_msg(lng('File not found'), 'error'); + } + + if (($ext == "zip" && !class_exists('ZipArchive')) || ($ext == "tar" && !class_exists('PharData'))) { + fm_set_msg(lng('Operations with archives are not available'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + + if ($isValid) { + //to folder + $tofolder = ''; + if (isset($_POST['tofolder'])) { + $tofolder = pathinfo($zip_path, PATHINFO_FILENAME); + if (fm_mkdir($path . '/' . $tofolder, true)) { + $path .= '/' . $tofolder; + } + } + + if ($ext == "zip") { + $zipper = new FM_Zipper(); + $res = $zipper->unzip($zip_path, $path); + } elseif ($ext == "tar") { + try { + $gzipper = new PharData($zip_path); + if (@$gzipper->extractTo($path, null, true)) { + $res = true; + } else { + $res = false; + } + } catch (Exception $e) { + //TODO:: need to handle the error + $res = true; + } + } + + if ($res) { + fm_set_msg(lng('Archive unpacked')); + } else { + fm_set_msg(lng('Archive not unpacked'), 'error'); + } + } else { + fm_set_msg(lng('File not found'), 'error'); + } + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +// Change Perms (not for Windows) +if (isset($_POST['chmod'], $_POST['token']) && !FM_READONLY && !FM_IS_WIN) { + + if (!verifyToken($_POST['token'])) { + fm_set_msg(lng("Invalid Token."), 'error'); + die("Invalid Token."); + } + + $path = FM_ROOT_PATH; + if (FM_PATH != '') { + $path .= '/' . FM_PATH; + } + + $file = $_POST['chmod']; + $file = fm_clean_path($file); + $file = str_replace('/', '', $file); + if ($file == '' || (!is_file($path . '/' . $file) && !is_dir($path . '/' . $file))) { + fm_set_msg(lng('File not found'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + } + + $mode = 0; + if (!empty($_POST['ur'])) { + $mode |= 0400; + } + if (!empty($_POST['uw'])) { + $mode |= 0200; + } + if (!empty($_POST['ux'])) { + $mode |= 0100; + } + if (!empty($_POST['gr'])) { + $mode |= 0040; + } + if (!empty($_POST['gw'])) { + $mode |= 0020; + } + if (!empty($_POST['gx'])) { + $mode |= 0010; + } + if (!empty($_POST['or'])) { + $mode |= 0004; + } + if (!empty($_POST['ow'])) { + $mode |= 0002; + } + if (!empty($_POST['ox'])) { + $mode |= 0001; + } + + if (@chmod($path . '/' . $file, $mode)) { + fm_set_msg(lng('Permissions changed')); + } else { + fm_set_msg(lng('Permissions not changed'), 'error'); + } + + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); +} + +/*************************** ACTIONS ***************************/ + +// get current path +$path = FM_ROOT_PATH; +if (FM_PATH != '') { + $path .= '/' . FM_PATH; +} + +// check path +if (!is_dir($path)) { + fm_redirect(FM_SELF_URL . '?p='); +} + +// get parent folder +$parent = fm_get_parent_path(FM_PATH); + +$objects = is_readable($path) ? scandir($path) : array(); +$folders = array(); +$files = array(); +$current_path = array_slice(explode("/", $path), -1)[0]; +if (is_array($objects) && fm_is_exclude_items($current_path, $path)) { + foreach ($objects as $file) { + if ($file == '.' || $file == '..') { + continue; + } + if (!FM_SHOW_HIDDEN && substr($file, 0, 1) === '.') { + continue; + } + $new_path = $path . '/' . $file; + if (@is_file($new_path) && fm_is_exclude_items($file, $new_path)) { + $files[] = $file; + } elseif (@is_dir($new_path) && $file != '.' && $file != '..' && fm_is_exclude_items($file, $new_path)) { + $folders[] = $file; + } + } +} + +if (!empty($files)) { + natcasesort($files); +} +if (!empty($folders)) { + natcasesort($folders); +} + +// upload form +if (isset($_GET['upload']) && !FM_READONLY) { + fm_show_header(); // HEADER + fm_show_nav_path(FM_PATH); // current path + //get the allowed file extensions + function getUploadExt() + { + $extArr = explode(',', FM_UPLOAD_EXTENSION); + if (FM_UPLOAD_EXTENSION && $extArr) { + array_walk($extArr, function (&$x) { + $x = ".$x"; + }); + return implode(',', $extArr); + } + return ''; + } + ?> + +
+ +
+
+ +
+
+

+ + : +

+ +
+ + + +
+ +
+
+ + +
+
+
+ + + +
+
+
+
+
+
+
+ + + ' . PHP_EOL; + } + ?> +

: , ', $copy_files) ?>

+

:
+ + / +

+

+ +

+

+   + + +

+ +
+
+
+ +
+

Copying

+

+ Source path:
+ Destination folder: +

+

+ Copy   + Move   + Cancel +

+

+
    + +
  • ..
  • + +
  • + +
  • + +
+
+ + +
+
+
+ + +
+
+
+ +
+ +
+ +
+
+
+ +
+
+ /> +
+
+
+ +
+ +
+
+ /> +
+
+
+ +
+ +
+
+ /> +
+
+
+ +
+ +
+ +
+
+ +
+
+ +
+
+ + * . +
+
+
+
+ + +
+
+
+ + +
+
+
+
+

+

Tiny File Manager

+

+

Author: PRAŚATH MANİ

+

Mail Us: ccpprogrammers [at] gmail [dot] com

+
+
+
+ +
+
+
+ +
+
+
+ +
+
+
    +
  • :
  • + +
  • :
  • +
  • :
  • +
  • :
  • +
  • :
  • + +
  • :
  • +
  • :
  • +
  • :
  • +
  • : %
  • + ' . lng('Image size') . ': ' . (isset($image_size[0]) ? $image_size[0] : '0') . ' x ' . (isset($image_size[1]) ? $image_size[1] : '0') . ''; + } + // Text info + if ($is_text) { + $is_utf8 = fm_is_utf8($content); + if (function_exists('iconv')) { + if (!$is_utf8) { + $content = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $content); + } + } + echo '
  • ' . lng('Charset') . ': ' . ($is_utf8 ? 'utf-8' : '8 bit') . '
  • '; + } + ?> +
+
+
+ +   +
+ + Delete + +
+ +
+ + + +
+
+ + + + +
+ + + + + + + + +
+
+ '; + } else if ($online_viewer == 'microsoft') { + echo ''; + } + } elseif ($is_zip) { + // ZIP content + if ($filenames !== false) { + echo ''; + foreach ($filenames as $fn) { + if ($fn['folder']) { + echo '' . fm_enc($fn['name']) . '
'; + } else { + echo $fn['name'] . ' (' . fm_get_filesize($fn['filesize']) . ')
'; + } + } + echo '
'; + } else { + echo '

' . lng('Error while fetching archive info') . '

'; + } + } elseif ($is_image) { + // Image content + if (in_array($ext, array('gif', 'jpg', 'jpeg', 'png', 'bmp', 'ico', 'svg', 'webp', 'avif'))) { + echo '

'; + } + } elseif ($is_audio) { + // Audio content + echo '

'; + } elseif ($is_video) { + // Video content + echo '
'; + } elseif ($is_text) { + if (FM_USE_HIGHLIGHTJS) { + // highlight + $hljs_classes = array( + 'shtml' => 'xml', + 'htaccess' => 'apache', + 'phtml' => 'php', + 'lock' => 'json', + 'svg' => 'xml', + ); + $hljs_class = isset($hljs_classes[$ext]) ? 'lang-' . $hljs_classes[$ext] : 'lang-' . $ext; + if (empty($ext) || in_array(strtolower($file), fm_get_text_names()) || preg_match('#\.min\.(css|js)$#i', $file)) { + $hljs_class = 'nohighlight'; + } + $content = '
' . fm_enc($content) . '
'; + } elseif (in_array($ext, array('php', 'php4', 'php5', 'phtml', 'phps'))) { + // php highlight + $content = highlight_string($content, true); + } else { + $content = '
' . fm_enc($content) . '
'; + } + echo $content; + } + ?> +
+
+
+' . $file . ''; + header('X-XSS-Protection:0'); + fm_show_header(); // HEADER + fm_show_nav_path(FM_PATH); // current path + + $file_url = FM_ROOT_URL . fm_convert_win((FM_PATH != '' ? '/' . FM_PATH : '') . '/' . $file); + $file_path = $path . '/' . $file; + + // normal editer + $isNormalEditor = true; + if (isset($_GET['env'])) { + if ($_GET['env'] == "ace") { + $isNormalEditor = false; + } + } + + // Save File + if (isset($_POST['savedata'])) { + $writedata = $_POST['savedata']; + $fd = fopen($file_path, "w"); + @fwrite($fd, $writedata); + fclose($fd); + fm_set_msg(lng('File Saved Successfully')); + } + + $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION)); + $mime_type = fm_get_mime_type($file_path); + $filesize = filesize($file_path); + $is_text = false; + $content = ''; // for text + + if (in_array($ext, fm_get_text_exts()) || substr($mime_type, 0, 4) == 'text' || in_array($mime_type, fm_get_text_mimes())) { + $is_text = true; + $content = file_get_contents($file_path); + } + +?> +
+
+
+ +
+
+
+ + + + + + + + + + + +
+
+
+ ' . htmlspecialchars($content) . ''; + echo ''; + } elseif ($is_text) { + echo '
' . htmlspecialchars($content) . '
'; + } else { + fm_set_msg(lng('FILE EXTENSION HAS NOT SUPPORTED'), 'error'); + } + ?> +
+ +
+
+
+ +
+
+

+ + :
+

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

+ +   + +

+
+
+
+
+ +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + '?'); + $group = array('name' => '?'); + if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) { + try { + $owner_id = fileowner($path . '/' . $f); + if ($owner_id != 0) { + $owner_info = posix_getpwuid($owner_id); + if ($owner_info) { + $owner = $owner_info; + } + } + $group_id = filegroup($path . '/' . $f); + $group_info = posix_getgrgid($group_id); + if ($group_info) { + $group = $group_info; + } + } catch (Exception $e) { + error_log("exception:" . $e->getMessage()); + } + } + ?> + + + + + + + + + + + + + + '?'); + $group = array('name' => '?'); + if (function_exists('posix_getpwuid') && function_exists('posix_getgrgid')) { + try { + $owner_id = fileowner($path . '/' . $f); + if ($owner_id != 0) { + $owner_info = posix_getpwuid($owner_id); + if ($owner_info) { + $owner = $owner_info; + } + } + $group_id = filegroup($path . '/' . $f); + $group_info = posix_getgrgid($group_id); + if ($group_info) { + $group = $group_info; + } + } catch (Exception $e) { + error_log("exception:" . $e->getMessage()); + } + } + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
..
+
+ + +
+
> +
+ + ' . readlink($path . '/' . $f) . '' : '') ?> +
+
"> + + + + + + + + + + + +
+
+ + +
+
> +
+ + + + + + + + + ' . readlink($path . '/' . $f) . '' : '') ?> +
+
"> + + + + + + + + + + +
+ ' . fm_get_filesize($all_files_size) . '' ?> + ' . $num_files . '' ?> + ' . $num_folders . '' ?> +
+
+ +
+ +
+ +
+ + + + +
+
+ +"; + return; + } + + echo "$external[$key]"; +} + +/** + * Verify CSRF TOKEN and remove after certified + * @param string $token + * @return bool + */ +function verifyToken($token) +{ + if (hash_equals($_SESSION['token'], $token)) { + return true; + } + return false; +} + +/** + * Delete file or folder (recursively) + * @param string $path + * @return bool + */ +function fm_rdelete($path) +{ + if (is_link($path)) { + return unlink($path); + } elseif (is_dir($path)) { + $objects = scandir($path); + $ok = true; + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (!fm_rdelete($path . '/' . $file)) { + $ok = false; + } + } + } + } + return ($ok) ? rmdir($path) : false; + } elseif (is_file($path)) { + return unlink($path); + } + return false; +} + +/** + * Recursive chmod + * @param string $path + * @param int $filemode + * @param int $dirmode + * @return bool + * @todo Will use in mass chmod + */ +function fm_rchmod($path, $filemode, $dirmode) +{ + if (is_dir($path)) { + if (!chmod($path, $dirmode)) { + return false; + } + $objects = scandir($path); + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (!fm_rchmod($path . '/' . $file, $filemode, $dirmode)) { + return false; + } + } + } + } + return true; + } elseif (is_link($path)) { + return true; + } elseif (is_file($path)) { + return chmod($path, $filemode); + } + return false; +} + +/** + * Check the file extension which is allowed or not + * @param string $filename + * @return bool + */ +function fm_is_valid_ext($filename) +{ + $allowed = (FM_FILE_EXTENSION) ? explode(',', FM_FILE_EXTENSION) : false; + + $ext = pathinfo($filename, PATHINFO_EXTENSION); + $isFileAllowed = ($allowed) ? in_array($ext, $allowed) : true; + + return ($isFileAllowed) ? true : false; +} + +/** + * Safely rename + * @param string $old + * @param string $new + * @return bool|null + */ +function fm_rename($old, $new) +{ + $isFileAllowed = fm_is_valid_ext($new); + + if (!is_dir($old)) { + if (!$isFileAllowed) return false; + } + + return (!file_exists($new) && file_exists($old)) ? rename($old, $new) : null; +} + +/** + * Copy file or folder (recursively). + * @param string $path + * @param string $dest + * @param bool $upd Update files + * @param bool $force Create folder with same names instead file + * @return bool + */ +function fm_rcopy($path, $dest, $upd = true, $force = true) +{ + if (!is_dir($path) && !is_file($path)) { + return false; + } + + if (is_dir($path)) { + if (!fm_mkdir($dest, $force)) { + return false; + } + + $objects = array_diff(scandir($path), ['.', '..']); + + foreach ($objects as $file) { + if (!fm_rcopy("$path/$file", "$dest/$file", $upd, $force)) { + return false; + } + } + + return true; + } + + // Handle file copying + return fm_copy($path, $dest, $upd); +} + + +/** + * Safely create folder + * @param string $dir + * @param bool $force + * @return bool + */ +function fm_mkdir($dir, $force) +{ + if (file_exists($dir)) { + if (is_dir($dir)) { + return $dir; + } elseif (!$force) { + return false; + } + unlink($dir); + } + return mkdir($dir, 0777, true); +} + +/** + * Safely copy file + * @param string $f1 + * @param string $f2 + * @param bool $upd Indicates if file should be updated with new content + * @return bool + */ +function fm_copy($f1, $f2, $upd) +{ + $time1 = filemtime($f1); + if (file_exists($f2)) { + $time2 = filemtime($f2); + if ($time2 >= $time1 && $upd) { + return false; + } + } + $ok = copy($f1, $f2); + if ($ok) { + touch($f2, $time1); + } + return $ok; +} + +/** + * Get mime type + * @param string $file_path + * @return mixed|string + */ +function fm_get_mime_type($file_path) +{ + if (function_exists('finfo_open')) { + $finfo = finfo_open(FILEINFO_MIME_TYPE); + $mime = finfo_file($finfo, $file_path); + finfo_close($finfo); + return $mime; + } elseif (function_exists('mime_content_type')) { + return mime_content_type($file_path); + } elseif (!stristr(ini_get('disable_functions'), 'shell_exec')) { + $file = escapeshellarg($file_path); + $mime = shell_exec('file -bi ' . $file); + return $mime; + } else { + return '--'; + } +} + +/** + * HTTP Redirect + * @param string $url + * @param int $code + */ +function fm_redirect($url, $code = 302) +{ + header('Location: ' . $url, true, $code); + exit; +} + +/** + * Path traversal prevention and clean the url + * It replaces (consecutive) occurrences of / and \\ with whatever is in DIRECTORY_SEPARATOR, and processes /. and /.. fine. + * @param $path + * @return string + */ +function get_absolute_path($path) +{ + $path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path); + $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'); + $absolutes = array(); + foreach ($parts as $part) { + if ('.' == $part) continue; + if ('..' == $part) { + array_pop($absolutes); + } else { + $absolutes[] = $part; + } + } + return implode(DIRECTORY_SEPARATOR, $absolutes); +} + +/** + * Clean path + * @param string $path + * @return string + */ +function fm_clean_path($path, $trim = true) +{ + $path = $trim ? trim($path) : $path; + $path = trim($path, '\\/'); + $path = str_replace(array('../', '..\\'), '', $path); + $path = get_absolute_path($path); + if ($path == '..') { + $path = ''; + } + return str_replace('\\', '/', $path); +} + +/** + * Get parent path + * @param string $path + * @return bool|string + */ +function fm_get_parent_path($path) +{ + $path = fm_clean_path($path); + if ($path != '') { + $array = explode('/', $path); + if (count($array) > 1) { + $array = array_slice($array, 0, -1); + return implode('/', $array); + } + return ''; + } + return false; +} + +function fm_get_display_path($file_path) +{ + global $path_display_mode, $root_path, $root_url; + switch ($path_display_mode) { + case 'relative': + return array( + 'label' => 'Path', + 'path' => fm_enc(fm_convert_win(str_replace($root_path, '', $file_path))) + ); + case 'host': + $relative_path = str_replace($root_path, '', $file_path); + return array( + 'label' => 'Host Path', + 'path' => fm_enc(fm_convert_win('/' . $root_url . '/' . ltrim(str_replace('\\', '/', $relative_path), '/'))) + ); + case 'full': + default: + return array( + 'label' => 'Full Path', + 'path' => fm_enc(fm_convert_win($file_path)) + ); + } +} + +/** + * Check file is in exclude list + * @param string $name The name of the file/folder + * @param string $path The full path of the file/folder + * @return bool + */ +function fm_is_exclude_items($name, $path) +{ + $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + if (isset($exclude_items) and sizeof($exclude_items)) { + unset($exclude_items); + } + + $exclude_items = FM_EXCLUDE_ITEMS; + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + $exclude_items = unserialize($exclude_items); + } + if (!in_array($name, $exclude_items) && !in_array("*.$ext", $exclude_items) && !in_array($path, $exclude_items)) { + return true; + } + return false; +} + +/** + * get language translations from json file + * @param int $tr + * @return array + */ +function fm_get_translations($tr) +{ + try { + $content = @file_get_contents('translation.json'); + if ($content !== FALSE) { + $lng = json_decode($content, TRUE); + global $lang_list; + foreach ($lng["language"] as $key => $value) { + $code = $value["code"]; + $lang_list[$code] = $value["name"]; + if ($tr) + $tr[$code] = $value["translation"]; + } + return $tr; + } + } catch (Exception $e) { + echo $e; + } +} + +/** + * @param string $file + * Recover all file sizes larger than > 2GB. + * Works on php 32bits and 64bits and supports linux + * @return int|string + */ +function fm_get_size($file) +{ + static $iswin = null; + static $isdarwin = null; + static $exec_works = null; + + // Set static variables once + if ($iswin === null) { + $iswin = strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'; + $isdarwin = strtoupper(PHP_OS) === 'DARWIN'; + $exec_works = function_exists('exec') && !ini_get('safe_mode') && @exec('echo EXEC') === 'EXEC'; + } + + // Attempt shell command if exec is available + if ($exec_works) { + $arg = escapeshellarg($file); + $cmd = $iswin ? "for %F in (\"$file\") do @echo %~zF" : ($isdarwin ? "stat -f%z $arg" : "stat -c%s $arg"); + @exec($cmd, $output); + + if (!empty($output) && ctype_digit($size = trim(implode("\n", $output)))) { + return $size; + } + } + + // Attempt Windows COM interface for Windows systems + if ($iswin && class_exists('COM')) { + try { + $fsobj = new COM('Scripting.FileSystemObject'); + $f = $fsobj->GetFile(realpath($file)); + if (ctype_digit($size = $f->Size)) { + return $size; + } + } catch (Exception $e) { + // COM failed, fallback to filesize + } + } + + // Default to PHP's filesize function + return filesize($file); +} + + +/** + * Get nice filesize + * @param int $size + * @return string + */ +function fm_get_filesize($size) +{ + $size = (float) $size; + $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); + $power = ($size > 0) ? floor(log($size, 1024)) : 0; + $power = ($power > (count($units) - 1)) ? (count($units) - 1) : $power; + return sprintf('%s %s', round($size / pow(1024, $power), 2), $units[$power]); +} + +/** + * Get info about zip archive + * @param string $path + * @return array|bool + */ +function fm_get_zif_info($path, $ext) +{ + if ($ext == 'zip' && function_exists('zip_open')) { + $arch = @zip_open($path); + if ($arch) { + $filenames = array(); + while ($zip_entry = @zip_read($arch)) { + $zip_name = @zip_entry_name($zip_entry); + $zip_folder = substr($zip_name, -1) == '/'; + $filenames[] = array( + 'name' => $zip_name, + 'filesize' => @zip_entry_filesize($zip_entry), + 'compressed_size' => @zip_entry_compressedsize($zip_entry), + 'folder' => $zip_folder + //'compression_method' => zip_entry_compressionmethod($zip_entry), + ); + } + @zip_close($arch); + return $filenames; + } + } elseif ($ext == 'tar' && class_exists('PharData')) { + $archive = new PharData($path); + $filenames = array(); + foreach (new RecursiveIteratorIterator($archive) as $file) { + $parent_info = $file->getPathInfo(); + $zip_name = str_replace("phar://" . $path, '', $file->getPathName()); + $zip_name = substr($zip_name, ($pos = strpos($zip_name, '/')) !== false ? $pos + 1 : 0); + $zip_folder = $parent_info->getFileName(); + $zip_info = new SplFileInfo($file); + $filenames[] = array( + 'name' => $zip_name, + 'filesize' => $zip_info->getSize(), + 'compressed_size' => $file->getCompressedSize(), + 'folder' => $zip_folder + ); + } + return $filenames; + } + return false; +} + +/** + * Encode html entities + * @param string $text + * @return string + */ +function fm_enc($text) +{ + return htmlspecialchars($text, ENT_QUOTES, 'UTF-8'); +} + +/** + * Prevent XSS attacks + * @param string $text + * @return string + */ +function fm_isvalid_filename($text) +{ + return (strpbrk($text, '/?%*:|"<>') === FALSE) ? true : false; +} + +/** + * Save message in session + * @param string $msg + * @param string $status + */ +function fm_set_msg($msg, $status = 'ok') +{ + $_SESSION[FM_SESSION_ID]['message'] = $msg; + $_SESSION[FM_SESSION_ID]['status'] = $status; +} + +/** + * Check if string is in UTF-8 + * @param string $string + * @return int + */ +function fm_is_utf8($string) +{ + return preg_match('//u', $string); +} + +/** + * Convert file name to UTF-8 in Windows + * @param string $filename + * @return string + */ +function fm_convert_win($filename) +{ + if (FM_IS_WIN && function_exists('iconv')) { + $filename = iconv(FM_ICONV_INPUT_ENC, 'UTF-8//IGNORE', $filename); + } + return $filename; +} + +/** + * @param $obj + * @return array + */ +function fm_object_to_array($obj) +{ + if (!is_object($obj) && !is_array($obj)) { + return $obj; + } + if (is_object($obj)) { + $obj = get_object_vars($obj); + } + return array_map('fm_object_to_array', $obj); +} + +/** + * Get CSS classname for file + * @param string $path + * @return string + */ +function fm_get_file_icon_class($path) +{ + // get extension + $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + + switch ($ext) { + case 'ico': + case 'gif': + case 'jpg': + case 'jpeg': + case 'jpc': + case 'jp2': + case 'jpx': + case 'xbm': + case 'wbmp': + case 'png': + case 'bmp': + case 'tif': + case 'tiff': + case 'webp': + case 'avif': + case 'svg': + $img = 'fa fa-picture-o'; + break; + case 'passwd': + case 'ftpquota': + case 'sql': + case 'js': + case 'ts': + case 'jsx': + case 'tsx': + case 'hbs': + case 'json': + case 'sh': + case 'config': + case 'twig': + case 'tpl': + case 'md': + case 'gitignore': + case 'c': + case 'cpp': + case 'cs': + case 'py': + case 'rs': + case 'map': + case 'lock': + case 'dtd': + case 'ps1': + $img = 'fa fa-file-code-o'; + break; + case 'txt': + case 'ini': + case 'conf': + case 'log': + case 'htaccess': + case 'yaml': + case 'yml': + case 'toml': + case 'tmp': + case 'top': + case 'bot': + case 'dat': + case 'bak': + case 'htpasswd': + case 'pl': + $img = 'fa fa-file-text-o'; + break; + case 'css': + case 'less': + case 'sass': + case 'scss': + $img = 'fa fa-css3'; + break; + case 'bz2': + case 'tbz2': + case 'tbz': + case 'zip': + case 'rar': + case 'gz': + case 'tgz': + case 'tar': + case '7z': + case 'xz': + case 'txz': + case 'zst': + case 'tzst': + $img = 'fa fa-file-archive-o'; + break; + case 'php': + case 'php4': + case 'php5': + case 'phps': + case 'phtml': + $img = 'fa fa-code'; + break; + case 'htm': + case 'html': + case 'shtml': + case 'xhtml': + $img = 'fa fa-html5'; + break; + case 'xml': + case 'xsl': + $img = 'fa fa-file-excel-o'; + break; + case 'wav': + case 'mp3': + case 'mp2': + case 'm4a': + case 'aac': + case 'ogg': + case 'oga': + case 'wma': + case 'mka': + case 'flac': + case 'ac3': + case 'tds': + $img = 'fa fa-music'; + break; + case 'm3u': + case 'm3u8': + case 'pls': + case 'cue': + case 'xspf': + $img = 'fa fa-headphones'; + break; + case 'avi': + case 'mpg': + case 'mpeg': + case 'mp4': + case 'm4v': + case 'flv': + case 'f4v': + case 'ogm': + case 'ogv': + case 'mov': + case 'mkv': + case '3gp': + case 'asf': + case 'wmv': + case 'webm': + $img = 'fa fa-file-video-o'; + break; + case 'eml': + case 'msg': + $img = 'fa fa-envelope-o'; + break; + case 'xls': + case 'xlsx': + case 'ods': + $img = 'fa fa-file-excel-o'; + break; + case 'csv': + $img = 'fa fa-file-text-o'; + break; + case 'bak': + case 'swp': + $img = 'fa fa-clipboard'; + break; + case 'doc': + case 'docx': + case 'odt': + $img = 'fa fa-file-word-o'; + break; + case 'ppt': + case 'pptx': + $img = 'fa fa-file-powerpoint-o'; + break; + case 'ttf': + case 'ttc': + case 'otf': + case 'woff': + case 'woff2': + case 'eot': + case 'fon': + $img = 'fa fa-font'; + break; + case 'pdf': + $img = 'fa fa-file-pdf-o'; + break; + case 'psd': + case 'ai': + case 'eps': + case 'fla': + case 'swf': + $img = 'fa fa-file-image-o'; + break; + case 'exe': + case 'msi': + $img = 'fa fa-file-o'; + break; + case 'bat': + $img = 'fa fa-terminal'; + break; + default: + $img = 'fa fa-info-circle'; + } + + return $img; +} + +/** + * Get image files extensions + * @return array + */ +function fm_get_image_exts() +{ + return array('ico', 'gif', 'jpg', 'jpeg', 'jpc', 'jp2', 'jpx', 'xbm', 'wbmp', 'png', 'bmp', 'tif', 'tiff', 'psd', 'svg', 'webp', 'avif'); +} + +/** + * Get video files extensions + * @return array + */ +function fm_get_video_exts() +{ + return array('avi', 'webm', 'wmv', 'mp4', 'm4v', 'ogm', 'ogv', 'mov', 'mkv'); +} + +/** + * Get audio files extensions + * @return array + */ +function fm_get_audio_exts() +{ + return array('wav', 'mp3', 'ogg', 'm4a'); +} + +/** + * Get text file extensions + * @return array + */ +function fm_get_text_exts() +{ + return array( + 'txt', + 'css', + 'ini', + 'conf', + 'log', + 'htaccess', + 'passwd', + 'ftpquota', + 'sql', + 'js', + 'ts', + 'jsx', + 'tsx', + 'mjs', + 'json', + 'sh', + 'config', + 'php', + 'php4', + 'php5', + 'phps', + 'phtml', + 'htm', + 'html', + 'shtml', + 'xhtml', + 'xml', + 'xsl', + 'm3u', + 'm3u8', + 'pls', + 'cue', + 'bash', + 'vue', + 'eml', + 'msg', + 'csv', + 'bat', + 'twig', + 'tpl', + 'md', + 'gitignore', + 'less', + 'sass', + 'scss', + 'c', + 'cpp', + 'cs', + 'py', + 'go', + 'zsh', + 'swift', + 'map', + 'lock', + 'dtd', + 'svg', + 'asp', + 'aspx', + 'asx', + 'asmx', + 'ashx', + 'jsp', + 'jspx', + 'cgi', + 'dockerfile', + 'ruby', + 'yml', + 'yaml', + 'toml', + 'vhost', + 'scpt', + 'applescript', + 'csx', + 'cshtml', + 'c++', + 'coffee', + 'cfm', + 'rb', + 'graphql', + 'mustache', + 'jinja', + 'http', + 'handlebars', + 'java', + 'es', + 'es6', + 'markdown', + 'wiki', + 'tmp', + 'top', + 'bot', + 'dat', + 'bak', + 'htpasswd', + 'pl', + 'ps1' + ); +} + +/** + * Get mime types of text files + * @return array + */ +function fm_get_text_mimes() +{ + return array( + 'application/xml', + 'application/javascript', + 'application/x-javascript', + 'image/svg+xml', + 'message/rfc822', + 'application/json', + ); +} + +/** + * Get file names of text files w/o extensions + * @return array + */ +function fm_get_text_names() +{ + return array( + 'license', + 'readme', + 'authors', + 'contributors', + 'changelog', + ); +} + +/** + * Get online docs viewer supported files extensions + * @return array + */ +function fm_get_onlineViewer_exts() +{ + return array('doc', 'docx', 'xls', 'xlsx', 'pdf', 'ppt', 'pptx', 'ai', 'psd', 'dxf', 'xps', 'rar', 'odt', 'ods'); +} + +/** + * It returns the mime type of a file based on its extension. + * @param extension The file extension of the file you want to get the mime type for. + * @return string|string[] The mime type of the file. + */ +function fm_get_file_mimes($extension) +{ + $fileTypes['swf'] = 'application/x-shockwave-flash'; + $fileTypes['pdf'] = 'application/pdf'; + $fileTypes['exe'] = 'application/octet-stream'; + $fileTypes['zip'] = 'application/zip'; + $fileTypes['doc'] = 'application/msword'; + $fileTypes['xls'] = 'application/vnd.ms-excel'; + $fileTypes['ppt'] = 'application/vnd.ms-powerpoint'; + $fileTypes['gif'] = 'image/gif'; + $fileTypes['png'] = 'image/png'; + $fileTypes['jpeg'] = 'image/jpg'; + $fileTypes['jpg'] = 'image/jpg'; + $fileTypes['webp'] = 'image/webp'; + $fileTypes['avif'] = 'image/avif'; + $fileTypes['rar'] = 'application/rar'; + + $fileTypes['ra'] = 'audio/x-pn-realaudio'; + $fileTypes['ram'] = 'audio/x-pn-realaudio'; + $fileTypes['ogg'] = 'audio/x-pn-realaudio'; + + $fileTypes['wav'] = 'video/x-msvideo'; + $fileTypes['wmv'] = 'video/x-msvideo'; + $fileTypes['avi'] = 'video/x-msvideo'; + $fileTypes['asf'] = 'video/x-msvideo'; + $fileTypes['divx'] = 'video/x-msvideo'; + + $fileTypes['mp3'] = 'audio/mpeg'; + $fileTypes['mp4'] = 'video/mp4'; + $fileTypes['mpeg'] = 'video/mpeg'; + $fileTypes['mpg'] = 'video/mpeg'; + $fileTypes['mpe'] = 'video/mpeg'; + $fileTypes['mov'] = 'video/quicktime'; + $fileTypes['swf'] = 'video/quicktime'; + $fileTypes['3gp'] = 'video/quicktime'; + $fileTypes['m4a'] = 'video/quicktime'; + $fileTypes['aac'] = 'video/quicktime'; + $fileTypes['m3u'] = 'video/quicktime'; + + $fileTypes['php'] = ['application/x-php']; + $fileTypes['html'] = ['text/html']; + $fileTypes['txt'] = ['text/plain']; + //Unknown mime-types should be 'application/octet-stream' + if (empty($fileTypes[$extension])) { + $fileTypes[$extension] = ['application/octet-stream']; + } + return $fileTypes[$extension]; +} + +/** + * This function scans the files and folder recursively, and return matching files + * @param string $dir + * @param string $filter + * @return array|null + */ +function scan($dir = '', $filter = '') +{ + $path = FM_ROOT_PATH . '/' . $dir; + if ($path) { + $ite = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)); + $rii = new RegexIterator($ite, "/(" . $filter . ")/i"); + + $files = array(); + foreach ($rii as $file) { + if (!$file->isDir()) { + $fileName = $file->getFilename(); + $location = str_replace(FM_ROOT_PATH, '', $file->getPath()); + $files[] = array( + "name" => $fileName, + "type" => "file", + "path" => $location, + ); + } + } + return $files; + } +} + +/** + * Parameters: downloadFile(File Location, File Name, + * max speed, is streaming + * If streaming - videos will show as videos, images as images + * instead of download prompt + * https://stackoverflow.com/a/13821992/1164642 + */ +function fm_download_file($fileLocation, $fileName, $chunkSize = 1024) +{ + if (connection_status() != 0) + return (false); + $extension = pathinfo($fileName, PATHINFO_EXTENSION); + + $contentType = fm_get_file_mimes($extension); + + if (is_array($contentType)) { + $contentType = implode(' ', $contentType); + } + + $size = filesize($fileLocation); + + if ($size == 0) { + fm_set_msg(lng('Zero byte file! Aborting download'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + + return (false); + } + + @ini_set('magic_quotes_runtime', 0); + $fp = fopen("$fileLocation", "rb"); + + if ($fp === false) { + fm_set_msg(lng('Cannot open file! Aborting download'), 'error'); + $FM_PATH = FM_PATH; + fm_redirect(FM_SELF_URL . '?p=' . urlencode($FM_PATH)); + return (false); + } + + // headers + header('Content-Description: File Transfer'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + header('Pragma: public'); + header("Content-Transfer-Encoding: binary"); + header("Content-Type: $contentType"); + + $contentDisposition = 'attachment'; + + if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) { + $fileName = preg_replace('/\./', '%2e', $fileName, substr_count($fileName, '.') - 1); + header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); + } else { + header("Content-Disposition: $contentDisposition;filename=\"$fileName\""); + } + + header("Accept-Ranges: bytes"); + $range = 0; + + if (isset($_SERVER['HTTP_RANGE'])) { + list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']); + str_replace($range, "-", $range); + $size2 = $size - 1; + $new_length = $size - $range; + header("HTTP/1.1 206 Partial Content"); + header("Content-Length: $new_length"); + header("Content-Range: bytes $range$size2/$size"); + } else { + $size2 = $size - 1; + header("Content-Range: bytes 0-$size2/$size"); + header("Content-Length: " . $size); + } + $fileLocation = realpath($fileLocation); + while (ob_get_level()) ob_end_clean(); + readfile($fileLocation); + + fclose($fp); + + return ((connection_status() == 0) and !connection_aborted()); +} + +/** + * Class to work with zip files (using ZipArchive) + */ +class FM_Zipper +{ + private $zip; + + public function __construct() + { + $this->zip = new ZipArchive(); + } + + /** + * Create archive with name $filename and files $files (RELATIVE PATHS!) + * @param string $filename + * @param array|string $files + * @return bool + */ + public function create($filename, $files) + { + $res = $this->zip->open($filename, ZipArchive::CREATE); + if ($res !== true) { + return false; + } + if (is_array($files)) { + foreach ($files as $f) { + $f = fm_clean_path($f); + if (!$this->addFileOrDir($f)) { + $this->zip->close(); + return false; + } + } + $this->zip->close(); + return true; + } else { + if ($this->addFileOrDir($files)) { + $this->zip->close(); + return true; + } + return false; + } + } + + /** + * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) + * @param string $filename + * @param string $path + * @return bool + */ + public function unzip($filename, $path) + { + $res = $this->zip->open($filename); + if ($res !== true) { + return false; + } + if ($this->zip->extractTo($path)) { + $this->zip->close(); + return true; + } + return false; + } + + /** + * Add file/folder to archive + * @param string $filename + * @return bool + */ + private function addFileOrDir($filename) + { + if (is_file($filename)) { + return $this->zip->addFile($filename); + } elseif (is_dir($filename)) { + return $this->addDir($filename); + } + return false; + } + + /** + * Add folder recursively + * @param string $path + * @return bool + */ + private function addDir($path) + { + if (!$this->zip->addEmptyDir($path)) { + return false; + } + $objects = scandir($path); + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (is_dir($path . '/' . $file)) { + if (!$this->addDir($path . '/' . $file)) { + return false; + } + } elseif (is_file($path . '/' . $file)) { + if (!$this->zip->addFile($path . '/' . $file)) { + return false; + } + } + } + } + return true; + } + return false; + } +} + +/** + * Class to work with Tar files (using PharData) + */ +class FM_Zipper_Tar +{ + private $tar; + + public function __construct() + { + $this->tar = null; + } + + /** + * Create archive with name $filename and files $files (RELATIVE PATHS!) + * @param string $filename + * @param array|string $files + * @return bool + */ + public function create($filename, $files) + { + $this->tar = new PharData($filename); + if (is_array($files)) { + foreach ($files as $f) { + $f = fm_clean_path($f); + if (!$this->addFileOrDir($f)) { + return false; + } + } + return true; + } else { + if ($this->addFileOrDir($files)) { + return true; + } + return false; + } + } + + /** + * Extract archive $filename to folder $path (RELATIVE OR ABSOLUTE PATHS) + * @param string $filename + * @param string $path + * @return bool + */ + public function unzip($filename, $path) + { + $res = $this->tar->open($filename); + if ($res !== true) { + return false; + } + if ($this->tar->extractTo($path)) { + return true; + } + return false; + } + + /** + * Add file/folder to archive + * @param string $filename + * @return bool + */ + private function addFileOrDir($filename) + { + if (is_file($filename)) { + try { + $this->tar->addFile($filename); + return true; + } catch (Exception $e) { + return false; + } + } elseif (is_dir($filename)) { + return $this->addDir($filename); + } + return false; + } + + /** + * Add folder recursively + * @param string $path + * @return bool + */ + private function addDir($path) + { + $objects = scandir($path); + if (is_array($objects)) { + foreach ($objects as $file) { + if ($file != '.' && $file != '..') { + if (is_dir($path . '/' . $file)) { + if (!$this->addDir($path . '/' . $file)) { + return false; + } + } elseif (is_file($path . '/' . $file)) { + try { + $this->tar->addFile($path . '/' . $file); + } catch (Exception $e) { + return false; + } + } + } + } + return true; + } + return false; + } +} + +/** + * Save Configuration + */ +class FM_Config +{ + var $data; + + function __construct() + { + global $root_path, $root_url, $CONFIG; + $fm_url = $root_url . $_SERVER["PHP_SELF"]; + $this->data = array( + 'lang' => 'en', + 'error_reporting' => true, + 'show_hidden' => true + ); + $data = false; + if (strlen($CONFIG)) { + $data = fm_object_to_array(json_decode($CONFIG)); + } else { + $msg = 'Tiny File Manager
Error: Cannot load configuration'; + if (substr($fm_url, -1) == '/') { + $fm_url = rtrim($fm_url, '/'); + $msg .= '
'; + $msg .= '
Seems like you have a trailing slash on the URL.'; + $msg .= '
Try this link: ' . $fm_url . ''; + } + die($msg); + } + if (is_array($data) && count($data)) $this->data = $data; + else $this->save(); + } + + function save() + { + global $config_file; + $fm_file = is_readable($config_file) ? $config_file : __FILE__; + $var_name = '$CONFIG'; + $var_value = var_export(json_encode($this->data), true); + $config_string = " + +' . $_SESSION[FM_SESSION_ID]['message'] . '

'; + unset($_SESSION[FM_SESSION_ID]['message']); + unset($_SESSION[FM_SESSION_ID]['status']); + } +} + +/** + * Show page header in Login Form + */ +function fm_show_header_login() +{ + header("Content-Type: text/html; charset=utf-8"); + header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); + header("Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0"); + header("Pragma: no-cache"); + + global $favicon_path; +?> + + "> + + + + + + + + + '; + } ?> + <?php echo fm_enc(APP_TITLE) ?> + + + + + + "> +
+ + +
+ + + + + + + + + + + + + + + + + + '; + } ?> + <?php echo fm_enc(APP_TITLE) ?> | <?php echo (isset($_GET['view']) ? $_GET['view'] : ((isset($_GET['edit'])) ? $_GET['edit'] : "H3K")); ?> + + + + + + + + + + + + + + + "> +
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + +
+ + + + diff --git a/servicios/tfm/translation.json b/servicios/tfm/translation.json new file mode 100644 index 00000000..2c3239ab --- /dev/null +++ b/servicios/tfm/translation.json @@ -0,0 +1,2936 @@ +{ + "appName": "Tiny File Manager", + "version": "2.6", + "language": [ + { + "name": "Română", + "code": "ro", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Titlu aplicație", + "Login": "Autentificare", + "Username": "Nume utilizator", + "Password": "Parolă", + "Logout": "Ieșire", + "Move": "Mută", + "Copy": "Copiază", + "Save": "Salvează", + "SelectAll": "Selectează tot", + "UnSelectAll": "Deselectează tot", + "File": "Fișier", + "Back": "Înapoi", + "Size": "Dimensiune", + "Perms": "Permisiuni", + "Modified": "Modificat", + "Owner": "Proprietar", + "Search": "Caută", + "NewItem": "Nou", + "Folder": "Dosar", + "Delete": "Șterge", + "Rename": "Redenumește", + "CopyTo": "Copiază în", + "DirectLink": "Legătură directă", + "UploadingFiles": "Se încarcă fișiere", + "ChangePermissions": "Schimbă permisiunile", + "Copying": "Se copiază", + "CreateNewItem": "Creează element nou", + "Name": "Denumire", + "AdvancedEditor": "Redactor avansat", + "RememberMe": "Ține-mă minte", + "Actions": "Acțiuni", + "Upload": "Încarcă", + "Cancel": "Anulează", + "InvertSelection": "Inversează selecția", + "DestinationFolder": "Dosar destinație", + "ItemType": "Tip element", + "ItemName": "Denumire element", + "CreateNow": "Creează acum", + "Download": "Descarcă", + "Open": "Deschide", + "UnZip": "Decomprimă", + "UnZipToFolder": "Decomprimă în dosar", + "Edit": "Modifică", + "NormalEditor": "Redactor standard", + "BackUp": "Copie de rezervă", + "SourceFolder": "Dosar sursă", + "Files": "Fișiere", + "Change": "Schimbă", + "Settings": "Configurări", + "Language": "Limba", + "MemoryUsed": "Memorie utilizată", + "PartitionSize": "Dimensiune partiție", + "ErrorReporting": "Raportare erori", + "ShowHiddenFiles": "Arată fișiere ascunse", + "Full size": "Dimensiune totală", + "Help": "Ajutor", + "Free of": "Liber din", + "Preview": "Previzualizează", + "Help Documents": "Documentație", + "Report Issue": "Raportează defect", + "Generate": "Generează", + "FullSize": "Dimensiune completă", + "FreeOf": "Liber din", + "CalculateFolderSize": "Calculează dimensiunea dosarului", + "ProcessID": "Id. proces", + "Created": "Creat", + "HideColumns": "Ascunde coloanele", + "Folder is empty": "Dosarul este gol", + "Check Latest Version": "Verifică ultima versiune", + "Generate new password hash": "Generează hash nou parolă", + "You are logged in": "Sunteți autentificat", + "Login failed. Invalid username or password": "Autentificare eșuată. Utilizator sau parolă incorecte", + "password_hash not supported, Upgrade PHP version": "Generare hash parolă nesuportată, actualizați versiunea de PHP", + "Theme": "Tematică", + "dark": "Întunecată", + "light": "Luminoasă" + } + }, + { + "name": "Hungarian", + "code": "hu", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Fájl kezelő", + "Login": "Bejelentkezés", + "Username": "Felhasználói név", + "Password": "Jelszó", + "Logout": "Kijelentkezés", + "Move": "Mozgatás", + "Copy": "Másolás", + "Save": "Mentés", + "SelectAll": "Mindet kijelöl", + "UnSelectAll": "Kijelölést megszüntet", + "File": "Fájl", + "Back": "Vissza", + "Size": "Méret", + "Perms": "Jogok", + "Modified": "Módosítás", + "Owner": "Tulajdonos", + "Search": "Keresés", + "NewItem": "Új", + "Folder": "Könyvtár", + "Delete": "Törlés", + "Rename": "Átnevezés", + "CopyTo": "Másolás ide", + "DirectLink": "Közvetlen link", + "UploadingFiles": "Fájlok feltöltése", + "ChangePermissions": "Jogosultságok módosítása", + "Copying": "Másolás", + "CreateNewItem": "Új létrehozása", + "Name": "Név", + "AdvancedEditor": "Haladó szerkesztő", + "RememberMe": "Emlékezzen rám", + "Actions": "Műveletek", + "Upload": "Feltöltés", + "Cancel": "Mégsem", + "InvertSelection": "Kijelöltés megfordítása", + "DestinationFolder": "Célmappa", + "ItemType": "Elem típus", + "ItemName": "Elem név", + "CreateNow": "Elkészít", + "Download": "Letöltés", + "Open": "Megnyitás", + "UnZip": "Kitömörítés", + "UnZipToFolder": "Kitömörítás adott mappába", + "Edit": "Szerkesztés", + "NormalEditor": "Alap szerkesztő", + "BackUp": "Biztonsági mentés", + "SourceFolder": "Forrás könyvtár", + "Files": "Szűrő", + "Change": "Módosítás", + "Settings": "Beállítások", + "Language": "Nyelv", + "MemoryUsed": "Használt memória", + "PartitionSize": "Partició mérete", + "ErrorReporting": "Hibabejelntés", + "ShowHiddenFiles": "Rejtett fájlok megjelenítése", + "Full size": "Teljes méret", + "Help": "Segítség", + "Free of": "ebből szabaf", + "Preview": "Előnézet", + "Help Documents": "Súgó dokumentum", + "Report Issue": "Probléma jelentése", + "Generate": "Generálás", + "FullSize": "Teljes méret", + "FreeOf": "ebből szabad", + "CalculateFolderSize": "Becsült mappa méret", + "ProcessID": "Folyamat azonosító", + "Created": "Készítés", + "HideColumns": "Oszlopok elrejtése", + "Folder is empty": "A mappa üres", + "Check Latest Version": "Új verzió ellenőrzése", + "Generate new password hash": "Új jelszó hash létrehozása", + "You are logged in": "Ön sikeresen bejelentkezett", + "Login failed. Invalid username or password": "Sikertelen bejelentkezés. Hibás felhasználói név vagy jelszó.", + "password_hash not supported, Upgrade PHP version": "password_hash ebben a PHP verzióban nem támogatott" + } + }, + { + "name": "Norsk", + "code": "no", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Fil behandler", + "Login": "Logg inn", + "Username": "Brukernavn", + "Password": "Passord", + "Logout": "Logg ut", + "Move": "Flytt", + "Copy": "Kopier", + "Save": "Lagre", + "SelectAll": "Velg alt", + "UnSelectAll": "Av velg alt", + "File": "Fil", + "Back": "Tilbake", + "Size": "Størelse", + "Perms": "Uprawnienia", + "Modified": "Endret", + "Owner": "Eier", + "Search": "Søk", + "NewItem": "Ny", + "Folder": "Mappe", + "Delete": "Slett", + "Rename": "Gi nytt navn", + "CopyTo": "Kopier til", + "DirectLink": "Direktelink", + "UploadingFiles": "Laster opp filer", + "ChangePermissions": "Endre rettigheter", + "Copying": "Kopierer", + "CreateNewItem": "Lag ny", + "Name": "Navn", + "AdvancedEditor": "Avansert Tekstbehandler", + "RememberMe": "Husk meg", + "Actions": "Handlinger", + "Upload": "Last opp", + "Cancel": "Avbryt", + "InvertSelection": "Inverter valgte", + "DestinationFolder": "Målmappe", + "ItemType": "Filtype", + "ItemName": "Filnavn", + "CreateNow": "Lag nå", + "Download": "Last ned", + "Open": "Åpne", + "UnZip": "Pakk ut", + "UnZipToFolder": "Pakk ut til mappe", + "Edit": "Endre", + "NormalEditor": "Normal Tekstbehandler", + "BackUp": "Sikkerhetskopier", + "SourceFolder": "Kildemappe", + "Files": "Filer", + "Change": "Endre", + "Settings": "Instillinger", + "Language": "Språk", + "MemoryUsed": "Minne brukt", + "PartitionSize": "Partitions størrelse", + "ErrorReporting": "Error raportering", + "ShowHiddenFiles": "Vis skjulte filer", + "Full size": "Mappe størelse", + "Help": "Hjelp", + "Free of": "Ledig av", + "Preview": "Forhåndsvisning", + "Help Documents": "Help dokumenter", + "Report Issue": "Raporter problem", + "Generate": "Generer", + "FullSize": "Mappe størelse", + "FreeOf": "ledig av", + "CalculateFolderSize": "Kalkuler mappestørelse", + "ProcessID": "Prosess ID", + "Created": "Opprettet", + "HideColumns": "Skjul tilganger/eier kolonner", + "Folder is empty": "Mappen er tom", + "Check Latest Version": "Se etter oppdateringer", + "Generate new password hash": "Generer en ny passord hash", + "You are logged in": "Du er innlogget", + "Login failed. Invalid username or password": "Innlogging feilet. Feil brukernavn eller passord", + "password_hash not supported, Upgrade PHP version": "password_hash er ikke støttet, venligst oppdater PHP versjonen" + } + }, + { + "name": "فارسی", + "code": "Fa", + "translation": { + "Tiny File Manager": "مدیریت فایل کوچک", + "File Manager": "مدیریت فایل", + "Sign in": "ورود", + "Username": "نام کاربری", + "Password": "گذرواژه", + "Sign Out": "خروج", + "Move": "جابجایی", + "Copy": "کپی", + "Save": "ذخیره", + "Select all": "انتخاب همه", + "Unselect all": "انتخاب نکردن همه", + "File": "فایل", + "Back": "برگشت", + "Size": "حجم", + "Perms": "دسترسی", + "Modified": "ویرایش شده", + "Owner": "مالک", + "Search": "جستجو", + "New Item": "افزودن", + "Folder": "پوشه", + "Delete": "حذف", + "Rename": "تغییر نام", + "Copy to": "کپی در", + "Direct link": "لینک مستقیم", + "Upload Files": "اپلود فایل ها", + "Change Permissions": "تغییر دسترسی", + "Copying": "کپی کردن", + "Create New Item": "افزودن", + "Name": "نام", + "Advanced Editor": "ویرایشگر پیشرفته", + "Remember Me": "مرا به خاطر داشته باشe", + "Actions": "اکشن", + "Upload": "آپلود", + "Cancel": "انصراف", + "Invert Selection": "معکوس کردن انتخاب ها", + "Destination Folder": "پوشه مقصد", + "Item Type": "نوع مورد", + "Item Name": "نام مورد", + "Create Now": "ایجاد در الان", + "Download": "دانلود", + "Open": "باز کردن", + "UnZip": "UnZip", + "UnZip to folder": "خارج کردن از حالت فشرده", + "Edit": "ویرایش", + "Normal Editor": "ویرایش معمولی", + "Back Up": "برگشت بالا", + "Source Folder": "منبه پوشه", + "Files": "فایل ها", + "Change": "تغییر", + "Settings": "تنظیمات", + "Language": "زبان", + "Memory used": "حافظه استفاده شده", + "Partition size": "حجم پارتیشن", + "Error Reporting": "گزارش خطا", + "Show Hidden Files": "نمایش فایل های مخفی", + "Full size": "فضا پر است", + "Help": "راهنما", + "Free of": "خالیی از", + "Preview": "پیشنمایش", + "Help Documents": "مستندات کمکی", + "Report Issue": "گزارش مشکل", + "Generate": "ایجاد", + "Full Size": "تمام حجم", + "free of": "خالی از", + "Calculate folder size": "محاسبه حجم پوشه", + "Check Latest Version": "بررسی آخرین نسخه", + "Generate new password hash": "ایجاد گذرواژه جدید", + "Hide Perms/Owner columns": "مخفی کردن ستون های دسترسی و مالک" + } + }, + { + "name": "Русский", + "code": "ru", + "translation": { + "Access denied. IP restriction applicable": "Доступ с данного IP запрещён", + "Actions": "Действия", + "AdvancedEditor": "Улучшенный редактор", + "Advanced Search": "Расширенный поиск", + "already exists": "уже существует", + "AppName": "Файловый менеджер", + "AppTitle": "Файловый менеджер", + "Archive": "Архив", + "Archive not created": "Архив не создан", + "Archive not unpacked": "Архив не распакован", + "Archive unpacked": "Архив распакован", + "Back": "Вернуться", + "BackUp": "Резервная копия", + "CalculateFolderSize": "Считать размер папки", + "Cancel": "Отмена", + "Change": "Изменения", + "ChangePermissions": "Изменить права", + "Check Latest Version": "Проверить последнюю версию", + "Copied from": "Скопирован(а)", + "Copy": "Копировать", + "Copying": "Копировать", + "CopyTo": "Скопировать в", + "Create archive?": "Создать архив?", + "Created": "Создан(а)", + "CreateNewItem": "Создать новый", + "CreateNow": "Создать сейчас", + "dark": "тёмная", + "Delete": "Удалить", + "Deleted": "удалён(ена)", + "Delete selected files and folders?": "Удалить выбранные файлы и папки?", + "DestinationFolder": "Папка назначения", + "DirectLink": "Ссылка", + "Download": "Загрузка", + "Edit": "Редактировать", + "ErrorReporting": "Сообщения об ошибках", + "Error while copying from": "Ошибка при копировании", + "Error while deleting items": "Ошибка при удалении элементов", + "Error while fetching archive info": "Ошибка при извлечении информации из архива", + "Error while moving from": "Ошибка при перемещении", + "Error while renaming from": "Ошибка при переименовании", + "Execute": "Исполнение", + "File": "Файл", + "File extension is not allowed": "Запрещённое расширение файла", + "File not found": "Файл не найден", + "File or folder with this path already exists": "Файл или папка с этим путем уже существует", + "File Saved Successfully": "Файл сохранён", + "Files": "Файлы", + "Folder": "Папка", + "Folder is empty": "Папка пуста", + "FreeOf": "свободно из", + "FullSize": "Размер файлов в папке", + "Generate": "Сгенерировать", + "Generate new password hash": "Сгенерировать хеш нового пароля", + "Group": "Группа", + "Help": "Помощь", + "Help Documents": "Справочная документация", + "HideColumns": "Скрыть столбцы права досупа и владелец", + "Invalid characters in file name": "Недопустимые символы в имени файла", + "Invalid characters in file or folder name": "Недопустимые символы в имени файла или папки", + "Invalid file or folder name": "Некорректное имя папки или файла", + "InvertSelection": "Обратная выборка", + "ItemName": "Имя элемента", + "ItemType": "Тип элемента", + "Language": "Язык", + "Login": "Войти", + "Login failed. Invalid username or password": "Не удалось войти. Логин или пароль неверны", + "light": "светлая", + "Logout": "Выйти", + "MemoryUsed": "Используемая память", + "Modified": "Обновление", + "Move": "Переместить", + "Moved from": "перемещён(ена)", + "Name": "Имя", + "NewItem": "Создать", + "NormalEditor": "Стандартный редактор", + "not found!": "не найдено!", + "Nothing selected": "Ничего не выбрано", + "Open": "Открыть", + "Operations with archives are not available": "Операции с архивами недоступны", + "Other": "Другие", + "Owner": "Владелец", + "PartitionSize": "Размер раздела", + "Password": "Пароль", + "password_hash not supported, Upgrade PHP version": "password_hash не поддерживается, обновите версию PHP", + "Paths must be not equal": "Пути должны быть разными", + "Perms": "Права доступа", + "Permissions changed": "Права доступа изменены", + "Permissions not changed": "Права доступа не изменены", + "Preview": "Просмотр", + "Read": "Чтение", + "RememberMe": "Запомнить меня", + "Rename": "Переименовать", + "Renamed from": "Переименован(а)", + "Report Issue": "Сообщить о проблеме", + "Root path": "Путь до корня", + "Save": "Сохранить", + "Saved Successfully": "Сохранено", + "Search": "Поиск", + "SelectAll": "Выбрать всё", + "Selected files and folder deleted": "Выбранные файли и папки удалены", + "Select folder": "Выберите папку", + "Settings": "Свойства", + "ShowHiddenFiles": "Показ скрытых файлов", + "Size": "Размер", + "SourceFolder": "Исходная папка", + "Source path not defined": "Путь к источнику не определён", + "Theme": "Тема", + "to": "в", + "UnSelectAll": "Отменить выбор", + "UnZip": "Разархивировать", + "UnZipToFolder": "Разархивировать в папку", + "Upload": "Загрузить", + "UploadingFiles": "Загрузка файлов", + "Username": "Пользователь", + "Write": "Запись", + "You are logged in": "Вы вошли в систему" + } + }, + { + "name": "Italiano", + "code": "it", + "translation": { + "Access denied. IP restriction applicable": "Accesso negato. Applicate restrizioni in base all'indirizzo IP", + "Actions": "Azioni", + "Advanced Search": "Ricerca avanzata", + "AdvancedEditor": "Editor avanzato", + "already exists": "già esistente", + "AppName": "Tiny File Manager", + "AppTitle": "File Manager", + "Archive not created": "Archivio non creato", + "Archive not unpacked": "Archivio non decompresso", + "Archive unpacked": "Archivio decompresso", + "Archive": "Archivio", + "Back": "Indietro", + "BackUp": "Backup", + "Cancel": "Annulla", + "Cannot open file! Aborting download": "Impossibile aprire il file! Download annullato", + "Change": "Modifica", + "ChangePermissions": "Modifica permessi", + "Copied from": "Copiato da", + "Copy": "Copia", + "Copying": "Copia in corso", + "CopyTo": "Copia su", + "Create archive?": "Creare un archivio", + "Created": "Creato", + "CreateNewItem": "Nuovo elemento", + "CreateNow": "Crea", + "dark": "scuro", + "Delete selected files and folders?": "Eliminare i file e le cartelle selezionati?", + "Delete": "Elimina", + "Deleted": "Eliminato", + "DestinationFolder": "Cartella di destinazione", + "DirectLink": "Link diretto", + "Download": "Scarica", + "Edit": "Modifica", + "Error while copying from": "Errore durante la copia da", + "Error while deleting items": "Errore durante l'eliminazione degli elementi", + "Error while fetching archive info": "Errore durante il recupero delle informazioni sull'archivio", + "Error while moving from": "Errore durante lo spostamento da", + "Error while renaming from": "Errore durante la ridenominazione da", + "ErrorReporting": "Segnala errori", + "Execute": "Esegui", + "FILE EXTENSION HAS NOT SUPPORTED": "IL FILE HA UN'ESTENSIONE NON SUPPORTATA", + "File extension is not allowed": "L'estensione del file non è autorizzata", + "File not found": "Impossibile trovare il file", + "File or folder with this path already exists": "Esiste già un file o una cartella con questo percorso", + "File Saved Successfully": "File salvato correttamente", + "File": "File", + "Files": "File", + "Filter": "Filtro", + "Folder is empty": "La cartella è vuota", + "Folder": "Cartella", + "FullSize": "Dimensione totale", + "Generate new password hash": "Genera un nuovo hash della password", + "Generate": "Genera", + "Group": "Gruppo", + "Help Documents": "Documentazione", + "Help": "Aiuto", + "HideColumns": "Nascondi le colonne dei permessi e del proprietario", + "Invalid characters in file name": "Caratteri non validi nel nome del file", + "Invalid characters in file or folder name": "Caratteri non validi nel nome del file o della cartella", + "Invalid file or folder name": "Nome di file o cartella non valido", + "Invalid Token.": "Token non valido.", + "InvertSelection": "Inverti selezione", + "ItemName": "Nome elemento", + "ItemType": "Tipo elemento", + "Language": "Lingua", + "light": "chiaro", + "Login failed. Invalid username or password": "Accesso fallito. Nome utente e/o password non validi", + "Login": "Accedi", + "Logout": "Disconnettiti", + "Modified": "Ultima modifica", + "Move": "Sposta", + "Moved from": "Spostato da", + "Name": "Nome", + "NewItem": "Nuovo elemento", + "NormalEditor": "Editor normale", + "not created": "non creato", + "not deleted": "not eliminato", + "not found!": "not trovato!", + "Nothing selected": "Nessuna selezione", + "Open": "Apri", + "Operations with archives are not available": "Le operazioni sugli archivi non sono disponibili", + "Other": "Altro", + "Owner": "Proprietario", + "Password": "Password", + "password_hash not supported, Upgrade PHP version": "password_hash not supportata, aggiorna la versione di PHP", + "Paths must be not equal": "I percorsi devono essere differenti", + "Permissions changed": "Permessi modificati", + "Permissions not changed": "Permessi non modificati", + "Perms": "Permessi", + "Read": "Leggi", + "Rename": "Rinomina", + "Renamed from": "Rinominato da", + "Report Issue": "Segnala un problema", + "Root path": "Percorso radice", + "Save": "Salva", + "Saved Successfully": "Salvato correttamente", + "Search file in folder and subfolders...": "Cerca file nella cartella e nelle sotto-cartelle...", + "Search": "Cerca", + "Select folder": "Seleziona cartella", + "SelectAll": "Seleziona tutto", + "Selected files and folder deleted": "I file e le cartelle selezionati sono stati eliminati", + "Settings": "Impostazioni", + "ShowHiddenFiles": "Mostra file nascosti", + "Size": "Dimensione", + "Source path not defined": "Percorso sorgente non definito", + "SourceFolder": "Cartella di origine", + "Tar": "Tar", + "Theme": "Tema", + "to": "a", + "UnSelectAll": "Deseleziona tutto", + "UnZip": "Decomprimi", + "UnZipToFolder": "Decomprimi in una cartella", + "Upload": "Carica", + "UploadingFiles": "Caricamento file", + "Username": "Nome utente", + "Write": "Scrivi", + "You are logged in": "Accesso effettuato", + "Zero byte file! Aborting download": "File con zero byte! Download annullato", + "Zip": "Zip" + } + }, + { + "name": "Français", + "code": "fr", + "translation": { + "Actions": "Actions", + "AdvancedEditor": "Editeur avancé", + "Advanced Search": "Recherche avancée", + "AppName": "Tiny File Manager", + "AppTitle": "Gestionnaire de fichiers", + "Back": "Retour", + "BackUp": "Sauvegarder", + "CalculateFolderSize": "Calculer la taille des dossiers", + "Cancel": "Annuler", + "Change": "Modifier", + "ChangePermissions": "Modifier les permissions", + "Check Latest Version": "Vérifier les mises à jour", + "Copy": "Copier", + "Copying": "Copie en cours", + "CopyTo": "Copier vers", + "CreateNewItem": "Créer un nouveau fichier", + "CreateNow": "Créer", + "Delete": "Supprimer", + "DestinationFolder": "Dossier de destination", + "DirectLink": "Lien direct", + "Download": "Télécharger", + "Edit": "Editer", + "ErrorReporting": "Rapport d'erreurs", + "File": "Fichier", + "Files": "Fichiers", + "Filter": "Filtrer", + "Folder": "Dossier", + "Free of": "libres sur", + "FreeOf": "Espace libre : ", + "Full size": "Taille totale", + "Generate": "Générer", + "Generate new password hash": "Générer un mot de passe haché", + "Help": "Aide", + "Help Documents": "Documentation", + "HideColumns": "Masquer les colonnes", + "InvertSelection": "Inverser la sélection", + "ItemName": "Nom de l'élément", + "ItemType": "Type d'élement", + "Language": "Langue", + "Login": "Connexion", + "Logout": "Déconnexion", + "MemoryUsed": "Mémoire utilisée", + "Modified": "Modifié le", + "Move": "Déplacer", + "Name": "Nom", + "NewItem": "Nouvel élément", + "NormalEditor": "Éditeur normal", + "Open": "Ouvrir", + "Owner": "Propriétaire", + "PartitionSize": "Taille de la partition", + "Password": "Mot de passe", + "Perms": "Permissions", + "ProcessID": "Identifiant processus", + "RememberMe": "Se souvenir de moi", + "Rename": "Renommer", + "Save": "Sauvegarder", + "Search": "Recherche", + "SelectAll": "Tout sélectionner", + "Settings": "Réglages", + "ShowHiddenFiles": "Afficher les fichiers masqués", + "Size": "Taille", + "SourceFolder": "Dossier source", + "UnSelectAll": "Tout déselectionner", + "Upload": "Envoyer", + "UploadingFiles": "Téléverser des fichiers", + "Username": "Utilisateur", + "UnZip": "Décompresser", + "UnZipToFolder": "Décompresser dans un dossier", + "You are logged in": "Vous êtes authentifié(e)" + } + }, + { + "name": "Español", + "code": "es", + "translation": { + "AppName": "Pequeño Administrador de Archivos", + "AppTitle": "Administrador de Archivos", + "Login": "Iniciar Sesión", + "Username": "Nombre de Usuario", + "Password": "Contraseña", + "Logout": "Desconectarse", + "Move": "Mover", + "Copy": "Copiar", + "Save": "Guardar", + "SelectAll": "Seleccionar Todo", + "UnSelectAll": "Deseleccionar Todo", + "File": "Archivo", + "Back": "Atrás", + "Size": "Tamaño", + "Perms": "Permisos", + "Modified": "Modificado", + "Owner": "Propietario", + "Search": "Buscar", + "NewItem": "Nuevo Ítem", + "Folder": "Carpeta", + "Delete": "Borrar", + "Rename": "Cambiar Nombre", + "CopyTo": "Copiar en", + "DirectLink": "Link Directo", + "UploadingFiles": "Subir Archivos", + "ChangePermissions": "Cambiar Permisos", + "Copying": "Copiando", + "CreateNewItem": "Crear nuevo Item", + "Name": "Nombre", + "AdvancedEditor": "Editor Avanzado", + "RememberMe": "Recuérdame", + "Actions": "Acciones", + "Upload": "Subir", + "Cancel": "Cancelar", + "InvertSelection": "Invertir Selección", + "DestinationFolder": "Carpeta Destino", + "ItemType": "Tipo de Ítem", + "ItemName": "Nombre del Ítem", + "CreateNow": "Crear", + "Download": "Descargar", + "Open": "Abrir", + "UnZip": "Descomprimir", + "UnZipToFolder": "Descomprimir en Carpeta", + "Edit": "Editar", + "NormalEditor": "Editor Normal", + "BackUp": "Copia de Seguridad", + "SourceFolder": "Carpeta Actual", + "Files": "Archivos", + "Change": "Cambiar", + "Settings": "Preferencias", + "Language": "Lenguaje" + } + }, + { + "name": "Galego", + "code": "gl", + "translation": { + "AppName": "Pequeno Administrador de Arquivos", + "AppTitle": "Administrador de Arquivos", + "Login": "Iniciar Sesión", + "Username": "Nome de Usuario", + "Password": "Contrasinal", + "Logout": "Desconectarse", + "Move": "Mover", + "Copy": "Copiar", + "Save": "Gardar", + "SelectAll": "Seleccionar Todo", + "UnSelectAll": "Des-seleccionar Todo", + "File": "Arquivo", + "Back": "Atrás", + "Size": "Tamaño", + "Perms": "Permisos", + "Modified": "Modificado", + "Owner": "Propietario", + "Search": "Buscar", + "NewItem": "Novo Elemento", + "Folder": "Cartafol", + "Delete": "Borrar", + "Rename": "Renomear", + "CopyTo": "Copiar en", + "DirectLink": "Enlace Directo", + "UploadingFiles": "Subir Arquivos", + "ChangePermissions": "Cambiar Permisos", + "Copying": "Copiando", + "CreateNewItem": "Crear novo Elemento", + "Name": "Nome", + "AdvancedEditor": "Editor Avanzado", + "RememberMe": "Lémbrame", + "Actions": "Accións", + "Upload": "Subir", + "Cancel": "Cancelar", + "InvertSelection": "Invertir Selección", + "DestinationFolder": "Cartafol Destino", + "ItemType": "Tipo de Elemento", + "ItemName": "Nome do Elemento", + "CreateNow": "Crear", + "Download": "Descargar", + "Open": "Abrir", + "UnZip": "Descomprimir", + "UnZipToFolder": "Descomprimir no Cartafol", + "Edit": "Editar", + "NormalEditor": "Editor Normal", + "BackUp": "Copia de Seguridade", + "SourceFolder": "Cartafol Actual", + "Files": "Arquivos", + "Change": "Cambiar", + "Settings": "Preferencias", + "Language": "Linguaxe" + } + }, + { + "name": "Català", + "code": "ca", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Administrador d'Arxius", + "Login": "Iniciar Sessió", + "Username": "Nom d'Usuari", + "Password": "Contrasenya", + "Logout": "Desconnectar-se", + "Move": "Moure", + "Copy": "Copiar", + "Save": "Desar", + "SelectAll": "Seleccionar Tot", + "UnSelectAll": "Deseleccionar Tot", + "File": "Arxiu", + "Back": "Enrere", + "Size": "Mida", + "Perms": "Permisos", + "Modified": "Modificat", + "Owner": "Propietari", + "Search": "Cercar", + "NewItem": "Nou Ítem", + "Folder": "Carpeta", + "Delete": "Esborrar", + "Rename": "Canviar Nom", + "CopyTo": "Copiar a", + "DirectLink": "Enllaç Directe", + "UploadingFiles": "Pujar Arxius", + "ChangePermissions": "Canviar Permisos", + "Copying": "Copiant", + "CreateNewItem": "Crear un Nou Ítem", + "Name": "Nom", + "AdvancedEditor": "Editor Avançat", + "RememberMe": "Recorda'm", + "Actions": "Accions", + "Upload": "Pujar", + "Cancel": "Cancel·lar", + "InvertSelection": "Invertir Selecció", + "DestinationFolder": "Carpeta Destí", + "ItemType": "Tipus d'Ítem", + "ItemName": "Nom de l'Ítem", + "CreateNow": "Crear", + "Download": "Descarregar", + "Open": "Obrir", + "UnZip": "Descomprimir", + "UnZipToFolder": "Descomprimir a Carpeta", + "Edit": "Editar", + "NormalEditor": "Editor Normal", + "BackUp": "Còpia de Seguretat", + "SourceFolder": "Carpeta Actual", + "Files": "Arxius", + "Change": "Canviar", + "Settings": "Preferències", + "Language": "Idioma", + "MemoryUsed": "Memòria usada", + "PartitionSize": "Mida de la partició", + "ErrorReporting": "Informe d'errors", + "ShowHiddenFiles": "Mostra Fitxers Ocults", + "Full size": "Mida sencera", + "Help": "Ajuda", + "Free of": "Lliure de", + "Preview": "Previsualitzar", + "Help Documents": "Documents d'ajuda", + "Report Issue": "Informe del problema", + "Generate": "Generar", + "FullSize": "Mida Total", + "FreeOf": "lliure de", + "CalculateFolderSize": "Calcular mida de la carpeta", + "ProcessID": "Procés ID", + "Created": "Creat", + "HideColumns": "Amagar Permisos/Propietari columnes", + "Folder is empty": "La carpeta és buida", + "Check Latest Version": "Comprova l'última versió", + "Generate new password hash": "Crear una nou hash de contrasenya", + "You are logged in": "Estàs autenticat", + "Login failed. Invalid username or password": "Error d'inici de sessió. El nom d'usuari o contrasenya són incorrectes", + "password_hash not supported, Upgrade PHP version": "no és compatible password_hash. Actualitza la versió de PHP" + } + }, + { + "name": "Deutsch", + "code": "de", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Dateimanager", + "Login": "Einloggen", + "Username": "Benutzername", + "Password": "Passwort", + "Logout": "Ausloggen", + "Move": "Verschieben", + "Copy": "Kopieren", + "Save": "Speichern", + "SelectAll": "Alles auswählen", + "UnSelectAll": "Alles abwählen", + "File": "Datei", + "Back": "Zurück", + "Size": "Größe", + "Perms": "Berechtigungen", + "Modified": "Geändert", + "Owner": "Eigentümer", + "Search": "Suchbegriff eingeben", + "NewItem": "Neues Element", + "Folder": "Ordner", + "Delete": "Löschen", + "Rename": "Umbenennen", + "CopyTo": "Kopieren nach", + "DirectLink": "Direktlink", + "UploadingFiles": "Dateien hochladen", + "ChangePermissions": "Berechtigungen ändern", + "Copying": "Kopieren", + "CreateNewItem": "Neues Element erstellen", + "Name": "Name", + "AdvancedEditor": "Erweiterter Editor", + "RememberMe": "Eingeloggt bleiben", + "Actions": "Aktionen", + "Upload": "Hochladen", + "Cancel": "Abbrechen", + "InvertSelection": "Auswahl umkehren", + "DestinationFolder": "Zielordner", + "ItemType": "Dateityp", + "ItemName": "Dateiname", + "CreateNow": "Jetzt erstellen", + "Download": "Download", + "Open": "Öffnen", + "UnZip": "Entpacken", + "UnZipToFolder": "Entpacken im Ordner", + "Edit": "Bearbeiten", + "NormalEditor": "Standard-Editor", + "BackUp": "Backup", + "SourceFolder": "Quellordner", + "Files": "Dateien", + "Change": "Ändern", + "Settings": "Einstellungen", + "Language": "Sprache", + "Folder is empty": "Ordner ist leer", + "PartitionSize": "Partitionsgröße", + "ErrorReporting": "Fehler-Berichterstattung", + "ShowHiddenFiles": "Versteckte Dateien anzeigen", + "Full size": "Gesamtgröße", + "Help": "Hilfe", + "Free of": "Frei von", + "Preview": "Vorschau", + "Help Documents": "Hilfe anzeigen (Englisch)", + "Report Issue": "Problem melden", + "Generate": "Erzeugen", + "FullSize": "Gesamtgröße", + "FreeOf": "frei von", + "CalculateFolderSize": "Ordnergröße berechnen", + "ProcessID": "Prozess-ID", + "Created": "Erstellt", + "HideColumns": "Spalten Berechtigungen / Besitzer verstecken", + "Generate new password hash": "Password-Hash neu erzeugen", + "Check Latest Version": "Auf neue Version überprüfen", + "You are logged in": "Du bist eingeloggt.", + "Login failed. Invalid username or password": "Login fehlgeschlagen. Falscher Benutzername oder Passwort.", + "password_hash not supported, Upgrade PHP version": "password_hash wird nicht unterstützt, aktualisiere die PHP-Version", + "Advanced Search": "Erweiterte Suche", + "Error while copying from": "Fehler beim Kopieren aus", + "Nothing selected": "Nichts ausgewählt", + "Paths must be not equal": "Quell- und Zielpfad dürfen nicht identisch sein", + "Renamed from": "Umbenannt von", + "Archive not unpacked": "Archiv nicht entpackt", + "Deleted": "Gelöscht", + "Archive not created": "Archiv nicht erstellt", + "Copied from": "Kopiert aus", + "Permissions changed": "Berechtigungen geändert", + "to": "nach", + "Saved Successfully": "Erfolgreich gespeichert", + "not found!": "nicht gefunden!", + "File Saved Successfully": "Datei erfolgreich gespeichert", + "Archive": "Archiv", + "Permissions not changed": "Berechtigungen nicht geändert", + "Select folder": "Ordner auswählen", + "Source path not defined": "Quellpfad nicht definiert", + "already exists": "existiert bereits", + "Error while moving from": "Fehler beim Verschieben aus", + "Create archive?": "Archiv erstellen?", + "Invalid file or folder name": "Ungültiger Datei- oder Ordnername", + "Archive unpacked": "Archive entpackt", + "File extension is not allowed": "Dateityp nicht erlaubt", + "Root path": "Quellverzeichnis", + "Error while renaming from": "Fehler beim Umbenennen von", + "File not found": "Datei nicht gefunden", + "Error while deleting items": "Fehler beim Löschen der Objekte", + "Invalid characters in file name": "Unzulässige Zeichen im Dateinamen", + "FILE EXTENSION HAS NOT SUPPORTED": "DATEITYP NICHT UNTERSTÜTZT", + "Selected files and folder deleted": "Ausgewählte Dateien und Ordner gelöscht", + "Error while fetching archive info": "Fehler beim Abrufen der Archiv-Informationen", + "Delete selected files and folders?": "Ausgewählte Dateien und Ordner löschen?", + "Search file in folder and subfolders...": "Suchen in Ordnern und Unterordnern...", + "Access denied. IP restriction applicable": "Zugriff verweigert - IP-Beschränkung.", + "Invalid characters in file or folder name": "Unzulässige Zeichen im Datei- oder Ordnernamen", + "Operations with archives are not available": "Archiv-Funktionen nicht verfügbar", + "File or folder with this path already exists": "Datei oder Ordner mit diesem Pfad existiert bereits", + "Moved from": "Verschoben aus", + "Are you sure want to rename?": "Wirklich umbenennen?", + "Enter new file name": "Neuen Dateinamen eingeben", + "Are you sure want to": "", + "Cancel": "Abbrechen", + "Sometimes the save action may not work on the first try, so please attempt it again": "Zweimal speichern, falls die Änderungen nicht übernommen werden", + "Upload from URL": "Upload von URL", + "Enter here...": "Hier eingeben..." + } + }, + { + "name": "ภาษาไทย", + "code": "th", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "ตัวจัดการไฟล์", + "Login": "เข้าสู่ระบบ", + "Username": "ชื่อผู้ใช้งาน", + "Password": "รหัสผ่าน", + "Logout": "ออกจากระบบ", + "Move": "ย้าย", + "Copy": "คัดลอก", + "Save": "บันทึก", + "SelectAll": "เลือกท้งหมด", + "UnSelectAll": "ไม่เลือกทั้งหมด", + "File": "ไฟล์", + "Back": "กลับ", + "Size": "ขนาด", + "Perms": "รหัสสิทธิ์", + "Modified": "แก้ไขล่าสุดเมื่อ", + "Owner": "เจ้าของ", + "Search": "ค้นหา", + "NewItem": "สร้างใหม่", + "Folder": "โฟลเดอร์", + "Delete": "ลบ", + "Rename": "เปลี่ยนชื่อ", + "CopyTo": "คัดลอกไปยัง", + "DirectLink": "ไปยังลิ้งก์นั้น", + "UploadingFiles": "อัพโหลด", + "ChangePermissions": "เปลี่ยนสิทธิ์", + "Copying": "กำลังย้ายข้อมูล", + "CreateNewItem": "สร้างไฟล์ใหม่", + "Name": "ชื่อ", + "AdvancedEditor": "แก้ไขขั้นสูง", + "RememberMe": "จดจำฉันไว้", + "Actions": "การทำงาน", + "Upload": "อัพโหลด", + "Cancel": "ยกเลิก", + "InvertSelection": "เปลี่ยนข้อมูล", + "DestinationFolder": "โฟลเดอร์ปลายทาง", + "ItemType": "ข้อมูลประเภท", + "ItemName": "ชื่อไฟล์", + "CreateNow": "สร้างตอนนี้", + "Download": "ดาวโหลด", + "Open": "เปิด", + "UnZip": "แตก Zip", + "UnZipToFolder": "แตกไฟล์ในโฟเดอร์นี้", + "Edit": "แก้ไข", + "NormalEditor": "แก้ไขปกติ", + "BackUp": "สำรองข้อมูล", + "SourceFolder": "โฟลเดอร์ต้นทาง", + "Files": "ไฟล์", + "Change": "เปลี่ยน", + "Settings": "การตั้งค่า", + "Language": "ภาษา" + } + }, + { + "name": "简体中文", + "code": "zh-CN", + "translation": { + "AppName": "文件管理器", + "AppTitle": "文件管理器", + "Login": "登录", + "Username": "账号", + "Password": "密码", + "Logout": "退出", + "Move": "移动", + "Copy": "复制", + "Save": "保存", + "SelectAll": "全选", + "UnSelectAll": "取消全选", + "File": "文件", + "Back": "取消", + "Size": "大小", + "Perms": "权限", + "Modified": "修改时间", + "Owner": "拥有者", + "Search": "查找", + "NewItem": "创建新文件/文件夹", + "Folder": "文件夹", + "Delete": "删除", + "CopyTo": "复制到", + "DirectLink": "直链", + "UploadingFiles": "上传", + "ChangePermissions": "修改权限", + "Copying": "复制中", + "CreateNewItem": "创建新文件", + "Name": "文件名", + "AdvancedEditor": "高级编辑器", + "RememberMe": "记住登录信息", + "Actions": "执行操作", + "Upload": "上传", + "Cancel": "取消", + "InvertSelection": "反向选择", + "DestinationFolder": "目标文件夹", + "ItemType": "文件类型", + "ItemName": "创建名称", + "CreateNow": "创建", + "Download": "下载", + "UnZip": "解压缩", + "UnZipToFolder": "解压至目标文件夹", + "Edit": "编辑", + "NormalEditor": "编辑器", + "BackUp": "备份", + "SourceFolder": "源文件夹", + "Files": "文件", + "Change": "修改", + "Settings": "设置", + "Language": "语言", + "Open": "打开", + "Group": "用户组", + "Other": "其它用户", + "Read": "读取权限", + "Write": "写入权限", + "Execute": "执行权限", + "Rename": "重命名", + "enable": "启用", + "disable": "禁用", + "ErrorReporting": "上传错误报告", + "ShowHiddenFiles": "显示隐藏文件", + "Help": "帮助", + "HideColumns": "隐藏权限&拥有者", + "CalculateFolderSize": "显示文件夹大小", + "FullSize": "所有文件大小", + "MemoryUsed": "使用内存", + "PartitionSize": "可用空间", + "FreeOf": "磁盘大小", + "Check Latest Version": "检查更新", + "Generate new password hash": "生成新的hash密码", + "Report Issue": "报告问题", + "Help Documents": "帮助文档", + "Generate": "生成", + "Renamed from": "生成", + "Preview": "预览", + "Access denied. IP restriction applicable": "访问被拒绝。适用的IP限制", + "You are logged in": "您已登录", + "Login failed. Invalid username or password": "登录失败。用户名或密码无效", + "password_hash not supported, Upgrade PHP version": "不支持password_hash,请升级PHP版本", + "Root path": "根路径", + "not found!": "没有找到!", + "File not found": "找不到文件", + "Deleted": "删除", + "not deleted": "未删除", + "Invalid file or folder name": "无效的文件或文件夹名", + "Created": "已创建", + "File extension is not allowed": "不允许文件扩展名", + "already exists": "已经存在", + "not created": "未创建", + "Invalid characters in file or folder name": "文件或文件夹名称中的无效字符", + "Source path not defined": "未定义源路径", + "Moved from": "移动自", + "to": "至", + "File or folder with this path already exists": "具有此路径的文件或文件夹已存在", + "Error while moving from": "移动时出错", + "Copied from": "复制自", + "Error while copying from": "复制时出错", + "Paths must be not equal": "路径必须不相等", + "Nothing selected": "未选择任何内容", + "Error while renaming from": "重命名时出错", + "Invalid characters in file name": "文件名中的无效字符", + "Invalid Token.": "无效令牌。", + "Selected files and folder deleted": "已删除选定的文件和文件夹", + "Error while deleting items": "删除项目时出错", + "Operations with archives are not available": "存档操作不可用", + "Archive": "存档", + "Archive not created": "未创建存档", + "Archive unpacked": "存档未打包", + "Archive not unpacked": "存档未打开", + "Permissions changed": "权限已更改", + "Permissions not changed": "权限未更改", + "Select folder": "选择文件夹", + "Theme": "主题", + "light": "浅色", + "dark": "深色", + "Error while fetching archive info": "获取存档信息时出错", + "File Saved Successfully": "文件保存成功", + "FILE EXTENSION HAS NOT SUPPORTED": "文件扩展名不受支持", + "Folder is empty": "文件夹为空", + "Delete selected files and folders?": "是否删除选定的文件和文件夹?", + "Create archive?": "创建存档?", + "Zip": "Zip", + "Tar": "Tar", + "Zero byte file! Aborting download": "零字节文件!正在中止下载", + "Cannot open file! Aborting download": "无法打开文件!正在中止下载", + "Filter": "过滤器", + "Advanced Search": "高级搜索", + "Search file in folder and subfolders...": "在文件夹和子文件夹中搜索文件…", + "Are you sure want to": "你确定要", + "Okay": "确定", + "a files": "一个文件", + "Enter here...": "在此处输入...", + "Enter new file name": "输入新文件名", + "Full path": "完整路径", + "File size": "文件大小", + "MIME-type": "MIME类型", + "Image sizes": "图像大小", + "Charset": "编码格式", + "Image": "图片", + "Audio": "音频", + "Video": "视频", + "Upload from URL": "从URL上传", + "Files in archive": "档案文件", + "Total size": "总大小", + "Compression": "压缩", + "Size in archive": "存档中的大小", + "Invalid Token.": "无效令牌", + "Fullscreen": "全屏", + "Search": "搜索", + "Word Wrap": "自动换行", + "Undo": "撤消", + "Redo": "恢复", + "Select Document Type": "选择文档类型", + "Select Mode": "选择模式", + "Select Theme": "选择主题", + "Select Font Size": "选择字体大小", + "Are you sure want to rename?": "是否确实要重命名?" + } + }, + { + "name": "中文(繁體)", + "code": "zh-TW", + "translation": { + "AppName": "檔案管理器", + "AppTitle": "檔案管理器", + "Login": "登入", + "Username": "帳號", + "Password": "密碼", + "Logout": "登出", + "Move": "移動", + "Copy": "複製", + "Save": "儲存", + "SelectAll": "選擇全部", + "UnSelectAll": "取消選擇全部", + "File": "檔案", + "Back": "返回", + "Size": "大小", + "Perms": "權限", + "Modified": "修改時間", + "Owner": "擁有者", + "Search": "搜尋", + "NewItem": "建立新檔案或資料夾", + "Folder": "資料夾", + "Delete": "刪除", + "CopyTo": "複製到", + "DirectLink": "直接連結", + "UploadingFiles": "上傳檔案", + "ChangePermissions": "變更權限", + "Copying": "複製", + "CreateNewItem": "建立新檔案", + "Name": "檔名", + "AdvancedEditor": "進階編輯", + "RememberMe": "記住我", + "Actions": "動作", + "Upload": "上傳", + "Cancel": "取消", + "InvertSelection": "選擇反轉", + "DestinationFolder": "目標資料夾", + "ItemType": "檔案類型", + "ItemName": "檔案檔名", + "CreateNow": "建立", + "Download": "下載", + "UnZip": "解壓縮", + "UnZipToFolder": "解壓縮至資料夾", + "Edit": "編輯", + "NormalEditor": "普通編輯", + "BackUp": "上傳", + "SourceFolder": "來源資料夾", + "Files": "檔案", + "Change": "變更", + "Settings": "設定", + "Language": "語言", + "Open": "開啟", + "Group": "群組", + "Other": "其他", + "Read": "讀取", + "Write": "寫入", + "Execute": "執行", + "Rename": "重新命名", + "enable": "開啟", + "disable": "關閉", + "ErrorReporting": "錯誤報告", + "Help": "幫助", + "ShowHiddenFiles": "顯示隱藏的檔案", + "HideColumns": "不顯示權限以及擁有者", + "CalculateFolderSize": "顯示資料夾大小", + "Help Documents": "幫助文件", + "Report Issue": "回報問題", + "Check Latest Version": "檢查最新版本", + "Generate new password hash": "建立新的密碼 Hash 函數", + "Generate": "建立", + "FullSize": "所有檔案容量", + "MemoryUsed": "使用的記憶體大小", + "PartitionSize": "剩餘可用空間", + "FreeOf": "硬碟容量:" + } + }, + { + "name": "Bahasa Indonesia", + "code": "id", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Pengelola Berkas", + "Login": "Masuk", + "Username": "Nama pengguna", + "Password": "Kata sandi", + "Logout": "Keluar", + "Move": "Pindah", + "Copy": "Salin", + "Save": "Simpan", + "SelectAll": "Tandai semua", + "UnSelectAll": "Urungkan tandai", + "File": "Berkas", + "Back": "Kembali", + "Size": "Ukuran", + "Perms": "Hak akses", + "Modified": "Terakhir diubah", + "Owner": "Pemilik", + "Search": "Cari", + "NewItem": "Item baru", + "Folder": "Folder", + "Delete": "Hapus", + "Rename": "Ganti nama", + "CopyTo": "Salin ke", + "DirectLink": "Tautan langsung", + "UploadingFiles": "Mengunggah berkas", + "ChangePermissions": "Ubah hak akses", + "Copying": "Menyalin", + "CreateNewItem": "Buat item baru", + "Name": "Nama", + "AdvancedEditor": "Editor tingkat lanjut", + "RememberMe": "Ingat saya", + "Actions": "Aksi", + "Upload": "Unggah", + "Cancel": "Urungkan", + "InvertSelection": "Tandai sebaliknya", + "DestinationFolder": "Folder tujuan", + "ItemType": "Tipe item", + "ItemName": "Nama item", + "CreateNow": "Buat sekarang", + "Download": "Unduh", + "Open": "Buka", + "UnZip": "UnZip", + "UnZipToFolder": "UnZip ke folder", + "Edit": "Edit", + "NormalEditor": "Editor normal", + "BackUp": "Cadangkan", + "SourceFolder": "Folder asal", + "Files": "Berkas-berkas", + "Change": "Ubah", + "Settings": "Setelan", + "Language": "Bahasa", + "MemoryUsed": "Memori digunakan", + "PartitionSize": "Ukuran partisi", + "ErrorReporting": "Pelaporan kesalahan", + "ShowHiddenFiles": "Tampilkan berkas tersembunyi", + "Full size": "Total ukuran", + "Help": "Bantuan", + "Free of": "dari", + "Preview": "Pratinjau", + "Help Documents": "Dokumen bantuan", + "Report Issue": "Laporkan masalah", + "Generate": "Hasilkan", + "FullSize": "Total ukuran", + "FreeOf": "dari", + "CalculateFolderSize": "Kalkulasi ukuran foler", + "ProcessID": "ID proses", + "Created": "Dibuat", + "HideColumns": "Sembunyikan kolom hak akses/pemilik", + "Folder is empty": "Folder kosong", + "Check Latest Version": "Periksa versi terbaru", + "Generate new password hash": "Buat hash kata sandi baru", + "You are logged in": "Anda sudah masuk", + "Login failed. Invalid username or password": "Gagal masuk. Nama pengguna atau kata sandi tidak valid", + "password_hash not supported, Upgrade PHP version": "Tidak mendukung password_hash, Perbarui versi PHP", + "Theme": "Tema", + "dark": "Gelap", + "light": "Terang" + } + }, + { + "name": "Ελληνικά", + "code": "gr", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "File Manager", + "Login": "Είσοδος", + "Username": "Username", + "Password": "Password", + "Logout": "Αποσύνδεση", + "Move": "Μετακίνση", + "Copy": "Αντιγραφή", + "Save": "Αποθήκευση", + "SelectAll": "Επιλογή όλων", + "UnSelectAll": "Αποεπιλογή όλων", + "File": "Αρχείο", + "Back": "Πίσω", + "Size": "Μέγεθος", + "Perms": "Άδειες", + "Modified": "Τροποποιημένο", + "Owner": "Ιδιοκτήτης", + "Search": "Αναζήτηση", + "NewItem": "Νέο Αντικείμενο", + "Folder": "Φάκελος", + "Delete": "Διαγραφή", + "Rename": "Μετονομασία", + "CopyTo": "Αντιγραφή σε", + "DirectLink": "Direct Link", + "UploadingFiles": "Ανέβασμα αρχείων", + "ChangePermissions": "Αλλαγή αδειών", + "Copying": "Αντιγραφή σε εξέλιξη", + "CreateNewItem": "Δημιουργία νέου αντικειμένου", + "Name": "Όνομα", + "AdvancedEditor": "Editor για προχωρημένους", + "RememberMe": "Θυμήσου με", + "Actions": "Ενέργειες", + "Upload": "Ανέβασμα", + "Cancel": "Ακύρωση", + "InvertSelection": "Αναίρεση επιλογής", + "DestinationFolder": "Φάκελος προορισμού", + "ItemType": "Τύπος αντικειμένου", + "ItemName": "Όνομα αντικειμένου", + "CreateNow": "Δημιούργησε τώρα", + "Download": "Download", + "Open": "Άνοιξε", + "UnZip": "Αποσυμπίεση", + "UnZipToFolder": "Αποσυμπίεση σε φάκελο", + "Edit": "Επεξεργασία", + "NormalEditor": "Βασικός editor", + "BackUp": "Back-Up", + "SourceFolder": "Πηγή", + "Files": "Αρχεία", + "Change": "Τροποποίησε", + "Settings": "Ρυθμίσεις", + "Language": "Γλώσσα", + "MemoryUsed": "Η μνήμη χρησιμοποιείται", + "PartitionSize": "Μέγεθος partition" + } + }, + { + "name": "Português Brasileiro", + "code": "pt_BR", + "translation": { + "AppName": "Gerenciador de arquivos Tiny", + "AppTitle": "Gerenciador de arquivos", + "Login": "Iniciar Sessão", + "Username": "Nome de usuário", + "Password": "Senha", + "Logout": "Sair", + "Move": "Mover", + "Copy": "Copiar", + "Save": "Salvar", + "SelectAll": "Selecionar tudo", + "UnSelectAll": "Desmarcar tudo", + "File": "Arquivo", + "Back": "Voltar", + "Size": "Tamanho", + "Perms": "Permissões", + "Modified": "Modificado", + "Owner": "Proprietário", + "Search": "Buscar", + "NewItem": "Novo Item", + "Folder": "Pasta", + "Delete": "Excluir", + "Rename": "Renomear", + "CopyTo": "Copiar em", + "DirectLink": "Link direto", + "UploadingFiles": "Upload de arquivos", + "ChangePermissions": "Alterar permissões", + "Copying": "Copiando", + "CreateNewItem": "Criar novo item", + "Name": "Nome", + "AdvancedEditor": "Editor Avançado", + "RememberMe": "Lembra de mim", + "Actions": "Ações", + "Upload": "Upload", + "Cancel": "Cancelar", + "InvertSelection": "Seleção reversa", + "DestinationFolder": "Pasta de destino", + "ItemType": "Tipo de Item", + "ItemName": "Nome do item", + "CreateNow": "Criar", + "Download": "Baixar", + "Open": "Abrir", + "UnZip": "Descompactar os arquivos", + "UnZipToFolder": "Descompactar na pasta", + "Edit": "Editar", + "NormalEditor": "Editor Normal", + "BackUp": "Copia de segurança", + "SourceFolder": "Pasta atual", + "Files": "Arquivos", + "Change": "Alterar", + "Settings": "Preferências", + "Language": "Idioma", + "Preview": "Visualizar", + "MemoryUsed": "Memória usada", + "PartitionSize": "Tamanho da partição", + "ErrorReporting": "Relatório de erros", + "ShowHiddenFiles": "Mostrar arquivos ocultos", + "Group": "Grupo", + "Other": "Outros", + "Read": "Ler", + "Write": "Escrever", + "Execute": "Executar", + "enable": "habilitar", + "disable": "desativar", + "FreeOf": "Livre de", + "Free Of": "Livre de", + "FullSize": "tamanho completo", + "Help": "Ajuda / Suporte", + "Generate": "Gerar", + "Report Issue": "Informar problema", + "Generate new password hash": "Gerar nova hash de senha", + "Help Documents": "Documentos de Ajuda", + "Check Latest Version": "Verifique a última versão", + "HideColumns": "Ocultar colunas Perms / Owner", + "CalculateFolderSize": "Calcular o tamanho da pasta", + "Advanced Search": "Busca Avançada", + "Nothing selected": "Nada selecionado", + "Renamed from": "Renomeado de", + "Deleted": "Excluído", + "Copied from": "Copiado de", + "to": "Para", + "Not found": "Não encontrado", + "Archive": "Arquivo", + "Select folder": "Selecione uma pasta", + "already exists": "já existe", + "Create archive?": "Criar arquivo?", + "Archive unpacked": "Arquivo descompactado", + "Root path": "Caminho raiz", + "File not found": "Arquivo não encontrado", + "Error while copying fro": "Erro ao copiar para lá", + "Paths must be not equal": "Os caminhos não devem ser iguais", + "Archive not unpacked": "Arquivo não descompactado", + "Archive not created": "Arquivo não criado", + "Permissions changed": "Permissões alteradas", + "Saved Successfully": "Salvo com sucesso ", + "File Saved Successfully": "Arquivo salvo com sucesso ", + "Permissions not changed": "Permissões não alteradas", + "Source path not defined": "Caminho de origem não definido", + "Error while moving from": "Erro ao mudar de", + "Invalid file or folder name": "Nome de arquivo ou pasta inválido", + "File extension is not allowed": "A extensão do arquivo não é permitida", + "Error while renaming from": "Erro ao renomear de", + "Error while deleting items": "Erro ao excluir itens", + "Invalid characters in file name": "Caracteres inválidos no nome do arquivo", + "FILE EXTENSION HAS NOT SUPPORTED": "A EXTENSÃO DE ARQUIVO NÃO É SUPORTADA", + "Selected files and folder deleted": "Arquivos e pastas selecionados excluídos", + "Error while fetching archive info": "Erro ao obter informações do arquivo", + "Delete selected files and folders?": "Excluir arquivos e pastas selecionados?", + "Search file in folder and subfolders...": "Pesquisar arquivo na pasta e nas subpastas ...", + "Access denied. IP restriction applicable": "Acesso negado. Restrição de IP aplicável", + "Invalid characters in file or folder name": "Caracteres inválidos no nome do arquivo ou pasta", + "Operations with archives are not available": "Operações com arquivos não estão disponíveis", + "File or folder with this path already exists": "O arquivo ou pasta com este caminho já existe", + "Folder is empty": "A pasta está vazia", + "Moved from": "Movido de", + "Created": "Criado", + "You are logged in": "Você está logado", + "Login failed. Invalid username or password": "Falha na autenticação. nome de usuário ou senha inválidos", + "Are you sure want to rename?": "Tem certeza de que deseja renomear?", + "Are you sure want to": "Tem certeza de que deseja" + } + }, + { + "name": "Português Europeu", + "code": "pt_PT", + "translation": { + "AppName": "Gestor de Ficheiros", + "AppTitle": "Gestor de Ficheiros", + "Login": "Iniciar sessão", + "Username": "Nome de utilizador", + "Password": "Palavra-passe", + "Logout": "Terminar sessão", + "Move": "Mover", + "Copy": "Copiar", + "Save": "Guardar", + "SelectAll": "Seleccionar tudo", + "UnSelectAll": "Desseleccionar tudo", + "File": "Ficheiro", + "Back": "Voltar", + "Size": "Tamanho", + "Perms": "Permissões", + "Modified": "Modificado", + "Owner": "Proprietário", + "Search": "Procurar", + "NewItem": "Novo item", + "Folder": "Pasta", + "Delete": "Eliminar", + "Rename": "Renomear", + "CopyTo": "Copiar para", + "DirectLink": "Ligação directa", + "UploadingFiles": "A enviar ficheiros", + "ChangePermissions": "Alterar permissões", + "Copying": "A copiar", + "CreateNewItem": "Criar novo item", + "Name": "Nome", + "AdvancedEditor": "Editor avançado", + "Actions": "Acções", + "Folder is empty": "A pasta está vazia", + "Upload": "Enviar", + "Cancel": "Cancelar", + "InvertSelection": "Inverter selecção", + "DestinationFolder": "Pasta de destino", + "ItemType": "Tipo de item", + "ItemName": "Nome do item", + "CreateNow": "Criar agora", + "Download": "Descarregar", + "Open": "Abrir", + "UnZip": "Descomprimir", + "UnZipToFolder": "Descomprimir para pasta", + "Edit": "Editar", + "NormalEditor": "Editor normal", + "BackUp": "Cópia de segurança", + "SourceFolder": "Pasta de origem", + "Files": "Ficheiros", + "Change": "Alterar", + "Settings": "Definições", + "Language": "Idioma", + "ErrorReporting": "Relatório de erros", + "ShowHiddenFiles": "Mostrar ficheiros ocultos", + "Help": "Ajuda", + "Created": "Criado", + "Help Documents": "Documentos de ajuda", + "Report Issue": "Comunicar problema", + "Generate": "Gerar", + "FullSize": "Tamanho total", + "HideColumns": "Ocultar colunas de permissões/proprietário", + "You are logged in": "Sessão iniciada", + "Nothing selected": "Nenhum ficheiro seleccionado seleccionado", + "Paths must be not equal": "Os caminhos não podem ser iguais", + "Renamed from": "Renomeado de", + "Archive not unpacked": "Arquivo não descomprimido", + "Deleted": "Eliminado", + "Archive not created": "Arquivo não criado", + "Copied from": "Copiado de", + "Permissions changed": "Permissões alteradas", + "to": "para", + "Saved Successfully": "Guardado com sucesso", + "not found!": "não encontrado!", + "File Saved Successfully": "Ficheiro guardado com sucesso", + "Archive": "Arquivo", + "Permissions not changed": "Permissões não alteradas", + "Select folder": "Seleccionar pasta", + "Source path not defined": "Caminho de origem não definido", + "already exists": "já existe", + "Error while moving from": "Erro ao mover de", + "Create archive?": "Deseja criar um arquivo?", + "Invalid file or folder name": "Nome de ficheiro ou pasta inválido", + "Archive unpacked": "Arquivo descomprimido", + "File extension is not allowed": "Extensão de ficheiro não permitida", + "Root path": "Caminho raiz", + "Error while renaming from": "Erro ao renomear de", + "File not found": "Ficheiro não encontrado", + "Error while deleting items": "Erro ao eliminar itens", + "Moved from": "Movido de", + "Generate new password hash": "Gerar novo hash de palavra-passe", + "Login failed. Invalid username or password": "Falha na autenticação. Nome de utilizador ou palavra-passe inválido", + "password_hash not supported, Upgrade PHP version": "password_hash não suportado. Actualize a versão do PHP", + "Advanced Search": "Pesquisa avançada", + "Error while copying from": "Erro ao copiar de", + "Invalid characters in file name": "Caracteres inválidos no nome do ficheiro", + "FILE EXTENSION HAS NOT SUPPORTED": "A EXTENSÃO DO FICHEIRO NÃO É SUPORTADA", + "Selected files and folder deleted": "Ficheiros e pasta seleccionados eliminados", + "Error while fetching archive info": "Erro ao obter informações do arquivo", + "Delete selected files and folders?": "Deseja eliminar os ficheiros e pastas seleccionados?", + "Search file in folder and subfolders...": "Procurar ficheiro na pasta e subpastas...", + "Access denied. IP restriction applicable": "Acesso negado. Restrição de IP activa", + "Invalid characters in file or folder name": "Caracteres inválidos no nome do ficheiro ou da pasta", + "Operations with archives are not available": "As operações com arquivos não estão disponíveis", + "File or folder with this path already exists": "Já existe um ficheiro ou pasta com este caminho", + "Are you sure want to rename?": "Tem a certeza que deseja renomear?", + "Are you sure want to": "Tem a certeza que deseja", + "Date Modified": "Data de modificação", + "File size": "Tamanho do ficheiro", + "MIME-type": "Tipo MIME" + } + }, + { + "name": "Polski", + "code": "pl", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Menedżer plików", + "Login": "Login", + "Username": "Nazwa Użytkownika", + "Password": "Hasło", + "Logout": "Wyloguj", + "Move": "Przenieś", + "Copy": "Kopiuj", + "Save": "Zapisz", + "SelectAll": "Zaznacz wszystko", + "UnSelectAll": "Odznacz wszystko", + "File": "Plik", + "Back": "Cofnij", + "Size": "Rozmiar", + "Perms": "Uprawnienia", + "Modified": "Zmodyfikowano", + "Owner": "Właściciel", + "Search": "Szukaj", + "NewItem": "Nowy plik", + "Folder": "Folder", + "Delete": "Usuń", + "Rename": "Zmień nazwę", + "CopyTo": "Kopiuj do", + "DirectLink": "Link bezpośredni", + "UploadingFiles": "Wysyłanie plików", + "ChangePermissions": "Zmień uprawnienia", + "Copying": "Kopiowanie", + "CreateNewItem": "Utwórz nowy plik", + "Name": "Nazwa", + "AdvancedEditor": "Zaawansowany edytor", + "RememberMe": "Pamiętaj mnie", + "Actions": "Akcje", + "Upload": "Wyślij", + "Cancel": "Anuluj", + "InvertSelection": "Odwróć zaznaczenie", + "DestinationFolder": "Folder docelowy", + "ItemType": "Typ pliku", + "ItemName": "Nazwa pliku", + "CreateNow": "Utwórz nowy", + "Download": "Pobierz", + "Open": "Otwórz", + "UnZip": "Rozpakuj", + "UnZipToFolder": "Rozpakuj do", + "Edit": "Edytuj", + "NormalEditor": "Edytuj normalnie", + "BackUp": "Kopia zapasowa", + "SourceFolder": "Folder źródłowy", + "Files": "Pliki", + "Change": "Zmień", + "Settings": "Ustawienia", + "Language": "Język" + } + }, + { + "name": "Tiếng Việt", + "code": "vi", + "translation": { + "AppName": "Trình quản lí tệp Tiny", + "AppTitle": "Quản lý tệp", + "Login": "Đăng nhập", + "Username": "Tên đăng nhập", + "Password": "Mật khẩu", + "Logout": "Đăng xuất", + "Move": "Di chuyển", + "Copy": "Sao chép", + "Save": "Lưu", + "SelectAll": "Chọn tất cả", + "UnSelectAll": "Hủy chọn tất cả", + "File": "Tệp tin", + "Back": "Trở về", + "Size": "Kích cỡ", + "Perms": "Quyền", + "Modified": "Sửa đổi lần cuối", + "Search": "Tìm kiếm", + "NewItem": "Tạo mới", + "Folder": "Thư mục", + "Delete": "Xóa", + "Rename": "Đổi tên", + "CopyTo": "Sao chép đến", + "DirectLink": "Đường dẫn URL", + "UploadingFiles": "Tải lên file", + "ChangePermissions": "Thay đổi quyền", + "Copying": "Sao chép", + "CreateNewItem": "Tạo mới", + "Name": "Tên", + "AdvancedEditor": "Chỉnh sửa nâng cao", + "RememberMe": "Ghi nhớ đăng nhập", + "Actions": "Tùy Chọn", + "Upload": "Tải lên", + "Cancel": "Hủy", + "InvertSelection": "Đảo ngược vùng chọn", + "DestinationFolder": "Đến", + "ItemType": "Tạo mới", + "ItemName": "Tên tệp/thư mục", + "CreateNow": "Tạo", + "Download": "Tải xuống", + "Open": "Mở", + "UnZip": "Giải nén", + "UnZipToFolder": "Giải nén đến thư mục", + "Edit": "Chỉnh sửa", + "NormalEditor": "Chỉnh sửa thông thường", + "BackUp": "Sao lưu", + "SourceFolder": "Từ", + "Files": "Tệp tin", + "Change": "Thay đổi", + "Settings": "Cài đặt", + "Language": "Ngôn ngữ", + "PartitionSize": "Còn trống", + "Advanced Search": "Tìm kiếm nâng cao", + "Full size": "Đã dùng", + "Folder is empty": "Thư mực rỗng", + "Search file in folder and subfolders...": "Tìm file toàn thư mục...", + "Help": "Trợ gúp", + "You are logged in": "Đăng nhập thành công", + "ErrorReporting": "Báo cáo lỗi", + "ShowHiddenFiles": "Hiển thị file ẩn", + "Preview": "Xem", + "Help Documents": "Hướng dẫn", + "Report Issue": "Báo cáo lỗi", + "Generate": "Tạo", + "FullSize": "Tổng dung lượng", + "FreeOf": "trong tổng số", + "Calculate folder size": "Kích thước thư mục", + "Check Latest Version": "Kiểm tra phiên bản mới", + "Generate new password hash": "Trình tạo mật khẩu mã hash", + "HideColumns": "Ẩn cột quyền/chủ sỡ hữu", + "Owner": "Chủ sở hữu/Owner", + "Group": "Nhóm/Group", + "Other": "Khác/Other", + "Read": "Đọc", + "Write": "Ghi", + "Execute": "Thực thi", + "enable": "Bật", + "disable": "Tắt", + "Free Of": "trong tổng số", + "CalculateFolderSize": "Tính toán kích thước thư mục", + "Nothing selected": "Không có gì được chọn", + "Renamed from": "Đã đổi tên từ", + "Deleted": "đã được xóa", + "Copied from": "Được sao chép từ", + "to": "sang", + "Not found": "Không tìm thấy", + "Archive": "Lưu trữ", + "Select folder": "Chọn thư mục", + "already exists": "đã tồn tại", + "Create archive?": "Tạo kho lưu trữ?", + "Archive unpacked": "Lưu trữ đã được giải nén", + "Root path": "Đường dẫn gốc", + "File not found": "Không tìm thấy tệp", + "Error while copying from": "Lỗi khi sao chép từ", + "Paths must be not equal": "Đường dẫn không được giống nhau", + "Archive not unpacked": "Lưu trữ chưa được giải nén", + "Archive not created": "Bản lưu trữ chưa được tạo", + "Permissions changed": "Đã thay đổi quyền", + "Saved Successfully": "Thành công ", + "File Saved Successfully": "Thành công ", + "Permissions not changed": "Quyền không được thay đổi", + "Source path not defined": "Đường dẫn nguồn không được xác định", + "Error while moving from": "Lỗi khi di chuyển từ", + "Invalid file or folder name": "Tên tệp hoặc thư mục không hợp lệ", + "File extension is not allowed": "Định dạng không được hỗ trợ", + "Error while renaming from": "Lỗi khi đổi tên từ", + "Error while deleting items": "Lỗi khi xóa các mục", + "Invalid characters in file name": "Ký tự không hợp lệ", + "FILE EXTENSION HAS NOT SUPPORTED": "ĐỊNH DẠNG KHÔNG ĐƯỢC HỖ TRỢ", + "Selected files and folder deleted": "Đã xóa các tệp và thư mục được chọn", + "Error while fetching archive info": "Lỗi", + "Delete selected files and folders?": "Xóa các tệp và thư mục đã chọn?", + "Access denied. IP restriction applicable": "Từ chối quyền truy cập", + "Invalid characters in file or folder name": "Ký tự không hợp lệ", + "Operations with archives are not available": "Không khả dụng", + "File or folder with this path already exists": "Tệp hoặc thư mục đã tồn tại", + "Moved from": "Chuyển từ", + "Created": "đã tạo", + "Login failed. Invalid username or password": "Không tìm thấy người dùng", + "Theme": "Chủ đề" + } + }, + { + "name": "Hebrew", + "code": "he", + "translation": { + "AppName": "סייר קבצים - טיני", + "AppTitle": "סייר קבצים", + "Login": "התחבר", + "Username": "שם משתמש", + "Password": "סיסמה", + "Logout": "התנתק", + "Move": "העבר", + "Copy": "העתק", + "Save": "שמור", + "SelectAll": "בחר הכל", + "UnSelectAll": "בטל בחירה מהכל", + "File": "קובץ", + "Back": "חזור", + "Size": "גודל", + "Perms": "הרשאות", + "Modified": "עודכן בתאריך", + "Owner": "בעלים", + "Search": "חיפוש", + "NewItem": "חדש", + "Folder": "תיקייה", + "Delete": "מחק", + "Rename": "שנה שם", + "CopyTo": "העתק ל", + "DirectLink": "קישור ישיר", + "UploadingFiles": "מעלה קבצים", + "ChangePermissions": "שנה הרשאות", + "Copying": "העותק", + "CreateNewItem": "צור פריט חדש", + "Name": "שם", + "AdvancedEditor": "עורך מתקדם", + "RememberMe": "זכור אותי", + "Actions": "פעולות", + "Upload": "העלה", + "Cancel": "ביטול", + "InvertSelection": "הפוך את הבחירה", + "DestinationFolder": "תיקיית יעד", + "ItemType": "סוג פריט", + "ItemName": "שם הפריט", + "CreateNow": "צור עכשיו", + "Download": "הורד", + "Open": "פתח", + "UnZip": "חילוץ", + "UnZipToFolder": "חלץ לתיקייה", + "Edit": "ערוך", + "NormalEditor": "עורך רגיל", + "BackUp": "גיבוי", + "SourceFolder": "תקיית מקור", + "Files": "קבצים", + "Change": "שנה", + "Settings": "הגדרות", + "Language": "שפה", + "MemoryUsed": "זיכרון בשימוש", + "PartitionSize": "גודל מחיצה" + } + }, + { + "name": "العربية", + "code": "Ar", + "translation": { + "AppName": "مدير الملفات الصغير", + "AppTitle": "مدير الملفات", + "Login": "دخول", + "Username": "اسم المستخدم", + "Password": "كلمة المرور", + "Logout": "خروج", + "Move": "نقل", + "Copy": "نسخ", + "Save": "حفظ", + "SelectAll": "تحديد الكل", + "UnSelectAll": "الغاء تحديد الكل", + "File": "ملف", + "Back": "رجوع", + "Size": "حجم", + "Perms": "صلاحيات", + "Modified": "عدل بـ", + "Owner": "المالك", + "Search": "بحث", + "NewItem": "عنصر جديد", + "Folder": "مجلد", + "Delete": "حذف", + "Rename": "تسمية", + "CopyTo": "نسخ الى", + "DirectLink": "رابط مباشر", + "UploadingFiles": "رفع ملفات", + "ChangePermissions": "تغيير الصلاحيات", + "Copying": "جاري النسخ", + "CreateNewItem": "انشاء عنصر جديد", + "Name": "اسم", + "AdvancedEditor": "محرر متقدم", + "RememberMe": "تذكرني", + "Actions": "عمليات", + "Upload": "رفع", + "Cancel": "الغاء", + "InvertSelection": "عكس التحديد", + "DestinationFolder": "مجلد", + "ItemType": "نوع العنصر", + "ItemName": "اسم العنصر", + "CreateNow": "انشأ الآن", + "Download": "تحميل", + "Open": "فتح", + "UnZip": "فك الضغط", + "UnZipToFolder": "فك الصغط لملف", + "Edit": "نحرير", + "NormalEditor": "محرر عادي", + "BackUp": "نسخة احتياطية", + "SourceFolder": "مجلد المصدر", + "Files": "ملفات", + "Change": "تغيير", + "Settings": "اعدادات", + "Language": "لغة", + "MemoryUsed": "الذاكرة المستخدمة", + "PartitionSize": "حجم القسم", + "Free of": "مساحة فارغة من ", + "Preview": "عرض", + "Full size": "الحجم الكلي", + "ErrorReporting": "التبليغ باخطاء", + "ShowHiddenFiles": "اظهار الملفات المخفية", + "Help": "مساعدة", + "Generate": "توليد", + "Report Issue": "التبليغ بمشكلة", + "Generate new password hash": "توليد هاش لكلمة المرور", + "Help Documents": "وثائق المساعدة", + "Check Latest Version": "تفقد آخر الاصدارات" + } + }, + { + "name": "Česky", + "code": "cz", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "File Manager", + "Login": "Přihlásit", + "Username": "Přihlašovací jméno", + "Password": "Heslo", + "Logout": "Odhlásit", + "Move": "Přesunout", + "Copy": "Kopírovat", + "Save": "Uložit", + "SelectAll": "Vybrat vše", + "UnSelectAll": "Odebrat vše", + "File": "Soubor", + "Back": "Zpět", + "Size": "Velikost", + "Perms": "Oprávnění", + "Modified": "Změněno", + "Owner": "Vlastník", + "Search": "Hledat", + "NewItem": "Nová položka", + "Folder": "Složka", + "Delete": "Smazat", + "Rename": "Přejmenovat", + "CopyTo": "Kopírovat do", + "DirectLink": "Přímý odkaz", + "UploadingFiles": "Nahrát soubory", + "ChangePermissions": "Změnit oprávnění", + "Copying": "Kopírování", + "CreateNewItem": "Vytvoř novou položku", + "Name": "Název", + "AdvancedEditor": "Vylepšený editor", + "RememberMe": "Pamatuj si mně", + "Actions": "Akce", + "Upload": "Nahrát", + "Cancel": "Zrušit", + "InvertSelection": "Obrať výběr", + "DestinationFolder": "Konečná složka", + "ItemType": "Typ položky", + "ItemName": "Název položky", + "CreateNow": "Vytvořit", + "Download": "Stáhnout", + "Open": "Otevřít", + "UnZip": "Rozbalit", + "UnZipToFolder": "Rozbalit do", + "Edit": "Upravit", + "NormalEditor": "Editor", + "BackUp": "Záloha", + "SourceFolder": "Zdrojová složka", + "Files": "Soubory", + "Change": "Změnit", + "Settings": "Nastavení", + "Language": "Jazyk", + "MemoryUsed": "Využitá paměť", + "PartitionSize": "Velikost oddílu", + "ErrorReporting": "Hlášení chyb", + "ShowHiddenFiles": "Zobrazit skryté soubory", + "Preview": "Náhled", + "Help": "Nápověda", + "FullSize": "Celková velikost", + "FreeOf": "volné z", + "Help Documents": "Dokumentace", + "Report Issue": "Nahlásit chybu", + "Generate": "Generovat", + "CalculateFolderSize": "Počítat velikosti složek", + "ProcessID": "ID procesu", + "Created": "Vytvořeno", + "HideColumns": "Skrýt sloupce oprávnění a vlastníka", + "Folder is empty": "Složka je prázdná", + "Check Latest Version": "Vyhledat aktualizace", + "Generate new password hash": "Vygenerovat nový hash hesla", + "You are logged in": "Jste přihlášen(a)", + "Login failed. Invalid username or password": "Chyba přihlášení: špatně zadané heslo nebo uživatelské jméno", + "password_hash not supported, Upgrade PHP version": "Funkce password_hash není dostupná, aktualizujte PHP na novější verzi" + } + }, + { + "name": "Türkçe", + "code": "tr", + "translation": { + "Tiny File Manager": "Tiny Dosya Yöneticisi", + "File Manager": "Dosya Yöneticisi", + "Sign in": "Giriş Yap", + "Username": "Kullanıcı adı", + "Password": "Parola", + "Sign Out": "Çıkış Yap", + "Move": "Taşı", + "Copy": "Kopyala", + "Save": "Kaydet", + "Select all": "Hepsini Seç", + "Unselect all": "Hepsini Bırak", + "File": "Dosya", + "Back": "Geri", + "Size": "Boyut", + "Perms": "İzinler", + "Modified": "Son Düzenleme", + "Owner": "Sahibi", + "Search": "Arama", + "New Item": "Yeni Dosya", + "Folder": "Klasör", + "Delete": "Sil", + "Rename": "Yeniden Adlandır", + "Copy to": "Şuraya Kopyala", + "Direct link": "Erişim Linki", + "Upload Files": "Dosyaları Yükle", + "Change Permissions": "İzinleri Değiştir", + "Copying": "Kopyalanıyor", + "Create New Item": "Yeni Dosya Oluştur", + "Name": "Ad", + "Advanced Editor": "Gelişmiş Düzenleyici", + "Remember Me": "Beni Hatırla", + "Actions": "Hareketler", + "Upload": "Yükle", + "Cancel": "İptal Et", + "Invert Selection": "Seçimi Geri Al", + "Destination Folder": "Hedef klasör", + "Item Type": "Dosya Türü", + "Item Name": "Dosya Adı", + "Create Now": "Oluştur", + "Download": "İndir", + "Open": "Aç", + "UnZip": "Arşivden çıkart", + "UnZip to folder": "Klasöre Çıkart", + "Edit": "Düzenle", + "Normal Editor": "Normal Düzenleyici", + "Back Up": "Yedekle", + "Source Folder": "Kaynak Klasör", + "Files": "Dosyalar", + "Change": "Değişim", + "Settings": "Ayarlar", + "Language": "Dil", + "Memory used": "Kullanılan Bellek", + "Partition size": "Disk Boyutu", + "Error Reporting": "Hata Raporlama", + "Show Hidden Files": "Gizli Dosyaları Göster", + "Full size": "Toplam Boyut", + "Help": "Yardım", + "Free of": "Boş Olan", + "Preview": "Görüntüle", + "Help Documents": "Dökümanlar", + "Report Issue": "Sorun Bildir", + "Generate": "Oluştur", + "Full Size": "Toplam Boyut", + "free of": "Boş olan", + "Calculate folder size": "Klasör Boyutlarını Hesapla", + "Check Latest Version": "Güncel Sürümü Kontrol Et", + "Generate new password hash": "Parola için Hash Üret", + "Hide Perms/Owner columns": "Yetki / Sahip Sütununu Gizle" + } + }, + { + "name": "Slovensky", + "code": "sk", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "File Manager", + "Login": "Prihlásiť sa", + "Username": "Prihlasovacie meno", + "Password": "Heslo", + "Logout": "Odhlásiť", + "Move": "Presunúť", + "Copy": "Kopírovať", + "Save": "Uložiť", + "SelectAll": "Vybrať všetko", + "UnSelectAll": "Zrušiť výber", + "File": "Súbor", + "Back": "Späť", + "Size": "Veľkosť", + "Perms": "Oprávnenia", + "Modified": "Zmenené", + "Owner": "Vlastník", + "Search": "Hľadať", + "NewItem": "Nový súbor", + "Folder": "Priečinok", + "Delete": "Zmazať", + "Rename": "Premenovať", + "CopyTo": "Kopírovať do", + "DirectLink": "Priamy odkaz", + "UploadingFiles": "Nahrať súbory", + "ChangePermissions": "Zmeniť oprávnenia", + "Copying": "Kopírovanie", + "CreateNewItem": "Vytvoriť nový súbor", + "Name": "Názov", + "AdvancedEditor": "Pokročilý editor", + "RememberMe": "Zapamätať", + "Actions": "Akcie", + "Upload": "Nahrať", + "Cancel": "Zrušiť", + "InvertSelection": "Obrátiť výber", + "DestinationFolder": "Cieľový priečinok", + "ItemType": "Typ súboru", + "ItemName": "Názov súboru", + "CreateNow": "Vytvoriť", + "Download": "Stiahnúť", + "Open": "Otvoriť", + "UnZip": "Rozbaliť", + "UnZipToFolder": "Rozbaliť do", + "Edit": "Upraviť", + "NormalEditor": "Editor", + "BackUp": "Záloha", + "SourceFolder": "Zdrojový priečinok", + "Files": "Súbory", + "Change": "Zmeniť", + "Settings": "Nastavenia", + "Language": "Jazyk", + "MemoryUsed": "Využitá pamäť", + "PartitionSize": "Veľkosť oddielu", + "ErrorReporting": "Hlásenie chýb", + "ShowHiddenFiles": "Zobraziť skryté súbory", + "Preview": "Náhľad", + "Help": "Pomoc", + "FullSize": "Celková veľkosť", + "FreeOf": "voľné z" + } + }, + { + "name": "Slovensko", + "code": "sl", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Raziskovalec", + "Login": "Prijava", + "Username": "Uporabniško ime", + "Password": "Geslo", + "Logout": "Odjava", + "Move": "Premakni", + "Copy": "Kopiraj", + "Save": "Shrani", + "SelectAll": "Izberi vse", + "UnSelectAll": "Izberi nič", + "File": "Datoteka", + "Back": "Nazaj", + "Size": "Velikost", + "Perms": "Pravice", + "Modified": "Spremenjeno", + "Owner": "Lastnik", + "Search": "Iskanje", + "NewItem": "Nov objekt", + "Folder": "Mapa", + "Delete": "Izbriši", + "Rename": "Preimenuj", + "CopyTo": "Kopiraj v", + "DirectLink": "Direktlink", + "UploadingFiles": "Naloži datoteko", + "ChangePermissions": "Spremeni pravice", + "Copying": "Kopiranje", + "CreateNewItem": "Ustvari nov objekt", + "Name": "Ime", + "AdvancedEditor": "Razširjeni urejevalnik", + "RememberMe": "Ostani prijavljen", + "Actions": "Aktivnosti", + "Upload": "Naloži", + "Cancel": "Prekliči", + "InvertSelection": "Obrni izbor", + "DestinationFolder": "Ciljna mapa", + "ItemType": "Tip objekta", + "ItemName": "Ime objekta", + "CreateNow": "Ustvari nov", + "Download": "Prenesi", + "Open": "Odpri", + "UnZip": "Razširi", + "UnZipToFolder": "Razširi v mapo", + "Edit": "Uredi", + "NormalEditor": "Standardni urejevalnik", + "BackUp": "Varnostna kopija", + "SourceFolder": "Izhodiščna mapa", + "Files": "Datoteke", + "Change": "Spremeni", + "Settings": "Nastavitve", + "Language": "Jezik", + "You are logged in": "Ste uspešno prijavljeni", + "Login failed. Invalid username or password": "Prijava je spodletela. Napačno uporabniško ime ali geslo.", + "password_hash not supported, Upgrade PHP version": "password_hash ni podprt, nadgradite različico PHP" + } + }, + { + "name": "Suomi", + "code": "fi", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "File Manager", + "Login": "Kirjautuminen", + "Username": "Käyttäjänimi", + "Password": "Salasana", + "Logout": "Kirjaudu ulos", + "Move": "Siirrä", + "Copy": "Kopioi", + "Save": "Tallenna", + "SelectAll": "Valitse kaikki", + "UnSelectAll": "Poista valinnat", + "File": "Tiedosto", + "Back": "Takaisin", + "Size": "Koko", + "Perms": "Oikeudet", + "Modified": "Muokattu", + "Owner": "Omistaja", + "Search": "Haku", + "NewItem": "Luo uusi...", + "Folder": "Kansio", + "Delete": "Poista", + "Rename": "Nimeä uudelleen", + "CopyTo": "Kopioi kohteeseen", + "DirectLink": "Suora linkki", + "UploadingFiles": "Siirrä tiedostoja", + "ChangePermissions": "Muuta oikeuksia", + "Copying": "Kopioidaan", + "CreateNewItem": "Luo uusi tiedosto tai kansio", + "Name": "Nimi", + "AdvancedEditor": "Edistynyt editori", + "RememberMe": "Muista minut", + "Actions": "Toiminnot", + "Upload": "Vie", + "Cancel": "Peruuta", + "InvertSelection": "Vaihda valinta", + "DestinationFolder": "Kohdekansio", + "ItemType": "Tiedoston tyyppi", + "ItemName": "Nimi", + "CreateNow": "Luo nyt", + "Download": "Lataa", + "Open": "Avaa", + "UnZip": "Pura", + "UnZipToFolder": "Pura kansioon", + "Edit": "Muokkaa", + "NormalEditor": "Editori", + "BackUp": "Varmuuskopioi", + "SourceFolder": "Kohdekansio", + "Files": "Tiedostot", + "Change": "Vaihda", + "Settings": "Asetukset", + "Language": "Kieli", + "MemoryUsed": "Muistia käytetty", + "PartitionSize": "Osion koko", + "ErrorReporting": "Virheraportit", + "ShowHiddenFiles": "Näytä piilotiedostot", + "Preview": "Esikatsele", + "Help": "Apua", + "FullSize": "Täysikokoinen", + "FreeOf": "Vapaana", + "CalculateFolderSize": "Laske kansion koko", + "CheckLatestVersion": "Tarkista päivitykset", + "Generate new password hash": "Luo uusi salasana-hash", + "HideColumns": "Piilota oikeudet-/omistaja-sarakkeet" + } + }, + { + "name": "한국어", + "code": "ko", + "translation": { + "Tiny File Manager": "Tiny File Manager", + "File Manager": "File Manager", + "Sign in": "로그인", + "Username": "아이디", + "Password": "비밀번호", + "Sign Out": "로그아웃", + "Move": "이동", + "Copy": "복사", + "Save": "저장", + "Select all": "전체 선택", + "Unselect all": "선택 해제", + "File": "파일", + "Back": "뒤로", + "Size": "용량", + "Perms": "권한", + "Modified": "마지막 수정", + "Owner": "소유자", + "Search": "검색", + "New Item": "새로 만들기", + "Folder": "폴더", + "Delete": "삭제", + "Rename": "이름 변경", + "Copy to": "지정된 위치로 복사", + "Direct link": "링크", + "Upload Files": "파일 업로드", + "Change Permissions": "권한 변경", + "Copying": "복사 중", + "Create New Item": "새로 만들기", + "Name": "이름", + "Advanced Editor": "고급 에디터", + "Remember Me": "로그인 정보 저장", + "Actions": "액션", + "Upload": "업로드", + "Cancel": "취소", + "Invert Selection": "선택 반전", + "Destination Folder": "대상 폴더", + "Item Type": "유형", + "Item Name": "이름", + "Create Now": "확인", + "Download": "다운로드", + "Open": "열기", + "UnZip": "압축 해제", + "UnZip to folder": "지정된 폴더에 압축 해제", + "Edit": "편집", + "Normal Editor": "일반 에디터", + "Back Up": "백업", + "Source Folder": "원본 폴더", + "Files": "파일", + "Change": "변경하기", + "Settings": "설정", + "Language": "언어", + "Memory used": "메모리 사용량", + "Partition size": "남은 용량", + "Error Reporting": "오류 보고", + "Show Hidden Files": "숨겨진 파일 보기", + "Full size": "현재 폴더 파일 용량", + "Help": "도움말", + "Free of": "파티션 총 용량:", + "Preview": "미리 보기", + "Help Documents": "참고 문서", + "Report Issue": "이슈 보고", + "Generate": "생성", + "Full Size": "총 용량", + "free of": "사용 가능 용량", + "Calculate folder size": "폴더 용량 표시", + "Check Latest Version": "최신 버전 체크", + "Generate new password hash": "새 비밀번호 해시 생성", + "Hide Perms/Owner columns": "권한/소유자 숨기기" + } + }, + { + "name": "日本語", + "code": "ja", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "File Manager", + "Login": "ログイン", + "Username": "Username", + "Password": "Password", + "Logout": "ログアウト", + "Move": "移動", + "Copy": "コピー", + "Save": "保存", + "SelectAll": "すべて選択", + "UnSelectAll": "選択解除", + "File": "ファイル", + "Back": "戻る", + "Size": "サイズ", + "Perms": "権限", + "Modified": "更新日時", + "Owner": "所有者", + "Search": "検索", + "NewItem": "新規作成", + "Folder": "フォルダ", + "Delete": "削除", + "Rename": "名前の変更", + "CopyTo": "宛先を指定してコピー", + "DirectLink": "直接リンク", + "UploadingFiles": "ファイルをアップロード", + "ChangePermissions": "権限を変更", + "Copying": "ファイルをコピー", + "CreateNewItem": "新規作成", + "Name": "名前", + "AdvancedEditor": "拡張エディタで編集", + "RememberMe": "Remember Me", + "Actions": "アクション", + "Upload": "アップロード", + "Cancel": "キャンセル", + "InvertSelection": "選択の切り替え", + "DestinationFolder": "宛先フォルダ", + "ItemType": "種類", + "ItemName": "名前", + "CreateNow": "作成する", + "Download": "ダウンロード", + "Open": "開く", + "UnZip": "解凍", + "UnZipToFolder": "フォルダに解凍", + "Edit": "編集", + "NormalEditor": "通常エディタで編集", + "BackUp": "バックアップ", + "SourceFolder": "元フォルダ", + "Files": "ファイル", + "Change": "変更", + "Settings": "設定", + "Language": "言語", + "MemoryUsed": "メモリ使用量", + "PartitionSize": "パーティションサイズ", + "ErrorReporting": "エラーを表示", + "ShowHiddenFiles": "隠しファイルを表示", + "Full size": "合計サイズ", + "Help": "ヘルプ", + "Free of": "free of", + "Preview": "プレビュー", + "Help Documents": "ヘルプドキュメント", + "Report Issue": "問題を報告", + "Generate": "生成", + "FullSize": "合計サイズ", + "FreeOf": "free of", + "CalculateFolderSize": "フォルダサイズを計算", + "ProcessID": "プロセスID", + "HideColumns": "権限・所有者を非表示", + "Check Latest Version": "更新の確認", + "Generate new password hash": "パスワードハッシュを生成", + "Folder is empty": "空のフォルダです", + "Created": "作成しました", + "You are logged in": "ログインしました", + "Login failed. Invalid username or password": "Username もしくは Password が違います", + "password_hash not supported, Upgrade PHP version": "password_hash がサポートされていません。PHPをアップグレードしてください", + "Group": "グループ", + "Other": "その他", + "Read": "読み込み", + "Write": "書き込み", + "Execute": "実行" + } + }, + { + "name": "Монгол", + "code": "mn_MN", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Файл зохицуулагчr", + "Login": "Нэвтрэх", + "Username": "Хэрэглэгчийн нэр", + "Password": "Нууц үг", + "Logout": "Гарах", + "Move": "Зөөх", + "Copy": "Хуулах", + "Save": "Хадгалах", + "SelectAll": "Бүгдийг сонгох", + "UnSelectAll": "Бүгдийг цэвэрлэх", + "File": "Файл", + "Back": "Буцах", + "Size": "Хэмжээ", + "Perms": "Эрх", + "Modified": "Өөрчлөгдсөн", + "Owner": "Эзэн", + "Search": "Хайх", + "NewItem": "Шинэ зүйл", + "Folder": "Хавтас", + "Delete": "Устгах", + "Rename": "Нэр солих", + "CopyTo": "Руу хуулах", + "DirectLink": "Шууд холбоос", + "UploadingFiles": "Файлуудыг хуулж байна", + "ChangePermissions": "Эрх солих", + "Copying": "Хуулж байна", + "CreateNewItem": "Шинээр үүсгэх", + "Name": "Нэр", + "AdvancedEditor": "Нарийн үйлдэлтэй засварлагч", + "RememberMe": "Remember Me", + "Actions": "Үйлдлүүд", + "Upload": "Хуулах", + "Cancel": "Болих", + "InvertSelection": "Сонголтыг эсрэгээр", + "DestinationFolder": "Очих хавтас", + "ItemType": "Төрөл", + "ItemName": "Нэр", + "CreateNow": "Үүсгэх", + "Download": "Татах", + "Open": "Нээх", + "UnZip": "Задлах", + "UnZipToFolder": "Хавтсанд задлах", + "Edit": "Засах", + "NormalEditor": "Энгийн засварлагч", + "BackUp": "Бакап", + "SourceFolder": "Хаанаас хавтас", + "Files": "Файл", + "Change": "Солих", + "Settings": "Тохиргоо", + "Language": "Хэл", + "MemoryUsed": "Хэрэглэгдэж буй санах ой", + "PartitionSize": "Партишны зай", + "ErrorReporting": "Алдаа харуулах", + "ShowHiddenFiles": "Нууц файлуудыг харуулах", + "Full size": "Нийт хэмжээ", + "Help": "Тусламж", + "Free of": "Хоосон зай", + "Preview": "Урьдчилан харах", + "Help Documents": "Тусламж", + "Report Issue": "Алдаа мэдэгдэх", + "Generate": "Үүсгэх", + "FullSize": "Нийт хэмжээ", + "FreeOf": "Хоосон зай", + "CalculateFolderSize": "Хавтасны хэмжээг бодох", + "ProcessID": "Процессын ID", + "HideColumns": "Багануудыг нуух", + "Check Latest Version": "Шинчэлэлт байгаа эсэхийг шалгах", + "Generate new password hash": "Шинэ нууц үгийн хаш үүсгэх", + "Folder is empty": "Хавтас хоосон байна", + "Created": "Үүсгэсэн", + "You are logged in": "Нэвтэрсэн байна", + "Login failed. Invalid username or password": "Нэр юмуу нууц үг буруу байна", + "password_hash not supported, Upgrade PHP version": "password_hash функц байхгүй байна. PHP хувилбар ахиулна уу.", + "Group": "Бүлэг", + "Other": "Бусад", + "Read": "Унших", + "Write": "Бичих", + "Execute": "Ажиллуулах" + } + }, + { + "name": "Dutch", + "code": "nl", + "translation": { + "AppName": "Tiny File Manager", + "AppTitle": "Bestandsbeheer ", + "Login": "Inloggen", + "Username": "Gebruikersnaam", + "Password": "Wachtwoord", + "Logout": "Uitloggen", + "Copy": "Kopiëren", + "Save": "Opslaan", + "SelectAll": "Alles selecteren", + "UnSelectAll": "Alles deselecteren", + "File": "Bestand", + "Back": "Terug", + "Size": "Grootte", + "Perms": "Rechten", + "Modified": "Bewerkt", + "Owner": "Eigenaar", + "Search": "Zoeken", + "NewItem": "Nieuw item", + "Folder": "Map", + "Delete": "Verwijder", + "Rename": "Hernoem", + "CopyTo": "Kopiëren naar", + "DirectLink": "Directe link", + "UploadingFiles": "Bestanden uploaden", + "ChangePermissions": "Rechten aanpassen", + "Copying": "Bezig met kopiëren", + "CreateNewItem": "Maak nieuw item", + "Name": "Naam", + "AdvancedEditor": "Geavanceerde editor", + "RememberMe": "Onthoud mij", + "Actions": "Acties", + "Upload": "Uploaden", + "Cancel": "Annuleren", + "InvertSelection": "Keer selectie om", + "DestinationFolder": "Doelmap", + "ItemType": "Item type", + "ItemName": "Item naam", + "CreateNow": "Nu aanmaken", + "Download": "Download", + "Open": "Openen", + "UnZip": "Uitpakken", + "UnZipToFolder": "Uitpakken in map", + "Edit": "Bewerken", + "NormalEditor": "Standaard editor", + "BackUp": "Back-up maken", + "SourceFolder": "Bronmap", + "Files": "Bestanden", + "Move": "Verplaatsen", + "Change": "Aanpassen", + "Settings": "Instellingen", + "Language": "Taal", + "Folder is empty": "Map is leeg", + "PartitionSize": "Partitiegrootte", + "ErrorReporting": "Foutmeldingen", + "ShowHiddenFiles": "Toon verborgen bestanden", + "Full size": "Volledige grootte", + "Help": "Help", + "Free of": "Ruimte vrij", + "Preview": "Voorbeeld", + "Help Documents": "Help documenten", + "Report Issue": "Probleem melden", + "Generate": "Genereer", + "FullSize": "Volledige grootte", + "FreeOf": "Ruimte vrij", + "CalculateFolderSize": "Bereken map grootte", + "ProcessID": "Proces-ID", + "Created": "Aangemaakt", + "HideColumns": "Verberg Rechten/Eigenaar kolommen", + "You are logged in": "U bent ingelogd", + "Check Latest Version": "Bekijk laatste versie", + "Generate new password hash": "Genereer een nieuwe wachtwoord hash", + "Login failed. Invalid username or password": "Inloggen mislukt. Onjuiste gebruikersnaam/wachtwoord combinatie", + "password_hash not supported, Upgrade PHP version": "password_hash is niet ondersteund, Upgrade PHP versie", + "Advanced Search": "Geavanceerd zoeken", + "Error while copying from": "Fout bij het kopiëren van", + "Nothing selected": "Niets geselecteerd", + "Paths must be not equal": "Paden mogen niet gelijk zijn", + "Renamed from": "Hernoemd naar", + "Archive not unpacked": "Archief niet uitgepakt", + "Deleted": "Verwijderd", + "Archive not created": "Archief niet aangemaakt", + "Copied from": "Gekopiëerd van", + "Permissions change": "Rechten aanpassen", + "to": "naar", + "Saved Successfully": "Succesvol opgeslagen", + "not found!": "niet gevonden!", + "File Saved Successfully": "Bestand succesvol opgeslagen", + "Archive": "Archief", + "Permissions not changed": "Rechten niet aangepast", + "Select folder": "Selecteer map", + "Source path not defined": "Bronmap is niet gedefiniëerd", + "already exists": "bestaat al", + "Error while moving from": "Fout bij het verplaatsen van", + "Create archive?": "Maak archief?", + "Invalid file or folder name": "Ongeldige bestands- of mapnaam", + "Archive unpacked": "Archief uitgepakt", + "File extension is not allowed": "Bestandstype is niet toegestaan", + "Root path": "Pad startpunt", + "Error while renaming from": "Fout bij het hernoemen van", + "File not found": "Bestand is niet gevonden", + "Error while deleting items": "Fout bij het verwijderen van items", + "Invalid characters in file name": "Ongeldige karakters in bestandsnaam", + "FILE EXTENSION HAS NOT SUPPORTED": "BESTANDSTYPE IS NIET ONDERSTEUND", + "Selected files and folder deleted": "Geselecteerde bestanden en mappen verwijderd", + "Error while fetching archive info": "Fout bij het verkrijgen van archief informatie", + "Delete selected files and folders?": "Verwijder de geselecteerde bestanden en mappen?", + "Search file in folder and subfolders...": "Zoek bestand in map en submappen...", + "Access denied. IP restriction applicable": "Toegang geweigerd. IP-beperking van toepassing", + "Invalid characters in file or folder name": "Ongeldige karakters in bestands- of mapnaam", + "Operations with archives are not available": "Bewerkingen met archieven zijn niet beschikbaar", + "File or folder with this path already exists": "Bestand of map met dit pad bestaat al", + "Moved from": "Verplaatst van", + "a files": "bestanden", + "Okay": "OK", + "Enter here...": "Voer hier in...", + "Enter new file name": "Voer nieuwe bestandsnaam in:", + "Full path": "Volledig path", + "File size": "Bestandsgrootte", + "Image sizes": "Afbeeldingsgrootte", + "Charset": "Karakterset", + "Image": "Afbeelding", + "Audio": "Audio", + "Video": "Video", + "Upload from URL": "Upload van URL ", + "Files in archive": "Bestanden in archief", + "Total size": "Totale grootte", + "Compression": "Compressie", + "Size in archive": "Grootte in archief", + "Invalid Token.": "Ongeldig token", + "Fullscreen": "Volledig scherm", + "Undo": "Ongedaan maken", + "Redo": "Opnieuw doen", + "Theme": "Thema", + "Select Theme": "Kies thema", + "Select Font Size": "Kies fontgrootte", + "Are you sure want to rename?": "Weet u zeker dat u de naam wilt wijzigen?", + "Are you sure want to": "Verder gaan met", + "dark": "donker", + "light": "licht" + } + }, + { + "name": "Dansk", + "code": "da", + "translation": { + "Access denied. IP restriction applicable": "Adgang nægtet. IP-begrænsning gælder", + "Actions": "Handlinger", + "Advanced Search": "Avanceret søgning", + "AdvancedEditor": "Advanceret Editor", + "AppTitle": "Filhåndtering", + "Archive not created": "Arkiv er ikke oprettet", + "Archive not unpacked": "Arkiv er ikke pakket ud", + "Archive unpacked": "Arkiv er udpakket", + "Archive": "Arkiv", + "Back": "Tilbage", + "BackUp": "Backup", + "CalculateFolderSize": "Beregn mappestørrelse", + "Cancel": "Afbryd", + "Change": "Ændre", + "ChangePermissions": "Ændre tilladelser", + "Check Latest Version": "Tjek seneste version", + "Copied from": "Kopieret fra", + "Copy": "Kopi", + "CopyTo": "Kopier til", + "Copying": "Kopierer", + "Create archive?": "Opret arkiv?", + "CreateNewItem": "Opret ny", + "CreateNow": "Opret nu", + "Created": "Oprettet", + "Delete selected files and folders?": "Slet valgte filer og mapper?", + "Delete": "Slet", + "Deleted": "Slettet", + "DestinationFolder": "Destinationsmappe", + "DirectLink": "Direkte link", + "Download": "Hent", + "Edit": "Rediger", + "Error while copying from": "Fejl ved kopiering fra", + "Error while deleting items": "Fejl ved sletning af elementer", + "Error while fetching archive info": "Fejl ved hentning af arkivoplysninger", + "Error while moving from": "Fejl ved flytning fra", + "Error while renaming from": "Fejl ved omdøbning fra", + "ErrorReporting": "Fejlrapportering", + "Execute": "Udfør", + "FILE EXTENSION HAS NOT SUPPORTED": "FILEXTENSION ER IKKE UNDERSTØTTET", + "File Saved Successfully": "Fil blev gemt", + "File extension is not allowed": "Filtypenavn er ikke tilladt", + "File not found": "Fil ikke fundet", + "File or folder with this path already exists": "Fil eller mappe med denne sti findes allerede", + "File": "Fil(er)", + "Files": "Filer", + "Folder is empty": "Mappen er tom", + "Folder": "Mappe(r)", + "FreeOf": "Ledig af", + "FullSize": "Fuld størrelse", + "Generate new password hash": "Generer ny adgangskode-hash", + "Generate": "Generer", + "Group": "Gruppe", + "Help Documents": "Hjælpedokumenter", + "Help": "Hjælp", + "HideColumns": "Skjul kolonner", + "Invalid characters in file name": "Ugyldige tegn i filnavn", + "Invalid characters in file or folder name": "Ugyldige tegn i fil- eller mappenavn", + "Invalid file or folder name": "Ugyldigt fil- eller mappenavn", + "InvertSelection": "Inverter valget", + "ItemName": "Emne navn", + "ItemType": "Emne type", + "Language": "Sprog", + "Login failed. Invalid username or password": "Login mislykkedes. Ugyldigt brugernavn eller adgangskode", + "Login": "Log på", + "Logout": "Log ud", + "Modified": "Ændret", + "Move": "Flyt", + "Moved from": "Flyttet fra", + "Name": "Navn", + "NewItem": "Nyt emne", + "NormalEditor": "Standard Editor", + "Nothing selected": "Intet valgt", + "Open": "Åben", + "Operations with archives are not available": "Operationer med arkiver er ikke tilgængelige", + "Other": "Andet", + "Owner": "Ejer", + "PartitionSize": "Partitionsstørrelse", + "Password": "Adgangskode", + "Paths must be not equal": "Stierne må ikke være ens", + "Permissions changed": "Tilladelser ændret", + "Permissions not changed": "Tilladelser ikke ændret", + "Perms": "Tilladelser", + "Preview": "Forhåndsvisning", + "Read": "Læs", + "Rename": "Omdøb", + "Renamed from": "Omdøbt fra", + "Report Issue": "Rapportér problem", + "Root path": "Rod mappe", + "Save": "Gem", + "Search file in folder and subfolders...": "Søg fil i mappe og undermapper...", + "Search": "Søg", + "Select folder": "Vælg mappe", + "SelectAll": "Vælg alle", + "Selected files and folder deleted": "Valgte filer og mappe slettet", + "Settings": "Indstillinger", + "ShowHiddenFiles": "Vis skjulte filer", + "Size": "Størrelse", + "Source path not defined": "Kildesti er ikke defineret", + "SourceFolder": "Kildemappe", + "Tar": "Tar", + "Theme": "Tema", + "UnSelectAll": "Fravælg alle", + "UnZip": "Pak ud", + "UnZipToFolder": "Pak ud i mappe", + "Upload": "Upload", + "UploadingFiles": "Uploader filer", + "Username": "Brugernavn", + "Write": "Skriv", + "You are logged in": "Du er logget ind", + "Zip": "Zip", + "already exists": "eksisterer allerede", + "dark": "mørkt", + "light": "lyst", + "not created": "ikke oprettet", + "not deleted": "ikke slettet", + "not found!": "ikke fundet!", + "password_hash not supported, Upgrade PHP version": "password_hash er ikke understøttet, opgrader PHP-versionen", + "to": "til" + } + }, + { + "name": "Bengali", + "code": "bn", + "translation": { + "Access denied. IP restriction applicable": "অ্যাক্সেস অস্বীকার করা হয়েছে৷ আইপি সীমাবদ্ধতা প্রযোজ্য", + "Actions": "একশন্স", + "Advanced Search": "উন্নত অনুসন্ধান", + "AdvancedEditor": "উন্নত এডিটর", + "AppTitle": "ফাইল ম্যানেজার", + "Archive not created": "আর্কাইভ তৈরি করা হয়নি", + "Archive not unpacked": "আর্কাইভ প্যাক করা হয়নি", + "Archive unpacked": "আর্কাইভ আনপ্যাক", + "Archive": "আর্কাইভ", + "Back": "পেছনে", + "BackUp": "ব্যাকআপ", + "CalculateFolderSize": "ফোল্ডার সাইজ গণনা করুন", + "Cancel": "বাতিল করুন", + "Change": "পরিবর্তন", + "ChangePermissions": "অনুমতি পরিবর্তন করুন", + "Check Latest Version": "সর্বশেষ সংস্করণ পরীক্ষা করুন", + "Copied from": "থেকে কপি করা হয়েছে", + "Copy": "কপি", + "CopyTo": "কপি করুন", + "Copying": "কপি করা হচ্ছে", + "Create archive?": "নতুন আর্কাইভ তৈরি করুন", + "CreateNewItem": "নতুন আইটেম তৈরি করুন", + "CreateNow": "এখন তৈরি করুন", + "Created": "তৈরি করা হয়েছে", + "Delete selected files and folders?": "নির্বাচিত ফাইল এবং ফোল্ডার মুছবেন?", + "Delete": "মুছে ফেলা", + "Deleted": "মুছে ফেলা হয়েছে", + "DestinationFolder": "গন্তব্য ফোল্ডার", + "DirectLink": "সরাসরি লিঙ্ক", + "Download": "ডাউনলোড", + "Edit": "এডিট", + "Error while copying from": "থেকে কপি করার সময় ত্রুটি", + "Error while deleting items": "থেকে মুছে ফেলার সময় ত্রুটি", + "Error while fetching archive info": "আর্কাইভ তথ্য আনার সময় ত্রুটি", + "Error while moving from": "থেকে সরানোর সময় ত্রুটি", + "Error while renaming from": "থেকে নাম পরিবর্তন করার সময় ত্রুটি", + "ErrorReporting": "এরর রিপোর্টিং", + "Execute": "এক্সিকিউট", + "FILE EXTENSION HAS NOT SUPPORTED": "ফাইল এক্সটেনশন সমর্থিত নয়", + "File Saved Successfully": "ফাইল সফলভাবে সংরক্ষিত হয়েছে৷", + "File extension is not allowed": "ফাইল এক্সটেনশন অনুমোদিত নয়", + "File not found": "ফাইল পাওয়া যায়নি", + "File or folder with this path already exists": "এই পথ সহ ফাইল বা ফোল্ডার ইতিমধ্যেই বিদ্যমান", + "File": "ফাইল", + "Files": "ফাইলস", + "Folder is empty": "ফোল্ডার খালি", + "Folder": "ফোল্ডার", + "FreeOf": "মুক্ত", + "FullSize": "ফুল সাইজ", + "Generate new password hash": "নতুন পাসওয়ার্ড হ্যাশ তৈরি করুন", + "Generate": "উৎপন্ন", + "Group": "গ্রুপ", + "Help Documents": "হেল্প ডকুমেন্টস", + "Help": "সাহায্য", + "HideColumns": "কলাম লুকান", + "Invalid characters in file name": "ফাইলের নামে অবৈধ অক্ষর", + "Invalid characters in file or folder name": "ফাইল বা ফোল্ডার নামের অবৈধ অক্ষর", + "Invalid file or folder name": "অবৈধ ফাইল বা ফোল্ডারের নাম", + "InvertSelection": "উল্টে নির্বাচন করুন", + "ItemName": "আইটেম নাম", + "ItemType": "আইটেম ধরন", + "Language": "ভাষা", + "Login failed. Invalid username or password": "লগইন ব্যর্থ. অবৈধ ব্যবহারকারীর নাম বা পাসওয়ার্ড", + "Login": "লগইন", + "Logout": "লগআউট", + "Modified": "পরিবর্তিত", + "Move": "সরান", + "Moved from": "থেকে সরানো", + "Name": "নাম", + "NewItem": "নতুন আইটেম", + "NormalEditor": "সাধারণ এডিটর", + "Nothing selected": "কিছুই নির্বাচিত নয়", + "Open": "খোলা", + "Operations with archives are not available": "আর্কাইভ সহ অপারেশন পাওয়া যায়নি", + "Other": "অন্যান্য", + "Owner": "মালিক", + "PartitionSize": "পার্টিশনের মাপ", + "Password": "পাসওয়ার্ড", + "Paths must be not equal": "পথ সমান হতে হবে না", + "Permissions changed": "অনুমতি পরিবর্তন", + "Permissions not changed": "অনুমতি পরিবর্তন করা হয়নি", + "Perms": "পারমস", + "Preview": "পূর্বরূপ", + "Read": "পড়ুন", + "Rename": "নাম পরিবর্তন করা হয়েছে", + "Renamed from": "থেকে নাম পরিবর্তন করা হয়েছে", + "Report Issue": "ইস্যুস রিপোর্ট করুন", + "Root path": "রুট পথ", + "Save": "সংরক্ষণ", + "Search file in folder and subfolders...": "ফোল্ডার এবং সাবফোল্ডারে ফাইল অনুসন্ধান করুন...", + "Search": "অনুসন্ধান করুন", + "Select folder": "ফোল্ডার নির্বাচন করুন", + "SelectAll": "সব নির্বাচন করুন", + "Selected files and folder deleted": "নির্বাচিত ফাইল এবং ফোল্ডার মুছে ফেলা হয়েছে", + "Settings": "সেটিংস", + "ShowHiddenFiles": "গোপন ফাইলগুলো দেখুন", + "Size": "সাইজ", + "Source path not defined": "সোর্স পথ সংজ্ঞায়িত করা হয়নি", + "SourceFolder": "সোর্স ফোল্ডার", + "Tar": "টার", + "Theme": "থিম", + "UnSelectAll": "সরিয়ে ফেলুন সব", + "UnZip": "আনজিপ করুন", + "UnZipToFolder": "ফোল্ডারে আনজিপ", + "Upload": "আপলোড", + "UploadingFiles": "ফাইল আপলোড করা হচ্ছে", + "Username": "ব্যবহারকারীর নাম", + "Write": "লিখুন", + "You are logged in": "আপনি লগ ইন করছেন", + "Zip": "জিপ", + "already exists": "আগে থেকেই আছে", + "dark": "ডার্ক", + "light": "লাইট", + "not created": "তৈরি করা হয়নি", + "not deleted": "মুছে ফেলা হয়নি", + "not found!": "পাওয়া যায় নি!", + "password_hash not supported, Upgrade PHP version": "পাসওয়ার্ড_হ্যাশ সমর্থিত নয়, পিএইচপি ভার্সন আপগ্রেড করুন", + "to": "to" + } + } + ] +}