Skip to content
Draft
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
64 changes: 64 additions & 0 deletions src/Discord/Helpers/ValidatesDiscordLimits.php
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong type of file (the interface itself); In php, if you don't know, there are other types of "classes" like Traits or Enum's - please use the proper one.

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

/*
* This file is a part of the DiscordPHP project.
*
* Copyright (c) 2015-2022 David Cole <david.cole1340@gmail.com>
* Copyright (c) 2020-present Valithor Obsidion <valithor@discordphp.org>
*
* This file is subject to the MIT license that is bundled
* with this source code in the LICENSE.md file.
*/

namespace Discord\Helpers;

/**
* Centralises Discord API payload size limits as shared constants.
*
* Classes that produce or validate Discord-bound payloads implement this
* interface to expose consistent limits in a single location. Grouping
* them prevents the "magic number" drift that happens when the same
* limit is repeated across builders and parts.
*
* @link https://docs.discord.com/developers/resources/message#embed-object-embed-limits
* @link https://docs.discord.com/developers/resources/message#create-message
*
* @since 10.48.0
*/
interface ValidatesDiscordLimits
{
/** Maximum characters in an embed title. */
public const EMBED_TITLE_MAX = 256;

/** Maximum characters in an embed description. */
public const EMBED_DESCRIPTION_MAX = 4096;

/** Maximum characters in an embed author name. */
public const EMBED_AUTHOR_NAME_MAX = 256;

/** Maximum characters in an embed footer text. */
public const EMBED_FOOTER_TEXT_MAX = 2048;

/** Maximum characters in an embed field name. */
public const EMBED_FIELD_NAME_MAX = 256;

/** Maximum characters in an embed field value. */
public const EMBED_FIELD_VALUE_MAX = 1024;

/** Maximum number of fields in an embed. */
public const EMBED_FIELDS_MAX = 25;

/** Maximum combined characters across all embed text fields. */
public const EMBED_TOTAL_CHARS_MAX = 6000;

/** Maximum characters in a message content field. */
public const MESSAGE_CONTENT_MAX = 2000;

/** Maximum embeds attached to a single message. */
public const MESSAGE_EMBEDS_MAX = 10;

/** Maximum file attachments on a single message. */
public const MESSAGE_FILES_MAX = 10;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some values are duplicated, if you're just going for naming, add both into 1 or add a function that calls the same value.

}
38 changes: 27 additions & 11 deletions src/Discord/Parts/Embed/Embed.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

use Carbon\Carbon;
use Discord\Helpers\ExCollectionInterface;
use Discord\Helpers\ValidatesDiscordLimits;
use Discord\Parts\Channel\Attachment;
use Discord\Parts\Part;

Expand Down Expand Up @@ -44,7 +45,7 @@
* @property ?ExCollectionInterface<Field>|Field[] $fields A collection of embed fields (max of 25).
* @property ?int|null $flags Embedded flags combined as a bitfield.
*/
class Embed extends Part
class Embed extends Part implements ValidatesDiscordLimits
{
public const TYPES = [
0 => Embed::class, // Fallback for unknown types
Expand Down Expand Up @@ -211,11 +212,11 @@ protected function setDescriptionAttribute($description): void
{
if (poly_strlen($description) === 0) {
$this->attributes['description'] = null;
} elseif (poly_strlen($description) > 4096) {
} elseif (poly_strlen($description) > self::EMBED_DESCRIPTION_MAX) {
throw new \LengthException('Embed description can not be longer than 4096 characters');
} else {
if ($this->exceedsOverallLimit(poly_strlen($description))) {
throw new \LengthException('Embed text values collectively can not exceed than 6000 characters');
throw new \LengthException('Embed text values collectively can not exceed 6000 characters');
}

$this->attributes['description'] = $description;
Expand Down Expand Up @@ -253,10 +254,10 @@ protected function setTitleAttribute(string $title): self
{
if (poly_strlen($title) === 0) {
$this->attributes['title'] = null;
} elseif (poly_strlen($title) > 256) {
} elseif (poly_strlen($title) > self::EMBED_TITLE_MAX) {
throw new \LengthException('Embed title can not be longer than 256 characters');
} elseif ($this->exceedsOverallLimit(poly_strlen($title))) {
throw new \LengthException('Embed text values collectively can not exceed than 6000 characters');
throw new \LengthException('Embed text values collectively can not exceed 6000 characters');
} else {
$this->attributes['title'] = $title;
}
Expand Down Expand Up @@ -334,14 +335,29 @@ public function setColor($color): self
public function addField(...$fields): self
{
foreach ($fields as $field) {
if (count($this->fields) > 25) {
if (count($this->fields) >= self::EMBED_FIELDS_MAX) {
throw new \OverflowException('Embeds can not have more than 25 fields.');
}

if ($field instanceof Field) {
$field = $field->getRawAttributes();
}

$name = is_string($field['name'] ?? null) ? $field['name'] : '';
$value = is_string($field['value'] ?? null) ? $field['value'] : '';

if (poly_strlen($name) > self::EMBED_FIELD_NAME_MAX) {
throw new \LengthException('Embed field name can not be longer than 256 characters');
}

if (poly_strlen($value) > self::EMBED_FIELD_VALUE_MAX) {
throw new \LengthException('Embed field value can not be longer than 1024 characters');
}

if ($this->exceedsOverallLimit(poly_strlen($name) + poly_strlen($value))) {
throw new \LengthException('Embed text values collectively can not exceed 6000 characters');
}

$this->attributes['fields'][] = $field;
}

Expand Down Expand Up @@ -385,10 +401,10 @@ public function setAuthor(string $name, $iconurl = null, ?string $url = null): s
$length = poly_strlen($name);
if ($length === 0) {
$this->author = null;
} elseif ($length > 256) {
} elseif ($length > self::EMBED_AUTHOR_NAME_MAX) {
throw new \LengthException('Author name can not be longer than 256 characters.');
} elseif ($this->exceedsOverallLimit($length)) {
throw new \LengthException('Embed text values collectively can not exceed than 6000 characters');
throw new \LengthException('Embed text values collectively can not exceed 6000 characters');
}

if ($iconurl instanceof Attachment) {
Expand Down Expand Up @@ -424,10 +440,10 @@ public function setFooter(string $text, $iconurl = null): self
$length = poly_strlen($text);
if ($length === 0) {
$this->footer = null;
} elseif ($length > 2048) {
} elseif ($length > self::EMBED_FOOTER_TEXT_MAX) {
throw new \LengthException('Footer text can not be longer than 2048 characters.');
} elseif ($this->exceedsOverallLimit($length)) {
throw new \LengthException('Embed text values collectively can not exceed than 6000 characters');
throw new \LengthException('Embed text values collectively can not exceed 6000 characters');
}

if ($iconurl instanceof Attachment) {
Expand Down Expand Up @@ -556,7 +572,7 @@ protected function exceedsOverallLimit(int $addition): bool
$total += poly_strlen($field['value']);
}

return ($total > 6000);
return ($total > self::EMBED_TOTAL_CHARS_MAX);
}

/**
Expand Down