This commit is contained in:
Brasdrive 2025-11-09 19:36:01 -04:00
parent 79fa886ee1
commit 799352708b
1 changed files with 74 additions and 162 deletions

View File

@ -4,180 +4,73 @@ declare(strict_types=1);
namespace FlysystemOffload\Filesystem\Adapters;
use FlysystemOffload\Filesystem\AdapterInterface; // ← CORRECTO (sin Adapters)
use League\Flysystem\FilesystemAdapter;
use League\Flysystem\UnixVisibility\PortableVisibilityConverter;
use League\Flysystem\Visibility;
use League\Flysystem\WebDAV\WebDAVAdapter as FlysystemWebDAVAdapter;
use League\Flysystem\WebDAV\WebDAVAdapter as LeagueWebDAVAdapter;
use Sabre\DAV\Client;
use InvalidArgumentException;
/**
* Adaptador WebDAV para Flysystem Offload
*
* Proporciona integración con servidores WebDAV usando Sabre/DAV
*/
class WebdavAdapter implements AdapterInterface
{
/**
* Crea y configura el adaptador WebDAV
*
* @param array $config Configuración del adaptador
* @return FilesystemAdapter
* @throws InvalidArgumentException Si la configuración es inválida
* {@inheritdoc}
*/
public function createAdapter(array $config): FilesystemAdapter
{
$this->validateConfig($config);
// Normalizar permisos de string a integer octal
$filePublic = $this->normalizePermission($config['file_public'] ?? '0644');
$filePrivate = $this->normalizePermission($config['file_private'] ?? '0600');
$dirPublic = $this->normalizePermission($config['dir_public'] ?? '0755');
$dirPrivate = $this->normalizePermission($config['dir_private'] ?? '0700');
// Configurar cliente WebDAV
$clientConfig = [
'baseUri' => rtrim($config['base_uri'], '/') . '/',
'userName' => $config['username'] ?? null,
'password' => $config['password'] ?? null,
];
// Añadir autenticación si está configurada
if (!empty($config['username'])) {
$clientConfig['userName'] = $config['username'];
$clientConfig['password'] = $config['password'] ?? '';
$clientConfig['authType'] = $this->normalizeAuthType($config['auth_type'] ?? 'basic');
}
// Configuración adicional opcional
if (isset($config['encoding'])) {
$clientConfig['encoding'] = $config['encoding'];
// Configurar tipo de autenticación
if (!empty($config['auth_type'])) {
$authType = strtolower($config['auth_type']);
$clientConfig['authType'] = match ($authType) {
'basic' => Client::AUTH_BASIC,
'digest' => Client::AUTH_DIGEST,
'ntlm' => Client::AUTH_NTLM,
default => Client::AUTH_BASIC,
};
}
// Crear cliente
$client = new Client($clientConfig);
// Crear convertidor de visibilidad con permisos normalizados
$visibility = new PortableVisibilityConverter(
$filePublic,
$filePrivate,
$dirPublic,
$dirPrivate,
Visibility::PRIVATE // Visibilidad por defecto
);
// Configurar permisos
$permissions = [
'file' => [
'public' => $this->normalizePermission($config['file_public'] ?? '0644'),
'private' => $this->normalizePermission($config['file_private'] ?? '0600'),
],
'dir' => [
'public' => $this->normalizePermission($config['dir_public'] ?? '0755'),
'private' => $this->normalizePermission($config['dir_private'] ?? '0700'),
],
];
// Crear y retornar el adaptador
return new FlysystemWebDAVAdapter(
error_log('[WebDAV Adapter] Creating adapter with permissions: ' . print_r($permissions, true));
// Crear adaptador
$adapter = new LeagueWebDAVAdapter(
$client,
$config['prefix'] ?? '',
$visibility
$permissions
);
error_log('[WebDAV Adapter] Adapter created successfully');
return $adapter;
}
/**
* Convierte permisos de string octal a integer
*
* @param mixed $permission Permiso en formato string u octal
* @return int Permiso como integer octal
* @throws InvalidArgumentException Si el formato es inválido
*/
private function normalizePermission($permission): int
{
// Si ya es integer, retornar directamente
if (is_int($permission)) {
return $permission;
}
// Si es string, convertir de octal a decimal
if (is_string($permission)) {
// Limpiar espacios
$permission = trim($permission);
// Si comienza con '0', es octal
if (str_starts_with($permission, '0')) {
$result = octdec($permission);
if ($result === false || $result === 0 && $permission !== '0' && $permission !== '0000') {
throw new InvalidArgumentException(
"Invalid octal permission format: {$permission}"
);
}
return $result;
}
// Si es decimal como '644', añadir el 0 y convertir
if (ctype_digit($permission)) {
return octdec('0' . $permission);
}
throw new InvalidArgumentException(
"Permission must be an octal string (e.g., '0644') or integer"
);
}
throw new InvalidArgumentException(
'Permission must be an integer or string, ' . gettype($permission) . ' given'
);
}
/**
* Normaliza el tipo de autenticación
*
* @param string|int $authType Tipo de autenticación
* @return int Constante de autenticación de Sabre\DAV\Client
*/
private function normalizeAuthType($authType): int
{
if (is_int($authType)) {
return $authType;
}
$authType = strtolower(trim($authType));
return match ($authType) {
'basic' => Client::AUTH_BASIC,
'digest' => Client::AUTH_DIGEST,
'ntlm' => Client::AUTH_NTLM,
default => Client::AUTH_BASIC,
};
}
/**
* Valida la configuración del adaptador
*
* @param array $config Configuración a validar
* @throws InvalidArgumentException Si falta configuración requerida
*/
private function validateConfig(array $config): void
{
// Validar base_uri requerido
if (empty($config['base_uri'])) {
throw new InvalidArgumentException('WebDAV base_uri is required');
}
// Validar formato de URL
if (!filter_var($config['base_uri'], FILTER_VALIDATE_URL)) {
throw new InvalidArgumentException(
'Invalid WebDAV base_uri format. Must be a valid URL (e.g., https://webdav.example.com/remote.php/dav/files/username/)'
);
}
// Validar que sea HTTP o HTTPS
$scheme = parse_url($config['base_uri'], PHP_URL_SCHEME);
if (!in_array($scheme, ['http', 'https'], true)) {
throw new InvalidArgumentException(
'WebDAV base_uri must use http:// or https:// scheme'
);
}
// Si hay username, debe haber password
if (!empty($config['username']) && !isset($config['password'])) {
throw new InvalidArgumentException(
'WebDAV password is required when username is provided'
);
}
}
/**
* Obtiene las claves de configuración requeridas
*
* @return array
* {@inheritdoc}
*/
public function getRequiredConfigKeys(): array
{
@ -185,9 +78,7 @@ class WebdavAdapter implements AdapterInterface
}
/**
* Obtiene las claves de configuración opcionales
*
* @return array
* {@inheritdoc}
*/
public function getOptionalConfigKeys(): array
{
@ -200,34 +91,55 @@ class WebdavAdapter implements AdapterInterface
'file_private',
'dir_public',
'dir_private',
'encoding',
];
}
/**
* Obtiene la descripción del adaptador
* Valida la configuración
*
* @return string
* @param array $config
* @throws InvalidArgumentException
*/
public function getDescription(): string
private function validateConfig(array $config): void
{
return 'WebDAV storage adapter for Nextcloud, ownCloud, and other WebDAV-compatible servers';
foreach ($this->getRequiredConfigKeys() as $key) {
if (empty($config[$key])) {
throw new InvalidArgumentException("WebDAV config key '{$key}' is required");
}
}
if (!filter_var($config['base_uri'], FILTER_VALIDATE_URL)) {
throw new InvalidArgumentException('WebDAV base_uri must be a valid URL');
}
}
/**
* Obtiene valores por defecto para la configuración
* Normaliza un permiso a entero octal
*
* @return array
* @param string|int $permission
* @return int
*/
public function getDefaultConfig(): array
private function normalizePermission($permission): int
{
return [
'auth_type' => 'basic',
'prefix' => '',
'file_public' => '0644',
'file_private' => '0600',
'dir_public' => '0755',
'dir_private' => '0700',
];
if (is_int($permission)) {
return $permission;
}
if (is_string($permission)) {
$permission = trim($permission);
// Si es octal string (ej: "0644")
if (preg_match('/^0[0-7]{3}$/', $permission)) {
return intval($permission, 8);
}
// Si es decimal string sin el 0 (ej: "644")
if (preg_match('/^[0-7]{3}$/', $permission)) {
return intval('0' . $permission, 8);
}
}
// Default
return 0644;
}
}