2.1.0
This commit is contained in:
parent
388f5112de
commit
6a4949f181
317
README.md
317
README.md
|
|
@ -1,116 +1,225 @@
|
||||||
# Flysystem Offload — Almacenamiento universal para WordPress
|
### Flysystem Offload
|
||||||
|
|
||||||
Flysystem Offload sustituye el sistema de archivos local de WordPress por un backend remoto operado con Flysystem v3. Los medios se suben, sirven y eliminan directamente desde el proveedor seleccionado (S3 y compatibles en la primera versión) sin modificar el flujo editorial.
|
Flysystem Offload es un plugin minimalista de WordPress que sustituye el almacenamiento local por un backend remoto usando [Flysystem v3](https://flysystem.thephpleague.com/v3/docs/). Inspirado por el estilo ligero de “S3 Uploads”, se concentra en proporcionar una integración transparente, sin panel de administración, y con compatibilidad total con el flujo estándar de medios de WordPress.
|
||||||
|
|
||||||
## Características
|
### Características
|
||||||
|
|
||||||
- **Proveedor seleccionable:** Amazon S3 y endpoints compatibles (MinIO, DigitalOcean Spaces, Wasabi, etc.).
|
- Registro temprano del stream wrapper para redirigir `wp-content/uploads` a almacenamiento remoto.
|
||||||
- **Integración transparente:** hooks de `upload_dir`, `wp_get_attachment_url`, stream wrapper `fly://` y borrado sincronizado.
|
- Generación automática de URLs públicas coherentes con el prefijo de bucket.
|
||||||
- **Arquitectura modular:** preparada para añadir SFTP, WebDAV y otros adaptadores en iteraciones futuras.
|
- Cabeceras `Cache-Control` y `Expires` aplicadas en las subidas.
|
||||||
- **Panel de ajustes:** selector de proveedor y credenciales gestionadas desde la administración.
|
- Limpieza remota de adjuntos al eliminarlos desde WordPress.
|
||||||
|
- Configuración declarativa vía `config/flysystem-offload.php`.
|
||||||
## Requisitos
|
|
||||||
|
|
||||||
- PHP 8.0+
|
|
||||||
- WordPress 6.0+
|
|
||||||
- Extensiones PHP: `curl`, `mbstring`, `xml`
|
|
||||||
- Acceso a Composer durante la construcción del paquete (o usar la imagen Docker proporcionada)
|
|
||||||
- Credenciales válidas de S3 o servicio compatible
|
|
||||||
|
|
||||||
## Instalación
|
|
||||||
|
|
||||||
### Opción A · Proyecto existente de WordPress
|
|
||||||
|
|
||||||
|
|
||||||
1. Clona este repositorio dentro del árbol de tu sitio:
|
### Requisitos
|
||||||
`git clone https://git.brasdrive.com.br/Brasdrive/flysystem-offload.git`
|
|
||||||
2. Entra en la carpeta del plugin y ejecuta Composer para traer las dependencias:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd flysystem-offload
|
|
||||||
composer install --no-dev --optimize-autoloader
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Empaqueta el plugin con la carpeta `vendor/` incluida y súbelo a `/wp-content/plugins/` del sitio que corresponda (vía SCP, rsync o panel de hosting).
|
|
||||||
4. Activa **Flysystem Offload** desde **Plugins > Plugins instalados** en el escritorio de WordPress.
|
|
||||||
|
|
||||||
### Opción B · Imagen Docker (multi-stage)
|
|
||||||
|
|
||||||
El repositorio incluye un Dockerfile que construye una imagen basada en `wordpress:6.8.3-php8.4-apache` y prepara el plugin en tiempo de build:
|
|
||||||
|
|
||||||
```Dockerfile
|
|
||||||
# Etapa 1: composer:2.8.12 instala las dependencias en /app/wp-content/plugins/flysystem-offload
|
|
||||||
# Etapa 2: copia el plugin con vendor/ dentro de /usr/src/wordpress y /var/www/html
|
|
||||||
# Instala redis, WP-CLI y algunas utilidades
|
|
||||||
# Habilita módulos de Apache y carga configuraciones personalizadas de PHP/Apache
|
|
||||||
```
|
|
||||||
|
|
||||||
Pasos para usarla:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Desde la raíz del repositorio
|
|
||||||
docker build -t flysystem-offload-wp .
|
|
||||||
# Arranca el contenedor exponiendo el puerto 80 (puedes convertirlo en un stack Compose si lo prefieres)
|
|
||||||
docker run --rm -p 8080:80 flysystem-offload-wp
|
|
||||||
```
|
|
||||||
|
|
||||||
La imagen resultante ya contiene:
|
|
||||||
|
|
||||||
- El plugin con todas sus dependencias PHP en `/usr/src/wordpress/wp-content/plugins/flysystem-offload`.
|
- WordPress 6.5 o superior.
|
||||||
- Copia pre-sincronizada en `/var/www/html/wp-content/plugins` para que esté disponible desde el primer arranque.
|
- PHP 8.2 o superior (probado en PHP 8.4).
|
||||||
- Extensión Redis habilitada, WP-CLI disponible y módulos `rewrite`, `headers`, `expires`, `deflate` activos.
|
- Extensiones PHP: `json`, `curl`, `mbstring`.
|
||||||
|
- Credenciales válidas para un servicio S3 compatible.
|
||||||
### Nota sobre Composer
|
- Composer para instalar dependencias (AWS SDK).
|
||||||
|
|
||||||
En entornos que no usan Docker, asegúrate de ejecutar `<plugin>/composer install` antes de empaquetar o desplegar. WordPress no ejecuta Composer automáticamente durante la activación de un plugin.
|
|
||||||
|
|
||||||
## Configuración inicial (S3 / compatible)
|
|
||||||
|
|
||||||
|
|
||||||
1. En el escritorio de WordPress abre **Ajustes > Flysystem Offload**.
|
### Instalación
|
||||||
2. Selecciona **Amazon S3 / Compatible**.
|
|
||||||
3. Completa los campos:
|
|
||||||
- Access Key
|
|
||||||
- Secret Key (permanece oculta tras guardarla)
|
|
||||||
- Región (`us-east-1`, `eu-west-1`, etc.)
|
|
||||||
- Bucket
|
|
||||||
- Prefijo opcional (subcarpeta dentro del bucket)
|
|
||||||
- Endpoint personalizado (solo para servicios compatibles con S3)
|
|
||||||
- URL CDN opcional (sustituye la URL pública del bucket por tu dominio CDN)
|
|
||||||
4. Guarda los cambios. El plugin reconstruye automáticamente el filesystem y el stream wrapper.
|
|
||||||
**Prefijo base:** Puedes definir un prefijo global (`wordpress/uploads/`) que se añadirá a todas las rutas remotas antes de delegar en el adaptador.
|
|
||||||
|
|
||||||
## Flujo de funcionamiento
|
|
||||||
|
|
||||||
|
|
||||||
- WordPress sigue usando `wp_handle_upload()`.
|
1. Clona el repositorio en `wp-content/plugins/flysystem-offload`.
|
||||||
- Los filtros de `upload_dir` cambian `basedir` a `fly://...`.
|
2. Ejecuta `composer install` dentro del plugin si el SDK no está en el proyecto.
|
||||||
- El stream wrapper reenvía lecturas/escrituras a Flysystem y este al cliente S3.
|
3. Copia `config/flysystem-offload.example.php` a `config/flysystem-offload.php`.
|
||||||
- `wp_get_attachment_url` reescribe la URL base con el dominio del bucket o el CDN configurado.
|
4. Ajusta las claves del archivo de configuración.
|
||||||
- Al eliminar un adjunto, se borran el archivo principal y sus derivadas desde el almacenamiento remoto.
|
5. Activa el plugin desde el dashboard de WordPress o vía `wp plugin activate flysystem-offload`.
|
||||||
|
|
||||||
## Roadmap inmediato
|
|
||||||
|
|
||||||
- Campos y validaciones para SFTP y WebDAV.
|
|
||||||
- Health check vía WP-CLI.
|
|
||||||
- Herramientas de migración para copiar la biblioteca existente al proveedor remoto.
|
|
||||||
- Adaptadores adicionales (GCS, Azure Blob) y conectores OAuth (Drive, OneDrive, Dropbox).
|
|
||||||
|
|
||||||
## Contribuir
|
|
||||||
|
|
||||||
|
|
||||||
1. Haz fork y crea una rama (`feature/tu-feature`).
|
### Configuración básica (`config/flysystem-offload.php`)
|
||||||
2. Sigue los [WordPress Coding Standards](https://developer.wordpress.org/coding-standards/).
|
|
||||||
3. Ejecuta tests si están disponibles y actualiza la documentación si corresponde.
|
|
||||||
4. Abre un Pull Request describiendo el cambio.
|
|
||||||
|
|
||||||
- Documentación: Este archivo.
|
```php
|
||||||
- Issues/Contacto: jdavidcamejo@gmail.com
|
<?php
|
||||||
|
return [
|
||||||
|
'driver' => 's3',
|
||||||
|
'visibility' => 'public',
|
||||||
|
|
||||||
## Licencia
|
'stream' => [
|
||||||
|
'protocol' => 'flysystem',
|
||||||
GPL v2. Consulta [LICENSE](LICENSE) para más detalles.
|
'root_prefix' => '',
|
||||||
|
'host' => 'uploads',
|
||||||
|
],
|
||||||
|
|
||||||
---
|
'uploads' => [
|
||||||
|
'base_url' => getenv('FLYSYSTEM_OFFLOAD_BASE_URL') ?: 'https://offload.brasdrive.com.br',
|
||||||
|
'delete_remote' => true,
|
||||||
|
'prefer_local_for_missing' => false,
|
||||||
|
'cache_control' => 'public, max-age=31536000, immutable',
|
||||||
|
'expires_ttl' => 31536000,
|
||||||
|
'expires' => null,
|
||||||
|
],
|
||||||
|
|
||||||
Desarrollado por [Brasdrive](https://brasdrive.com.br).
|
'admin' => [
|
||||||
|
'enabled' => false,
|
||||||
|
],
|
||||||
|
|
||||||
|
's3' => [
|
||||||
|
'key' => getenv('AWS_ACCESS_KEY_ID') ?: null,
|
||||||
|
'secret' => getenv('AWS_SECRET_ACCESS_KEY') ?: null,
|
||||||
|
'session_token' => getenv('AWS_SESSION_TOKEN') ?: null,
|
||||||
|
'region' => getenv('AWS_DEFAULT_REGION') ?: 'us-east-1',
|
||||||
|
'bucket' => getenv('FLYSYSTEM_OFFLOAD_BUCKET') ?: 'your-bucket-name',
|
||||||
|
'prefix' => getenv('FLYSYSTEM_OFFLOAD_PREFIX') ?: 'wordpress',
|
||||||
|
'endpoint' => getenv('FLYSYSTEM_OFFLOAD_ENDPOINT') ?: null,
|
||||||
|
'use_path_style_endpoint' => (bool) (getenv('AWS_USE_PATH_STYLE_ENDPOINT') ?: false),
|
||||||
|
'version' => 'latest',
|
||||||
|
'options' => [],
|
||||||
|
'default_options' => [],
|
||||||
|
'acl_public' => 'public-read',
|
||||||
|
'acl_private' => 'private',
|
||||||
|
],
|
||||||
|
];
|
||||||
|
```
|
||||||
|
|
||||||
|
### Normalización de configuración
|
||||||
|
|
||||||
|
`Plugin::normaliseConfig()` establece valores por defecto, garantiza que `uploads.base_url` termine sin `/`, y fusiona `s3.prefix`, `stream.root_prefix` y `stream.host` para producir el prefijo remoto final.
|
||||||
|
|
||||||
|
### Funcionamiento del stream wrapper
|
||||||
|
|
||||||
|
- El filtro `upload_dir` devuelve rutas como `flysystem://uploads/2025/01`.
|
||||||
|
- `MediaHooks` reescribe automáticamente `wp_get_attachment_url` para apuntar a la ruta remota (`base_url + prefijo + archivo`).
|
||||||
|
- El prefijo remoto resultante combina `s3.prefix`, `stream.root_prefix` y `stream.host` para reflejar exactamente la clave almacenada en el bucket (ej.: `wordpress/uploads/2025/01/file.jpg`).
|
||||||
|
|
||||||
|
### Cabeceras de caché
|
||||||
|
|
||||||
|
El adaptador S3 añade `Cache-Control` y `Expires` a través de las opciones por defecto de Flysystem:
|
||||||
|
|
||||||
|
```php
|
||||||
|
$defaultOptions['CacheControl'] = 'public, max-age=31536000, immutable';
|
||||||
|
$defaultOptions['Expires'] = gmdate('D, d M Y H:i:s \G\M\T', time() + 31536000);
|
||||||
|
```
|
||||||
|
|
||||||
|
Puede personalizarse mediante el filtro `flysystem_offload_s3_default_write_options`.
|
||||||
|
|
||||||
|
### Escenario bucket público (probado con IDrive e2)
|
||||||
|
|
||||||
|
1. Marcar bucket como público en la consola de IDrive e2.
|
||||||
|
2. Aplicar policy simple (la UI sólo acepta una versión sin `Condition`).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Sid": "AllowPublicReadUploads",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": { "AWS": "*" },
|
||||||
|
"Action": [
|
||||||
|
"s3:GetObject"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::flysystem-offload/wordpress/uploads/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Configurar CORS si el panel o el frontend cargan las imágenes desde otro origen.
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"AllowedOrigins": [
|
||||||
|
"https://offload.brasdrive.com.br"
|
||||||
|
],
|
||||||
|
"AllowedMethods": [
|
||||||
|
"GET",
|
||||||
|
"HEAD"
|
||||||
|
],
|
||||||
|
"AllowedHeaders": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"ExposeHeaders": [
|
||||||
|
"ETag",
|
||||||
|
"Last-Modified",
|
||||||
|
"x-amz-request-id",
|
||||||
|
"x-amz-id-2"
|
||||||
|
],
|
||||||
|
"AllowCredentials": false,
|
||||||
|
"MaxAgeSeconds": 86400
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Escenario recomendado: bucket privado + Cloudflare
|
||||||
|
|
||||||
|
1. **Bucket privado**
|
||||||
|
- Mantenerlo cerrado; permitir `s3:GetObject` sólo a IPs de Cloudflare.
|
||||||
|
- Aplicar policy vía CLI (`aws s3api put-bucket-policy`). Ejemplo con `Condition` por IP (mantén la lista actualizada con la API `GET /client/v4/ips`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Sid": "AllowCloudflareAccess",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": { "AWS": "*" },
|
||||||
|
"Action": [
|
||||||
|
"s3:GetObject"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"arn:aws:s3:::flysystem-offload/wordpress/uploads/*"
|
||||||
|
],
|
||||||
|
"Condition": {
|
||||||
|
"IpAddress": {
|
||||||
|
"aws:SourceIp": [
|
||||||
|
"173.245.48.0/20",
|
||||||
|
"103.21.244.0/22"
|
||||||
|
// ...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Cloudflare**
|
||||||
|
|
||||||
|
- CNAME `offload.brasdrive.com.br` → endpoint IDrive (ej.`u8k6.va11.idrivee2-9.com`).
|
||||||
|
- Proxy naranja activado; SSL universal.
|
||||||
|
- Reglas WAF o Rate Limiting opcionales.
|
||||||
|
|
||||||
|
3. **WordPress**
|
||||||
|
|
||||||
|
- `uploads.base_url = 'https://offload.brasdrive.com.br'`.
|
||||||
|
- Mantener `prefer_local_for_missing = false`.
|
||||||
|
|
||||||
|
4. **Automatización**
|
||||||
|
|
||||||
|
- Script/cron que consulte la API de Cloudflare, regenere la policy con los nuevos rangos IP y la aplique (controlando con `etag`).
|
||||||
|
|
||||||
|
5. **Caché y purgas**
|
||||||
|
|
||||||
|
- Cloudflare respeta las cabeceras `Cache-Control` y `Expires`.
|
||||||
|
- Purgar desde la consola de Cloudflare cuando sea necesario (por URL o caché completa).
|
||||||
|
|
||||||
|
### Compatibilidad de backends
|
||||||
|
|
||||||
|
Actualmente Flysystem Offload proporciona el adaptador **S3**. El código está preparado para admitir otros backends soportados por Flysystem (WebDAV, SFTP, etc.), pero aún deben agregarse adaptadores específicos (`WebdavAdapter`, `SftpAdapter`, etc.) y sus respectivas configuraciones. Esto forma parte del plan inmediato de ampliación: se crearán clases adicionales en `src/Filesystem/Adapters/`, se extenderá la factoría de adaptadores y se actualizará la documentación para cada backend.
|
||||||
|
|
||||||
|
### Notas sobre IDrive e2
|
||||||
|
|
||||||
|
- Para habilitar un bucket público reciente, es necesario contactar soporte.
|
||||||
|
- El editor web de políticas no soporta `Condition`; aplicar policies complejas via CLI/API.
|
||||||
|
- CORS sí puede configurarse desde la UI mientras se respete el formato simple.
|
||||||
|
- Usa el endpoint regional del bucket como `endpoint` en configuración y CLI.
|
||||||
|
|
||||||
|
### Solución de problemas
|
||||||
|
|
||||||
|
- URLs sin prefijo: actualizar a la versión reciente de `MediaHooks.php`.
|
||||||
|
- Confirmar `s3.prefix`, `stream.root_prefix`, `stream.host`.
|
||||||
|
- Falta de `Cache-Control`/`Expires`: revisar `config` y `s3.default_options`.
|
||||||
|
- Error `_.filter` en la UI: bug del formulario; usar CLI.
|
||||||
|
- Archivos inaccesibles con bucket privado: verificar policy, rangos Cloudflare, CNAME activo.
|
||||||
|
|
||||||
|
### Contribuciones
|
||||||
|
|
||||||
|
Se aceptan PRs. Mantén el enfoque minimalista, sin panel de administración, y prioriza compatibilidad con el flujo nativo de WordPress. Roadmap cercano: añadir adaptadores para otros drivers Flysystem.
|
||||||
|
|
||||||
|
### Licencia
|
||||||
|
|
||||||
|
MIT. Revisa el archivo `LICENSE`.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue