Browse Source

[TOOLS][CS-FIXER] Run new PHP CS Fixer config. Notably, adds strict_types

remotes/upstream/experimental
parent
commit
9109c61af5
Signed by: diogo <mail@diogo.site> GPG Key ID: 18D2D35001FBFAB0
100 changed files with 775 additions and 1125 deletions
  1. +24
    -15
      components/Avatar/Avatar.php
  2. +3
    -1
      components/Avatar/Controller/Avatar.php
  3. +4
    -12
      components/Avatar/Entity/Avatar.php
  4. +2
    -0
      components/Avatar/Exception/NoAvatarException.php
  5. +2
    -0
      components/Bridge/Bridge.php
  6. +6
    -4
      components/Bridge/Entity/ForeignLink.php
  7. +4
    -2
      components/Bridge/Entity/ForeignService.php
  8. +3
    -1
      components/Bridge/Entity/ForeignSubscription.php
  9. +4
    -2
      components/Bridge/Entity/ForeignUser.php
  10. +4
    -38
      components/FreeNetwork/Entity/FreenetworkActor.php
  11. +3
    -1
      components/FreeNetwork/FreeNetwork.php
  12. +3
    -1
      components/Left/Left.php
  13. +67
    -70
      components/Link/Link.php
  14. +9
    -21
      components/Posting/Posting.php
  15. +3
    -1
      components/Right/Right.php
  16. +6
    -6
      components/Search/Controller/Search.php
  17. +5
    -3
      components/Search/Search.php
  18. +9
    -12
      components/Search/Util/Parser.php
  19. +3
    -1
      components/Tag/Controller/Tag.php
  20. +8
    -9
      components/Tag/Tag.php
  21. +27
    -25
      config/bootstrap.php
  22. +2
    -0
      config/bundles.php
  23. +2
    -0
      config/cli-config.php
  24. +2
    -0
      config/phpstan-bootstrap.php
  25. +4
    -2
      config/preload.php
  26. +2
    -0
      config/routes.php
  27. +209
    -218
      extlib/Validate.php
  28. +15
    -28
      plugins/ActivityPub/ActivityPub.php
  29. +6
    -4
      plugins/ActivityPub/Controller/Inbox.php
  30. +4
    -2
      plugins/ActivityPub/Entity/ActivitypubActivity.php
  31. +4
    -38
      plugins/ActivityPub/Entity/ActivitypubActor.php
  32. +4
    -7
      plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToEntity.php
  33. +5
    -4
      plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToGSActor.php
  34. +6
    -8
      plugins/ActivityPub/Util/Model/AS2ToEntity/AS2ToNote.php
  35. +5
    -6
      plugins/ActivityPub/Util/Model/EntityToType/EntityToType.php
  36. +3
    -6
      plugins/ActivityPub/Util/Model/EntityToType/GSActorToType.php
  37. +5
    -6
      plugins/ActivityPub/Util/Model/EntityToType/NoteToType.php
  38. +6
    -6
      plugins/ActivityPub/Util/Response/AbstractResponse.php
  39. +4
    -6
      plugins/ActivityPub/Util/Response/ActorResponse.php
  40. +4
    -5
      plugins/ActivityPub/Util/Response/NoteResponse.php
  41. +4
    -2
      plugins/ActivityPub/Util/Response/TypeResponse.php
  42. +16
    -16
      plugins/ActivityPub/Util/Type.php
  43. +46
    -80
      plugins/ActivityPub/Util/Type/AbstractObject.php
  44. +2
    -3
      plugins/ActivityPub/Util/Type/Core/AbstractActivity.php
  45. +2
    -3
      plugins/ActivityPub/Util/Type/Core/Activity.php
  46. +2
    -8
      plugins/ActivityPub/Util/Type/Core/Collection.php
  47. +2
    -6
      plugins/ActivityPub/Util/Type/Core/CollectionPage.php
  48. +2
    -3
      plugins/ActivityPub/Util/Type/Core/IntransitiveActivity.php
  49. +2
    -14
      plugins/ActivityPub/Util/Type/Core/Link.php
  50. +2
    -19
      plugins/ActivityPub/Util/Type/Core/ObjectType.php
  51. +2
    -3
      plugins/ActivityPub/Util/Type/Core/OrderedCollection.php
  52. +2
    -5
      plugins/ActivityPub/Util/Type/Core/OrderedCollectionPage.php
  53. +2
    -14
      plugins/ActivityPub/Util/Type/Extended/AbstractActor.php
  54. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Accept.php
  55. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Announce.php
  56. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Block.php
  57. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Create.php
  58. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Delete.php
  59. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Follow.php
  60. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Ignore.php
  61. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Join.php
  62. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Leave.php
  63. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Like.php
  64. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Question.php
  65. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Reject.php
  66. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Remove.php
  67. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Undo.php
  68. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Activity/Update.php
  69. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Actor/Application.php
  70. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Actor/Group.php
  71. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Actor/Organization.php
  72. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Actor/Person.php
  73. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Actor/Service.php
  74. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Article.php
  75. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Audio.php
  76. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Document.php
  77. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Event.php
  78. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Image.php
  79. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Mention.php
  80. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Note.php
  81. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Page.php
  82. +2
    -15
      plugins/ActivityPub/Util/Type/Extended/Object/Place.php
  83. +2
    -5
      plugins/ActivityPub/Util/Type/Extended/Object/Profile.php
  84. +2
    -5
      plugins/ActivityPub/Util/Type/Extended/Object/Tombstone.php
  85. +2
    -3
      plugins/ActivityPub/Util/Type/Extended/Object/Video.php
  86. +14
    -29
      plugins/ActivityPub/Util/Type/TypeResolver.php
  87. +58
    -152
      plugins/ActivityPub/Util/Type/Util.php
  88. +11
    -13
      plugins/ActivityPub/Util/Type/Validator.php
  89. +2
    -3
      plugins/ActivityPub/Util/Type/Validator/AccuracyValidator.php
  90. +14
    -18
      plugins/ActivityPub/Util/Type/Validator/ActorValidator.php
  91. +3
    -8
      plugins/ActivityPub/Util/Type/Validator/AltitudeValidator.php
  92. +5
    -6
      plugins/ActivityPub/Util/Type/Validator/AnyOfValidator.php
  93. +4
    -5
      plugins/ActivityPub/Util/Type/Validator/AttachmentValidator.php
  94. +3
    -4
      plugins/ActivityPub/Util/Type/Validator/AttributedToValidator.php
  95. +3
    -4
      plugins/ActivityPub/Util/Type/Validator/AudienceValidator.php
  96. +3
    -4
      plugins/ActivityPub/Util/Type/Validator/BccValidator.php
  97. +3
    -4
      plugins/ActivityPub/Util/Type/Validator/BtoValidator.php
  98. +3
    -4
      plugins/ActivityPub/Util/Type/Validator/CcValidator.php
  99. +6
    -7
      plugins/ActivityPub/Util/Type/Validator/ClosedValidator.php
  100. +2
    -5
      plugins/ActivityPub/Util/Type/Validator/ContentMapValidator.php

+ 24
- 15
components/Avatar/Avatar.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -46,8 +48,6 @@ class Avatar extends Component
}

/**
* @param mixed $tabs
*
* @throws \App\Util\Exception\ClientException
*/
public function onPopulateProfileSettingsTabs(Request $request, &$tabs): bool
@@ -82,14 +82,20 @@ class Avatar extends Component
public static function getAvatar(?int $actor_id = null): Entity\Avatar
{
$actor_id = $actor_id ?: Common::userId();
return GSFile::error(NoAvatarException::class,
return GSFile::error(
NoAvatarException::class,
$actor_id,
Cache::get("avatar-{$actor_id}",
Cache::get(
"avatar-{$actor_id}",
function () use ($actor_id) {
return DB::dql('select a from Component\Avatar\Entity\Avatar a ' .
'where a.actor_id = :actor_id',
['actor_id' => $actor_id]);
}));
return DB::dql(
'select a from Component\Avatar\Entity\Avatar a '
. 'where a.actor_id = :actor_id',
['actor_id' => $actor_id],
);
},
),
);
}

/**
@@ -112,14 +118,17 @@ class Avatar extends Component
*/
public static function getAvatarFileInfo(int $actor_id, string $size = 'full'): array
{
$res = Cache::get("avatar-file-info-{$actor_id}-{$size}",
$res = Cache::get(
"avatar-file-info-{$actor_id}-{$size}",
function () use ($actor_id) {
return DB::dql('select f.id, f.filename, a.title, f.mimetype ' .
'from App\Entity\Attachment f ' .
'join Component\Avatar\Entity\Avatar a with f.id = a.attachment_id ' .
'where a.actor_id = :actor_id',
['actor_id' => $actor_id]);
}
return DB::dql(
'select f.id, f.filename, a.title, f.mimetype '
. 'from App\Entity\Attachment f '
. 'join Component\Avatar\Entity\Avatar a with f.id = a.attachment_id '
. 'where a.actor_id = :actor_id',
['actor_id' => $actor_id],
);
},
);
if ($res === []) { // Avatar not found
$filepath = INSTALLDIR . '/public/assets/default-avatar.svg';


+ 3
- 1
components/Avatar/Controller/Avatar.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -96,7 +98,7 @@ class Avatar extends Controller
// Cropped client side
$matches = [];
if (!empty(preg_match('/data:([^;]*)(;(base64))?,(.*)/', $data['hidden'], $matches))) {
list(, , , $encoding_user, $data_user) = $matches;
[, , , $encoding_user, $data_user] = $matches;
if ($encoding_user === 'base64') {
$data_user = base64_decode($data_user);
$tempfile = new TemporaryFile(['prefix' => 'gs-avatar']);


+ 4
- 12
components/Avatar/Entity/Avatar.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -75,17 +77,11 @@ class Avatar extends Entity
return $this->attachment_id;
}

/**
* @return null|string
*/
public function getTitle(): ?string
{
return $this->title;
}

/**
* @param null|string $title
*/
public function setTitle(?string $title): void
{
$this->title = $title;
@@ -121,14 +117,12 @@ class Avatar extends Entity
public function getUrl(string $size = 'full', int $type = Router::ABSOLUTE_PATH): string
{
$actor_id = $this->getActorId();
return Cache::get("avatar-url-{$actor_id}-{$size}-{$type}", function () use ($actor_id, $size, $type) {
return Router::url('avatar_actor', ['actor_id' => $actor_id, 'size' => $size], $type);
});
return Cache::get("avatar-url-{$actor_id}-{$size}-{$type}", fn () => Router::url('avatar_actor', ['actor_id' => $actor_id, 'size' => $size], $type));
}

public function getAttachment(): Attachment
{
$this->attachment = $this->attachment ?? DB::findOneBy('attachment', ['id' => $this->attachment_id]);
$this->attachment ??= DB::findOneBy('attachment', ['id' => $this->attachment_id]);
return $this->attachment;
}

@@ -144,8 +138,6 @@ class Avatar extends Entity

/**
* Delete this avatar and kill corresponding attachment
*
* @return bool
*/
public function delete(): bool
{


+ 2
- 0
components/Avatar/Exception/NoAvatarException.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social


+ 2
- 0
components/Bridge/Bridge.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//


+ 6
- 4
components/Bridge/Entity/ForeignLink.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -46,10 +48,10 @@ class ForeignLink
private int $noticesync = 1;
private int $friendsync = 2;
private int $profilesync = 1;
private ?\DateTimeInterface $last_noticesync;
private ?\DateTimeInterface $last_friendsync;
private \DateTimeInterface $created;
private \DateTimeInterface $modified;
private ?DateTimeInterface $last_noticesync;
private ?DateTimeInterface $last_friendsync;
private DateTimeInterface $created;
private DateTimeInterface $modified;

public function setUserId(int $user_id): self
{


+ 4
- 2
components/Bridge/Entity/ForeignService.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -42,8 +44,8 @@ class ForeignService
private int $id;
private string $name;
private ?string $description;
private \DateTimeInterface $created;
private \DateTimeInterface $modified;
private DateTimeInterface $created;
private DateTimeInterface $modified;

public function setId(int $id): self
{


+ 3
- 1
components/Bridge/Entity/ForeignSubscription.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -42,7 +44,7 @@ class ForeignSubscription
private int $service;
private int $subscriber;
private int $subscribed;
private \DateTimeInterface $created;
private DateTimeInterface $created;

public function setService(int $service): self
{


+ 4
- 2
components/Bridge/Entity/ForeignUser.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -43,8 +45,8 @@ class ForeignUser
private int $service;
private string $uri;
private ?string $nickname;
private \DateTimeInterface $created;
private \DateTimeInterface $modified;
private DateTimeInterface $created;
private DateTimeInterface $modified;

public function setId(int $id): self
{


+ 4
- 38
components/FreeNetwork/Entity/FreenetworkActor.php View File

@@ -1,4 +1,6 @@
<?php

declare(strict_types = 1);
// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -50,100 +52,64 @@ class FreenetworkActor extends Entity
private string $source;
private int $actor_id;
private bool $is_local;
private \DateTimeInterface $created;
private \DateTimeInterface $modified;
private DateTimeInterface $created;
private DateTimeInterface $modified;

/**
* @return string
*/
public function getActorUri(): string
{
return $this->actor_uri;
}

/**
* @param string $actor_uri
*/
public function setActorUri(string $actor_uri): void
{
$this->actor_uri = $actor_uri;
}

/**
* @return string
*/
public function getSource(): string
{
return $this->source;
}

/**
* @param string $source
*/
public function setSource(string $source): void
{
$this->source = $source;
}

/**
* @return int
*/
public function getActorId(): int
{
return $this->actor_id;
}

/**
* @param int $actor_id
*/
public function setActorId(int $actor_id): void
{
$this->actor_id = $actor_id;
}

/**
* @return bool
*/
public function isIsLocal(): bool
{
return $this->is_local;
}

/**
* @param bool $is_local
*/
public function setIsLocal(bool $is_local): void
{
$this->is_local = $is_local;
}

/**
* @return DateTimeInterface
*/
public function getCreated(): DateTimeInterface
{
return $this->created;
}

/**
* @param DateTimeInterface $created
*/
public function setCreated(DateTimeInterface $created): void
{
$this->created = $created;
}

/**
* @return DateTimeInterface
*/
public function getModified(): DateTimeInterface
{
return $this->modified;
}

/**
* @param DateTimeInterface $modified
*/
public function setModified(DateTimeInterface $modified): void
{
$this->modified = $modified;


+ 3
- 1
components/FreeNetwork/FreeNetwork.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -23,4 +25,4 @@ use App\Core\Modules\Component;

class FreeNetwork extends Component
{
}
}

+ 3
- 1
components/Left/Left.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -29,7 +31,7 @@ class Left extends Component
*
* @param array $styles stylesheets path
*
* @return bool hook value; true means continue processing, false means stop.
* @return bool hook value; true means continue processing, false means stop
*/
public function onEndShowStyles(array &$styles, string $route): bool
{


+ 67
- 70
components/Link/Link.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -68,68 +70,68 @@ class Link extends Component
$geouri_pctencoded_regex = '(?:\%[0-9a-fA-F][0-9a-fA-F])';
$geouri_paramchar_regex = $geouri_unreserved_regex . $geouri_punreserved_regex; //FIXME: add $geouri_pctencoded_regex here so it works

return '#' .
'(?:^|[\s\<\>\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])' .
'(' .
'(?:' .
'(?:' . //Known protocols
'(?:' .
'(?:(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_COLON_DOUBLE_SLASH)) . ')://)' .
'|' .
'(?:(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_SINGLE_COLON)) . '):)' .
')' .
'(?:[\pN\pL\-\_\+\%\~]+(?::[\pN\pL\-\_\+\%\~]+)?\@)?' . //user:pass@
'(?:' .
'(?:' .
'\[[\pN\pL\-\_\:\.]+(?<![\.\:])\]' . //[dns]
')|(?:' .
'[\pN\pL\-\_\:\.]+(?<![\.\:])' . //dns
')' .
')' .
')' .
'|(?:' .
'(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_COLON_COORDINATES)) . '):' .
return '#'
. '(?:^|[\s\<\>\(\)\[\]\{\}\\\'\\\";]+)(?![\@\!\#])'
. '('
. '(?:'
. '(?:' //Known protocols
. '(?:'
. '(?:(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_COLON_DOUBLE_SLASH)) . ')://)'
. '|'
. '(?:(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_SINGLE_COLON)) . '):)'
. ')'
. '(?:[\pN\pL\-\_\+\%\~]+(?::[\pN\pL\-\_\+\%\~]+)?\@)?' //user:pass@
. '(?:'
. '(?:'
. '\[[\pN\pL\-\_\:\.]+(?<![\.\:])\]' //[dns]
. ')|(?:'
. '[\pN\pL\-\_\:\.]+(?<![\.\:])' //dns
. ')'
. ')'
. ')'
. '|(?:'
. '(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_COLON_COORDINATES)) . '):'
// There's an order that must be followed here too, if ;crs= is used, it must precede ;u=
// Also 'crsp' (;crs=$crsp) must match $geouri_labeltext_regex
// Also 'uval' (;u=$uval) must be a pnum: \-?[0-9]+
'(?:' .
'(?:[0-9]+(?:\.[0-9]+)?(?:\,[0-9]+(?:\.[0-9]+)?){1,2})' . // 1(.23)?(,4(.56)){1,2}
'(?:\;(?:[' . $geouri_labeltext_regex . ']+)(?:\=[' . $geouri_paramchar_regex . ']+)*)*' .
')' .
')' .
. '(?:'
. '(?:[0-9]+(?:\.[0-9]+)?(?:\,[0-9]+(?:\.[0-9]+)?){1,2})' // 1(.23)?(,4(.56)){1,2}
. '(?:\;(?:[' . $geouri_labeltext_regex . ']+)(?:\=[' . $geouri_paramchar_regex . ']+)*)*'
. ')'
. ')'
// URLs without domain name, like magnet:?xt=...
'|(?:(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_NO_DOMAIN)) . '):(?=\?))' . // zero-length lookahead requires ? after :
(Common::config('linkify', 'ipv4') // Convert IPv4 addresses to hyperlinks
. '|(?:(?:' . implode('|', $this->URLSchemes(self::URL_SCHEME_NO_DOMAIN)) . '):(?=\?))' // zero-length lookahead requires ? after :
. (Common::config('linkify', 'ipv4') // Convert IPv4 addresses to hyperlinks
? '|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
: '') .
(Common::config('linkify', 'ipv6') // Convert IPv6 addresses to hyperlinks
? '|(?:' . //IPv6
'\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?<!:)' .
')'
: '') .
(Common::config('linkify', 'bare_domains')
? '|(?:' . //DNS
'(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?' . //user:pass@
'[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.' .
: '')
. (Common::config('linkify', 'ipv6') // Convert IPv6 addresses to hyperlinks
? '|(?:' //IPv6
. '\[?(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}(?:(?:[0-9A-Fa-f]{1,4})|:))|(?:(?:[0-9A-Fa-f]{1,4}:){6}(?::|(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})|(?::[0-9A-Fa-f]{1,4})))|(?:(?:[0-9A-Fa-f]{1,4}:){5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){4}(?::[0-9A-Fa-f]{1,4}){0,1}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){3}(?::[0-9A-Fa-f]{1,4}){0,2}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:){2}(?::[0-9A-Fa-f]{1,4}){0,3}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:[0-9A-Fa-f]{1,4}:)(?::[0-9A-Fa-f]{1,4}){0,4}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?::(?::[0-9A-Fa-f]{1,4}){0,5}(?:(?::(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})?)|(?:(?::[0-9A-Fa-f]{1,4}){1,2})))|(?:(?:(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[01]?\d{1,2})){3})))\]?(?<!:)'
. ')'
: '')
. (Common::config('linkify', 'bare_domains')
? '|(?:' //DNS
. '(?:[\pN\pL\-\_\+\%\~]+(?:\:[\pN\pL\-\_\+\%\~]+)?\@)?' //user:pass@
. '[\pN\pL\-\_]+(?:\.[\pN\pL\-\_]+)*\.'
//tld list from http://data.iana.org/TLD/tlds-alpha-by-domain.txt, also added local, loc, and onion
'(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZONE|ZW|local|loc|onion)' .
')(?![\pN\pL\-\_])'
: '') . // if common_config('linkify', 'bare_domains') is false, don't add anything here
')' .
'(?:' .
'(?:\:\d+)?' . //:port
'(?:/[' . URL_REGEX_VALID_PATH_CHARS . ']*)?' . // path
'(?:\?[' . URL_REGEX_VALID_QSTRING_CHARS . ']*)?' . // ?query string
'(?:\#[' . URL_REGEX_VALID_FRAGMENT_CHARS . ']*)?' . // #fragment
')(?<![' . URL_REGEX_EXCLUDED_END_CHARS . '])' .
')' .
'#ixu';
. '(?:AC|AD|AE|AERO|AF|AG|AI|AL|AM|AN|AO|AQ|AR|ARPA|AS|ASIA|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BIZ|BJ|BM|BN|BO|BR|BS|BT|BV|BW|BY|BZ|CA|CAT|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|COM|COOP|CR|CU|CV|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EDU|EE|EG|ER|ES|ET|EU|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GOV|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|INFO|INT|IO|IQ|IR|IS|IT|JE|JM|JO|JOBS|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MG|MH|MIL|MK|ML|MM|MN|MO|MOBI|MP|MQ|MR|MS|MT|MU|MUSEUM|MV|MW|MX|MY|MZ|NA|NAME|NC|NE|NET|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|ORG|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PRO|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|ST|SU|SV|SY|SZ|TC|TD|TEL|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TP|TR|TRAVEL|TT|TV|TW|TZ|UA|UG|UK|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|XN--0ZWM56D|测试|XN--11B5BS3A9AJ6G|परीक्षा|XN--80AKHBYKNJ4F|испытание|XN--9T4B11YI5A|테스트|XN--DEBA0AD|טעסט|XN--G6W251D|測試|XN--HGBK6AJ7F53BBA|آزمایشی|XN--HLCJ6AYA9ESC7A|பரிட்சை|XN--JXALPDLP|δοκιμή|XN--KGBECHTV|إختبار|XN--ZCKZAH|テスト|YE|YT|YU|ZA|ZM|ZONE|ZW|local|loc|onion)'
. ')(?![\pN\pL\-\_])'
: '') // if common_config('linkify', 'bare_domains') is false, don't add anything here
. ')'
. '(?:'
. '(?:\:\d+)?' //:port
. '(?:/[' . URL_REGEX_VALID_PATH_CHARS . ']*)?' // path
. '(?:\?[' . URL_REGEX_VALID_QSTRING_CHARS . ']*)?' // ?query string
. '(?:\#[' . URL_REGEX_VALID_FRAGMENT_CHARS . ']*)?' // #fragment
. ')(?<![' . URL_REGEX_EXCLUDED_END_CHARS . '])'
. ')'
. '#ixu';
}

const URL_SCHEME_COLON_DOUBLE_SLASH = 1;
const URL_SCHEME_SINGLE_COLON = 2;
const URL_SCHEME_NO_DOMAIN = 4;
const URL_SCHEME_COLON_COORDINATES = 8;
public const URL_SCHEME_COLON_DOUBLE_SLASH = 1;
public const URL_SCHEME_SINGLE_COLON = 2;
public const URL_SCHEME_NO_DOMAIN = 4;
public const URL_SCHEME_COLON_COORDINATES = 8;

public function URLSchemes($filter = null)
{
@@ -162,13 +164,11 @@ class Link extends Component
'geo' => self::URL_SCHEME_COLON_COORDINATES,
];

return array_keys(array_filter($schemes, fn ($scheme) => is_null($filter) || ($scheme & $filter)));
return array_keys(array_filter($schemes, fn ($scheme) => \is_null($filter) || ($scheme & $filter)));
}

/**
* Find links in the given text and pass them to the given callback function.
*
* @param string $text
*/
public function replaceURLs(string $text): string
{
@@ -180,16 +180,13 @@ class Link extends Component
* Intermediate callback for `replaceURLs()`, which helps resolve some
* ambiguous link forms before passing on to the final callback.
*
* @param array $matches
* @param callable(string $text): string $callback: return replacement text
*
* @return string
*/
private function callbackHelper(array $matches, callable $callback): string
{
$url = $matches[1];
$left = strpos($matches[0], $url);
$right = $left + strlen($url);
$left = mb_strpos($matches[0], $url);
$right = $left + mb_strlen($url);

$groupSymbolSets = [
[
@@ -214,23 +211,23 @@ class Link extends Component
do {
$original_url = $url;
foreach ($groupSymbolSets as $groupSymbolSet) {
if (substr($url, -1) == $groupSymbolSet['right']) {
$group_left_count = substr_count($url, $groupSymbolSet['left']);
$group_right_count = substr_count($url, $groupSymbolSet['right']);
if (mb_substr($url, -1) == $groupSymbolSet['right']) {
$group_left_count = mb_substr_count($url, $groupSymbolSet['left']);
$group_right_count = mb_substr_count($url, $groupSymbolSet['right']);
if ($group_left_count < $group_right_count) {
--$right;
$url = substr($url, 0, -1);
$url = mb_substr($url, 0, -1);
}
}
}
if (in_array(substr($url, -1), $cannotEndWith)) {
if (\in_array(mb_substr($url, -1), $cannotEndWith)) {
--$right;
$url = substr($url, 0, -1);
$url = mb_substr($url, 0, -1);
}
} while ($original_url != $url);

$result = $callback($url);
return substr($matches[0], 0, $left) . $result . substr($matches[0], $right);
return mb_substr($matches[0], 0, $left) . $result . mb_substr($matches[0], $right);
}

/**
@@ -242,7 +239,7 @@ class Link extends Component
// functions
$url = htmlspecialchars_decode($url);

if (strpos($url, '@') !== false && strpos($url, ':') === false && ($email = filter_var($url, FILTER_VALIDATE_EMAIL)) !== false) {
if (str_contains($url, '@') && !str_contains($url, ':') && ($email = filter_var($url, \FILTER_VALIDATE_EMAIL)) !== false) {
//url is an email address without the mailto: protocol
$url = "mailto:{$email}";
}


+ 9
- 21
components/Posting/Posting.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -63,8 +65,10 @@ class Posting extends Component

$actor_id = $user->getId();
$to_tags = [];
$tags = Cache::get("actor-circle-{$actor_id}",
fn () => DB::dql('select c.tag from App\Entity\ActorCircle c where c.tagger = :tagger', ['tagger' => $actor_id]));
$tags = Cache::get(
"actor-circle-{$actor_id}",
fn () => DB::dql('select c.tag from App\Entity\ActorCircle c where c.tagger = :tagger', ['tagger' => $actor_id]),
);
foreach ($tags as $t) {
$t = $t['tag'];
$to_tags[$t] = $t;
@@ -87,7 +91,7 @@ class Posting extends Component
['content', TextareaType::class, ['label' => _m('Content:'), 'data' => $initial_content, 'attr' => ['placeholder' => _m($placeholder)]]],
['attachments', FileType::class, ['label' => _m('Attachments:'), 'data' => null, 'multiple' => true, 'required' => false]],
];
if (count($available_content_types) > 1) {
if (\count($available_content_types) > 1) {
$form_params[] = ['content_type', ChoiceType::class,
[
'label' => _m('Text format:'), 'multiple' => false, 'expanded' => false,
@@ -121,13 +125,6 @@ class Posting extends Component
* $actor_id, possibly as a reply to note $reply_to and with flag
* $is_local. Sanitizes $content and $attachments
*
* @param Actor $actor
* @param string $content
* @param string $content_type
* @param array $attachments
* @param null|Note $reply_to
* @param null|Note $repeat_of
*
* @throws ClientException
* @throws ServerException
*/
@@ -149,8 +146,8 @@ class Posting extends Component
$filesize = $f->getSize();
$max_file_size = Common::config('attachments', 'file_quota');
if ($max_file_size < $filesize) {
throw new ClientException(_m('No file may be larger than {quota} bytes and the file you sent was {size} bytes. ' .
'Try to upload a smaller version.', ['quota' => $max_file_size, 'size' => $filesize]));
throw new ClientException(_m('No file may be larger than {quota} bytes and the file you sent was {size} bytes. '
. 'Try to upload a smaller version.', ['quota' => $max_file_size, 'size' => $filesize], ));
}
Event::handle('EnforceUserFileQuota', [$filesize, $actor->getId()]);
$processed_attachments[] = [GSFile::storeFileAsAttachment($f), $f->getClientOriginalName()];
@@ -193,11 +190,6 @@ class Posting extends Component
* Get a unique representation of a file on disk
*
* This can be used in the future to deduplicate images by visual content
*
* @param string $filename
* @param null|string $out_hash
*
* @return bool
*/
public function onHashFile(string $filename, ?string &$out_hash): bool
{
@@ -207,10 +199,6 @@ class Posting extends Component

/**
* Fill the list with allowed sizes for an attachment, to prevent potential DoS'ing by requesting thousands of different thumbnail sizes
*
* @param null|array $sizes
*
* @return bool
*/
public function onGetAllowedThumbnailSizes(?array &$sizes): bool
{


+ 3
- 1
components/Right/Right.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social
//
@@ -29,7 +31,7 @@ class Right extends Component
*
* @param array $styles stylesheets path
*
* @return bool hook value; true means continue processing, false means stop.
* @return bool hook value; true means continue processing, false means stop
*/
public function onEndShowStyles(array &$styles, string $route): bool
{


+ 6
- 6
components/Search/Controller/Search.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -40,14 +42,12 @@ class Search extends Controller
$actor_qb->select('actor')->from('App\Entity\Actor', 'actor');
Event::handle('SeachQueryAddJoins', [&$note_qb, &$actor_qb]);
$notes = $actors = [];
if (!is_null($note_criteria)) {
if (!\is_null($note_criteria)) {
$note_qb->addCriteria($note_criteria);
$notes = $note_qb->getQuery()->execute();
} else {
if (!is_null($actor_criteria)) {
$actor_qb->addCriteria($actor_criteria);
$actors = $actor_qb->getQuery()->execute();
}
} elseif (!\is_null($actor_criteria)) {
$actor_qb->addCriteria($actor_criteria);
$actors = $actor_qb->getQuery()->execute();
}

return [


+ 5
- 3
components/Search/Search.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -23,12 +25,12 @@ namespace Component\Search;

use App\Core\Event;
use App\Core\Form;
use function App\Core\I18n\_m;
use App\Core\Modules\Component;
use App\Util\Exception\RedirectException;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use function App\Core\I18n\_m;

class Search extends Component
{
@@ -44,7 +46,7 @@ class Search extends Component
{
$form = Form::create([
['query', TextType::class, [
'attr' => ['placeholder' => _m('Search tags...')]
'attr' => ['placeholder' => _m('Search tags...')],
]],
[$form_name = 'submit_search', SubmitType::class,
[
@@ -74,7 +76,7 @@ class Search extends Component
*
* @param array $styles stylesheets path
*
* @return bool hook value; true means continue processing, false means stop.
* @return bool hook value; true means continue processing, false means stop
*/
public function onEndShowStyles(array &$styles, string $route): bool
{


+ 9
- 12
components/Search/Util/Parser.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -27,7 +29,6 @@ use Doctrine\Common\Collections\Criteria;

abstract class Parser
{

/**
* Merge $parts into $criteria_arr
*/
@@ -74,21 +75,17 @@ abstract class Parser

foreach (['&', '|', ' '] as $delimiter) {
if ($input[$index] === $delimiter || $end = ($index === $lenght - 1)) {
$term = substr($input, $left, $end ? null : $right - $left);
$term = mb_substr($input, $left, $end ? null : $right - $left);
$note_res = $actor_res = null;
$ret = Event::handle('SearchCreateExpression', [$eb, $term, &$note_res, &$actor_res]);
if ((is_null($note_res) && is_null($actor_res)) || $ret == Event::next) {
if ((\is_null($note_res) && \is_null($actor_res)) || $ret == Event::next) {
throw new ServerException("No one claimed responsibility for a match term: {$term}");
} elseif (!\is_null($note_res)) {
$note_parts[] = $note_res;
} elseif (!\is_null($actor_res)) {
$actor_parts[] = $actor_res;
} else {
if (!is_null($note_res)) {
$note_parts[] = $note_res;
} else {
if (!is_null($actor_res)) {
$actor_parts[] = $actor_res;
} else {
throw new ServerException('Unexpected state in Search parser');
}
}
throw new ServerException('Unexpected state in Search parser');
}

$right = $left = $index + 1;


+ 3
- 1
components/Tag/Controller/Tag.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

namespace Component\Tag\Controller;

use App\Core\Cache;
@@ -19,7 +21,7 @@ class Tag extends Controller
query: 'select n from note n join note_tag nt with n.id = nt.note_id where nt.canonical = :canon order by nt.created DESC, nt.note_id DESC',
query_args: ['canon' => $canonical],
actor: $user,
page: $page
page: $page,
);

return [


+ 8
- 9
components/Tag/Tag.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
@@ -43,13 +45,13 @@ use Doctrine\ORM\QueryBuilder;
*/
class Tag extends Component
{
const MAX_TAG_LENGTH = 64;
const TAG_REGEX = '/(^|\\s)(#[\\pL\\pN_\\-\\.]{1,64})/u'; // Brion Vibber 2011-02-23 v2:classes/Notice.php:367 function saveTags
const TAG_SLUG_REGEX = '[A-Za-z0-9]{1,64}';
public const MAX_TAG_LENGTH = 64;
public const TAG_REGEX = '/(^|\\s)(#[\\pL\\pN_\\-\\.]{1,64})/u'; // Brion Vibber 2011-02-23 v2:classes/Notice.php:367 function saveTags
public const TAG_SLUG_REGEX = '[A-Za-z0-9]{1,64}';

public function onAddRoute($r): bool
{
$r->connect('tag', '/tag/{tag<' . self::TAG_SLUG_REGEX . '>}' , [Controller\Tag::class, 'tag']);
$r->connect('tag', '/tag/{tag<' . self::TAG_SLUG_REGEX . '>}', [Controller\Tag::class, 'tag']);
return Event::next;
}

@@ -60,7 +62,7 @@ class Tag extends Component
{
$matched_tags = [];
$processed_tags = false;
preg_match_all(self::TAG_REGEX, $content, $matched_tags, PREG_SET_ORDER);
preg_match_all(self::TAG_REGEX, $content, $matched_tags, \PREG_SET_ORDER);
foreach ($matched_tags as $match) {
$tag = $match[2];
$canonical_tag = self::canonicalTag($tag);
@@ -87,16 +89,13 @@ class Tag extends Component

public static function canonicalTag(string $tag): string
{
return substr(Formatting::slugify($tag), 0, self::MAX_TAG_LENGTH);
return mb_substr(Formatting::slugify($tag), 0, self::MAX_TAG_LENGTH);
}

/**
* Populate $note_expr with an expression to match a tag, if the term looks like a tag
*
* $term /^(note|tag|people|actor)/ means we want to match only either a note or an actor
*
* @param mixed $note_expr
* @param mixed $actor_expr
*/
public function onSearchCreateExpression(ExpressionBuilder $eb, string $term, &$note_expr, &$actor_expr)
{


+ 27
- 25
config/bootstrap.php View File

@@ -1,17 +1,19 @@
<?php

declare(strict_types = 1);

use App\Core\ModuleManager;
use Symfony\Component\Dotenv\Dotenv;

$loader = require dirname(__DIR__) . '/vendor/autoload.php';
$loader = require \dirname(__DIR__) . '/vendor/autoload.php';

// Load cached env vars if the .env.local.php file exists
// Run "composer dump-env prod" to create it (requires symfony/flex >=1.2)
if (\is_array($env = @include dirname(__DIR__) . '/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) {
if (\is_array($env = @include \dirname(__DIR__) . '/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) {
foreach ($env as $k => $v) {
$_ENV[$k] = $_ENV[$k] ?? (isset($_SERVER[$k]) && 0 !== strpos($k, 'HTTP_') ? $_SERVER[$k] : $v);
$_ENV[$k] = $_ENV[$k] ?? (isset($_SERVER[$k]) && !str_starts_with($k, 'HTTP_') ? $_SERVER[$k] : $v);
}
} elseif (!\class_exists(Dotenv::class)) {
} elseif (!class_exists(Dotenv::class)) {
throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.');
} else {
// load all the .env files
@@ -19,38 +21,38 @@ if (\is_array($env = @include dirname(__DIR__) . '/.env.local.php') && (!isset($
}

$_SERVER += $_ENV;
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
$_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
define('INSTALLDIR', dirname(__DIR__));
define('SRCDIR', INSTALLDIR . '/src');
define('PUBLICDIR', INSTALLDIR . '/public');
define('GNUSOCIAL_ENGINE_NAME', 'GNU social');
$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
$_SERVER['APP_DEBUG'] ??= $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], \FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
\define('INSTALLDIR', \dirname(__DIR__));
\define('SRCDIR', INSTALLDIR . '/src');
\define('PUBLICDIR', INSTALLDIR . '/public');
\define('GNUSOCIAL_ENGINE_NAME', 'GNU social');
// MERGE Change to https://gnu.io/social/
define('GNUSOCIAL_PROJECT_URL', 'https://gnusocial.rocks/');
define('GNUSOCIAL_ENGINE_URL', GNUSOCIAL_PROJECT_URL);
\define('GNUSOCIAL_PROJECT_URL', 'https://gnusocial.rocks/');
\define('GNUSOCIAL_ENGINE_URL', GNUSOCIAL_PROJECT_URL);
// MERGE Change to https://git.gnu.io/gnu/gnu-social
define('GNUSOCIAL_REPOSITORY_URL', 'https://code.undefinedhackers.net/GNUsocial/gnu-social');
\define('GNUSOCIAL_REPOSITORY_URL', 'https://code.undefinedhackers.net/GNUsocial/gnu-social');
// Current base version, major.minor.patch
define('GNUSOCIAL_BASE_VERSION', '3.0.0');
\define('GNUSOCIAL_BASE_VERSION', '3.0.0');
// 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
define('GNUSOCIAL_LIFECYCLE', 'dev');
define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE);
define('GNUSOCIAL_CODENAME', 'Big bang');
\define('GNUSOCIAL_LIFECYCLE', 'dev');
\define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE);
\define('GNUSOCIAL_CODENAME', 'Big bang');

define('MODULE_CACHE_FILE', INSTALLDIR . '/var/cache/module_manager.php');
\define('MODULE_CACHE_FILE', INSTALLDIR . '/var/cache/module_manager.php');

/**
* StatusNet had this string as valid path characters: '\pN\pL\,\!\(\)\.\:\-\_\+\/\=\&\;\%\~\*\$\'\@'
* Some of those characters can be troublesome when auto-linking plain text. Such as "http://some.com/)"
* URL encoding should be used whenever a weird character is used, the following strings are not definitive.
*/
define('URL_REGEX_VALID_PATH_CHARS', '\pN\pL\,\!\.\:\-\_\+\/\@\=\;\%\~\*\(\)');
define('URL_REGEX_VALID_QSTRING_CHARS', URL_REGEX_VALID_PATH_CHARS . '\&');
define('URL_REGEX_VALID_FRAGMENT_CHARS', URL_REGEX_VALID_QSTRING_CHARS . '\?\#');
define('URL_REGEX_EXCLUDED_END_CHARS', '\?\.\,\!\#\:\''); // don't include these if they are directly after a URL
define('URL_REGEX_DOMAIN_NAME', '(?:(?!-)[A-Za-z0-9\-]{1,63}(?<!-)\.)+[A-Za-z]{2,10}');
\define('URL_REGEX_VALID_PATH_CHARS', '\pN\pL\,\!\.\:\-\_\+\/\@\=\;\%\~\*\(\)');
\define('URL_REGEX_VALID_QSTRING_CHARS', URL_REGEX_VALID_PATH_CHARS . '\&');
\define('URL_REGEX_VALID_FRAGMENT_CHARS', URL_REGEX_VALID_QSTRING_CHARS . '\?\#');
\define('URL_REGEX_EXCLUDED_END_CHARS', '\?\.\,\!\#\:\''); // don't include these if they are directly after a URL
\define('URL_REGEX_DOMAIN_NAME', '(?:(?!-)[A-Za-z0-9\-]{1,63}(?<!-)\.)+[A-Za-z]{2,10}');

// Work internally in UTC
date_default_timezone_set('UTC');


+ 2
- 0
config/bundles.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

return [
Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],
Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],


+ 2
- 0
config/cli-config.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

require_once 'bootstrap.php';

use App\Kernel;


+ 2
- 0
config/phpstan-bootstrap.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

require_once 'bootstrap.php';

use App\Kernel;


+ 4
- 2
config/preload.php View File

@@ -1,5 +1,7 @@
<?php

if (file_exists(dirname(__DIR__) . '/var/cache/prod/App_KernelProdContainer.preload.php')) {
require dirname(__DIR__) . '/var/cache/prod/App_KernelProdContainer.preload.php';
declare(strict_types = 1);

if (file_exists(\dirname(__DIR__) . '/var/cache/prod/App_KernelProdContainer.preload.php')) {
require \dirname(__DIR__) . '/var/cache/prod/App_KernelProdContainer.preload.php';
}

+ 2
- 0
config/routes.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;

return function (RoutingConfigurator $routes) {


+ 209
- 218
extlib/Validate.php View File

@@ -1,4 +1,6 @@
<?php

declare(strict_types = 1);
/**
* Validation class
*
@@ -27,35 +29,38 @@
*
* @category Validate
* @package Validate
*
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Pierre-Alain Joye <pajoye@php.net>
* @author Amir Mohammad Saied <amir@php.net>
* @copyright 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*
* @version CVS: $Id$
* @link http://pear.php.net/package/Validate
*
* @see http://pear.php.net/package/Validate
*/

// {{{ Constants
/**
* Methods for common data validations
*/
define('VALIDATE_NUM', '0-9');
define('VALIDATE_SPACE', '\s');
define('VALIDATE_ALPHA_LOWER', 'a-z');
define('VALIDATE_ALPHA_UPPER', 'A-Z');
define('VALIDATE_ALPHA', VALIDATE_ALPHA_LOWER . VALIDATE_ALPHA_UPPER);
define('VALIDATE_EALPHA_LOWER', VALIDATE_ALPHA_LOWER . 'áéíóúýàèìòùäëïöüÿâêîôûãñõ¨åæç½ðøþß');
define('VALIDATE_EALPHA_UPPER', VALIDATE_ALPHA_UPPER . 'ÁÉÍÓÚÝÀÈÌÒÙÄËÏÖܾÂÊÎÔÛÃÑÕ¦ÅÆǼÐØÞ');
define('VALIDATE_EALPHA', VALIDATE_EALPHA_LOWER . VALIDATE_EALPHA_UPPER);
define('VALIDATE_PUNCTUATION', VALIDATE_SPACE . '\.,;\:&"\'\?\!\(\)');
define('VALIDATE_NAME', VALIDATE_EALPHA . VALIDATE_SPACE . "'" . '\-');
define('VALIDATE_STREET', VALIDATE_NUM . VALIDATE_NAME . "/\\ºª\.");
define('VALIDATE_ITLD_EMAILS', 1);
define('VALIDATE_GTLD_EMAILS', 2);
define('VALIDATE_CCTLD_EMAILS', 4);
define('VALIDATE_ALL_EMAILS', 8);
\define('VALIDATE_NUM', '0-9');
\define('VALIDATE_SPACE', '\s');
\define('VALIDATE_ALPHA_LOWER', 'a-z');
\define('VALIDATE_ALPHA_UPPER', 'A-Z');
\define('VALIDATE_ALPHA', VALIDATE_ALPHA_LOWER . VALIDATE_ALPHA_UPPER);
\define('VALIDATE_EALPHA_LOWER', VALIDATE_ALPHA_LOWER . 'áéíóúýàèìòùäëïöüÿâêîôûãñõ¨åæç½ðøþß');
\define('VALIDATE_EALPHA_UPPER', VALIDATE_ALPHA_UPPER . 'ÁÉÍÓÚÝÀÈÌÒÙÄËÏÖܾÂÊÎÔÛÃÑÕ¦ÅÆǼÐØÞ');
\define('VALIDATE_EALPHA', VALIDATE_EALPHA_LOWER . VALIDATE_EALPHA_UPPER);
\define('VALIDATE_PUNCTUATION', VALIDATE_SPACE . '\.,;\:&"\'\?\!\(\)');
\define('VALIDATE_NAME', VALIDATE_EALPHA . VALIDATE_SPACE . "'" . '\-');
\define('VALIDATE_STREET', VALIDATE_NUM . VALIDATE_NAME . '/\\ºª\\.');
\define('VALIDATE_ITLD_EMAILS', 1);
\define('VALIDATE_GTLD_EMAILS', 2);
\define('VALIDATE_CCTLD_EMAILS', 4);
\define('VALIDATE_ALL_EMAILS', 8);
// }}}

/**
@@ -71,14 +76,17 @@ define('VALIDATE_ALL_EMAILS', 8);
*
* @category Validate
* @package Validate
*
* @author Tomas V.V.Cox <cox@idecnet.com>
* @author Pierre-Alain Joye <pajoye@php.net>
* @author Amir Mohammad Saied <amir@php.net>
* @author Diogo Cordeiro <diogo@fc.up.pt>
* @copyright 1997-2006 Pierre-Alain Joye,Tomas V.V.Cox,Amir Mohammad Saied
* @license http://www.opensource.org/licenses/bsd-license.php New BSD License
*
* @version Release: @package_version@
* @link http://pear.php.net/package/Validate
*
* @see http://pear.php.net/package/Validate
*/
class Validate
{
@@ -91,7 +99,7 @@ class Validate
*
* @var array $itld (International top-level domains)
*/
protected static $itld = [
protected static array $itld = [
'arpa',
'root',
];
@@ -104,7 +112,7 @@ class Validate
*
* @var array $gtld (Generic top-level domains)
*/
protected static $gtld = [
protected static array $gtld = [
'aero',
'biz',
'cat',
@@ -137,7 +145,7 @@ class Validate
*
* @var array $cctld (Country Code Top-Level Domain)
*/
protected static $cctld = [
protected static array $cctld = [
'ac',
'ad', 'ae', 'af', 'ag',
'ai', 'al', 'am', 'an',
@@ -210,10 +218,9 @@ class Validate
*
* @param string $uri tag URI to validate
*
* @return bool true if valid tag URI, false if not
*
* @access private
* @throws Exception
*
* @return bool true if valid tag URI, false if not
*/
private static function uriRFC4151(string $uri): bool
{
@@ -221,15 +228,15 @@ class Validate
if (preg_match(
'/^tag:(?<name>.*),(?<date>\d{4}-?\d{0,2}-?\d{0,2}):(?<specific>.*)(.*:)*$/',
$uri,
$matches
$matches,
)) {
$date = $matches['date'];
$date = $matches['date'];
$date6 = strtotime($date);
if ((strlen($date) == 4) && $date <= date('Y')) {
if ((mb_strlen($date) == 4) && $date <= date('Y')) {
$datevalid = true;
} elseif ((strlen($date) == 7) && ($date6 < strtotime("now"))) {
} elseif ((mb_strlen($date) == 7) && ($date6 < strtotime('now'))) {
$datevalid = true;
} elseif ((strlen($date) == 10) && ($date6 < strtotime("now"))) {
} elseif ((mb_strlen($date) == 10) && ($date6 < strtotime('now'))) {
$datevalid = true;
}
if (self::email($matches['name'])) {
@@ -246,28 +253,28 @@ class Validate
/**
* Validate a number
*
* @param string $number Number to validate
* @param array $options array where:
* 'decimal' is the decimal char or false when decimal
* not allowed.
* i.e. ',.' to allow both ',' and '.'
* 'dec_prec' Number of allowed decimals
* 'min' minimum value
* 'max' maximum value
* @param string $number Number to validate
* @param array $options array where:
* 'decimal' is the decimal char or false when decimal
* not allowed.
* i.e. ',.' to allow both ',' and '.'
* 'dec_prec' Number of allowed decimals
* 'min' minimum value
* 'max' maximum value
*
* @return bool true if valid number, false if not
*/
public static function number($number, array $options = []): bool
public static function number(string $number, array $options = []): bool
{
$decimal = $dec_prec = $min = $max = null;
if (is_array($options)) {
if (\is_array($options)) {
extract($options);
}

$dec_prec = $dec_prec ? "{1,$dec_prec}" : '+';
$dec_regex = $decimal ? "[$decimal][0-9]$dec_prec" : '';
$dec_prec = $dec_prec ? "{1,{$dec_prec}}" : '+';
$dec_regex = $decimal ? "[{$decimal}][0-9]{$dec_prec}" : '';

if (!preg_match("|^[-+]?\s*[0-9]+($dec_regex)?\$|", $number)) {
if (!preg_match("|^[-+]?\\s*[0-9]+({$dec_regex})?\$|", $number)) {
return false;
}

@@ -275,15 +282,12 @@ class Validate
$number = strtr($number, $decimal, '.');
}

$number = (float)str_replace(' ', '', $number);
$number = (float) str_replace(' ', '', $number);
if ($min !== null && $min > $number) {
return false;
}

if ($max !== null && $max < $number) {
return false;
}
return true;
return !($max !== null && $max < $number);
}

/**
@@ -291,29 +295,28 @@ class Validate
*
* @param string $string string to be converted
*
* @return string converted string
* @return string converted string
*/
private static function stringToUtf7(string $string): string
{
$return = '';
$utf7 = [
$utf7 = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2',
'3', '4', '5', '6', '7', '8', '9', '+', ','
'3', '4', '5', '6', '7', '8', '9', '+', ',',
];


$state = 0;

if (!empty($string)) {
$i = 0;
while ($i <= strlen($string)) {
$char = substr($string, $i, 1);
while ($i <= mb_strlen($string)) {
$char = mb_substr($string, $i, 1);
if ($state == 0) {
if ((ord($char) >= 0x7F) || (ord($char) <= 0x1F)) {
if ((\ord($char) >= 0x7F) || (\ord($char) <= 0x1F)) {
if ($char) {
$return .= '&';
}
@@ -323,13 +326,13 @@ class Validate
} else {
$return .= $char;
}
} elseif (($i == strlen($string) ||
!((ord($char) >= 0x7F)) || (ord($char) <= 0x1F))) {
} elseif (($i == mb_strlen($string)
|| !((\ord($char) >= 0x7F)) || (\ord($char) <= 0x1F))) {
if ($state != 1) {
if (ord($char) > 64) {
if (\ord($char) > 64) {
$return .= '';
} else {
$return .= $utf7[ord($char)];
$return .= $utf7[\ord($char)];
}
}
$return .= '-';
@@ -337,23 +340,23 @@ class Validate
} else {
switch ($state) {
case 1:
$return .= $utf7[ord($char) >> 2];
$residue = (ord($char) & 0x03) << 4;
$state = 2;
$return .= $utf7[\ord($char) >> 2];
$residue = (\ord($char) & 0x03) << 4;
$state = 2;
break;
case 2:
$return .= $utf7[$residue | (ord($char) >> 4)];
$residue = (ord($char) & 0x0F) << 2;
$state = 3;
$return .= $utf7[$residue | (\ord($char) >> 4)];
$residue = (\ord($char) & 0x0F) << 2;
$state = 3;
break;
case 3:
$return .= $utf7[$residue | (ord($char) >> 6)];
$return .= $utf7[ord($char) & 0x3F];
$return .= $utf7[$residue | (\ord($char) >> 6)];
$return .= $utf7[\ord($char) & 0x3F];
$state = 1;
break;
}
}
$i++;
++$i;
}
return $return;
}
@@ -363,15 +366,15 @@ class Validate
/**
* Validate an email according to full RFC822 (inclusive human readable part)
*
* @param string $email email to validate,
* @param string $email email to validate,
* will return the address for optional dns validation
* @param array $options email() options
* @param array $options email() options
*
* @return bool true if valid email, false if not
*/
private static function emailRFC822(string &$email, array &$options): bool
{
static $address = null;
static $address = null;
static $uncomment = null;
if (!$address) {
// atom = 1*<any CHAR except specials, SPACE and CTLs>
@@ -416,9 +419,9 @@ class Validate
// / group ; named list
$address = '/^\s*(?:' . $mailbox . '|' . $group . ')$/';

$uncomment =
'/((?:(?:\\\\"|[^("])*(?:' . $quoted_string .
')?)*)((?<!\\\\)\((?:(?2)|.)*?(?<!\\\\)\))/';
$uncomment
= '/((?:(?:\\\\"|[^("])*(?:' . $quoted_string
. ')?)*)((?<!\\\\)\((?:(?2)|.)*?(?<!\\\\)\))/';
}
// strip comments
$email = preg_replace($uncomment, '$1 ', $email);
@@ -431,27 +434,27 @@ class Validate
* This function is used to make a much more proficient validation
* against all types of official domain names.
*
* @param string $email The email address to check.
* @param array $options The options for validation
* @param string $email the email address to check
* @param array $options The options for validation
*
* @return bool True if validating succeeds
*/
protected static function fullTLDValidation(
string $email,
array $options
array $options,
): bool {
$validate = [];
if (!empty($options["VALIDATE_ITLD_EMAILS"])) {
array_push($validate, 'itld');
if (!empty($options['VALIDATE_ITLD_EMAILS'])) {
$validate[] = 'itld';
}
if (!empty($options["VALIDATE_GTLD_EMAILS"])) {
array_push($validate, 'gtld');
if (!empty($options['VALIDATE_GTLD_EMAILS'])) {
$validate[] = 'gtld';
}
if (!empty($options["VALIDATE_CCTLD_EMAILS"])) {
array_push($validate, 'cctld');
if (!empty($options['VALIDATE_CCTLD_EMAILS'])) {
$validate[] = 'cctld';
}

if (count($validate) === 0) {
if (\count($validate) === 0) {
array_push($validate, 'itld', 'gtld', 'cctld');
}

@@ -460,7 +463,7 @@ class Validate
foreach ($validate as $valid) {
$tmpVar = (string) $valid;

$toValidate[$valid] = self::$$tmpVar;
$toValidate[$valid] = self::${$tmpVar};
}

$e = self::executeFullEmailValidation($email, $toValidate);
@@ -474,19 +477,19 @@ class Validate
* This function will execute the full email vs tld
* validation using an array of tlds passed to it.
*
* @param string $email The email to validate.
* @param array $arrayOfTLDs The array of the TLDs to validate
* @param string $email the email to validate
* @param array $arrayOfTLDs The array of the TLDs to validate
*
* @return bool true or false (Depending on if it validates or if it does not)
*/
public static function executeFullEmailValidation(
string $email,
array $arrayOfTLDs
array $arrayOfTLDs,
): bool {
$emailEnding = explode('.', $email);
$emailEnding = $emailEnding[count($emailEnding) - 1];
$emailEnding = $emailEnding[\count($emailEnding) - 1];
foreach ($arrayOfTLDs as $validator => $keys) {
if (in_array($emailEnding, $keys)) {
if (\in_array($emailEnding, $keys)) {
return true;
}
}
@@ -511,18 +514,19 @@ class Validate
* 'VALIDATE_CCTLD_EMAILS' => 'true',
* 'VALIDATE_ITLD_EMAILS' => 'true',
* ];
*
* @return bool true if valid email, false if not
* @param null|mixed $options
*
* @throws Exception
*
* @return bool true if valid email, false if not
*/
public static function email(string $email, $options = null): bool
{
$check_domain = false;
$use_rfc822 = false;
if (is_bool($options)) {
$use_rfc822 = false;
if (\is_bool($options)) {
$check_domain = $options;
} elseif (is_array($options)) {
} elseif (\is_array($options)) {
extract($options);
}

@@ -538,20 +542,20 @@ class Validate
}

if ($hasIDNA === true) {
if (strpos($email, '@') !== false) {
if (str_contains($email, '@')) {
$tmpEmail = explode('@', $email);
$domain = array_pop($tmpEmail);
$domain = array_pop($tmpEmail);

// Check if the domain contains characters > 127 which means
// it's an idn domain name.
$chars = count_chars($domain, 1);
if (!empty($chars) && max(array_keys($chars)) > 127) {
$idna =& Net_IDNA2::singleton();
$idna = &Net_IDNA2::singleton();
$domain = $idna->encode($domain);
}

array_push($tmpEmail, $domain);
$email = implode('@', $tmpEmail);
$tmpEmail[] = $domain;
$email = implode('@', $tmpEmail);
}
}

@@ -580,14 +584,11 @@ class Validate
$&xi';

//checks if exists the domain (MX or A)
if ($use_rfc822 ? self::emailRFC822($email, $options) :
preg_match($regex, $email)) {
if ($check_domain && function_exists('checkdnsrr')) {
if ($use_rfc822 ? self::emailRFC822($email, $options)
: preg_match($regex, $email)) {
if ($check_domain && \function_exists('checkdnsrr')) {
$domain = preg_replace('/[^-a-z.0-9]/i', '', array_pop(explode('@', $email)));
if (checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A')) {
return true;
}
return false;
return (bool) (checkdnsrr($domain, 'MX') || checkdnsrr($domain, 'A'));
}
return true;
}
@@ -597,38 +598,34 @@ class Validate
/**
* Validate a string using the given format 'format'
*
* @param string $string String to validate
* @param string $string String to validate
* @param array|string $options Options array where:
* 'format' is the format of the string
* 'format' is the format of the string
* Ex:VALIDATE_NUM . VALIDATE_ALPHA (see constants)
* 'min_length' minimum length
* 'max_length' maximum length
* 'min_length' minimum length
* 'max_length' maximum length
*
* @return bool true if valid string, false if not
*/
public static function string(string $string, $options): bool
{
$format = null;
$format = null;
$min_length = 0;
$max_length = 0;

if (is_array($options)) {
if (\is_array($options)) {
extract($options);
}

if ($format && !preg_match("|^[$format]*\$|s", $string)) {
if ($format && !preg_match("|^[{$format}]*\$|s", $string)) {
return false;
}

if ($min_length && strlen($string) < $min_length) {
if ($min_length && mb_strlen($string) < $min_length) {
return false;
}

if ($max_length && strlen($string) > $max_length) {
return false;
}

return true;
return !($max_length && mb_strlen($string) > $max_length);
}

/**
@@ -651,35 +648,35 @@ class Validate
* the characters ';/?:@$,' will not be accepted in the query part
* if not urlencoded, refer to the option "strict'"
*
* @param string $url URI to validate
* @param array|null $options Options used by the validation method.
* key => type
* 'domain_check' => boolean
* Whether to check the DNS entry or not
* 'allowed_schemes' => array, list of protocols
* List of allowed schemes ('http',
* 'ssh+svn', 'mms')
* 'strict' => string the refused chars
* in query and fragment parts
* default: ';/?:@$,'
* empty: accept all rfc2396 foreseen chars
*
* @return bool true if valid uri, false if not
* @param string $url URI to validate
* @param null|array $options Options used by the validation method.
* key => type
* 'domain_check' => boolean
* Whether to check the DNS entry or not
* 'allowed_schemes' => array, list of protocols
* List of allowed schemes ('http',
* 'ssh+svn', 'mms')
* 'strict' => string the refused chars
* in query and fragment parts
* default: ';/?:@$,'
* empty: accept all rfc2396 foreseen chars
*
* @throws Exception
*
* @return bool true if valid uri, false if not
*/
public static function uri(string $url, ?array $options = null): bool
{
$strict = ';/?:@$,';
$domain_check = false;
$strict = ';/?:@$,';
$domain_check = false;
$allowed_schemes = null;
if (is_array($options)) {
if (\is_array($options)) {
extract($options);
}
if (is_array($allowed_schemes) &&
in_array("tag", $allowed_schemes)
if (\is_array($allowed_schemes)
&& \in_array('tag', $allowed_schemes)
) {
if (strpos($url, "tag:") === 0) {
if (str_starts_with($url, 'tag:')) {
return self::uriRFC4151($url);
}
}
@@ -696,12 +693,12 @@ class Validate
(?:\#((?:%[0-9a-f]{2}|[-a-z0-9_.!~*\'();/?:@\&=+$,])*))? # 8. fragment
$&xi',
$url,
$matches
$matches,
)) {
$scheme = isset($matches[1]) ? $matches[1] : '';
$authority = isset($matches[3]) ? $matches[3] : '';
if (is_array($allowed_schemes) &&
!in_array($scheme, $allowed_schemes)
$scheme = $matches[1] ?? '';
$authority = $matches[3] ?? '';
if (\is_array($allowed_schemes)
&& !\in_array($scheme, $allowed_schemes)
) {
return false;
}
@@ -712,7 +709,7 @@ class Validate
return false;
}
}
} elseif ($domain_check && function_exists('checkdnsrr')) {
} elseif ($domain_check && \function_exists('checkdnsrr')) {
if (!checkdnsrr($authority, 'A')) {
return false;
}
@@ -732,65 +729,63 @@ class Validate
/**
* Substr
*
* @param string &$date Date
* @param string $num Length
* @param string|false $opt Unknown
*
* @return string
* @param string &$date Date
* @param string $num Length
* @param false|string $opt Unknown
*/
private static function substr(
string &$date,
string $num,
$opt = false
$opt = false,
): string {
if (
$opt
&& strlen($date) >= $opt
&& mb_strlen($date) >= $opt
&& preg_match('/^[0-9]{' . $opt . '}/', $date, $m)
) {
$ret = $m[0];
} else {
$ret = substr($date, 0, $num);
$ret = mb_substr($date, 0, $num);
}
$date = substr($date, strlen($ret));
$date = mb_substr($date, mb_strlen($ret));
return $ret;
}

protected static function modf($val, $div)
{
if (function_exists('bcmod')) {
if (\function_exists('bcmod')) {
return bcmod($val, $div);
} elseif (function_exists('fmod')) {
} elseif (\function_exists('fmod')) {
return fmod($val, $div);
}
$r = $val / $div;
$i = intval($r);
return intval($val - $i * $div + .1);
$i = (int) $r;
return (int) ($val - $i * $div + .1);
}

/**
* Calculates sum of product of number digits with weights
*
* @param string $number number string
* @param array $weights reference to array of weights
* @param string $number number string
* @param array $weights reference to array of weights
*
* @return int returns product of number digits with weights
*/
protected static function multWeights(
string $number,
array &$weights
array &$weights,
): int {
if (!is_array($weights)) {
if (!\is_array($weights)) {
return -1;
}
$sum = 0;

$count = min(count($weights), strlen($number));
$count = min(\count($weights), mb_strlen($number));
if ($count == 0) { // empty string or weights array
return -1;
}
for ($i = 0; $i < $count; ++$i) {
$sum += intval(substr($number, $i, 1)) * $weights[$i];
$sum += (int) (mb_substr($number, $i, 1)) * $weights[$i];
}

return $sum;
@@ -799,20 +794,20 @@ class Validate
/**
* Calculates control digit for a given number
*
* @param string $number number string
* @param array $weights reference to array of weights
* @param int $modulo (optionsl) number
* @param int $subtract (optional) number
* @param bool $allow_high (optional) true if function can return number higher than 10
* @param string $number number string
* @param array $weights reference to array of weights
* @param int $modulo (optionsl) number
* @param int $subtract (optional) number
* @param bool $allow_high (optional) true if function can return number higher than 10
*
* @return int -1 calculated control number is returned
* @return int -1 calculated control number is returned
*/
protected static function getControlNumber(
string $number,
array &$weights,
int $modulo = 10,
int $subtract = 0,
bool $allow_high = false
bool $allow_high = false,
): int {
// calc sum
$sum = self::multWeights($number, $weights);
@@ -833,30 +828,29 @@ class Validate
/**
* Validates a number
*
* @param string $number number to validate
* @param array $weights reference to array of weights
* @param int $modulo (optional) number
* @param int $subtract (optional) number
* @param string $number number to validate
* @param array $weights reference to array of weights
* @param int $modulo (optional) number
* @param int $subtract (optional) number
*
* @return bool true if valid, false if not
* @return bool true if valid, false if not
*/
protected static function checkControlNumber(
string $number,
array &$weights,
int $modulo = 10,
int $subtract = 0
): bool
{
if (strlen($number) < count($weights)) {
int $subtract = 0,
): bool {
if (mb_strlen($number) < \count($weights)) {
return false;
}
$target_digit = substr($number, count($weights), 1);
$target_digit = mb_substr($number, \count($weights), 1);
$control_digit = self::getControlNumber(
$number,
$weights,
$modulo,
$subtract,
($modulo > 10)
($modulo > 10),
);

if ($control_digit == -1) {
@@ -865,10 +859,7 @@ class Validate
if ($target_digit === 'X' && $control_digit == 10) {
return true;
}
if ($control_digit != $target_digit) {
return false;
}
return true;
return !($control_digit != $target_digit);
}

/**
@@ -876,22 +867,22 @@ class Validate
* assoc array in the form $var_name => $value.
* Can be used on any of Validate subpackages
*
* @param array $data Ex: ['name' => 'toto', 'email' => 'toto@thing.info'];
* @param array $data Ex: ['name' => 'toto', 'email' => 'toto@thing.info'];
* @param array $val_type Contains the validation type and all parameters used in.
* 'val_type' is not optional
* others validations properties must have the same name as the function
* parameters.
* Ex: ['toto' => ['type'=>'string','format'='toto@thing.info','min_length'=>5]];
* @param bool $remove if set, the elements not listed in data will be removed
* 'val_type' is not optional
* others validations properties must have the same name as the function
* parameters.
* Ex: ['toto' => ['type'=>'string','format'='toto@thing.info','min_length'=>5]];
* @param bool $remove if set, the elements not listed in data will be removed
*
* @return array value name => true|false the value name comes from the data key
* @return array value name => true|false the value name comes from the data key
*/
public static function multiple(
array &$data,
array &$val_type,
bool $remove = false
bool $remove = false,
): array {
$keys = array_keys($data);
$keys = array_keys($data);
$valid = [];

foreach ($keys as $var_name) {
@@ -901,45 +892,45 @@ class Validate
}
continue;
}
$opt = $val_type[$var_name];
$methods = get_class_methods('Validate');
$opt = $val_type[$var_name];
$methods = get_class_methods('Validate');
$val2check = $data[$var_name];
// core validation method
if (in_array(strtolower($opt['type']), $methods)) {
if (\in_array(mb_strtolower($opt['type']), $methods)) {
//$opt[$opt['type']] = $data[$var_name];
$method = $opt['type'];
unset($opt['type']);

if (sizeof($opt) == 1 && is_array(reset($opt))) {
if (sizeof($opt) == 1 && \is_array(reset($opt))) {
$opt = array_pop($opt);
}
$valid[$var_name] = call_user_func(['Validate', $method], $val2check, $opt);
$valid[$var_name] = \call_user_func(['Validate', $method], $val2check, $opt);

/**
* external validation method in the form:
* "<class name><underscore><method name>"
* Ex: us_ssn will include class Validate/US.php and call method ssn()
*/
} elseif (strpos($opt['type'], '_') !== false) {
} elseif (str_contains($opt['type'], '_')) {
$validateType = explode('_', $opt['type']);
$method = array_pop($validateType);
$class = implode('_', $validateType);
$classPath = str_replace('_', DIRECTORY_SEPARATOR, $class);
$class = 'Validate_' . $class;
$method = array_pop($validateType);
$class = implode('_', $validateType);
$classPath = str_replace('_', \DIRECTORY_SEPARATOR, $class);
$class = 'Validate_' . $class;
if (self::includePathFileExists("Validate/{$classPath}.php")) {
include_once "Validate/{$classPath}.php";
} else {
trigger_error("$class isn't installed or you may have some permission issues", E_USER_ERROR);
trigger_error("{$class} isn't installed or you may have some permission issues", \E_USER_ERROR);
}

$ce = substr(phpversion(), 0, 1) > 4 ?
class_exists($class, false) : class_exists($class);
if (!$ce ||
!in_array($method, get_class_methods($class))
$ce = mb_substr(phpversion(), 0, 1) > 4
? class_exists($class, false) : class_exists($class);
if (!$ce
|| !\in_array($method, get_class_methods($class))
) {
trigger_error(
"Invalid validation type $class::$method",
E_USER_WARNING
"Invalid validation type {$class}::{$method}",
\E_USER_WARNING,
);
continue;
}
@@ -947,15 +938,15 @@ class Validate
if (sizeof($opt) == 1) {
$opt = array_pop($opt);
}
$valid[$var_name] = call_user_func(
array($class, $method),
$valid[$var_name] = \call_user_func(
[$class, $method],
$data[$var_name],
$opt
$opt,
);
} else {
trigger_error(
"Invalid validation type {$opt['type']}",
E_USER_WARNING
\E_USER_WARNING,
);
}
}
@@ -971,11 +962,11 @@ class Validate
*/
private static function includePathFileExists(string $filename): bool
{
$paths = explode(":", ini_get("include_path"));
$paths = explode(':', ini_get('include_path'));
$result = false;

foreach ($paths as $val) {
$result = file_exists($val . "/" . $filename);
$result = file_exists($val . '/' . $filename);
if ($result) {
break;
}


+ 15
- 28
plugins/ActivityPub/ActivityPub.php View File

@@ -1,5 +1,7 @@
<?php

declare(strict_types = 1);

namespace Plugin\ActivityPub;

use App\Core\Event;
@@ -23,9 +25,7 @@ class ActivityPub extends Plugin
* This code executes when GNU social creates the page routing, and we hook
* on this event to add our Inbox and Outbox handler for ActivityPub.
*
* @param RouteLoader $r the router that was initialized.
*
* @return bool
* @param RouteLoader $r the router that was initialized
*/
public function onAddRoute(RouteLoader $r): bool
{
@@ -33,19 +33,19 @@ class ActivityPub extends Plugin
'activitypub_actor_inbox',
'/actor/{gsactor_id<\d+>}/inbox.json',
[Inbox::class, 'handle'],
options: ['accept' => self::$accept_headers]
options: ['accept' => self::$accept_headers],
);
$r->connect(
'activitypub_actor_outbox',
'/actor/{gsactor_id<\d+>}/outbox.json',
[Inbox::class, 'handle'],
options: ['accept' => self::$accept_headers]
options: ['accept' => self::$accept_headers],
);
$r->connect(
'activitypub_inbox',
'/inbox.json',
[Inbox::class, 'handle'],
options: ['accept' => self::$accept_headers]
options: ['accept' => self::$accept_headers],
);
return Event::next;
}
@@ -53,23 +53,19 @@ class ActivityPub extends Plugin
/**
* Validate HTTP Accept headers
*
* @param null|array|string $accept
* @param bool $strict Strict mode
* @param bool $strict Strict mode
*
* @throws Exception when strict mode enabled
*
* @return bool
*
*/
public static function validateAcceptHeader(array|string|null $accept, bool $strict): bool
{
if (is_string($accept)
&& in_array($accept, self::$accept_headers)
if (\is_string($accept)
&& \in_array($accept, self::$accept_headers)
) {
return true;
} elseif (is_array($accept)
&& count(
array_intersect($accept, self::$accept_headers)
} elseif (\is_array($accept)
&& \count(
array_intersect($accept, self::$accept_headers),
) > 0