Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion com.woltlab.wcf/templates/shared_unfurlUrl.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*}{if $object->hasSquaredImage()} unfurlUrlCardSquaredImage{/if}{*
*}">
{if $object->hasImageUrl()}
<img src="{$object->getImageUrl()}" height="{$object->height}" width="{$object->width}" class="unfurlUrlImage" alt="" loading="lazy">
<img src="{$object->getImageUrl()}" height="{$object->getImage()->height}" width="{$object->getImage()->width}" class="unfurlUrlImage" alt="" loading="lazy">
{/if}
<div class="unfurlUrlInformation">
<a class="unfurlUrlTitle" {anchorAttributes url=$object->url appendClassname=false isUgc=$enableUgc}>{$object->title}</a>
Expand Down
12 changes: 0 additions & 12 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -636,24 +636,12 @@ parameters:
count: 1
path: wcfsetup/install/files/lib/data/trophy/TrophyAction.class.php

-
message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
identifier: empty.notAllowed
count: 4
path: wcfsetup/install/files/lib/data/unfurl/url/UnfurlUrl.class.php

-
message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
identifier: empty.notAllowed
count: 3
path: wcfsetup/install/files/lib/data/unfurl/url/UnfurlUrlAction.class.php

-
message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
identifier: empty.notAllowed
count: 1
path: wcfsetup/install/files/lib/data/unfurl/url/UnfurlUrlList.class.php

-
message: '#^Construct empty\(\) is not allowed\. Use more strict comparison\.$#'
identifier: empty.notAllowed
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

namespace wcf\command\unfurl\url;

use wcf\data\unfurl\url\UnfurlUrl;
use wcf\data\unfurl\url\UnfurlUrlBuilder;
use wcf\event\unfurl\url\UnfurlUrlCreated;
use wcf\system\event\EventHandler;

/**
* Creates a new unfurl url.
*
* @author Marcel Werk
* @copyright 2001-2026 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @since 6.3
*/
final class CreateUnfurlUrl
{
public function __construct(
private readonly UnfurlUrlBuilder $builder,
) {}

public function __invoke(): UnfurlUrl
{
$unfurlUrl = $this->builder->create();

EventHandler::getInstance()->fire(new UnfurlUrlCreated($unfurlUrl, $this->builder));

return $unfurlUrl;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

namespace wcf\command\unfurl\url;

use wcf\data\file\File;
use wcf\data\file\FileEditor;
use wcf\data\unfurl\url\UnfurlUrl;
use wcf\system\exception\SystemException;
use wcf\system\image\adapter\exception\ImageNotProcessable;
use wcf\system\image\adapter\exception\ImageNotReadable;
use wcf\system\image\ImageHandler;
use wcf\util\FileUtil;

use function wcf\functions\exception\logThrowable;

/**
* Creates a webp thumbnail for the given image and stores it base64 encoded in a new `.bin` file.
*
* Returns `null` if the image could not be processed.
*
* @author Marcel Werk
* @copyright 2001-2026 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @since 6.3
*/
final class CreateUnfurlUrlImageFile
{
public function __construct(
private readonly string $pathname,
private readonly string $originalFilename,
) {}

public function __invoke(): ?File
{
$imageData = @\getimagesize($this->pathname);
if ($imageData === false) {
return null;
}

$imageAdapter = ImageHandler::getInstance()->getAdapter();
if (!$imageAdapter->checkMemoryLimit($imageData[0], $imageData[1], $imageData['mime'])) {
return null;
}

$webpFile = FileUtil::getTemporaryFilename(extension: 'webp');
$binFile = FileUtil::getTemporaryFilename(extension: 'bin');

try {
$imageAdapter->loadFile($this->pathname);
$thumbnail = $imageAdapter->createThumbnail(UnfurlUrl::THUMBNAIL_WIDTH, UnfurlUrl::THUMBNAIL_HEIGHT);
$imageAdapter->saveImageAs($thumbnail, $webpFile, 'webp', 80);

// Clean up the thumbnail
$thumbnail = null;

$webpContent = \file_get_contents($webpFile);
if ($webpContent === false) {
return null;
}

// Save the webp file as a base64 encoded binary file
\file_put_contents($binFile, \base64_encode($webpContent));

return FileEditor::createFromExistingFile(
$binFile,
\pathinfo($this->originalFilename, \PATHINFO_BASENAME) . ".bin",
'com.woltlab.wcf.unfurl'
);
} catch (SystemException | ImageNotReadable $e) {
return null;
} catch (ImageNotProcessable $e) {
logThrowable($e);

return null;
} catch (\Throwable $e) {
logThrowable($e);
// Ignore any errors trying to save the file unless in debug mode.
if (\ENABLE_DEBUG_MODE !== 0) {
throw $e;
}

return null;
} finally {
// Clean up temporary files
@\unlink($webpFile);
@\unlink($binFile);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace wcf\command\unfurl\url;

use wcf\data\unfurl\url\UnfurlUrl;
use wcf\data\unfurl\url\UnfurlUrlAction;
use wcf\data\unfurl\url\UnfurlUrlBuilder;
use wcf\system\background\BackgroundQueueHandler;
use wcf\system\background\job\UnfurlUrlBackgroundJob;

Expand All @@ -28,15 +28,8 @@ public function __invoke(): UnfurlUrl
$object = UnfurlUrl::getByUrl($this->url);

if ($object === null) {
$returnValues = (new UnfurlUrlAction([], 'create', [
'data' => [
'url' => $this->url,
'urlHash' => \sha1($this->url),
],
]))->executeAction();

$object = $returnValues['returnValues'];
\assert($object instanceof UnfurlUrl);
$object = new CreateUnfurlUrl(UnfurlUrlBuilder::forCreate()
->setUrl($this->url))();
}

if ($object->status !== UnfurlUrl::STATUS_PENDING && $object->lastFetch < \TIME_NOW - self::REFETCH_UNFURL_URL) {
Expand Down
99 changes: 26 additions & 73 deletions wcfsetup/install/files/lib/data/unfurl/url/UnfurlUrl.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,9 @@

namespace wcf\data\unfurl\url;

use wcf\action\ImageProxyAction;
use wcf\data\DatabaseObject;
use wcf\system\cache\runtime\FileRuntimeCache;
use wcf\system\request\LinkHandler;
use wcf\data\CollectionDatabaseObject;
use wcf\data\unfurl\url\image\UnfurlUrlImage;
use wcf\system\WCF;
use wcf\util\CryptoUtil;
use wcf\util\Url;

/**
Expand All @@ -23,19 +20,13 @@
* @property-read string $urlHash
* @property-read string $title
* @property-read ?string $description
* @property-read string $imageHash
* @property-read string $imageUrl
* @property-read ?string $imageUrlHash
* @property-read ?string $imageExtension
* @property-read int $width
* @property-read int $height
* @property-read int $lastFetch
* @property-read ?int $imageID
* @property-read int $isStored
* @property-read string $status
* @property-read ?int $fileID
* @property-read int $lastFetch
*
* @extends CollectionDatabaseObject<UnfurlUrlCollection>
*/
class UnfurlUrl extends DatabaseObject
class UnfurlUrl extends CollectionDatabaseObject
{
private const IMAGE_SQUARED = "SQUARED";

Expand All @@ -56,27 +47,6 @@ class UnfurlUrl extends DatabaseObject
public const THUMBNAIL_WIDTH = 800;
public const THUMBNAIL_HEIGHT = 400;

public function __construct(null|string|int $id, ?array $row = null, ?DatabaseObject $object = null)
{
if ($id !== null) {
$sql = "SELECT unfurl_url.*, unfurl_url_image.*
FROM wcf1_unfurl_url unfurl_url
LEFT JOIN wcf1_unfurl_url_image unfurl_url_image
ON unfurl_url_image.imageID = unfurl_url.imageID
WHERE unfurl_url.urlID = ?";
$statement = WCF::getDB()->prepare($sql);
$statement->execute([$id]);
$row = $statement->fetchArray();

// enforce data type 'array'
if ($row === false) {
$row = [];
}
}

parent::__construct(null, $row, $id !== null ? null : $object);
}

/**
* Renders the unfurl url card and returns the template.
*/
Expand All @@ -98,41 +68,22 @@ public function getHost(): string
return $url['host'];
}

/**
* Returns the image url for the url.
*
* @throws \wcf\system\exception\SystemException
*/
public function getImageUrl(): ?string
{
if (\URL_UNFURLING_SAVE_IMAGES !== 0 && $this->isStored !== 0 && $this->fileID !== null) {
$file = FileRuntimeCache::getInstance()->getObject($this->fileID);

return 'data:image/webp;base64, ' . \file_get_contents($file->getPathname());
} elseif (!empty($this->imageUrl)) {
if (\MODULE_IMAGE_PROXY !== 0) {
$key = CryptoUtil::createSignedString($this->imageUrl);

return LinkHandler::getInstance()->getControllerLink(ImageProxyAction::class, [
'key' => $key,
]);
} elseif (\IMAGE_ALLOW_EXTERNAL_SOURCE !== 0) {
return $this->imageUrl;
}
if ($this->imageID === null) {
return null;
}

return null;
return $this->getImage()->getImageUrl();
}

public function hasImageUrl(): bool
{
if (\URL_UNFURLING_SAVE_IMAGES !== 0 && $this->isStored !== 0 && $this->fileID !== null) {
return true;
} elseif (!empty($this->imageUrl) && (\MODULE_IMAGE_PROXY !== 0 || \IMAGE_ALLOW_EXTERNAL_SOURCE !== 0)) {
return true;
if ($this->imageID === null) {
return false;
}

return false;
return $this->getImage()->hasImageUrl();
}

public function hasCoverImage(): bool
Expand All @@ -147,7 +98,7 @@ public function hasSquaredImage(): bool

public function isPlainUrl(): bool
{
return empty($this->description) && empty($this->imageID);
return ($this->description ?? '') === '' && $this->imageID === null;
}

private function getImageType(): string
Expand All @@ -156,7 +107,7 @@ private function getImageType(): string
return self::IMAGE_NO_IMAGE;
}

if ($this->width === $this->height) {
if ($this->getImage()->width === $this->getImage()->height) {
return self::IMAGE_SQUARED;
}

Expand All @@ -171,6 +122,14 @@ public function hasFetchedContent(): bool
return $this->status === self::STATUS_SUCCESSFUL;
}

/**
* @since 6.3
*/
public function getImage(): ?UnfurlUrlImage
{
return $this->getCollection()->getImage($this);
}

/**
* Returns the unfurl url object for a given url.
*
Expand All @@ -182,18 +141,12 @@ public static function getByUrl(string $url): ?self
throw new \InvalidArgumentException("Given URL is not a valid URL.");
}

$sql = "SELECT unfurl_url.*, unfurl_url_image.*
FROM wcf1_unfurl_url unfurl_url
LEFT JOIN wcf1_unfurl_url_image unfurl_url_image
ON unfurl_url_image.imageID = unfurl_url.imageID
WHERE unfurl_url.urlHash = ?";
$sql = "SELECT *
FROM wcf1_unfurl_url
WHERE urlHash = ?";
$statement = WCF::getDB()->prepare($sql);
$statement->execute([\sha1($url)]);
$row = $statement->fetchArray();
if ($row === false) {
return null;
}

return new self(null, $row);
return $statement->fetchSingleObject(self::class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* @copyright 2001-2021 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @since 5.4
* @deprecated 6.3 Use `UnfurlUrlBuilder` instead.
*
* @extends AbstractDatabaseObjectAction<UnfurlUrl, UnfurlUrlEditor>
*/
Expand Down
Loading
Loading