Make WebDAV derivative test fully parallel

This commit is contained in:
Terranom674
2026-08-20 14:19:43 +02:00
parent 34a473fa07
commit bc5a94dc10

View File

@@ -1,13 +1,6 @@
<?php <?php
define('PHPWG_ROOT_PATH', '../../'); define('PHPWG_ROOT_PATH', '../../');
include_once(PHPWG_ROOT_PATH.'include/common.inc.php'); include_once(PHPWG_ROOT_PATH.'include/common.inc.php');
if (!defined('BRATONIEN_TOOLS_PATH'))
{
define('BRATONIEN_TOOLS_ID', basename(__DIR__));
define('BRATONIEN_TOOLS_PATH', PHPWG_ROOT_PATH.'plugins/'.BRATONIEN_TOOLS_ID.'/');
}
require_once(BRATONIEN_TOOLS_PATH.'include/webdav_image_runtime.inc.php');
require_once(PHPWG_ROOT_PATH.'include/derivative.inc.php'); require_once(PHPWG_ROOT_PATH.'include/derivative.inc.php');
function bratonien_tools_webdav_derivative_test_abort($status, $message) function bratonien_tools_webdav_derivative_test_abort($status, $message)
@@ -157,6 +150,7 @@ function bratonien_tools_webdav_derivative_test_download(array $source, $destina
$detail = 'Connector-Schluessel fehlt.'; $detail = 'Connector-Schluessel fehlt.';
return false; return false;
} }
$key_row = pwg_db_fetch_assoc($key_result); $key_row = pwg_db_fetch_assoc($key_result);
$credentials = bratonien_tools_webdav_derivative_test_decrypt_secret((string)$row['secret_blob'], (string)$key_row['value']); $credentials = bratonien_tools_webdav_derivative_test_decrypt_secret((string)$row['secret_blob'], (string)$key_row['value']);
if (!is_array($credentials)) if (!is_array($credentials))
@@ -193,7 +187,7 @@ function bratonien_tools_webdav_derivative_test_download(array $source, $destina
CURLOPT_RETURNTRANSFER => false, CURLOPT_RETURNTRANSFER => false,
CURLOPT_FAILONERROR => false, CURLOPT_FAILONERROR => false,
CURLOPT_FILE => $fp, CURLOPT_FILE => $fp,
CURLOPT_USERAGENT => 'Bratonien-Tools-WebDAV-Derivative-Test', CURLOPT_USERAGENT => 'Bratonien-Tools-WebDAV-Derivative-Parallel-Test',
)); ));
$ok = curl_exec($ch); $ok = curl_exec($ch);
@@ -246,7 +240,7 @@ function bratonien_tools_webdav_derivative_test_call_i($url, &$response_body, &$
CURLOPT_TIMEOUT => 180, CURLOPT_TIMEOUT => 180,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_FAILONERROR => false, CURLOPT_FAILONERROR => false,
CURLOPT_USERAGENT => 'Bratonien-Tools-Derivative-Gate', CURLOPT_USERAGENT => 'Bratonien-Tools-Derivative-Parallel-Gate',
)); ));
$body = curl_exec($ch); $body = curl_exec($ch);
@@ -299,77 +293,65 @@ if (!pwg_db_num_rows($result))
bratonien_tools_webdav_derivative_test_abort(404, 'Bild nicht gefunden.'); bratonien_tools_webdav_derivative_test_abort(404, 'Bild nicht gefunden.');
} }
$image_row = pwg_db_fetch_assoc($result); $image_row = pwg_db_fetch_assoc($result);
$src_image = new SrcImage($image_row);
$source = bratonien_tools_webdav_derivative_test_source_info($image_id, $image_row); $source = bratonien_tools_webdav_derivative_test_source_info($image_id, $image_row);
if (!$source) if (!$source)
{ {
bratonien_tools_webdav_derivative_test_abort(404, 'Keine WebDAV-Quelle fuer dieses Bild gefunden.'); bratonien_tools_webdav_derivative_test_abort(404, 'Keine WebDAV-Quelle fuer dieses Bild gefunden.');
} }
$derivative = new DerivativeImage($defined[$type], $src_image); $test_root = PHPWG_ROOT_PATH.'_data/bratonien-tools/webdav-derivative-test';
if ($derivative->same_as_source()) if (!is_dir($test_root) && !@mkdir($test_root, 0755, true))
{ {
bratonien_tools_webdav_derivative_test_abort(409, 'Dieser Typ ist fuer das Bild identisch mit der Quelle und erzeugt kein Derivat.'); bratonien_tools_webdav_derivative_test_abort(500, 'Paralleler Testbereich konnte nicht angelegt werden.');
} }
$derivative_path = $derivative->get_path(); if (!is_writable($test_root))
if (is_file($derivative_path) && is_readable($derivative_path))
{ {
header('X-Bratonien-WebDAV-Test: derivative-already-exists'); bratonien_tools_webdav_derivative_test_abort(500, 'Paralleler Testbereich ist fuer PHP nicht beschreibbar.');
header('Content-Type: '.(function_exists('mime_content_type') ? (mime_content_type($derivative_path) ?: 'application/octet-stream') : 'application/octet-stream'));
header('Content-Length: '.filesize($derivative_path));
header('Cache-Control: no-store');
readfile($derivative_path);
exit;
} }
$image_path = (string)($image_row['path'] ?? ''); $lock_path = $test_root.'/image-'.$image_id.'.lock';
$absolute_image_path = $image_path;
if (strpos($absolute_image_path, '/') !== 0)
{
$absolute_image_path = PHPWG_ROOT_PATH.ltrim(preg_replace('#^\./#', '', $absolute_image_path), '/');
}
$materialize_path = realpath($absolute_image_path);
if ($materialize_path === false || !is_file($materialize_path))
{
bratonien_tools_webdav_derivative_test_abort(500, 'Placeholder-Quelldatei konnte nicht aufgeloest werden.');
}
$normalized_materialize = str_replace('\\', '/', $materialize_path);
if (!preg_match('#/nc-webdav-source/connection-'.(int)$source['connection_id'].'/#', $normalized_materialize))
{
bratonien_tools_webdav_derivative_test_abort(500, 'Aufgeloester Placeholder-Pfad passt nicht zur WebDAV-Verbindung.');
}
$lock_path = $materialize_path.'.bratonien-materialize.lock';
$lock = @fopen($lock_path, 'c'); $lock = @fopen($lock_path, 'c');
if (!$lock || !flock($lock, LOCK_EX)) if (!$lock || !flock($lock, LOCK_EX))
{ {
if ($lock) fclose($lock); if ($lock) fclose($lock);
bratonien_tools_webdav_derivative_test_abort(503, 'Materialisierungs-Lock konnte nicht gesetzt werden.'); bratonien_tools_webdav_derivative_test_abort(503, 'Paralleler Test-Lock konnte nicht gesetzt werden.');
} }
$temp_path = $materialize_path.'.bratonien-real.'.getmypid().'.'.bin2hex(random_bytes(4)).'.part'; $extension = strtolower(pathinfo((string)($image_row['path'] ?? ''), PATHINFO_EXTENSION));
$backup_path = $materialize_path.'.bratonien-placeholder.'.getmypid().'.'.bin2hex(random_bytes(4)); if (!in_array($extension, array('jpg', 'jpeg', 'png', 'gif', 'webp'), true))
$materialized = false; {
$backup_created = false; $extension = 'jpg';
}
$token = getmypid().'-'.bin2hex(random_bytes(6));
$source_filename = 'source-'.$image_id.'-'.$token.'.'.$extension;
$source_path = $test_root.'/'.$source_filename;
$source_rel = './_data/bratonien-tools/webdav-derivative-test/'.$source_filename;
$temp_image_id = 0;
$derivative_path = '';
$cleaned = false; $cleaned = false;
$cleanup = function() use (&$cleaned, &$materialized, &$backup_created, $materialize_path, $backup_path, $temp_path, $lock) $cleanup = function() use (&$cleaned, &$temp_image_id, &$derivative_path, $source_path, $lock)
{ {
if ($cleaned) return; if ($cleaned) return;
$cleaned = true; $cleaned = true;
if ($materialized && $backup_created && is_file($backup_path)) if ($temp_image_id > 0)
{ {
@rename($backup_path, $materialize_path); @pwg_query('DELETE FROM '.IMAGES_TABLE.' WHERE id='.(int)$temp_image_id.' LIMIT 1');
} $temp_image_id = 0;
elseif ($backup_created && is_file($backup_path) && !is_file($materialize_path))
{
@rename($backup_path, $materialize_path);
} }
if (is_file($temp_path)) @unlink($temp_path); if ($derivative_path !== '' && is_file($derivative_path))
if (is_file($backup_path)) @unlink($backup_path); {
@unlink($derivative_path);
}
if (is_file($source_path))
{
@unlink($source_path);
}
@flock($lock, LOCK_UN); @flock($lock, LOCK_UN);
@fclose($lock); @fclose($lock);
@@ -379,28 +361,55 @@ register_shutdown_function($cleanup);
try try
{ {
$detail = ''; $detail = '';
if (!bratonien_tools_webdav_derivative_test_download($source, $temp_path, $detail)) if (!bratonien_tools_webdav_derivative_test_download($source, $source_path, $detail))
{ {
bratonien_tools_webdav_derivative_test_abort(502, $detail); bratonien_tools_webdav_derivative_test_abort(502, $detail);
} }
if (!@link($materialize_path, $backup_path)) $dimensions = @getimagesize($source_path);
if (!is_array($dimensions) || empty($dimensions[0]) || empty($dimensions[1]))
{ {
bratonien_tools_webdav_derivative_test_abort(500, 'Placeholder konnte nicht sicher per Hardlink gesichert werden.'); bratonien_tools_webdav_derivative_test_abort(500, 'Paralleles Original besitzt keine gueltigen Bildabmessungen.');
} }
$backup_created = true;
if (!@rename($temp_path, $materialize_path)) $test_row = $image_row;
unset($test_row['id']);
$test_row['path'] = $source_rel;
$test_row['file'] = $source_filename;
if (array_key_exists('width', $test_row)) $test_row['width'] = (int)$dimensions[0];
if (array_key_exists('height', $test_row)) $test_row['height'] = (int)$dimensions[1];
single_insert(IMAGES_TABLE, $test_row);
$temp_image_id = (int)pwg_db_insert_id();
if ($temp_image_id < 1)
{ {
bratonien_tools_webdav_derivative_test_abort(500, 'Nextcloud-Bild konnte nicht atomar materialisiert werden.'); bratonien_tools_webdav_derivative_test_abort(500, 'Temporaerer Piwigo-Testeintrag konnte nicht angelegt werden.');
}
$test_row['id'] = $temp_image_id;
$test_src = new SrcImage($test_row);
$derivative = new DerivativeImage($defined[$type], $test_src);
if ($derivative->same_as_source())
{
bratonien_tools_webdav_derivative_test_abort(409, 'Dieser Typ ist fuer das parallele Testbild identisch mit der Quelle.');
}
$derivative_path = $derivative->get_path();
if ($derivative_path === '')
{
bratonien_tools_webdav_derivative_test_abort(500, 'Piwigo konnte keinen Derivat-Zielpfad fuer den parallelen Test bestimmen.');
}
if (is_file($derivative_path))
{
@unlink($derivative_path);
clearstatcache(true, $derivative_path);
} }
$materialized = true;
clearstatcache(true, $materialize_path);
$inner_url = bratonien_tools_webdav_derivative_test_inner_url($derivative_path); $inner_url = bratonien_tools_webdav_derivative_test_inner_url($derivative_path);
if ($inner_url === null) if ($inner_url === null)
{ {
bratonien_tools_webdav_derivative_test_abort(500, 'Piwigo-i.php-URL konnte nicht bestimmt werden.'); bratonien_tools_webdav_derivative_test_abort(500, 'Piwigo-i.php-URL konnte fuer den parallelen Test nicht bestimmt werden.');
} }
$body = ''; $body = '';
@@ -411,14 +420,30 @@ try
bratonien_tools_webdav_derivative_test_abort(502, $detail."\n".$body); bratonien_tools_webdav_derivative_test_abort(502, $detail."\n".$body);
} }
$cleanup();
clearstatcache(true, $derivative_path); clearstatcache(true, $derivative_path);
if (!is_file($derivative_path) || !is_readable($derivative_path)) if (!is_file($derivative_path) || !is_readable($derivative_path))
{ {
bratonien_tools_webdav_derivative_test_abort(500, 'i.php lieferte eine Antwort, aber das Piwigo-Derivat wurde nicht gefunden.'); bratonien_tools_webdav_derivative_test_abort(
500,
"i.php antwortete, aber das parallele Piwigo-Derivat wurde nicht erzeugt.\n"
.'Testquelle: '.$source_rel."\n"
.'i.php: '.$inner_url
);
} }
header('X-Bratonien-WebDAV-Test: generated-by-piwigo-i.php'); $derivative_size = @getimagesize($derivative_path);
if (!is_array($derivative_size) || empty($derivative_size[0]) || empty($derivative_size[1]))
{
bratonien_tools_webdav_derivative_test_abort(500, 'Das von i.php erzeugte parallele Derivat ist keine lesbare Bilddatei.');
}
$generated_width = (int)$derivative_size[0];
$generated_height = (int)$derivative_size[1];
$cleanup();
header('X-Bratonien-WebDAV-Test: parallel-i.php-success');
header('X-Bratonien-WebDAV-Test-Size: '.$generated_width.'x'.$generated_height);
header('Content-Type: '.$content_type); header('Content-Type: '.$content_type);
header('Content-Length: '.strlen($body)); header('Content-Length: '.strlen($body));
header('Cache-Control: no-store'); header('Cache-Control: no-store');