option('disk'); $diskConfig = config("filesystems.disks.{$diskName}"); if (! is_array($diskConfig)) { $this->error("Filesystem disk [{$diskName}] is not configured."); return self::FAILURE; } $this->line('Testing object storage upload.'); $this->line('Disk: '.$diskName); $this->line('Driver: '.(string) ($diskConfig['driver'] ?? 'unknown')); $this->line('Bucket: '.(string) ($diskConfig['bucket'] ?? 'n/a')); $this->line('Region: '.(string) ($diskConfig['region'] ?? 'n/a')); $this->line('Endpoint: '.((string) ($diskConfig['endpoint'] ?? '') !== '' ? (string) $diskConfig['endpoint'] : '[not set]')); $this->line('Path style: '.((bool) ($diskConfig['use_path_style_endpoint'] ?? false) ? 'true' : 'false')); if ((string) ($diskConfig['endpoint'] ?? '') === '') { $this->warn('No endpoint is configured for this S3 disk. Many S3-compatible providers, including Contabo object storage, require AWS_ENDPOINT to be set.'); } $remotePath = $this->resolveRemotePath(); $keepObject = (bool) $this->option('keep'); $sourceFile = $this->option('file'); $filesystem = Storage::disk($diskName); try { if (is_string($sourceFile) && trim($sourceFile) !== '') { $localPath = $this->resolveLocalPath($sourceFile); if ($localPath === null) { $this->error('The file passed to --file does not exist.'); return self::FAILURE; } $stream = fopen($localPath, 'rb'); if ($stream === false) { $this->error('Unable to open the local file for reading.'); return self::FAILURE; } try { $written = $filesystem->put($remotePath, $stream); } finally { fclose($stream); } $sourceLabel = $localPath; } else { $contents = $this->buildProbeContents($diskName); $written = $filesystem->put($remotePath, $contents); $sourceLabel = '[generated probe payload]'; } if ($written !== true) { $this->error('Upload did not complete successfully. The storage driver returned a failure status.'); return self::FAILURE; } $exists = $filesystem->exists($remotePath); $size = $exists ? $filesystem->size($remotePath) : null; $this->info('Upload succeeded.'); $this->line('Source: '.$sourceLabel); $this->line('Object key: '.$remotePath); $this->line('Exists after upload: '.($exists ? 'yes' : 'no')); if ($size !== null) { $this->line('Stored size: '.number_format((int) $size).' bytes'); } if (! $keepObject && $exists) { $filesystem->delete($remotePath); $this->line('Cleanup: deleted uploaded test object'); } elseif ($keepObject) { $this->warn('Cleanup skipped because --keep was used.'); } return $exists ? self::SUCCESS : self::FAILURE; } catch (Throwable $exception) { $this->error('Object storage test failed.'); $this->line($exception->getMessage()); return self::FAILURE; } } private function resolveRemotePath(): string { $provided = trim((string) $this->option('path')); if ($provided !== '') { return ltrim(str_replace('\\', '/', $provided), '/'); } return 'tests/object-storage/'.now()->format('Ymd-His').'-'.Str::random(10).'.txt'; } private function resolveLocalPath(string $path): ?string { $trimmed = trim($path); if ($trimmed === '') { return null; } if (is_file($trimmed)) { return $trimmed; } $relative = base_path($trimmed); return is_file($relative) ? $relative : null; } private function buildProbeContents(string $diskName): string { return implode("\n", [ 'Skinbase object storage upload test', 'disk='.$diskName, 'timestamp='.now()->toIso8601String(), 'app_url='.(string) config('app.url'), 'random='.Str::uuid()->toString(), '', ]); } }