/**
* Represents an unfurl url object in the database.
*
- * @author Joshua Ruesweg
+ * @author Joshua Ruesweg
* @copyright 2001-2021 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Unfurl\Url
- * @since 5.4
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Unfurl\Url
+ * @since 5.4
*
* @property-read string $url
* @property-read string $urlHash
*/
class UnfurlUrl extends DatabaseObject
{
- public const IMAGE_SQUARED = "SQUARED";
- public const IMAGE_COVER = "COVER";
- public const IMAGE_NO_IMAGE = "NOIMAGE";
+ public const IMAGE_SQUARED = "SQUARED";
- public const STATUS_PENDING = "PENDING";
- public const STATUS_SUCCESSFUL = "SUCCESSFUL";
- public const STATUS_REJECTED = "REJECTED";
+ public const IMAGE_COVER = "COVER";
+
+ public const IMAGE_NO_IMAGE = "NOIMAGE";
+
+ public const STATUS_PENDING = "PENDING";
+
+ public const STATUS_SUCCESSFUL = "SUCCESSFUL";
+
+ public const STATUS_REJECTED = "REJECTED";
/**
* Renders the unfurl url card and returns the template.
*
* @return string
*/
- public function render() : string
+ public function render(): string
{
return WCF::getTPL()->fetch('unfurlUrl', 'wcf', [
'object' => $this,
]);
}
-
+
/**
* Returns the hostname of the url.
*
* @return string
*/
- public function getHost() : string
+ public function getHost(): string
{
$url = Url::parse($this->url);
-
+
return $url['host'];
}
-
+
/**
* Returns the image url for the url.
*
* @throws \wcf\system\exception\SystemException
*/
- public function getImageUrl() : ?string
+ public function getImageUrl(): ?string
{
if (!empty($this->imageHash)) {
return WCF::getPath() . 'images/unfurlUrl/' . \substr($this->imageHash, 0, 2) . '/' . $this->imageHash;
} elseif (!empty($this->imageUrl)) {
if (MODULE_IMAGE_PROXY) {
$key = CryptoUtil::createSignedString($this->imageUrl);
-
+
return LinkHandler::getInstance()->getLink('ImageProxy', [
'key' => $key,
]);
}
}
- return null;
+ return null;
}
-
+
/**
* Returns the unfurl url object for a given url.
*
* @throws \InvalidArgumentException If the given URL is invalid.
*/
- public static function getByUrl(string $url) : UnfurlUrl
+ public static function getByUrl(string $url): self
{
if (!Url::is($url)) {
throw new \InvalidArgumentException("Given URL is not a valid URL.");
}
-
+
$sql = "SELECT unfurl_url.*
FROM wcf" . WCF_N . "_unfurl_url unfurl_url
WHERE unfurl_url.urlHash = ?";
if (!$row) {
$row = [];
}
-
+
return new self(null, $row);
}
}
use wcf\data\AbstractDatabaseObjectAction;
use wcf\system\background\BackgroundQueueHandler;
-use wcf\system\background\job\UnfurlURLJob;
+use wcf\system\background\job\UnfurlUrlBackgroundJob;
/**
* Contains all dbo actions for unfurl url objects.
*
- * @author Joshua Ruesweg
+ * @author Joshua Ruesweg
* @copyright 2001-2021 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Unfurl\Url
- * @since 5.4
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Unfurl\Url
+ * @since 5.4
*
- * @method UnfurlUrlEditor[] getObjects()
- * @method UnfurlUrlEditor getSingleObject()
+ * @method UnfurlUrlEditor[] getObjects()
+ * @method UnfurlUrlEditor getSingleObject()
*/
class UnfurlUrlAction extends AbstractDatabaseObjectAction
{
{
/** @var UnfurlUrl $object */
$object = parent::create();
-
+
BackgroundQueueHandler::getInstance()->enqueueIn([
- new UnfurlURLJob($object),
+ new UnfurlUrlBackgroundJob($object),
]);
BackgroundQueueHandler::getInstance()->forceCheck();
-
+
return $object;
}
-
+
/**
* Returns the unfurl url object to a given url.
*
public function findOrCreate()
{
$object = UnfurlUrl::getByUrl($this->parameters['data']['url']);
-
+
if (!$object->urlID) {
$returnValues = (new self([], 'create', [
'data' => [
'urlHash' => \sha1($this->parameters['data']['url']),
],
]))->executeAction();
-
+
return $returnValues['returnValues'];
}
-
+
return $object;
}
}
/**
* Provide functions to edit an unfurl url.
*
- * @author Joshua Ruesweg
+ * @author Joshua Ruesweg
* @copyright 2001-2021 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Unfurl\Url
- * @since 5.4
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Unfurl\Url
+ * @since 5.4
*
- * @method UnfurlUrl getDecoratedObject()
- * @mixin UnfurlUrl
+ * @method UnfurlUrl getDecoratedObject()
+ * @mixin UnfurlUrl
*/
class UnfurlUrlEditor extends DatabaseObjectEditor
{
/**
* Represents a list of unfurled urls.
*
- * @author Joshua Ruesweg
+ * @author Joshua Ruesweg
* @copyright 2001-2021 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\Data\Unfurl\Url
- * @since 5.4
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\Data\Unfurl\Url
+ * @since 5.4
*
- * @method UnfurlUrl current()
- * @method UnfurlUrl[] getObjects()
- * @method UnfurlUrl|null search($objectID)
- * @property UnfurlUrl[] $objects
+ * @method UnfurlUrl current()
+ * @method UnfurlUrl[] getObjects()
+ * @method UnfurlUrl|null search($objectID)
+ * @property UnfurlUrl[] $objects
*/
class UnfurlUrlList extends DatabaseObjectList
{
--- /dev/null
+<?php
+
+namespace wcf\system\background\job;
+
+use wcf\data\unfurl\url\UnfurlUrl;
+use wcf\data\unfurl\url\UnfurlUrlAction;
+use wcf\util\FileUtil;
+use wcf\util\StringUtil;
+use wcf\util\UnfurlUrlUtil;
+
+/**
+ * Represents a background job to get information for an url.
+ *
+ * @author Joshua Ruesweg
+ * @copyright 2001-2020 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Background\Job
+ * @since 5.4
+ */
+class UnfurlUrlBackgroundJob extends AbstractBackgroundJob
+{
+ /**
+ * @var UnfurlUrl
+ */
+ private $url;
+
+ /**
+ * UnfurlURLJob constructor.
+ *
+ * @param UnfurlUrl $url
+ */
+ public function __construct(UnfurlUrl $url)
+ {
+ $this->url = $url;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function retryAfter()
+ {
+ switch ($this->getFailures()) {
+ case 1:
+ // 5 minutes
+ return 5 * 60;
+ case 2:
+ // 30 minutes
+ return 30 * 60;
+ case 3:
+ // 2 hours
+ return 2 * 60 * 60;
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function perform()
+ {
+ try {
+ $url = new UnfurlUrlUtil($this->url->url);
+
+ if (empty(StringUtil::trim($url->getTitle()))) {
+ $urlAction = new UnfurlUrlAction([$this->url], 'update', [
+ 'data' => [
+ 'title' => '',
+ 'description' => '',
+ 'status' => UnfurlUrl::STATUS_REJECTED,
+ ],
+ ]);
+ $urlAction->executeAction();
+ } else {
+ $title = StringUtil::truncate($url->getTitle(), 255);
+ $description = $url->getDescription();
+ $data = [
+ 'title' => $title,
+ 'description' => $description !== null ? StringUtil::truncate($description, 500) : '',
+ 'status' => UnfurlUrl::STATUS_SUCCESSFUL,
+ ];
+
+ if ($url->getImageUrl()) {
+ $image = UnfurlUrlUtil::downloadImageFromUrl($url->getImageUrl());
+
+ if ($image !== null) {
+ $imageData = @\getimagesizefromstring($image);
+
+ // filter images which are too large or too small
+ $isSquared = $imageData[0] === $imageData[1];
+ if (
+ (!$isSquared && ($imageData[0] < 300 && $imageData[1] < 150))
+ || \min($imageData[0], $imageData[1]) < 50
+ ) {
+ $data['imageType'] = UnfurlUrl::IMAGE_NO_IMAGE;
+ } else {
+ if ($imageData[0] === $imageData[1]) {
+ $data['imageUrl'] = $url->getImageUrl();
+ $data['imageType'] = UnfurlUrl::IMAGE_SQUARED;
+ } else {
+ $data['imageUrl'] = $url->getImageUrl();
+ $data['imageType'] = UnfurlUrl::IMAGE_COVER;
+ }
+
+ // Download image, if there is no image proxy or external source images allowed.
+ if (!(MODULE_IMAGE_PROXY || IMAGE_ALLOW_EXTERNAL_SOURCE)) {
+ if (isset($data['imageType'])) {
+ switch ($imageData[2]) {
+ case \IMAGETYPE_PNG:
+ $extension = 'png';
+ break;
+ case \IMAGETYPE_GIF:
+ $extension = 'gif';
+ break;
+ case \IMAGETYPE_JPEG:
+ $extension = 'jpg';
+ break;
+ default:
+ throw new \RuntimeException();
+ }
+
+ $data['imageHash'] = \sha1($image) . '.' . $extension;
+
+ $path = WCF_DIR . 'images/unfurlUrl/' . \substr($data['imageHash'], 0, 2);
+ FileUtil::makePath($path);
+
+ $fileLocation = $path . '/' . $data['imageHash'];
+
+ \file_put_contents($fileLocation, $image);
+
+ @\touch($fileLocation);
+ }
+ }
+ }
+ }
+ }
+
+ $urlAction = new UnfurlUrlAction([$this->url], 'update', [
+ 'data' => $data,
+ ]);
+ $urlAction->executeAction();
+ }
+ } catch (\InvalidArgumentException $e) {
+ \wcf\functions\exception\logThrowable($e);
+ }
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function onFinalFailure()
+ {
+ $urlAction = new UnfurlUrlAction([$this->url], 'update', [
+ 'data' => [
+ 'title' => '',
+ 'description' => '',
+ 'status' => 'REJECTED',
+ ],
+ ]);
+ $urlAction->executeAction();
+ }
+}
+++ /dev/null
-<?php
-
-namespace wcf\system\background\job;
-
-use wcf\data\unfurl\url\UnfurlUrl;
-use wcf\data\unfurl\url\UnfurlUrlAction;
-use function wcf\functions\exception\logThrowable;
-use wcf\util\FileUtil;
-use wcf\util\StringUtil;
-use wcf\util\UnfurlUrlUtil;
-
-/**
- * Represents a background job to get information for an url.
- *
- * @author Joshua Ruesweg
- * @copyright 2001-2020 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Background\Job
- * @since 5.4
- */
-class UnfurlURLJob extends AbstractBackgroundJob
-{
- /**
- * @var UnfurlUrl
- */
- private $url;
-
- /**
- * UnfurlURLJob constructor.
- *
- * @param UnfurlUrl $url
- */
- public function __construct(UnfurlUrl $url)
- {
- $this->url = $url;
- }
-
- /**
- * @inheritDoc
- */
- public function retryAfter()
- {
- switch ($this->getFailures()) {
- case 1:
- // 5 minutes
- return 5 * 60;
- case 2:
- // 30 minutes
- return 30 * 60;
- case 3:
- // 2 hours
- return 2 * 60 * 60;
- }
- }
-
- /**
- * @inheritDoc
- */
- public function perform()
- {
- try {
- $url = new UnfurlUrlUtil($this->url->url);
-
- if (empty(StringUtil::trim($url->getTitle()))) {
- $urlAction = new UnfurlUrlAction([$this->url], 'update', [
- 'data' => [
- 'title' => '',
- 'description' => '',
- 'status' => UnfurlUrl::STATUS_REJECTED,
- ],
- ]);
- $urlAction->executeAction();
- } else {
- $title = StringUtil::truncate($url->getTitle(), 255);
- $description = $url->getDescription();
- $data = [
- 'title' => $title,
- 'description' => $description !== null ? StringUtil::truncate($description, 500) : '',
- 'status' => UnfurlUrl::STATUS_SUCCESSFUL,
- ];
-
- if ($url->getImageUrl()) {
- $image = UnfurlUrlUtil::downloadImageFromUrl($url->getImageUrl());
-
- if ($image !== null) {
- $imageData = @\getimagesizefromstring($image);
-
- // filter images which are too large or too small
- $isSquared = $imageData[0] === $imageData[1];
- if ((!$isSquared && ($imageData[0] < 300 && $imageData[1] < 150))
- || \min($imageData[0], $imageData[1]) < 50) {
- $data['imageType'] = UnfurlUrl::IMAGE_NO_IMAGE;
- } else {
- if ($imageData[0] === $imageData[1]) {
- $data['imageUrl'] = $url->getImageUrl();
- $data['imageType'] = UnfurlUrl::IMAGE_SQUARED;
- } else {
- $data['imageUrl'] = $url->getImageUrl();
- $data['imageType'] = UnfurlUrl::IMAGE_COVER;
- }
-
- // Download image, if there is no image proxy or external source images allowed.
- if (!(MODULE_IMAGE_PROXY || IMAGE_ALLOW_EXTERNAL_SOURCE)) {
- if (isset($data['imageType'])) {
- switch ($imageData[2]) {
- case \IMAGETYPE_PNG:
- $extension = 'png';
- break;
- case \IMAGETYPE_GIF:
- $extension = 'gif';
- break;
- case \IMAGETYPE_JPEG:
- $extension = 'jpg';
- break;
- default:
- throw new \RuntimeException();
- }
-
- $data['imageHash'] = \sha1($image) . '.' . $extension;
-
- $path = WCF_DIR . 'images/unfurlUrl/' . \substr($data['imageHash'], 0, 2);
- FileUtil::makePath($path);
-
- $fileLocation = $path . '/' . $data['imageHash'];
-
- \file_put_contents($fileLocation, $image);
-
- @\touch($fileLocation);
- }
- }
- }
- }
- }
-
- $urlAction = new UnfurlUrlAction([$this->url], 'update', [
- 'data' => $data,
- ]);
- $urlAction->executeAction();
- }
- } catch (\InvalidArgumentException $e) {
- logThrowable($e);
- }
- }
-
- /**
- * @inheritDoc
- */
- public function onFinalFailure()
- {
- $urlAction = new UnfurlUrlAction([$this->url], 'update', [
- 'data' => [
- 'title' => '',
- 'description' => '',
- 'status' => 'REJECTED',
- ],
- ]);
- $urlAction->executeAction();
- }
-}
namespace wcf\system\html\input\node;
-use wcf\data\unfurl\url\UnfurlUrlAction;
use wcf\system\bbcode\BBCodeHandler;
use wcf\system\event\EventHandler;
use wcf\system\html\node\AbstractHtmlNodeProcessor;
/**
* Helper class to unfurl link objects.
*
- * @author Joshua Ruesweg
+ * @author Joshua Ruesweg
* @copyright 2001-2021 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Html\Node
- * @since 5.4
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Html\Node
+ * @since 5.4
*/
class HtmlNodeUnfurlLink extends HtmlNodePlainLink
{
* @inheritDoc
*/
protected $tagName = 'a';
-
+
/**
* @inheritDoc
*/
/** @var \DOMElement $element */
foreach ($elements as $element) {
$attribute = $element->getAttribute(HtmlNodeUnfurlLink::UNFURL_URL_ID_ATTRIBUTE_NAME);
- if ($this->outputType === 'text/html'
+ if (
+ $this->outputType === 'text/html'
&& !empty($attribute)
- && MessageEmbeddedObjectManager::getInstance()->getObject('com.woltlab.wcf.unfurlUrl', $attribute) !== null) {
+ && MessageEmbeddedObjectManager::getInstance()->getObject('com.woltlab.wcf.unfurlUrl', $attribute) !== null
+ ) {
$nodeIdentifier = StringUtil::getRandomID();
$htmlNodeProcessor->addNodeData($this, $nodeIdentifier, ['urlId' => $attribute]);
-
+
$htmlNodeProcessor->renameTag($element, 'wcfNode-' . $nodeIdentifier);
}
}
}
-
+
/**
* @inheritDoc
*/
/**
* Represents the unfurl url embedded object handlers.
*
- * @author Joshua Ruesweg
+ * @author Joshua Ruesweg
* @copyright 2001-2021 WoltLab GmbH
- * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @package WoltLabSuite\Core\System\Message\Embedded\Object
- * @since 5.4
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @package WoltLabSuite\Core\System\Message\Embedded\Object
+ * @since 5.4
*/
class UnfurlUrlEmbeddedObjectHandler extends AbstractMessageEmbeddedObjectHandler
{
return $urlList->getObjects();
}
-
+
/**
* @inheritDoc
*/
$unfurlUrlIDs = [];
foreach ($htmlInputProcessor->getHtmlInputNodeProcessor()->getDocument()->getElementsByTagName('a') as $element) {
/** @var \DOMElement $element */
- $id = intval($element->getAttribute(HtmlNodeUnfurlLink::UNFURL_URL_ID_ATTRIBUTE_NAME));
-
+ $id = \intval($element->getAttribute(HtmlNodeUnfurlLink::UNFURL_URL_ID_ATTRIBUTE_NAME));
+
if (!empty($id)) {
$unfurlUrlIDs[] = $id;
}
}
-
+
return $unfurlUrlIDs;
}
}
* @var string
*/
private $url;
-
+
/**
* @var string
*/
private $body;
-
+
/**
* @var \DOMDocument
*/
private $domDocument;
-
+
public function __construct(string $url)
{
if (!Url::is($url)) {
throw new \InvalidArgumentException('Given URL "' . $url . '" is not a valid URL.');
}
-
+
$this->url = $url;
-
+
$this->fetchUrl();
}
-
+
/**
* Fetches the body of the given url and converts the body to utf-8.
*/
'range' => \sprintf('bytes=%d-%d', 0, self::MAX_SIZE - 1),
]);
$response = $client->send($request);
-
+
$this->body = "";
while (!$response->getBody()->eof()) {
$this->body .= $response->getBody()->read(8192);
}
}
$response->getBody()->close();
-
+
if (\mb_detect_encoding($this->body) !== 'UTF-8') {
$this->body = StringUtil::convertEncoding(\mb_detect_encoding($this->body), 'UTF-8', $this->body);
}
// Ignore these exceptions.
}
}
-
+
/**
* Returns the dom document of the website.
*/
$this->domDocument = new \DOMDocument();
$this->domDocument->loadHTML('<?xml version="1.0" encoding="UTF-8"?>' . $this->body);
}
-
+
return $this->domDocument;
}
-
+
/**
* Determines the title of the website.
*/
{
if (!empty($this->body)) {
$metaTags = $this->getDomDocument()->getElementsByTagName('meta');
-
+
// og
foreach ($metaTags as $metaTag) {
foreach ($metaTag->attributes as $attr) {
}
}
}
-
+
// title tag
$title = $this->getDomDocument()->getElementsByTagName('title');
if ($title->length) {
return null;
}
-
+
/**
* Determines the description of the website.
*/
return null;
}
-
+
/**
* Returns the image url for the current url.
*/
{
if (!empty($this->body)) {
$metaTags = $this->getDomDocument()->getElementsByTagName('meta');
-
+
// og:image
foreach ($metaTags as $metaTag) {
foreach ($metaTag->attributes as $attr) {
return null;
}
-
+
/**
* Downloads the image from a url and returns the image body.
*/
.unfurlCard {
background-color: $wcfContentBackground;
- box-shadow: 0 0 3px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24);
+ box-shadow: 0 0 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
display: inline-block;
margin: 20px 0;
white-space: nowrap;
-
+
@include screen-md-up {
max-width: 700px;
}
-
+
@include screen-sm-down {
max-width: 100%;
}
-
+
> a {
color: $wcfContentText;
-
+
.unfurlInformation {
position: relative;
padding: 10px 20px 20px;
}
-
+
.urlTitle {
display: block;
overflow: hidden;
text-overflow: ellipsis;
-
+
@include wcfFontHeadline;
}
-
+
.urlDescription {
white-space: normal;
}
-
+
.urlHost {
@include wcfFontSmall;
float: right;
bottom: 5px;
position: absolute;
right: 5px;
-
+
img {
height: 12px !important;
}
}
}
-
+
&.unfurlLargeContentImage {
min-width: 300px;
-
+
> a > :first-child:not(:last-child) {
min-height: 150px;
background-position: center;
position: relative;
}
}
-
+
&.unfurlSquaredContentImage {
> a {
display: flex;
-
+
> :first-child:not(:last-child) {
flex: 0 0 auto;
height: 128px !important;
background-size: cover;
position: relative;
}
-
+
> :last-child {
flex: 1 1 auto;
overflow: hidden;
padding-left: 10px;
}
-
+
@include screen-sm-down {
> :first-child:not(:last-child) {
display: none;
}
}
}
-}
\ No newline at end of file
+}