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,133 +4,35 @@ declare(strict_types=1);
namespace FlysystemOffload\Filesystem\Adapters; namespace FlysystemOffload\Filesystem\Adapters;
use FlysystemOffload\Filesystem\AdapterInterface; // ← CORRECTO (sin Adapters)
use League\Flysystem\FilesystemAdapter; use League\Flysystem\FilesystemAdapter;
use League\Flysystem\UnixVisibility\PortableVisibilityConverter; use League\Flysystem\WebDAV\WebDAVAdapter as LeagueWebDAVAdapter;
use League\Flysystem\Visibility;
use League\Flysystem\WebDAV\WebDAVAdapter as FlysystemWebDAVAdapter;
use Sabre\DAV\Client; use Sabre\DAV\Client;
use InvalidArgumentException; use InvalidArgumentException;
/** /**
* Adaptador WebDAV para Flysystem Offload * Adaptador WebDAV para Flysystem Offload
*
* Proporciona integración con servidores WebDAV usando Sabre/DAV
*/ */
class WebdavAdapter implements AdapterInterface class WebdavAdapter implements AdapterInterface
{ {
/** /**
* Crea y configura el adaptador WebDAV * {@inheritdoc}
*
* @param array $config Configuración del adaptador
* @return FilesystemAdapter
* @throws InvalidArgumentException Si la configuración es inválida
*/ */
public function createAdapter(array $config): FilesystemAdapter public function createAdapter(array $config): FilesystemAdapter
{ {
$this->validateConfig($config); $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 // Configurar cliente WebDAV
$clientConfig = [ $clientConfig = [
'baseUri' => rtrim($config['base_uri'], '/') . '/', 'baseUri' => rtrim($config['base_uri'], '/') . '/',
'userName' => $config['username'] ?? null,
'password' => $config['password'] ?? null,
]; ];
// Añadir autenticación si está configurada // Configurar tipo de autenticación
if (!empty($config['username'])) { if (!empty($config['auth_type'])) {
$clientConfig['userName'] = $config['username']; $authType = strtolower($config['auth_type']);
$clientConfig['password'] = $config['password'] ?? ''; $clientConfig['authType'] = match ($authType) {
$clientConfig['authType'] = $this->normalizeAuthType($config['auth_type'] ?? 'basic');
}
// Configuración adicional opcional
if (isset($config['encoding'])) {
$clientConfig['encoding'] = $config['encoding'];
}
$client = new Client($clientConfig);
// Crear convertidor de visibilidad con permisos normalizados
$visibility = new PortableVisibilityConverter(
$filePublic,
$filePrivate,
$dirPublic,
$dirPrivate,
Visibility::PRIVATE // Visibilidad por defecto
);
// Crear y retornar el adaptador
return new FlysystemWebDAVAdapter(
$client,
$config['prefix'] ?? '',
$visibility
);
}
/**
* 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, 'basic' => Client::AUTH_BASIC,
'digest' => Client::AUTH_DIGEST, 'digest' => Client::AUTH_DIGEST,
'ntlm' => Client::AUTH_NTLM, 'ntlm' => Client::AUTH_NTLM,
@ -138,46 +40,37 @@ class WebdavAdapter implements AdapterInterface
}; };
} }
/** // Crear cliente
* Valida la configuración del adaptador $client = new Client($clientConfig);
*
* @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 // Configurar permisos
if (!filter_var($config['base_uri'], FILTER_VALIDATE_URL)) { $permissions = [
throw new InvalidArgumentException( 'file' => [
'Invalid WebDAV base_uri format. Must be a valid URL (e.g., https://webdav.example.com/remote.php/dav/files/username/)' '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'),
],
];
// Validar que sea HTTP o HTTPS error_log('[WebDAV Adapter] Creating adapter with permissions: ' . print_r($permissions, true));
$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 // Crear adaptador
if (!empty($config['username']) && !isset($config['password'])) { $adapter = new LeagueWebDAVAdapter(
throw new InvalidArgumentException( $client,
'WebDAV password is required when username is provided' $config['prefix'] ?? '',
$permissions
); );
}
error_log('[WebDAV Adapter] Adapter created successfully');
return $adapter;
} }
/** /**
* Obtiene las claves de configuración requeridas * {@inheritdoc}
*
* @return array
*/ */
public function getRequiredConfigKeys(): array public function getRequiredConfigKeys(): array
{ {
@ -185,9 +78,7 @@ class WebdavAdapter implements AdapterInterface
} }
/** /**
* Obtiene las claves de configuración opcionales * {@inheritdoc}
*
* @return array
*/ */
public function getOptionalConfigKeys(): array public function getOptionalConfigKeys(): array
{ {
@ -200,34 +91,55 @@ class WebdavAdapter implements AdapterInterface
'file_private', 'file_private',
'dir_public', 'dir_public',
'dir_private', '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 [ if (is_int($permission)) {
'auth_type' => 'basic', return $permission;
'prefix' => '', }
'file_public' => '0644',
'file_private' => '0600', if (is_string($permission)) {
'dir_public' => '0755', $permission = trim($permission);
'dir_private' => '0700',
]; // 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;
} }
} }