first commit

This commit is contained in:
salam committed 2026-10-06 19:40:28 +02:00
commit e81864e683
2984 files changed
+267797

No files matched your search

@@ -0,0 +1,142 @@
<?php declare(strict_types=1);
/*
* This file is part of the package bk2k/bootstrap-package.
*
* For the full copyright and license information, please read the
* LICENSE file that was distributed with this source code.
*/
namespace BK2K\BootstrapPackage\Utility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* ExternalMediaUtility
*/
class ExternalMediaUtility
{
/**
* @var array Provider that can be handled, the provider is equal the hostname and needs a process function
*/
protected $mediaProvider = [
'youtube',
'youtu',
'vimeo'
];
/**
* Get the embed code for the given url if possible
* and add a css class on the iframe
*
* @param string $url
* @param string $class
* @return string|null
*/
public function getEmbedCode(string $url, string $class): ?string
{
// Prepare url
$url = $this->setProtocolToHttps($url);
// Get method
$method = $this->getMethod($url);
if ($method !== null) {
$embedUrl = $this->{$method}($url);
if ($embedUrl !== null) {
return '<iframe ' . GeneralUtility::implodeAttributes([
'class' => $class,
'src' => $embedUrl,
'frameborder' => '0'
], true) . ' allowfullscreen></iframe>';
}
}
return null;
}
/**
* Resolves if possible a method name to process the url
*
* @param string $url
* @return string|null
*/
protected function getMethod(string $url): ?string
{
$urlInformation = @parse_url($url);
if (is_array($urlInformation) && isset($urlInformation['host'])) {
$hostName = GeneralUtility::trimExplode('.', $urlInformation['host'], true);
foreach ($this->mediaProvider as $provider) {
$functionName = 'process' . ucfirst($provider);
if (in_array($provider, $hostName, true) && is_callable([$this, $functionName])) {
return $functionName;
}
}
}
return null;
}
/**
* Processes YouTube url
*
* @param string $url
* @return string|null
*/
protected function processYoutube(string $url): ?string
{
$firstMatches = [];
$pattern = '%^(?:https?://)?(?:www\.)?(?:youtu\.be/|youtube\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=))([^"&?/ ]{11})(?:.+)?$%xs';
if ((bool) preg_match($pattern, $url, $firstMatches)) {
$toEmbed = $firstMatches[1];
$patternForAdditionalParams = '%^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=))(?:[^"&?\/ ]{11})(.+)?(?:.+)?$%xs';
$secondMatches = [];
if (preg_match($patternForAdditionalParams, $url, $secondMatches) > 1) {
$toEmbed .= '?' . substr($secondMatches[1], 1);
}
return 'https://www.youtube-nocookie.com/embed/' . $toEmbed;
}
return null;
}
/**
* Process YouTube short url
*
* @param string $url
* @return string|null
*/
protected function processYoutu(string $url): ?string
{
return $this->processYoutube($url);
}
/**
* Processes Vimeo url
*
* @param string $url
* @return string
*/
protected function processVimeo(string $url): ?string
{
$matches = [];
if ((bool) preg_match('/[\\/#](\\d+)$/', $url, $matches)) {
return 'https://player.vimeo.com/video/' . $matches[1];
}
return null;
}
/**
* Change every protocol to https and add it if missing
*
* @param string $url URL
* @return string
*/
protected function setProtocolToHttps(string $url): string
{
$processUrl = trim($url);
if (strpos($url, 'http://') === 0) {
$processUrl = substr($processUrl, 7);
} elseif (strpos($processUrl, 'https://') === 0) {
$processUrl = substr($processUrl, 8);
} elseif (strpos($processUrl, '//') === 0) {
$processUrl = substr($processUrl, 2);
}
return 'https://' . $processUrl;
}
}
@@ -0,0 +1,246 @@
<?php
declare(strict_types = 1);
/*
* This file is part of the package bk2k/bootstrap-package.
*
* For the full copyright and license information, please read the
* LICENSE file that was distributed with this source code.
*/
namespace BK2K\BootstrapPackage\Utility;
/**
* Calculate image variants
*/
class ImageVariantsUtility
{
/**
* @var array
*/
protected static $allowedVariantProperties = [
'breakpoint',
'width',
'aspectRatio',
'sizes',
];
/**
* @var array
*/
protected static $defaultVariants = [
'default' => [
'breakpoint' => 1400,
'width' => 1280
],
'xlarge' => [
'breakpoint' => 1200,
'width' => 1100
],
'large' => [
'breakpoint' => 992,
'width' => 920
],
'medium' => [
'breakpoint' => 768,
'width' => 680
],
'small' => [
'breakpoint' => 576,
'width' => 500
],
'extrasmall' => [
'width' => 374
]
];
/**
* @param array|null $variants
* @param array|null $multiplier
* @param array|null $gutters
* @param array|null $corrections
* @param float|null $aspectRatio
* @return array
*/
public static function getImageVariants(?array $variants = null, ?array $multiplier = null, ?array $gutters = null, ?array $corrections = null, ?float $aspectRatio = null): array
{
$variants = $variants !== null ? $variants : [];
$variants = self::processVariants($variants);
$variants = self::processResolutions($variants);
if ($gutters !== null) {
$variants = self::removeGutters($variants, $gutters);
}
if ($multiplier !== null) {
$variants = self::processMultiplier($variants, $multiplier);
}
if ($corrections !== null) {
$variants = self::processCorrections($variants, $corrections);
}
if ($aspectRatio !== null) {
$variants = self::processAspectRatio($variants, $aspectRatio);
}
return $variants;
}
/**
* @param array $variants
* @return array
*/
protected static function processResolutions(array $variants): array
{
foreach ($variants as $variant => $properties) {
if (!array_key_exists('sizes', $properties)) {
$properties['sizes'] = [];
}
$properties['sizes'] = self::processSizes($properties['sizes']);
$variants[$variant] = $properties;
}
return $variants;
}
/**
* @param array $sizes
* @return array
*/
protected static function processSizes(array $sizes): array
{
$resultSizes = [];
$workingSizes = [];
foreach ($sizes as $key => $settings) {
if (!array_key_exists('multiplier', $settings) ||
!is_numeric($settings['multiplier']) ||
$settings['multiplier'] < 1 ||
!self::isValidSizeKey($key)
) {
continue;
}
$settings['multiplier'] = gettype($settings['multiplier']) === 'double' ? $settings['multiplier'] : (int) $settings['multiplier'];
$workingSizes[substr($key, 0, -1) . ''] = [
'multiplier' => 1 * $settings['multiplier'],
];
}
if (!isset($workingSizes['1'])) {
$workingSizes['1'] = ['multiplier' => 1];
}
ksort($workingSizes);
foreach ($workingSizes as $workingKey => $workingSettings) {
$resultSizes[$workingKey . 'x'] = $workingSettings;
}
return $resultSizes;
}
/**
* @param array $variants
* @return array
*/
protected static function processVariants(array $variants): array
{
$variants = count($variants) > 0 ? $variants : self::$defaultVariants;
foreach ($variants as $variant => $properties) {
if (!is_array($properties)) {
unset($variants[$variant]);
continue;
}
foreach ($properties as $key => $value) {
if (!in_array($key, self::$allowedVariantProperties, true)) {
unset($variants[$variant][$key]);
continue;
}
if ($key === 'sizes') {
continue;
} elseif ($key === 'aspectRatio') {
if (is_numeric($value) && $value > 0) {
$variants[$variant][$key] = (float) $value;
} else {
unset($variants[$variant][$key]);
}
} elseif (is_numeric($value) && $value > 0) {
$variants[$variant][$key] = (int) $value;
} else {
unset($variants[$variant][$key]);
}
}
if (count($variants[$variant]) === 0 || !isset($variants[$variant]['width'])) {
unset($variants[$variant]);
}
}
return $variants;
}
/**
* @param array $variants
* @param array $gutters
* @return array
*/
protected static function removeGutters(array $variants, array $gutters): array
{
foreach ($gutters as $variant => $value) {
if (is_numeric($value) && $value > 0 && isset($variants[$variant]['width'])) {
$variants[$variant]['width'] = (int) ceil($variants[$variant]['width'] - (float) $value);
}
}
return $variants;
}
/**
* @param array $variants
* @param array $multiplier
* @return array
*/
protected static function processMultiplier(array $variants, array $multiplier): array
{
foreach ($multiplier as $variant => $value) {
if (is_numeric($value) && $value > 0 && isset($variants[$variant]['width'])) {
$variants[$variant]['width'] = (int) ceil($variants[$variant]['width'] * (float) $value);
}
}
return $variants;
}
/**
* @param array $variants
* @param array $corrections
* @return array
*/
protected static function processCorrections(array $variants, array $corrections): array
{
foreach ($corrections as $variant => $value) {
if (is_numeric($value) && $value > 0 && isset($variants[$variant]['width'])) {
$variants[$variant]['width'] -= $value;
}
}
return $variants;
}
/**
* @param array $variants
* @param float $aspectRatio
* @return array
*/
protected static function processAspectRatio(array $variants, float $aspectRatio): array
{
if ($aspectRatio > 0) {
foreach ($variants as $variant => $value) {
$variants[$variant]['aspectRatio'] = $aspectRatio;
}
}
return $variants;
}
/**
* @param mixed $key
* @return bool
*/
public static function isValidSizeKey($key): bool
{
return !(
!is_string($key) ||
substr($key, -1, 1) !== 'x' ||
!is_numeric(substr($key, 0, -1)) ||
(float) substr($key, 0, -1) < 1 ||
(float) substr($key, 0, -1) !== round((float) substr($key, 0, -1), 1)
);
}
}
@@ -0,0 +1,128 @@
<?php
declare(strict_types = 1);
/*
* This file is part of the package bk2k/bootstrap-package.
*
* For the full copyright and license information, please read the
* LICENSE file that was distributed with this source code.
*/
namespace BK2K\BootstrapPackage\Utility;
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Service\ImageService;
/**
* SvgUtility
*/
class SvgUtility
{
/**
* @param string $src
* @param FileInterface|null $image
* @param int|null $height
* @param int|null $width
* @param string|null $class
* @return string
*/
public static function getInlineSvg(
string $src = '',
?FileInterface $image = null,
?int $width = null,
?int $height = null,
?string $class = null
): string {
if (($src === '' && $image === null) || ($src !== '' && $image !== null)) {
throw new \Exception('You must either specify a string src or a File object.', 1530601100);
}
try {
$imageService = self::getImageService();
$image = $imageService->getImage($src, $image, false);
if ($image->getProperty('extension') !== 'svg') {
return '';
}
$svgContent = $image->getContents();
$svgContent = trim((string) preg_replace('/<script[\s\S]*?>[\s\S]*?<\/script>/i', '', $svgContent));
// Exit if file does not contain content
if ($svgContent === '') {
return '';
}
// Disables the functionality to allow external entities to be loaded when parsing the XML, must be kept
$previousValueOfEntityLoader = false;
if (PHP_MAJOR_VERSION < 8) {
$previousValueOfEntityLoader = libxml_disable_entity_loader(true);
}
$svgElement = simplexml_load_string($svgContent);
if (PHP_MAJOR_VERSION < 8) {
libxml_disable_entity_loader($previousValueOfEntityLoader);
}
if (!$svgElement instanceof \SimpleXMLElement) {
return '';
}
// Override attributes
$class = htmlspecialchars($class ?? '');
$svgElement = self::setAttribute($svgElement, 'class', $class);
$width = intval($width) > 0 ? (string) intval($width) : null;
$svgElement = self::setAttribute($svgElement, 'width', $width);
$height = intval($height) > 0 ? (string) intval($height) : null;
$svgElement = self::setAttribute($svgElement, 'height', $height);
// remove xml version tag
$domXml = dom_import_simplexml($svgElement);
/** @phpstan-ignore-next-line */
if (!$domXml instanceof \DOMElement || !$domXml->ownerDocument instanceof \DOMDocument) {
return '';
}
return (string) $domXml->ownerDocument->saveXML($domXml->ownerDocument->documentElement);
} catch (ResourceDoesNotExistException $e) {
// thrown if file does not exist
throw new \Exception($e->getMessage(), 1530601100, $e);
} catch (\UnexpectedValueException $e) {
// thrown if a file has been replaced with a folder
throw new \Exception($e->getMessage(), 1530601101, $e);
} catch (\RuntimeException $e) {
// RuntimeException thrown if a file is outside of a storage
throw new \Exception($e->getMessage(), 1530601102, $e);
} catch (\InvalidArgumentException $e) {
// thrown if file storage does not exist
throw new \Exception($e->getMessage(), 1530601103, $e);
}
}
/**
* @param \SimpleXMLElement $element
* @param string $attribute
* @param string $value
*/
protected static function setAttribute(\SimpleXMLElement $element, string $attribute, ?string $value): \SimpleXMLElement
{
if ($value !== null) {
if (isset($element->attributes()->$attribute)) {
$element->attributes()->$attribute = $value;
} else {
$element->addAttribute($attribute, $value);
}
}
return $element;
}
/**
* Return an instance of ImageService using object manager
*
* @return ImageService
*/
protected static function getImageService(): ImageService
{
return GeneralUtility::makeInstance(ImageService::class);
}
}