Feature/asynchron ftp upload#1463
Open
flacoonb wants to merge 4 commits intoPhotoboothProject:devfrom
Open
Conversation
… remote gallery This commit introduces a fully asynchronous upload pipeline for FTP/SFTP remote storage, decoupling image upload from the photo capture workflow so the Photobooth UI is never blocked while files are transferred. Core architecture ----------------- - New SQLite-backed UploadQueueService (src/Service/UploadQueueService.php) manages a persistent job queue (pending → in_progress → completed/failed). Each job stores a random 32-hex-character remote filename so local and remote filenames are never the same, preventing enumeration. - New EncryptionService (src/Service/EncryptionService.php) encrypts the FTP password at rest using libsodium secretbox; key is stored in var/run/. - New Symfony Console command UploadWorkerCommand (src/Command/UploadWorkerCommand.php) runs as a long-lived background worker (or once with --once). Picks up jobs, calls RemoteStorageService, retries up to 5 times on failure, and reloads config on every run so admin panel changes are picked up without restarting. - New api/ftpListFolders.php lets the admin panel browse remote directories before saving configuration. - resources/config/photobooth-upload-worker.service: systemd unit for running the worker as www-data. API / backend changes --------------------- - api/applyEffects.php: instead of uploading directly, enqueues a job via UploadQueueService and triggers the worker process in the background. - api/deletePhoto.php: resolves the remote random filename via UploadQueueService::getRemoteFilename() before deleting on FTP, so the correct remote file is removed. - api/qrcode.php, api/print.php: QR URLs now use UploadQueueService to look up the remote filename when FTP + useForQr is enabled. - api/admin.php: exposes upload queue status (pending/failed counts) for the debug panel. - api/serverInfo.php: includes FTP queue stats in server-info response. - RemoteStorageService::getWebpageUri() correctly appends baseFolder to the website URL. - RemoteStorageService::createWebpage() removes legacy .htaccess files (caused 403 on hosts without AllowOverride Options) and instead uploads index.php redirect guards to images/ and thumbs/. - ConfigurationService: decrypts FTP password on load via EncryptionService. - FtpConfiguration: password field marked as sensitive. - src/Console/Application.php: registers UploadWorkerCommand. Admin UI -------- - lib/configsetup.inc.php: removed deprecated folder/urlTemplate fields; added folder browser (ftpListFolders API), queue status display, and "Test Connection" improvements. - assets/js/admin/buttons.js: folder-browser modal, queue status polling, FTP test-connection wiring. - resources/lang/en.json: removed ftp:folder / ftp:urlTemplate keys; updated manual:ftp:website description. Remote gallery (resources/template/index.php) --------------------------------------------- - Single-image view: image is rendered immediately with a JS onload/onerror spinner; onerror auto-reloads every 3 s while upload is in progress. Removed the PHP-side file_exists() upload-wait loop. - Gallery mode: fixed guard so gallery is only rendered when gallery_enabled=true (was falling through to else). - Images sorted newest-first via usort + filemtime. - ZIP download: fixed corrupt archive by using ZipArchive::CREATE | ZipArchive::OVERWRITE (tempnam creates an existing file). - Share button: uses Web Share API with native file sharing where supported; falls back to wa.me deep-link. Icon changed from fa-brands fa-whatsapp to fa-solid fa-share-nodes. - Lightbox navigation: prev/next arrow buttons with wrap-around and keyboard support (ArrowLeft / ArrowRight / Escape). Code style ---------- - PHP CS Fixer: expanded single-line closures in Configuration/Section/* to multi-line form for consistency with project style rules.
- Remove obsolete 'folder' and 'urlTemplate' config fields - Document SFTP support and type selector - Explain async upload queue (SQLite-backed, background worker) - Add systemd service setup and manual worker commands - Describe random remote filenames, directory listing protection - Document automatic QR URL building (no template needed) - Describe online gallery features: spinner, share button, lightbox nav - Add 'Delete on local delete' subsection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prerequisites checklist
What is the purpose of this pull request? (put an "x" next to an item)
What changes did you make? (Give an overview)
Asynchronous FTP/SFTP upload queue
Previously, photos were uploaded to the FTP/SFTP server synchronously during image processing, blocking the UI until the transfer completed. This PR replaces that with a persistent, SQLite-backed upload queue and a background worker:
UploadQueueServicemanages jobs (pending → in_progress → completed / failed, up to 5 retries).photobooth:upload:worker(--onceor continuous mode, configurable poll interval). A systemd unit is provided inresources/config/photobooth-upload-worker.service.api/ftpListFolders.phpallows browsing the remote directory tree from the admin panel before saving the configuration.EncryptionServiceencrypts the FTP/SFTP password at rest using libsodium secretbox; the key is stored invar/run/.Bug fixes
RemoteStorageService::getWebpageUri()now correctly appendsbaseFolderto the website URL. Previously the QR code pointed to the bare domain, ignoring the configured subfolder.createWebpage()removes legacyimages/.htaccess/thumbs/.htaccessfiles (which caused HTTP 403 on hosts withoutAllowOverride Options) and replaces them withindex.phpredirect guards.api/deletePhoto.phpnow resolves the random remote filename viaUploadQueueService::getRemoteFilename()before deleting on FTP, instead of using the local filename which no longer matches.ZipArchive::CREATEfails silently whentempnam()pre-creates the file; fixed withZipArchive::CREATE | ZipArchive::OVERWRITE.Remote gallery improvements (
resources/template/index.php)file_exists()polling with a JSonload/onerrorspinner. While the upload is in progress the visitor sees "Your photo is being uploaded…"; ononerrorthe page reloads every 3 s automatically.elsethat rendered the gallery even whengallery_enabledwasfalse.usort+filemtime.wa.medeep-link. Icon changed fromfa-brands fa-whatsapptofa-solid fa-share-nodes.Admin UI / config cleanup
folderandurlTemplatefields from admin UI anden.json; the QR URL is now built automatically fromwebsite+baseFolder.Documentation
docs/faq/index.md: rewrote the FTP/SFTP section to reflect async uploads, removed obsolete fields, documented worker setup, online gallery features, and the delete-on-local-delete option.CI
build-faq.yml: fixed hardcodedgit push origin devthat caused the workflow to fail when triggered viaworkflow_dispatchfrom a non-devbranch; replaced withgit push origin HEAD:${{ github.ref_name }}.Is there anything you'd like reviewers to focus on?
UploadWorkerCommandreloads the config on every job so admin panel changes are picked up without restarting — please verify this is a safe pattern.AI used to create this Pull Request?
This Pull Request was developed with the assistance of Claude (Anthropic). The AI contributed to architecture decisions (async queue design, libsodium encryption, systemd service), code implementation across all changed files, bug analysis and fixes (403 .htaccess issue, corrupt ZIP, wrong remote filename on delete), and the remote gallery JS rewrite. All generated code was reviewed, tested, and adjusted iteratively based on real-world test results on a live Photobooth installation.