Skip to content

Commit a5b7749

Browse files
committed
task: introduce sftp
This patch introduces Flysystem (https://flysystem.thephpleague.com/) as the underlying package to handle remote storage. For now, we are only integrating SFTP in addition to FTP to allow more connection options for FTP uploads. There will now be an option to select FTP or SFTP, and the correct adapter will be used to create the connection. The code has been restructured to move logic away from the endpoints towards a central service. This will make it easier to implement and maintain in the future. Some options have been removed as they do not seem to work reliably: - `ftp:appendDate` is a nice idea, but it has a flawed implementation as the date is evaluated on each request. This results in a mismatch between requested and actual URLs to files. - `ftp:upload_thumb`: Thumbnails are now always uploaded, ensuring all files are available on the server for the generated webpage. Defaults were introduced for several config settings. This way, we can rely on the settings being set and do not need to guess. The template for the server has been restructured. Instead of parsing the template and potentially risking breaking it, we are now providing a dedicated config file that can be loaded without problems. Additionally, a test template that uses local data is now available.
1 parent a7d303c commit a5b7749

30 files changed

+1102
-556
lines changed

admin/debug/index.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
echo getNavItemDebug('myconfig');
6161
echo getNavItemDebug('remotebuzzerlog');
6262
echo getNavItemDebug('synctodrivelog');
63+
echo getNavItemDebug('remotestoragelog');
6364
echo getNavItemDebug('devlog');
6465
if (Environment::isLinux()) {
6566
echo getNavItemDebug('serverprocesses');

api/applyEffects.php

Lines changed: 7 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
require_once '../lib/boot.php';
66

77
use Photobooth\Image;
8-
use Photobooth\Helper;
98
use Photobooth\Collage;
109
use Photobooth\Enum\FolderEnum;
1110
use Photobooth\Enum\ImageFilterEnum;
1211
use Photobooth\Service\DatabaseManagerService;
1312
use Photobooth\Service\LoggerService;
13+
use Photobooth\Service\RemoteStorageService;
1414
use Photobooth\Utility\ImageUtility;
1515

1616
header('Content-Type: application/json');
@@ -19,6 +19,7 @@
1919
$logger->debug(basename($_SERVER['PHP_SELF']));
2020

2121
$database = DatabaseManagerService::getInstance();
22+
$remoteStorage = RemoteStorageService::getInstance();
2223

2324
try {
2425
if (empty($_POST['file'])) {
@@ -255,106 +256,13 @@
255256
}
256257
}
257258

258-
// send to ftp server
259+
// Store images on remote storage
259260
if ($config['ftp']['enabled']) {
260-
// init connection to ftp server
261-
$ftp = ftp_ssl_connect($config['ftp']['baseURL'], $config['ftp']['port']);
262-
263-
if ($ftp === false) {
264-
$message = 'Failed to connect to FTP Server!';
265-
$logger->error($message, $config['ftp']);
266-
echo json_encode(['error' => $message]);
267-
die();
261+
$remoteStorage->write($remoteStorage->getStorageFolder() . '/images/' . $image, (string) file_get_contents($filename_photo));
262+
$remoteStorage->write($remoteStorage->getStorageFolder() . '/thumbs/' . $image, (string) file_get_contents($filename_thumb));
263+
if ($config['ftp']['create_webpage']) {
264+
$remoteStorage->createWebpage();
268265
}
269-
ftp_set_option($ftp, FTP_TIMEOUT_SEC, 10);
270-
271-
// login to ftp server
272-
$login_result = ftp_login($ftp, $config['ftp']['username'], $config['ftp']['password']);
273-
274-
if (!$login_result) {
275-
$message = 'Can\'t connect to FTP Server!';
276-
$logger->error($message, $config['ftp']);
277-
echo json_encode(['error' => $message]);
278-
die();
279-
}
280-
281-
// turn passive mode on to enable creation of folder and upload of files
282-
ftp_pasv($ftp, true);
283-
284-
$destination = empty($config['ftp']['baseFolder']) ? '' : DIRECTORY_SEPARATOR . $config['ftp']['baseFolder'] . DIRECTORY_SEPARATOR;
285-
286-
$destination .= $config['ftp']['folder'] . DIRECTORY_SEPARATOR . Helper::slugify($config['ftp']['title']);
287-
if ($config['ftp']['appendDate']) {
288-
$destination .= DIRECTORY_SEPARATOR . date('Y/m/d');
289-
}
290-
291-
// navigate trough folder on the server to the destination
292-
@Helper::cdFTPTree($ftp, $destination);
293-
294-
// upload processed picture into destination folder
295-
$put_result = @ftp_put($ftp, $image, $filename_photo, FTP_BINARY);
296-
297-
if (!$put_result) {
298-
$message = 'Unable to save file on FTP Server!';
299-
$logger->error($message, $config['ftp']);
300-
echo json_encode(['error' => $message]);
301-
die();
302-
}
303-
304-
// upload the thumbnail if enabled
305-
if ($config['ftp']['upload_thumb']) {
306-
$thumb_result = ftp_put($ftp, 'tmb_' . $image, $filename_thumb, FTP_BINARY);
307-
if (!$thumb_result) {
308-
$logger->error('Unable to load the thumbnail', $config['ftp']);
309-
}
310-
}
311-
312-
// check if the webpage is enabled and is not already loaded on the ftp server
313-
if ($config['ftp']['create_webpage'] && (!isset($_SESSION['ftpWebpageLoaded']) || $_SESSION['ftpWebpageLoaded'] != $config['ftp']['title'])) {
314-
// if the date folder structure is appended, return to the main folder
315-
if ($config['ftp']['appendDate']) {
316-
@Helper::cdFTPTree($ftp, '../../../');
317-
}
318-
319-
// another security check on the file in the server (e.g. 2-day event with the same ftp folder location)
320-
$webpage_exist = ftp_size($ftp, 'index.php');
321-
if ($webpage_exist == -1) {
322-
// get the index.php template file from the configured location
323-
$webpage_template = file_get_contents($config['ftp']['template_location']);
324-
325-
if ($webpage_template === false) {
326-
throw new \Exception('File could not be read: ' . $config['ftp']['template_location']);
327-
}
328-
// set the {title} variable
329-
$final_webpage = str_replace('{title}', $config['ftp']['title'], $webpage_template);
330-
331-
// put the file into a stream
332-
$stream = fopen('php://memory', 'r+');
333-
if ($stream === false) {
334-
throw new \Exception('Could not put the file into a stream!');
335-
}
336-
fwrite($stream, $final_webpage);
337-
rewind($stream);
338-
339-
// load the index.php result file in the ftp server
340-
$upload_webpage = ftp_fput($ftp, 'index.php', $stream, FTP_BINARY);
341-
342-
fclose($stream);
343-
344-
if (!$upload_webpage) {
345-
$message = 'Unable to save file on FTP Server!';
346-
$logger->error($message, $config['ftp']);
347-
echo json_encode(['error' => $message]);
348-
die();
349-
}
350-
351-
// update the session variable to avoid unnecessary checks
352-
$_SESSION['ftpWebpageLoaded'] = $config['ftp']['title'];
353-
}
354-
}
355-
356-
// close the connection
357-
@ftp_close($ftp);
358266
}
359267

360268
// Change permissions

api/deletePhoto.php

Lines changed: 5 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66

77
use Photobooth\Enum\FolderEnum;
88
use Photobooth\FileDelete;
9-
use Photobooth\Helper;
109
use Photobooth\Service\DatabaseManagerService;
1110
use Photobooth\Service\LoggerService;
11+
use Photobooth\Service\RemoteStorageService;
1212

1313
header('Content-Type: application/json');
1414

1515
$logger = LoggerService::getInstance()->getLogger('main');
1616
$logger->debug(basename($_SERVER['PHP_SELF']));
1717

18+
$remoteStorage = RemoteStorageService::getInstance();
19+
1820
try {
1921
if (empty($_POST['file'])) {
2022
throw new \Exception('No file provided');
@@ -47,56 +49,8 @@
4749
}
4850

4951
if ($config['ftp']['enabled'] && $config['ftp']['delete']) {
50-
$ftp = ftp_ssl_connect($config['ftp']['baseURL'], $config['ftp']['port']);
51-
52-
if ($ftp === false) {
53-
$message = 'Failed to connect to FTP Server!';
54-
$logger->error($message, $config['ftp']);
55-
echo json_encode(['error' => $message]);
56-
die();
57-
}
58-
59-
// login to ftp server
60-
$login_result = ftp_login($ftp, $config['ftp']['username'], $config['ftp']['password']);
61-
62-
if (!$login_result) {
63-
$message = 'Can\'t connect to FTP Server!';
64-
$logger->error($message, $config['ftp']);
65-
echo json_encode(['error' => $message]);
66-
die();
67-
}
68-
69-
$remote_dest = empty($config['ftp']['baseFolder']) ? '' : DIRECTORY_SEPARATOR . $config['ftp']['baseFolder'] . DIRECTORY_SEPARATOR;
70-
71-
$remote_dest .= $config['ftp']['folder'] . DIRECTORY_SEPARATOR . Helper::slugify($config['ftp']['title']);
72-
if ($config['ftp']['appendDate']) {
73-
$remote_dest .= DIRECTORY_SEPARATOR . date('Y/m/d');
74-
}
75-
76-
@Helper::cdFTPTree($ftp, $remote_dest);
77-
78-
$delete_result = ftp_delete($ftp, $file);
79-
80-
if (!$delete_result) {
81-
$message = 'Unable to delete file on ftp server ' . $file;
82-
$logger->error($message, $config['ftp']);
83-
echo json_encode(['error' => $message]);
84-
die();
85-
}
86-
87-
if ($config['ftp']['upload_thumb']) {
88-
$delete_result = ftp_delete($ftp, 'tmb_' . $file);
89-
90-
if (!$delete_result) {
91-
$message = 'Unable to delete thumb on ftp server ' . $file;
92-
$logger->error($message, $config['ftp']);
93-
echo json_encode(['error' => $message]);
94-
die();
95-
}
96-
}
97-
98-
// close the connection
99-
@ftp_close($ftp);
52+
$remoteStorage->delete($remoteStorage->getStorageFolder() . '/images/' . $file);
53+
$remoteStorage->delete($remoteStorage->getStorageFolder() . '/thumbs/' . $file);
10054
}
10155

10256
if (!$logData['success'] || $config['dev']['loglevel'] > 1) {

api/print.php

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Photobooth\Image;
99
use Photobooth\Service\LoggerService;
1010
use Photobooth\Service\PrintManagerService;
11+
use Photobooth\Service\RemoteStorageService;
1112
use Photobooth\Utility\PathUtility;
1213

1314
header('Content-Type: application/json');
@@ -74,14 +75,18 @@
7475
}
7576

7677
if ($config['print']['qrcode']) {
77-
// create qr code
78-
if ($config['ftp']['enabled'] && $config['ftp']['useForQr'] && isset($config['ftp']['processedTemplate'])) {
79-
$imageHandler->qrUrl = $config['ftp']['processedTemplate'] . DIRECTORY_SEPARATOR . $filename;
80-
} elseif ($config['qr']['append_filename']) {
81-
$imageHandler->qrUrl = PathUtility::getPublicPath($config['qr']['url'] . $filename, true);
82-
} else {
83-
$imageHandler->qrUrl = PathUtility::getPublicPath($config['qr']['url'], true);
78+
$url = $config['qr']['url'];
79+
if ($config['ftp']['enabled'] && $config['ftp']['useForQr']) {
80+
$remoteStorageService = RemoteStorageService::getInstance();
81+
$url = $remoteStorageService->getWebpageUri();
82+
if ($config['qr']['append_filename']) {
83+
$url .= '/images/';
84+
}
8485
}
86+
if ($config['qr']['append_filename']) {
87+
$url .= $filename;
88+
}
89+
$imageHandler->qrUrl = PathUtility::getPublicPath($url, true);
8590
$imageHandler->qrSize = $config['print']['qrSize'];
8691
$imageHandler->qrMargin = $config['print']['qrMargin'];
8792
$imageHandler->qrColor = $config['print']['qrBgColor'];

api/qrcode.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,26 @@
22

33
/** @var array $config */
44

5+
use Photobooth\Service\RemoteStorageService;
56
use Photobooth\Utility\PathUtility;
67
use Photobooth\Utility\QrCodeUtility;
78

89
require_once '../lib/boot.php';
910

1011
$filename = (isset($_GET['filename']) && $_GET['filename']) != '' ? $_GET['filename'] : false;
11-
12-
if ($filename || !$config['qr']['append_filename']) {
13-
if ($config['ftp']['enabled'] && $config['ftp']['useForQr'] && isset($config['ftp']['processedTemplate'])) {
14-
$url = $config['ftp']['processedTemplate'] . DIRECTORY_SEPARATOR . $filename;
15-
} elseif ($config['qr']['append_filename']) {
16-
$url = PathUtility::getPublicPath($config['qr']['url'] . $filename, true);
17-
} else {
18-
$url = PathUtility::getPublicPath($config['qr']['url'], true);
12+
if ($filename) {
13+
$url = $config['qr']['url'];
14+
if ($config['ftp']['enabled'] && $config['ftp']['useForQr']) {
15+
$remoteStorageService = RemoteStorageService::getInstance();
16+
$url = $remoteStorageService->getWebpageUri();
17+
if ($config['qr']['append_filename']) {
18+
$url .= '/images/';
19+
}
1920
}
21+
if ($config['qr']['append_filename']) {
22+
$url .= $filename;
23+
}
24+
$url = PathUtility::getPublicPath($url, true);
2025
try {
2126
$result = QrCodeUtility::create($url);
2227
header('Content-Type: ' . $result->getMimeType());
@@ -28,6 +33,7 @@
2833
echo $e->getMessage();
2934
}
3035
}
36+
3137
} else {
3238
http_response_code(400);
3339
echo 'No filename defined.';

api/serverInfo.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ function handleDebugPanel(string $content, array $config): string|false
1818
return readFileContents(PathUtility::getAbsolutePath('var/log/remotebuzzer.log'));
1919
case 'nav-synctodrivelog':
2020
return readFileContents(PathUtility::getAbsolutePath('var/log/synctodrive.log'));
21+
case 'nav-remotestoragelog':
22+
return readFileContents(PathUtility::getAbsolutePath('var/log/remotestorage.log'));
2123
case 'nav-myconfig':
2224
echo implode("\n", showConfig($config));
2325
return json_encode('');

api/testFtpConnection.php

Lines changed: 15 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,57 +2,23 @@
22

33
require_once '../lib/boot.php';
44

5-
use Photobooth\Service\LoggerService;
5+
use Photobooth\Service\RemoteStorageService;
66

77
header('Content-Type: application/json');
88

9-
$logger = LoggerService::getInstance()->getLogger('main');
10-
$logger->debug(basename($_SERVER['PHP_SELF']));
11-
12-
$data = $_POST;
13-
14-
$params = ['baseURL', 'port', 'username', 'password'];
15-
16-
$result = [
17-
'response' => 'error',
18-
'message' => 'ftp:missing_parameters',
19-
'missing' => [],
20-
];
21-
22-
foreach ($params as $param) {
23-
if ($data['ftp'][$param] == '') {
24-
$result['missing'][] = $param;
25-
}
26-
}
27-
28-
if (!empty($result['missing'])) {
29-
die(json_encode($result));
9+
$remoteStorage = RemoteStorageService::getInstance();
10+
if (!$remoteStorage->testConnection()) {
11+
echo json_encode([
12+
'response' => 'error',
13+
'message' => 'ftp:no_connection',
14+
'missing' => [],
15+
]);
16+
exit();
3017
}
3118

32-
$baseUrl = $data['ftp']['baseURL'];
33-
$port = $data['ftp']['port'];
34-
$username = $data['ftp']['username'];
35-
$password = $data['ftp']['password'];
36-
37-
// init connection to ftp server
38-
$ftp = ftp_ssl_connect($baseUrl, $port, 10);
39-
40-
if ($ftp === false) {
41-
$logger->error('Can\'t connect to FTP Server!');
42-
$result['response'] = 'error';
43-
$result['message'] = 'ftp:no_connection';
44-
die(json_encode($result));
45-
}
46-
47-
// login to ftp server
48-
$login_result = @ftp_login($ftp, $username, $password);
49-
$result['response'] = 'success';
50-
$result['message'] = 'ftp:connected';
51-
52-
if (!$login_result) {
53-
$logger->error('Can\'t connect to FTP Server!');
54-
$result['response'] = 'error';
55-
$result['message'] = 'ftp:no_connection';
56-
}
57-
@ftp_close($ftp);
58-
die(json_encode($result));
19+
echo json_encode([
20+
'response' => 'success',
21+
'message' => 'ftp:connected',
22+
'missing' => [],
23+
]);
24+
exit();

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
"ext-zip": "*",
1111
"endroid/qr-code": "^5.0",
1212
"league/commonmark": "^2.4",
13+
"league/flysystem": "^3.0",
14+
"league/flysystem-ftp": "^3.0",
15+
"league/flysystem-sftp-v3": "^3.0",
1316
"monolog/monolog": "^3.5",
1417
"phpmailer/phpmailer": "^6.8",
1518
"symfony/asset": "^7.0",

0 commit comments

Comments
 (0)