diff --git a/include/webdav_materialize_runtime.inc.php b/include/webdav_materialize_runtime.inc.php new file mode 100644 index 0000000..31041d1 --- /dev/null +++ b/include/webdav_materialize_runtime.inc.php @@ -0,0 +1,274 @@ +$image_id, + 'connection_id'=>$connection_id, + 'root_fileid'=>$root_fileid, + 'relative_path'=>$relative_path, + 'webdav_path'=>$webdav_path, + 'content_type'=>$content_type, + 'size'=>$size, + 'etag'=>$etag, + 'coi'=>$row['coi'] ?? null, + ); +} + +function bratonien_tools_webdav_materialize_image_url($image_id) +{ + $info = bratonien_tools_webdav_materialize_source_info($image_id); + if (!$info) return null; + + $url = get_root_url().'plugins/'.BRATONIEN_TOOLS_ID.'/webdav-image.php?id='.(int)$image_id; + if ($info['etag'] !== '') $url .= '&v='.rawurlencode(substr(sha1($info['etag']), 0, 12)); + return $url; +} + +function bratonien_tools_webdav_materialize_custom_params($key) +{ + if (!class_exists('DerivativeParams') || !class_exists('SizingParams')) return null; + + $tokens = explode('_', trim((string)$key)); + if (!$tokens || $tokens[0] === '') return null; + + $parse_size = function($value) + { + if (!preg_match('/^[0-9]+(?:x[0-9]+)?$/', (string)$value)) return null; + $parts = explode('x', (string)$value, 2); + $width = (int)$parts[0]; + $height = count($parts) === 1 ? $width : (int)$parts[1]; + if ($width < 1 || $height < 1 || $width > 20000 || $height > 20000) return null; + return array($width, $height); + }; + + $token = array_shift($tokens); + $crop = 0; + $min_size = null; + + if (isset($token[0]) && $token[0] === 's') + { + $size = $parse_size(substr($token, 1)); + } + elseif (isset($token[0]) && $token[0] === 'e') + { + $crop = 1; + $size = $min_size = $parse_size(substr($token, 1)); + } + else + { + if (count($tokens) < 2) return null; + $size = $parse_size($token); + $crop_token = (string)array_shift($tokens); + $min_size = $parse_size(array_shift($tokens)); + if (!preg_match('/^[a-z]$/', $crop_token) || $min_size === null) return null; + $crop = function_exists('char_to_fraction') ? char_to_fraction($crop_token) : 0; + } + + if ($size === null) return null; + + $params = new DerivativeParams(new SizingParams($size, $crop, $min_size)); + if (class_exists('ImageStdParams')) ImageStdParams::apply_global($params); + return $params; +} + +function bratonien_tools_webdav_materialize_variant_from_params($params) +{ + if (!is_object($params) || !class_exists('ImageStdParams')) return null; + + $type = (string)($params->type ?? ''); + $defined = ImageStdParams::get_defined_type_map(); + if ($type !== '' && defined('IMG_CUSTOM') && $type !== IMG_CUSTOM && isset($defined[$type])) + { + return 'standard:'.$type; + } + + if (!method_exists($params, 'add_url_tokens')) return null; + $tokens = array(); + $params->add_url_tokens($tokens); + if (!$tokens) return null; + + $key = implode('_', $tokens); + if (!preg_match('/^[A-Za-z0-9_x-]+$/', $key)) return null; + return 'custom:'.$key; +} + +function bratonien_tools_webdav_materialize_params_from_variant($variant) +{ + $variant = trim((string)$variant); + if ($variant === '' || !class_exists('ImageStdParams')) return null; + + if (strpos($variant, 'standard:') === 0) + { + $type = substr($variant, strlen('standard:')); + $defined = ImageStdParams::get_defined_type_map(); + return isset($defined[$type]) ? $defined[$type] : null; + } + + if (strpos($variant, 'custom:') === 0) + { + $key = substr($variant, strlen('custom:')); + if (!preg_match('/^[A-Za-z0-9_x-]+$/', $key)) return null; + return bratonien_tools_webdav_materialize_custom_params($key); + } + + return null; +} + +function bratonien_tools_webdav_materialize_b64url_encode($value) +{ + return rtrim(strtr(base64_encode((string)$value), '+/', '-_'), '='); +} + +function bratonien_tools_webdav_materialize_after_signature($image_id, $variant, $after_url) +{ + global $conf; + $key = !empty($conf['secret_key']) ? $conf['secret_key'] : ($conf['db_password'] ?? 'bratonien-tools'); + return hash_hmac('sha256', (int)$image_id.'|'.(string)$variant.'|'.(string)$after_url, $key); +} + +function bratonien_tools_webdav_materialize_derivative_url($image_id, $variant, array $info, $after_url='') +{ + $url = get_root_url().'plugins/'.BRATONIEN_TOOLS_ID.'/webdav-derivative.php?id='.(int)$image_id.'&variant='.rawurlencode($variant); + if ($after_url !== '') + { + $url .= '&after='.rawurlencode(bratonien_tools_webdav_materialize_b64url_encode($after_url)); + $url .= '&sig='.rawurlencode(bratonien_tools_webdav_materialize_after_signature($image_id, $variant, $after_url)); + } + if (!empty($info['etag'])) $url .= '&v='.rawurlencode(substr(sha1((string)$info['etag']), 0, 12)); + return $url; +} + +function bratonien_tools_filter_webdav_materialize_src_url($url, $src_image) +{ + if (!is_object($src_image) || empty($src_image->id)) return $url; + $webdav_url = bratonien_tools_webdav_materialize_image_url((int)$src_image->id); + return $webdav_url ?: $url; +} + +function bratonien_tools_filter_webdav_materialize_derivative_url($url, $params, $src_image, $rel_url) +{ + if (!is_object($src_image) || empty($src_image->id)) return $url; + + $image_id = (int)$src_image->id; + $info = bratonien_tools_webdav_materialize_source_info($image_id); + if (!$info) return $url; + + try + { + $derivative = new DerivativeImage($params, $src_image); + if ($derivative->same_as_source()) + { + $source_url = bratonien_tools_webdav_materialize_image_url($image_id); + return $source_url ?: $url; + } + + $path = $derivative->get_path(); + if ($path !== '' && is_file($path) && is_readable($path)) return $url; + + $variant = bratonien_tools_webdav_materialize_variant_from_params($params); + if ($variant === null) return $url; + + return bratonien_tools_webdav_materialize_derivative_url($image_id, $variant, $info, (string)$url); + } + catch (Throwable $e) + { + error_log('Bratonien WebDAV materialize derivative #'.$image_id.': '.$e->getMessage()); + return $url; + } +}