Compare commits

..

28 commits
4.1.4 ... 4.2

Author SHA1 Message Date
chevereto
ed56a10e50 Automatic push 4.2.4 2024-12-05 13:33:13 +00:00
Rodolfo Berrios
ecf4742588
update screen 2024-11-27 18:24:25 -03:00
Rodolfo Berrios
0426ff90c1
Update README.md
edition compare
2024-11-27 18:17:38 -03:00
Rodolfo Berrios
62bee30a42
Add requirements
close #94
2024-11-27 18:13:17 -03:00
Rodolfo Berrios
a6d8888af6
Update README.md 2024-11-24 08:32:03 -03:00
chevereto
ebd7cd081c Automatic push 4.2.3 2024-11-18 22:22:00 +00:00
chevereto
0ad52d80f1 Automatic push 4.2.3 2024-11-18 12:51:08 +00:00
Rodolfo Berrios
7c29ba0424
Merge pull request #89 from antropolouco/patch-5 2024-11-17 17:36:27 -03:00
Thiago Cavalcanti
9cf7d71085
Update pt-BR.po
More updates to Brazilian Portuguese translation, making it more fluid and natural for native speakers. More than 50% of the file was reviewed at this point (work in progress).
2024-11-14 15:36:43 -03:00
Rodolfo Berrios
0cca40399b
Merge pull request #87 from antropolouco/patch-2
Update pt.po
2024-11-14 12:11:43 -03:00
Rodolfo Berrios
e46e23c920
Merge pull request #86 from antropolouco/patch-3
Update pt-BR.po
2024-11-14 12:11:09 -03:00
Thiago Cavalcanti
46746ae763
Update pt-BR.po
Improving Brazilian Portuguese translation. Found mistakes related to proper reference to past time (we should never use "a", but "há" when it comes to time, and never append "atrás" to "há", for example), and "adicionar" (the act of adding) instead of "adicionado" (which means added).
2024-11-14 11:55:43 -03:00
Thiago Cavalcanti
68a1e3da5a
Update pt.po
Improving Portuguese translation. Mistakes related to proper reference to past time, same as the commit for pt-BR.po.
2024-11-14 11:52:38 -03:00
chevereto
6fbd5e2d84 Automatic push 4.2.2 2024-11-07 18:49:03 +00:00
Rodolfo Berrios
55a98d0286
sql update chevereto_version_installed 2024-11-07 11:07:41 -03:00
Rodolfo Berrios
d13ad37f0c
prevent session_start false positive 2024-11-07 10:22:59 -03:00
Rodolfo Berrios
31b37b7574
close #85 2024-11-05 17:11:47 -03:00
chevereto
03f09cff1a Automatic push 4.2.1 2024-11-04 15:00:36 +00:00
chevereto
edc9a5cb09 Automatic push 4.2.1 2024-11-04 12:38:10 +00:00
chevereto
e658c086e0 Automatic push 4.2.1 2024-11-04 12:10:06 +00:00
Rodolfo Berrios
53449a3f57
missing files/code 2024-10-28 11:02:01 -03:00
Rodolfo Berrios
f9071bce3d
mysql support for tags 2024-10-28 11:01:12 -03:00
Rodolfo Berrios
651c863cc2
missing file 2024-10-25 17:59:15 -03:00
Rodolfo Berrios
7d8571c680
Update README.md 2024-10-24 21:21:16 -03:00
chevereto
05318e7545 Automatic push 4.2.0 2024-10-24 14:11:04 +00:00
Rodolfo Berrios
4e796d821a
drop pos to nic 2024-10-14 11:04:39 -03:00
Rodolfo Berrios
fb5ef97461
close #71 2024-09-26 11:13:04 -03:00
Rodolfo Berrios
ee8ee19862
Update README.md 2024-09-26 11:07:07 -03:00
353 changed files with 51378 additions and 32300 deletions

View file

@ -1,9 +1,9 @@
<?php
/*
* This file is part of Chevere.
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevere.org>
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@ -11,202 +11,113 @@
declare(strict_types=1);
use PhpCsFixer\Fixer\Alias\NoAliasFunctionsFixer;
use PhpCsFixer\Fixer\Alias\NoAliasLanguageConstructCallFixer;
use PhpCsFixer\Fixer\Alias\NoMixedEchoPrintFixer;
use PhpCsFixer\Fixer\ArrayNotation\ArraySyntaxFixer;
use PhpCsFixer\Fixer\ArrayNotation\NoWhitespaceBeforeCommaInArrayFixer;
use PhpCsFixer\Fixer\ArrayNotation\WhitespaceAfterCommaInArrayFixer;
use PhpCsFixer\Fixer\Basic\BracesFixer;
use PhpCsFixer\Fixer\Basic\EncodingFixer;
use PhpCsFixer\Fixer\Casing\ConstantCaseFixer;
use PhpCsFixer\Fixer\Casing\LowercaseKeywordsFixer;
use PhpCsFixer\Fixer\CastNotation\LowercaseCastFixer;
use PhpCsFixer\Fixer\CastNotation\ShortScalarCastFixer;
use PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer;
use PhpCsFixer\Fixer\ClassNotation\ClassDefinitionFixer;
use PhpCsFixer\Fixer\ClassNotation\NoBlankLinesAfterClassOpeningFixer;
use PhpCsFixer\Fixer\ClassNotation\ProtectedToPrivateFixer;
use PhpCsFixer\Fixer\ClassNotation\SingleClassElementPerStatementFixer;
use PhpCsFixer\Fixer\ClassNotation\VisibilityRequiredFixer;
use PhpCsFixer\Fixer\ArrayNotation\NoMultilineWhitespaceAroundDoubleArrowFixer;
use PhpCsFixer\Fixer\ArrayNotation\NormalizeIndexBraceFixer;
use PhpCsFixer\Fixer\Casing\IntegerLiteralCaseFixer;
use PhpCsFixer\Fixer\Casing\LowercaseStaticReferenceFixer;
use PhpCsFixer\Fixer\Casing\MagicConstantCasingFixer;
use PhpCsFixer\Fixer\Casing\MagicMethodCasingFixer;
use PhpCsFixer\Fixer\Casing\NativeFunctionCasingFixer;
use PhpCsFixer\Fixer\Casing\NativeFunctionTypeDeclarationCasingFixer;
use PhpCsFixer\Fixer\CastNotation\NoShortBoolCastFixer;
use PhpCsFixer\Fixer\CastNotation\NoUnsetCastFixer;
use PhpCsFixer\Fixer\Comment\HeaderCommentFixer;
use PhpCsFixer\Fixer\Comment\NoTrailingWhitespaceInCommentFixer;
use PhpCsFixer\Fixer\Comment\SingleLineCommentStyleFixer;
use PhpCsFixer\Fixer\ControlStructure\ElseifFixer;
use PhpCsFixer\Fixer\ControlStructure\IncludeFixer;
use PhpCsFixer\Fixer\ControlStructure\NoBreakCommentFixer;
use PhpCsFixer\Fixer\ControlStructure\NoUnneededControlParenthesesFixer;
use PhpCsFixer\Fixer\ControlStructure\NoUnneededCurlyBracesFixer;
use PhpCsFixer\Fixer\ControlStructure\SwitchCaseSemicolonToColonFixer;
use PhpCsFixer\Fixer\ControlStructure\SwitchCaseSpaceFixer;
use PhpCsFixer\Fixer\FunctionNotation\FunctionDeclarationFixer;
use PhpCsFixer\Fixer\FunctionNotation\MethodArgumentSpaceFixer;
use PhpCsFixer\Fixer\FunctionNotation\NoSpacesAfterFunctionNameFixer;
use PhpCsFixer\Fixer\FunctionNotation\ReturnTypeDeclarationFixer;
use PhpCsFixer\Fixer\Import\NoLeadingImportSlashFixer;
use PhpCsFixer\Fixer\Import\NoUnusedImportsFixer;
use PhpCsFixer\Fixer\ControlStructure\NoAlternativeSyntaxFixer;
use PhpCsFixer\Fixer\FunctionNotation\LambdaNotUsedImportFixer;
use PhpCsFixer\Fixer\Import\OrderedImportsFixer;
use PhpCsFixer\Fixer\Import\SingleImportPerStatementFixer;
use PhpCsFixer\Fixer\Import\SingleLineAfterImportsFixer;
use PhpCsFixer\Fixer\LanguageConstruct\CombineConsecutiveUnsetsFixer;
use PhpCsFixer\Fixer\LanguageConstruct\DeclareEqualNormalizeFixer;
use PhpCsFixer\Fixer\NamespaceNotation\BlankLineAfterNamespaceFixer;
use PhpCsFixer\Fixer\Operator\BinaryOperatorSpacesFixer;
use PhpCsFixer\Fixer\Operator\ConcatSpaceFixer;
use PhpCsFixer\Fixer\Operator\NewWithBracesFixer;
use PhpCsFixer\Fixer\LanguageConstruct\SingleSpaceAroundConstructFixer;
use PhpCsFixer\Fixer\ListNotation\ListSyntaxFixer;
use PhpCsFixer\Fixer\NamespaceNotation\CleanNamespaceFixer;
use PhpCsFixer\Fixer\Operator\NoSpaceAroundDoubleColonFixer;
use PhpCsFixer\Fixer\Operator\ObjectOperatorWithoutWhitespaceFixer;
use PhpCsFixer\Fixer\Operator\TernaryOperatorSpacesFixer;
use PhpCsFixer\Fixer\Operator\UnaryOperatorSpacesFixer;
use PhpCsFixer\Fixer\PhpTag\BlankLineAfterOpeningTagFixer;
use PhpCsFixer\Fixer\PhpTag\FullOpeningTagFixer;
use PhpCsFixer\Fixer\PhpTag\NoClosingTagFixer;
use PhpCsFixer\Fixer\Operator\StandardizeNotEqualsFixer;
use PhpCsFixer\Fixer\PhpTag\LinebreakAfterOpeningTagFixer;
use PhpCsFixer\Fixer\ReturnNotation\NoUselessReturnFixer;
use PhpCsFixer\Fixer\ReturnNotation\ReturnAssignmentFixer;
use PhpCsFixer\Fixer\Semicolon\MultilineWhitespaceBeforeSemicolonsFixer;
use PhpCsFixer\Fixer\Semicolon\NoEmptyStatementFixer;
use PhpCsFixer\Fixer\Semicolon\NoSinglelineWhitespaceBeforeSemicolonsFixer;
use PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer;
use PhpCsFixer\Fixer\StringNotation\SingleQuoteFixer;
use PhpCsFixer\Fixer\Whitespace\BlankLineBeforeStatementFixer;
use PhpCsFixer\Fixer\Whitespace\CompactNullableTypehintFixer;
use PhpCsFixer\Fixer\Whitespace\IndentationTypeFixer;
use PhpCsFixer\Fixer\Whitespace\LineEndingFixer;
use PhpCsFixer\Fixer\Whitespace\NoExtraBlankLinesFixer;
use PhpCsFixer\Fixer\Whitespace\NoSpacesInsideParenthesisFixer;
use PhpCsFixer\Fixer\Whitespace\NoTrailingWhitespaceFixer;
use PhpCsFixer\Fixer\Whitespace\SingleBlankLineAtEofFixer;
use SlevomatCodingStandard\Sniffs\ControlStructures\RequireShortTernaryOperatorSniff;
use SlevomatCodingStandard\Sniffs\Functions\UnusedInheritedVariablePassedToClosureSniff;
use SlevomatCodingStandard\Sniffs\Operators\RequireCombinedAssignmentOperatorSniff;
use SlevomatCodingStandard\Sniffs\PHP\DisallowDirectMagicInvokeCallSniff;
use SlevomatCodingStandard\Sniffs\PHP\UselessParenthesesSniff;
use SlevomatCodingStandard\Sniffs\PHP\UselessSemicolonSniff;
use SlevomatCodingStandard\Sniffs\Variables\UnusedVariableSniff;
use SlevomatCodingStandard\Sniffs\Variables\UselessVariableSniff;
use PhpCsFixer\Fixer\Whitespace\TypesSpacesFixer;
use Symplify\CodingStandard\Fixer\Commenting\ParamReturnAndVarTagMalformsFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Option;
use Symplify\EasyCodingStandard\ValueObject\Set\SetList;
return static function (ECSConfig $containerConfigurator): void {
return static function (ECSConfig $ecsConfig): void {
$ecsConfig->parallel();
$headerFile = __DIR__ . '/.header';
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::SETS, [
SetList::COMMON,
]);
$services = $containerConfigurator->services();
$ecsConfig->sets([SetList::PSR_12, SetList::COMMON]);
if (file_exists($headerFile)) {
$services->set(HeaderCommentFixer::class)
->call('configure', [[
'header' => file_get_contents($headerFile),
'location' => 'after_open',
]]);
$ecsConfig->ruleWithConfiguration(HeaderCommentFixer::class, [
'header' => file_get_contents($headerFile),
'location' => 'after_open',
]);
}
$services->set(EncodingFixer::class);
$services->set(FullOpeningTagFixer::class);
$services->set(BlankLineAfterNamespaceFixer::class);
$services->set(BracesFixer::class);
$services->set(ClassDefinitionFixer::class);
$services->set(ConstantCaseFixer::class);
$services->set(ElseifFixer::class);
$services->set(FunctionDeclarationFixer::class);
$services->set(IndentationTypeFixer::class);
$services->set(LineEndingFixer::class);
$services->set(LowercaseKeywordsFixer::class);
$services->set(MethodArgumentSpaceFixer::class)
->call('configure', [[
'on_multiline' => 'ensure_fully_multiline',
]]);
$services->set(NoBreakCommentFixer::class);
$services->set(NoClosingTagFixer::class);
$services->set(NoSpacesAfterFunctionNameFixer::class);
$services->set(NoSpacesInsideParenthesisFixer::class);
$services->set(NoTrailingWhitespaceFixer::class);
$services->set(NoTrailingWhitespaceInCommentFixer::class);
$services->set(SingleBlankLineAtEofFixer::class);
$services->set(SingleClassElementPerStatementFixer::class)
->call('configure', [[
'elements' => ['property'],
]]);
$services->set(SingleImportPerStatementFixer::class);
$services->set(SingleLineAfterImportsFixer::class);
// $services->set(SwitchCaseSemicolonToColonFixer::class); broken for php 8.0
$services->set(SwitchCaseSpaceFixer::class);
$services->set(VisibilityRequiredFixer::class);
$services->set(LowercaseCastFixer::class);
$services->set(ShortScalarCastFixer::class);
$services->set(BlankLineAfterOpeningTagFixer::class);
$services->set(NoLeadingImportSlashFixer::class);
$services->set(OrderedImportsFixer::class)
->call('configure', [[
'importsOrder' => ['class', 'function', 'const'],
]]);
$services->set(DeclareEqualNormalizeFixer::class)
->call('configure', [[
'space' => 'none',
]]);
$services->set(NewWithBracesFixer::class);
$services->set(BracesFixer::class)
->call('configure', [[
'allow_single_line_closure' => false,
'position_after_functions_and_oop_constructs' => 'next',
'position_after_control_structures' => 'same',
'position_after_anonymous_constructs' => 'same',
]]);
$services->set(NoBlankLinesAfterClassOpeningFixer::class);
$services->set(VisibilityRequiredFixer::class)
->call('configure', [[
'elements' => ['const', 'method', 'property'],
]]);
$services->set(BinaryOperatorSpacesFixer::class);
$services->set(TernaryOperatorSpacesFixer::class);
$services->set(UnaryOperatorSpacesFixer::class);
$services->set(ReturnTypeDeclarationFixer::class);
$services->set(NoTrailingWhitespaceFixer::class);
$services->set(ConcatSpaceFixer::class)
->call('configure', [[
'spacing' => 'one',
]]);
$services->set(NoSinglelineWhitespaceBeforeSemicolonsFixer::class);
$services->set(NoWhitespaceBeforeCommaInArrayFixer::class);
$services->set(WhitespaceAfterCommaInArrayFixer::class);
$services->set(DeclareStrictTypesFixer::class);
$services->set(CompactNullableTypehintFixer::class);
$services->set(BlankLineBeforeStatementFixer::class);
$services->set(CombineConsecutiveUnsetsFixer::class);
$services->set(ClassAttributesSeparationFixer::class);
$services->set(MultilineWhitespaceBeforeSemicolonsFixer::class);
$services->set(SingleLineCommentStyleFixer::class);
$services->set(IncludeFixer::class);
$services->set(ObjectOperatorWithoutWhitespaceFixer::class);
$services->set(DisallowDirectMagicInvokeCallSniff::class);
$services->set(ParamReturnAndVarTagMalformsFixer::class);
$services->set(UnusedVariableSniff::class);
$services->set(UselessVariableSniff::class);
$services->set(UnusedInheritedVariablePassedToClosureSniff::class);
$services->set(UselessSemicolonSniff::class);
// $services->set(UselessParenthesesSniff::class); // broken for php 8.0
$services->set(ArraySyntaxFixer::class)
->call('configure', [[
'syntax' => 'short',
]]);
$services->set(NoUnusedImportsFixer::class);
$services->set(OrderedImportsFixer::class);
$services->set(NoEmptyStatementFixer::class);
$services->set(ProtectedToPrivateFixer::class);
$services->set(NoUnneededControlParenthesesFixer::class);
$services->set(NoUnneededCurlyBracesFixer::class);
$services->set(ReturnAssignmentFixer::class);
$services->set(RequireShortTernaryOperatorSniff::class);
$services->set(RequireCombinedAssignmentOperatorSniff::class);
$services->set(NoExtraBlankLinesFixer::class)
->call('configure', [[
'tokens' => [
'curly_brace_block',
'extra',
'parenthesis_brace_block',
'square_brace_block',
'throw',
'use',
]
]]);
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::SKIP, [
$ecsConfig->rule(TypesSpacesFixer::class);
$ecsConfig->rule(NoUselessReturnFixer::class);
$ecsConfig->rule(LinebreakAfterOpeningTagFixer::class);
$ecsConfig->rule(StandardizeNotEqualsFixer::class);
$ecsConfig->rule(NoSpaceAroundDoubleColonFixer::class);
$ecsConfig->rule(CleanNamespaceFixer::class);
$ecsConfig->rule(ListSyntaxFixer::class);
$ecsConfig->rule(SingleSpaceAroundConstructFixer::class);
$ecsConfig->rule(LambdaNotUsedImportFixer::class);
$ecsConfig->rule(NoAlternativeSyntaxFixer::class);
$ecsConfig->rule(NoUnsetCastFixer::class);
$ecsConfig->rule(NoShortBoolCastFixer::class);
$ecsConfig->rule(NativeFunctionTypeDeclarationCasingFixer::class);
$ecsConfig->rule(NativeFunctionCasingFixer::class);
$ecsConfig->rule(MagicMethodCasingFixer::class);
$ecsConfig->rule(MagicConstantCasingFixer::class);
$ecsConfig->rule(LowercaseStaticReferenceFixer::class);
$ecsConfig->rule(IntegerLiteralCaseFixer::class);
$ecsConfig->rule(NormalizeIndexBraceFixer::class);
$ecsConfig->rule(NoMultilineWhitespaceAroundDoubleArrowFixer::class);
$ecsConfig->rule(BlankLineBeforeStatementFixer::class);
$ecsConfig->rule(CombineConsecutiveUnsetsFixer::class);
$ecsConfig->rule(CompactNullableTypehintFixer::class);
$ecsConfig->rule(DeclareStrictTypesFixer::class);
$ecsConfig->rule(IncludeFixer::class);
$ecsConfig->rule(MultilineWhitespaceBeforeSemicolonsFixer::class);
$ecsConfig->rule(NoAliasFunctionsFixer::class);
$ecsConfig->rule(NoAliasLanguageConstructCallFixer::class);
$ecsConfig->rule(NoEmptyStatementFixer::class);
$ecsConfig->rule(NoMixedEchoPrintFixer::class);
$ecsConfig->rule(ObjectOperatorWithoutWhitespaceFixer::class);
$ecsConfig->rule(ParamReturnAndVarTagMalformsFixer::class);
$ecsConfig->rule(ReturnAssignmentFixer::class);
$ecsConfig->ruleWithConfiguration(SingleLineCommentStyleFixer::class, [
'comment_types' => ['hash'],
]);
$ecsConfig->rule(SingleQuoteFixer::class);
$ecsConfig->ruleWithConfiguration(OrderedImportsFixer::class, [
'imports_order' => ['class', 'function', 'const'],
]);
$ecsConfig->ruleWithConfiguration(ArraySyntaxFixer::class, [
'syntax' => 'short',
]);
$ecsConfig->ruleWithConfiguration(NoExtraBlankLinesFixer::class, [
'tokens' => [
'curly_brace_block',
'extra',
'parenthesis_brace_block',
'square_brace_block',
'throw',
'use',
],
]);
$ecsConfig->skip([
SingleImportPerStatementFixer::class => null,
]);
};

View file

@ -10,13 +10,15 @@
*/
use PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer;
use PhpCsFixer\Fixer\Strict\StrictComparisonFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
use Symplify\EasyCodingStandard\ValueObject\Option;
return static function (ECSConfig $containerConfigurator): void {
$containerConfigurator->import(__DIR__ . '/ecs-chevere.php');
$services = $containerConfigurator->services();
$services->remove(DeclareStrictTypesFixer::class);
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::SKIP, []);
return static function (ECSConfig $ecsConfig): void {
$ecsConfig->import(__DIR__ . '/ecs-chevere.php');
$ecsConfig->skip([
DeclareStrictTypesFixer::class,
StrictComparisonFixer::class,
getcwd() . '/vendor/*',
getcwd() . '/content/legacy/themes/Peafowl/',
]);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 537 KiB

View file

@ -14,7 +14,10 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
php: ["8.2"]
php: ["8.1"]
env:
tools: composer
ini-values: default_charset='UTF-8'
name: Build on PHP ${{ matrix.php }} ${{ matrix.os }}
steps:
- name: Checkout
@ -27,6 +30,14 @@ jobs:
raw=$(git branch -r --contains ${{ github.ref }})
echo "branch=${raw##*/}" >> $GITHUB_OUTPUT
- run: echo ${{ steps.get-branch.outputs.branch }}
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
ini-values: ${{ env.ini-values }}
tools: ${{ env.tools }}
env:
fail-fast: true
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
@ -42,7 +53,7 @@ jobs:
type=semver,pattern={{major}}
labels: |
org.opencontainers.image.title=Chevereto V4
org.opencontainers.image.description=Ultimate image sharing software
org.opencontainers.image.description=Ultimate image and video sharing software
org.opencontainers.image.vendor=Chevereto
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
@ -73,6 +84,7 @@ jobs:
rm -rf README.md chevereto.svg rector.php
rm -rf app/tests app/phpunit*.xml
rm -rf app/.editions app/bin/edition
mkdir images/_assets
mkdir importing/{parse-users,parse-albums,no-parse}
mv .package ..
ls -la ../.package

View file

@ -54,6 +54,7 @@ jobs:
rm -rf README.md chevereto.svg rector.php
rm -rf app/tests app/phpunit*.xml
rm -rf app/.editions app/bin/edition
mkdir images/_assets
mkdir importing/{parse-users,parse-albums,no-parse}
mv .package ..
ls -la ../.package

2
.gitignore vendored
View file

@ -2,7 +2,7 @@
/.env
/.idea
/app/.upgrading
/app/CHEVERETO_LICENSE_KEY
/app/CHEVERETO_LICENSE_KEY**
/app/vendor
/app/build
/app/.phpunit.cache

View file

@ -1,9 +0,0 @@
Chevereto 4.1.4 (2024-05-24)
- ✅ Added checking for CHEVERETO_HOSTNAME_PATH setting
- 🌎 Updated Chinese Traditional translation
- 🌎 Updated French translation
- 🐋 Improved upgrading instructions when using Docker
- 🐞 Fixed bug affecting video uploads when using max image size
- 🐞 Removed album hashing when upgrading from V3
- 🐞 Removed login providers encryption when upgrading from V3

8
.package/4.2.4.txt Normal file
View file

@ -0,0 +1,8 @@
Chevereto 4.2.4 (2024-12-05)
- Added Chevereto Lite edition
- Added placeholders for comments code
- Improved comment code page id
- Improved ENV handling
- Fixed bug affecting CLI runtime
- Fixed bug affecting MariaDB 10.4 compatibility

View file

@ -9,6 +9,7 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\getCheveretoEnv;
use function Chevereto\Legacy\loaderHandler;
class CustomTinkerwellDriver extends TinkerwellDriver
@ -25,7 +26,7 @@ class CustomTinkerwellDriver extends TinkerwellDriver
require $projectPath . '/app/legacy/load/loader.php';
include loaderHandler(
_cookie: [],
_env: $_ENV,
_env: getCheveretoEnv(),
_files: [],
_get: [],
_post: [],

272
README.md
View file

@ -8,19 +8,24 @@
[![Chevereto Docs](https://img.shields.io/badge/chevereto-docs-50C878?style=flat-square)](https://v4-docs.chevereto.com/)
[![Chevereto Community](https://img.shields.io/badge/chevereto-community-blue?style=flat-square)](https://chevereto.com/community)
[![Chevereto Discord](https://img.shields.io/badge/chevereto-discord-5865F2?style=flat-square)](https://chevereto.com/go/discord)
[![Chevereto Demo](https://img.shields.io/badge/chevereto-demo-d4af37?style=flat-square)](https://demo.chevereto.com)
[![Chevereto Demo](https://img.shields.io/badge/chevereto-demo-d4af37?style=flat-square&color=red)](https://demo.chevereto.com)
[![AGPL-3.0-only](https://img.shields.io/github/license/chevereto/chevereto?style=flat-square)](LICENSE)
[![Legacy stars](https://img.shields.io/github/stars/rodber/chevereto-free?style=flat-square&logo=github&label=Legacy%20stars&color=red)](https://github.com/rodber/chevereto-free)
[![Legacy stars](https://img.shields.io/github/stars/rodber/chevereto-free?style=flat-square&logo=github&label=Legacy%20stars&color=gold)](https://github.com/rodber/chevereto-free)
[![Awesome F/OSS](https://img.shields.io/badge/Awesome_F%2FOSS-Certified-black?colorA=&colorB=874efe&style=flat-square)](https://awsmfoss.com/chevereto/)
> 🔔 [Subscribe](https://chv.to/newsletter) to don't miss any update regarding Chevereto.
> 🔔 [Subscribe](https://chevereto.com/go/newsletter) to don't miss any update regarding Chevereto.
Chevereto enables to create a media sharing website on your own server. It's your hosting and your rules, say goodbye to closures and restrictions. ⭐️ [Live demo](https://demo.chevereto.com)
Chevereto is a robust, self-hosted media-sharing platform that prioritizes flexibility and control. It enables you to build and manage a media-sharing website on your own server, granting you complete autonomy over your hosting environment and policies. With Chevereto, you eliminate the risk of platform restrictions and shutdowns, ensuring your site operates entirely on your terms.
Chevereto is a turnkey system which main use case is to provide a self-hosted platform for content creators, communities and businesses. It's features are all about media sharing, with a strong focus on user experience, privacy and security. On its pro edition Chevereto excels as a content management system with heavy business related features that you won't get on other systems.
This is the repository for **Chevereto Free** edition. You can [compare editions](https://v4-docs.chevereto.com/introduction/editions/compare.html) to find the Chevereto edition that best suits your needs.
![screen](.github/screen/user-profile.jpeg)
![screen](.github/screen/user-listing-selected.webp)
## Requirements
* A [webserver](https://v4-docs.chevereto.com/application/stack/web-server.html) (Apache recommended)
* [PHP](https://v4-docs.chevereto.com/application/stack/php.html) 8.1+ with [extensions](https://v4-docs.chevereto.com/application/stack/php.html#extensions)
* [MySQL Server](https://v4-docs.chevereto.com/application/stack/mysql-server.html) 8.0.1+ or MariaDB Server 10.2.2+
## Install
@ -35,12 +40,12 @@ Install Chevereto following our guides for:
* [cPanel](https://v4-docs.chevereto.com/guides/cpanel/)
* [Plesk](https://v4-docs.chevereto.com/guides/plesk/)
Chevereto is also available at [DigitalOcean Marketplace](https://chevereto.com/go/digitalocean), [Vultr Marketplace](https://chevereto.com/go/vultr), [Installatron](https://installatron.com/chevereto) and [Softaculous](https://www.softaculous.com/apps/galleries/Chevereto). Review our [Installation docs](https://v4-docs.chevereto.com/application/installing/installation.html) for all alternatives.
Chevereto is also available at [DigitalOcean Marketplace](https://chevereto.com/go/digitalocean), [Vultr Marketplace](https://chevereto.com/go/vultr), [Installatron](https://installatron.com/chevereto), [Softaculous](https://www.softaculous.com/apps/galleries/Chevereto) and [SwiftWave](https://swiftwave.org/docs/dashboard/swiftwave_app_store/).
Review our [Installation docs](https://v4-docs.chevereto.com/application/installing/installation.html) for all alternatives.
## Updating
For Chevereto V4 users:
* Follow the [Updating guide](https://v4-docs.chevereto.com/application/installing/updating.html) to keep your Chevereto V4 system updated.
## Upgrading
@ -50,246 +55,17 @@ For Chevereto V3 users:
* Follow the [Upgrading guide](https://v4-docs.chevereto.com/application/installing/upgrading.html) to upgrade to Chevereto V4.
* Check the [Welcome Back](https://v4-docs.chevereto.com/introduction/changelog/welcome-back.html#from-chevereto-v3) reference.
## Files supported
For Chevereto V2 users:
With Chevereto you can upload and share the following media types from device file browser, drag and drop, on-the-fly device camera (video and photos), clipboard, URL, ShareX and via API.
* image/jpeg
* image/gif
* image/png
* image/webp
* image/bmp
* video/quicktime
* video/mp4
* video/webm
* Follow the [Upgrading guide](https://v3-docs.chevereto.com/setup/server/upgrading.html) but skip directly to Chevereto V4.
## Documentation
Chevereto is so **feature-rich**, mature and robust that we need three layers of documentation for it. The Chevereto software project started on **2007** and it has been actively maintained since then.
Chevereto [Documentation](https://v4-docs.chevereto.com) covers the system requirements, installation, configuration, and usage of the software. It also includes a [User manual](https://v4-user.chevereto.com/) and an [Admin manual](https://v4-admin.chevereto.com/).
* [Documentation](https://v4-docs.chevereto.com)
* [User manual](https://v4-user.chevereto.com/)
* [Admin manual](https://v4-admin.chevereto.com/)
## Contributing
## Features
**Note:** This is the repository for Chevereto free edition. This software is intended for **personal usage** as it doesn't contain [all the features](https://chevereto.com/features) of commercial editions. This is a short, not exhaustive, list of features available on Chevereto editions. Feel free to request a free demo of the pro edition at [chevereto.com](https://chevereto.com) to see all the features in action.
### Uploading features
| Feature | Free | Lite | Pro |
| ---------------------------------------- | :---: | :---: | :---: |
| Image & Video uploads | ✅ | ✅ | ✅ |
| JPEG PNG BMP GIF WEBP MOV MP4 WEBM | ✅ | ✅ | ✅ |
| ShareX support | ✅ | ✅ | ✅ |
| 360° images | ✅ | ✅ | ✅ |
| Strip image EXIF data | ✅ | ✅ | ✅ |
| Clipboard upload | ✅ | ✅ | ✅ |
| Drag-and-drop upload | ✅ | ✅ | ✅ |
| File delete link | ✅ | ✅ | ✅ |
| Time-based expirable uploads | ✅ | ✅ | ✅ |
| Thumbs & medium sized images | ✅ | ✅ | ✅ |
| Video frame image | ✅ | ✅ | ✅ |
| Duplicate media detection | ✅ | ✅ | ✅ |
| Auto file naming options | ✅ | ✅ | ✅ |
| Storage modes (date, direct) | ✅ | ✅ | ✅ |
| Upload user interface (container, route) | ✅ | ✅ | ✅ |
| Upload plugin (PUP.js) | | ✅ | ✅ |
| Watermark image uploads | | | ✅ |
| Upload moderation | | | ✅ |
| External storage servers | | | ✅ |
| Bulk content importer | | | ✅ |
### Sharing features
| Feature | Free | Lite | Pro |
| ------------------------------ | :---: | :---: | :---: |
| Direct link sharing | ✅ | ✅ | ✅ |
| Sharing button | ✅ | ✅ | ✅ |
| Media oEmbed | ✅ | ✅ | ✅ |
| HTML, Markdown & BBCode | ✅ | ✅ | ✅ |
| Embed codes on upload complete | ✅ | ✅ | ✅ |
| Embed codes on selected media | ✅ | ✅ | ✅ |
| Embed codes media page | ✅ | ✅ | ✅ |
### User features
| Feature | Free | Lite | Pro |
| --------------------------- | :---: | :---: | :---: |
| User profiles | ✅ | ✅ | ✅ |
| Private user profiles | ✅ | ✅ | ✅ |
| User-based API | ✅ | ✅ | ✅ |
| Multiple users & management | | ✅ | ✅ |
| Guest API | | ✅ | ✅ |
### Social features
| Feature | Free | Lite | Pro |
| ---------------------------- | :---: | :---: | :---: |
| Call-to-action album buttons | ✅ | ✅ | ✅ |
| Random button | ✅ | ✅ | ✅ |
| Notifications | | ✅ | ✅ |
| List users | | ✅ | ✅ |
| Followers | | | ✅ |
| Likes | | | ✅ |
### Organization features
| Feature | Free | Lite | Pro |
| --------------------------------- | :---: | :---: | :---: |
| Albums & Sub-albums | ✅ | ✅ | ✅ |
| Categories | ✅ | ✅ | ✅ |
| Search | ✅ | ✅ | ✅ |
| Media & Album listings | ✅ | ✅ | ✅ |
| Configurable list items per page | ✅ | ✅ | ✅ |
| Classic + Endless scroll listings | ✅ | ✅ | ✅ |
| Listing viewer | ✅ | ✅ | ✅ |
| Image listing size (fixed, fluid) | ✅ | ✅ | ✅ |
| Album listing requirement | ✅ | ✅ | ✅ |
| Listing columns per device | ✅ | ✅ | ✅ |
| Explore & Discovery | | ✅ | ✅ |
| Advanced search | | ✅ | ✅ |
### Security features
| Feature | Free | Lite | Pro |
| ------------------------------- | :---: | :---: | :---: |
| Two-Factor Authentication (2FA) | ✅ | ✅ | ✅ |
| Encrypt secrets | ✅ | ✅ | ✅ |
| Crypt-salted IDs | ✅ | ✅ | ✅ |
| IP banning | | | ✅ |
| Stop words | | | ✅ |
### Admin features
| Feature | Free | Lite | Pro |
| --------------------------------------------------------------------------------------------- | :---: | :---: | :---: |
| Dashboard (admin UI) | ✅ | ✅ | ✅ |
| System stats & usage | ✅ | ✅ | ✅ |
| Website name | ✅ | ✅ | ✅ |
| Website doctitle | ✅ | ✅ | ✅ |
| Website description | ✅ | ✅ | ✅ |
| Website privacy mode (public, private) | ✅ | ✅ | ✅ |
| Default timezone | ✅ | ✅ | ✅ |
| Uploadable file extensions | ✅ | ✅ | ✅ |
| Guest uploads auto delete | ✅ | ✅ | ✅ |
| Upload threads | ✅ | ✅ | ✅ |
| Upload maximum image size | ✅ | ✅ | ✅ |
| Upload Exif removal | ✅ | ✅ | ✅ |
| Upload max file size (users and guest) | ✅ | ✅ | ✅ |
| Upload path | ✅ | ✅ | ✅ |
| Upload file naming | ✅ | ✅ | ✅ |
| Upload thumb size | ✅ | ✅ | ✅ |
| Upload medium size and dimension | ✅ | ✅ | ✅ |
| Semantics | ✅ | ✅ | ✅ |
| Default palette | ✅ | ✅ | ✅ |
| Default font | ✅ | ✅ | ✅ |
| Image load max file size | ✅ | ✅ | ✅ |
| Image first tab | ✅ | ✅ | ✅ |
| Embed codes (content) | ✅ | ✅ | ✅ |
| Custom JS & CSS | ✅ | ✅ | ✅ |
| Universal CDN support | ✅ | ✅ | ✅ |
| [Default language](https://v4-admin.chevereto.com/settings/languages.html#default-language) | ✅ | ✅ | ✅ |
| Homepage style | | ✅ | ✅ |
| Homepage cover images | | ✅ | ✅ |
| Homepage title & paragraph | | ✅ | ✅ |
| Homepage call to action | | ✅ | ✅ |
| Pages | | ✅ | ✅ |
| Lock NSFW editing | | ✅ | ✅ |
| User min age required | | ✅ | ✅ |
| User avatar max file size | | ✅ | ✅ |
| User background max file size | | ✅ | ✅ |
| Guest API key | | ✅ | ✅ |
| [Enabled languages](https://v4-admin.chevereto.com/settings/languages.html#enabled-languages) | | | ✅ |
| Hide "Powered by Chevereto" | | | ✅ |
| Logo & branding | | | ✅ |
| Logo type (vector, image, text) | | | ✅ |
| Logo height | | | ✅ |
| Logo favicon image | | | ✅ |
| Routing (user, image, album) | | | ✅ |
| Routing root | | | ✅ |
| External services | | | ✅ |
| Comments API (Disqus, JS) | | | ✅ |
| Analytics code | | | ✅ |
| Akismet spam protection | | | ✅ |
| StopForumSpam spam protection | | | ✅ |
| CAPTCHA (reCAPTCHA, hCaptcha) | | | ✅ |
| CAPTCHA threshold | | | ✅ |
| Project Arachnid | | | ✅ |
| ModerateContent (auto approve, block, flag) | | | ✅ |
| OAuth2 login providers (Amazon, Google, Discord, etc) | | | ✅ |
| Banners | | | ✅ |
| Watermark uploads (guest, user, admin) | | | ✅ |
| Watermark file toggles | | | ✅ |
| Watermark size requirement | | | ✅ |
| Watermark custom image | | | ✅ |
| Watermark position | | | ✅ |
| Watermark percentage | | | ✅ |
| Watermark margin | | | ✅ |
| Watermark opacity | | | ✅ |
### Admin toggles
| Feature | Free | Lite | Pro |
| ------------------------------------------------------------------------------------------- | :---: | :---: | :---: |
| Search (users and guest) | ✅ | ✅ | ✅ |
| Explore (users and guest) | ✅ | ✅ | ✅ |
| Random (users and guest) | ✅ | ✅ | ✅ |
| NSFW listings | ✅ | ✅ | ✅ |
| Blur NSFW content | ✅ | ✅ | ✅ |
| NSFW on random mode | ✅ | ✅ | ✅ |
| Banners on NSFW | ✅ | ✅ | ✅ |
| Uploads (users and guest) | ✅ | ✅ | ✅ |
| Uploads (URL) | ✅ | ✅ | ✅ |
| Upload moderation | ✅ | ✅ | ✅ |
| Upload embed codes | ✅ | ✅ | ✅ |
| Upload redirection | ✅ | ✅ | ✅ |
| Upload duplication | ✅ | ✅ | ✅ |
| Upload expiration | ✅ | ✅ | ✅ |
| Upload NSFW checkbox | ✅ | ✅ | ✅ |
| Download button | ✅ | ✅ | ✅ |
| Right click | ✅ | ✅ | ✅ |
| Show Exif data | ✅ | ✅ | ✅ |
| Social share buttons | ✅ | ✅ | ✅ |
| Automatic updates check | ✅ | ✅ | ✅ |
| Dump update query | ✅ | ✅ | ✅ |
| Debug errors | ✅ | ✅ | ✅ |
| Consent screen (age gate) | | ✅ | ✅ |
| User sign up | | ✅ | ✅ |
| User content delete | | ✅ | ✅ |
| User notify sign up | | ✅ | ✅ |
| User email confirmation | | ✅ | ✅ |
| User email for social login | | ✅ | ✅ |
| [Auto language](https://v4-admin.chevereto.com/settings/languages.html#auto-language) | | | ✅ |
| [Language chooser](https://v4-admin.chevereto.com/settings/languages.html#language-chooser) | | | ✅ |
| SEO URLs (media and album) | | | ✅ |
| Cookie law compliance | | | ✅ |
| Flood protection | | | ✅ |
| Flood protection notify | | | ✅ |
| Watermarks | | | ✅ |
### System features
| Feature | Free | Lite | Pro |
| -------------------------------------------------- | :---: | :-------------------: | :-------------------: |
| Roles available | admin | admin, manager & user | admin, manager & user |
| Image handling GD & ImageMagick | ✅ | ✅ | ✅ |
| Theme palettes (10) | ✅ | ✅ | ✅ |
| One-click upgrade (web & CLI) | ✅ | ✅ | ✅ |
| Maintenance mode | ✅ | ✅ | ✅ |
| Email SMTP + phpmail() | ✅ | ✅ | ✅ |
| Decode ID | ✅ | ✅ | ✅ |
| Encode ID | ✅ | ✅ | ✅ |
| Test-email | ✅ | ✅ | ✅ |
| Export user | ✅ | ✅ | ✅ |
| Regenerate external storage stats | ✅ | ✅ | ✅ |
| Migrate external storage records | ✅ | ✅ | ✅ |
| Docker support | ✅ | ✅ | ✅ |
| CLI console | ✅ | ✅ | ✅ |
| Built-in debugger ([xrDebug](https://xrdebug.com)) | ✅ | ✅ | ✅ |
| Built-in REPL (PsySH) | ✅ | ✅ | ✅ |
| Supports Tinkerwel REPL | ✅ | ✅ | ✅ |
| Queue handling | | | ✅ |
Chevereto is an open-source project, and while contributions are welcomed, they are entirely voluntary. We appreciate any assistance aimed at enhancing the software and making it better for the community. Please note that any contributions to this repository will fall under the AGPLv3 license, ensuring that your work remains open-source and accessible to all.
## License
@ -305,10 +81,12 @@ You should have received a copy of the GNU Affero General Public License along w
### Commercial license
The commercial license is designed to for you to use Chevereto in commercial products and applications, without the provisions of the AGPLv3. With the commercial license, your code is kept proprietary, to yourself. See the Chevereto Commercial License at [Chevereto License](https://chevereto.com/license)
The commercial license allows you to use Chevereto in commercial products and applications without the obligations imposed by the AGPLv3. The commercial license ensures that your code remains proprietary and exclusive to you. For more details, please refer to the Chevereto Commercial License at [Chevereto License](https://chevereto.com/license).
### Compare licenses
Chevereto free edition is licensed under AGPLv3, which means that you can use it for free as long as you comply with the AGPLv3 terms. If you modify the code and distribute it, you must provide the source code to the users.
The Chevereto Free edition is licensed under AGPLv3, allowing free use as long as you comply with its terms. If you modify and distribute the software, you are required to provide the source code to your users.
**Chevereto Lite** and **Chevereto Pro** editions are released under the **Chevereto License**, which is proprietary and it can be used for commercial purposes.
Both **Chevereto Lite** and **Chevereto Pro** are distributed under the proprietary **Chevereto License**, which permits use for commercial purposes.
*Note: Proprietary licensing does not mean closed source; the source code is accessible, but its use is governed by the specific terms of the Chevereto License.*

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
<?php
$translation_header = array (
'Project-Id-Version' => 'VERSION',
'POT-Creation-Date' => '2023-05-22 15:49+0000',
'PO-Revision-Date' => '2023-05-22 15:49+0000',
'POT-Creation-Date' => '2024-11-14 15:22+0000',
'PO-Revision-Date' => '2024-11-14 15:22+0000',
'Last-Translator' => 'FULL NAME <EMAIL@ADDRESS>',
'Language-Team' => 'LANGUAGE TEAM <EMAIL@ADDRESS>',
'Language' => 'pt',
@ -19,21 +19,39 @@ $translation_table = [
"You have been forbidden to use this website." => [
0 => "Foi proibido de usar este site.",
],
"Moderate" => [
0 => "Moderar",
],
"View all my images" => [
0 => "Ver todas as minhas imagens",
],
"Recent" => [
0 => "Recente",
],
"Trending" => [
0 => "Popular agora",
],
"Popular" => [
0 => "Popular",
],
"Animated" => [
0 => "Animadas",
],
"Request denied" => [
0 => "Pedido negado",
],
"terms" => [
0 => "termos",
],
"privacy policy" => [
0 => "política de privacidade",
],
"That page doesn't exist" => [
0 => "Esta página não existe",
],
"Page %s" => [
0 => "Página %s",
],
"Forgot password?" => [
0 => "Esqueceu-se da senha?",
],
@ -49,11 +67,14 @@ $translation_table = [
"Awaiting confirmation" => [
0 => "Aguardando confirmação",
],
"Two-factor authentication" => [
0 => "Autenticação de dois factores",
],
"Email changed" => [
0 => "E-mail alterado",
],
"Invalid Username/Email" => [
0 => "Nome de usuário inválido / Email",
0 => "Nome de utilizador/Email inválido",
],
"User doesn't have an email." => [
0 => "O utilizador não tem um e-mail.",
@ -64,6 +85,9 @@ $translation_table = [
"Account already activated" => [
0 => "Conta activada",
],
"Account banned" => [
0 => "Conta banida",
],
"Allow up to 15 minutes for the email. You can try again later." => [
0 => "Aguarde até 15 minutos pela recepção do e-mail. Poderá tentar novamente mais tarde.",
],
@ -88,6 +112,9 @@ $translation_table = [
"Email already being used" => [
0 => "Esse e-mail já está a ser utilizado",
],
"Invalid code" => [
0 => "Código inválido",
],
"Check the errors in the form to continue." => [
0 => "Verifique os erros no formulário para continuar.",
],
@ -97,6 +124,9 @@ $translation_table = [
"Embed codes" => [
0 => "Códigos para Incorporar",
],
"albums" => [
0 => "álbuns",
],
"%a album hosted in %w" => [
0 => "Álbum %a alojado em %w",
],
@ -104,12 +134,6 @@ $translation_table = [
0 => "imagem",
1 => "imagens",
],
"Stats" => [
0 => "Estatísticas",
],
"Images" => [
0 => "Imagens",
],
"Album" => [
0 => "Álbum",
1 => "Álbuns",
@ -133,8 +157,11 @@ $translation_table = [
"Listings" => [
0 => "Resultados",
],
"Image upload" => [
0 => "Envio de imagem",
"File uploads" => [
0 => "Envios de ficheiros",
],
"Semantics" => [
0 => "Semântica",
],
"Categories" => [
0 => "Categorias",
@ -151,8 +178,11 @@ $translation_table = [
"Email" => [
0 => "E-mail",
],
"External storage" => [
0 => "Alojamento externo",
"Tools" => [
0 => "Ferramentas",
],
"Logo" => [
0 => "Logo",
],
"Homepage" => [
0 => "Página principal",
@ -160,11 +190,23 @@ $translation_table = [
"Pages" => [
0 => "Páginas",
],
"Consent screen" => [
0 => "Janela de consentimento",
],
"Guests %s" => [
0 => "Convidados %s",
],
"External storage" => [
0 => "Alojamento externo",
],
"Routing" => [
0 => "Redireccionamento",
],
"External services" => [
0 => "Serviços externos",
],
"Flood protection" => [
0 => "Protecção contra as inundações",
0 => "Protecção contra abuso",
],
"IP bans" => [
0 => "Banimentos por IP",
@ -172,57 +214,41 @@ $translation_table = [
"Watermarks" => [
0 => "Marcas de água",
],
"Documentation" => [
0 => "Documentação",
],
"Support" => [
0 => "Suport",
],
"Community" => [
0 => "Comunidade",
0 => "Suporte",
],
"install update" => [
0 => "Instalar actualização",
],
"Stats" => [
0 => "Estatísticas",
],
"Rebuild stats" => [
0 => "Estatísticas de reconstrução",
],
"Not your IP?" => [
0 => "Não é o seu IP?",
],
"PHP version" => [
0 => "Versão do PHP",
],
"Server" => [
0 => "Servidor",
],
"MySQL version" => [
0 => "Versão do MySQL",
],
"MySQL server info" => [
0 => "Informação do servidor MySQL",
],
"File uploads" => [
0 => "Envios de ficheiros",
],
"Enabled" => [
0 => "Ativado",
],
"Disabled" => [
0 => "Desactivado",
],
"Max. execution time" => [
0 => "Tempo máximo de execução",
"Releases" => [
0 => "Lançamentos",
],
"%d second" => [
0 => "%d segundo",
1 => "%d segundos",
"Community" => [
0 => "Comunidade",
],
"Memory limit" => [
0 => "Limite de memória",
"Cron last ran" => [
0 => "Última execução do agendamento",
],
"External" => [
0 => "Externo",
"PHP version" => [
0 => "Versão do PHP",
],
"Server" => [
0 => "Servidor",
],
"All" => [
0 => "Todas",
@ -230,33 +256,15 @@ $translation_table = [
"search content" => [
0 => "conteúdo de pesquisa",
],
"Before pagination" => [
0 => "Antes de paginação",
],
"After pagination" => [
0 => "Depois de paginação",
],
"Before comments" => [
0 => "Antes dos comentários",
],
"Image page" => [
0 => "Página da imagem",
],
"Inside viewer top (image page)" => [
0 => "Topo da página para visualizar a imagem",
],
"Footer (image page)" => [
0 => "Rodapé (página imagem)",
],
"User profile page" => [
0 => "Página de perfil do utilizador",
],
"After top (user profile)" => [
0 => "Depois de topo (perfil do utlizador)",
],
"Explore" => [
0 => "Explorar",
],
"After top (%s page)" => [
0 => "Depois do topo (%s página)",
],
"NSFW" => [
0 => "18+",
],
"Invalid website name" => [
0 => "Nome da página inválido",
],
@ -266,6 +274,9 @@ $translation_table = [
"Invalid timezone" => [
0 => "Fuso horário inválido",
],
"Invalid value: %s" => [
0 => "Valor inválido: %s",
],
"Invalid thumb width" => [
0 => "largura da miniatura inválida",
],
@ -278,45 +289,6 @@ $translation_table = [
"Invalid value" => [
0 => "Valor inválido",
],
"Invalid theme image listing size" => [
0 => "Tamanho para os resultados do tema inválido",
],
"Invalid user id" => [
0 => "ID de usuário Inválido",
],
"Invalid email mode" => [
0 => "Modo de e-mail inválido",
],
"Invalid SMTP port" => [
0 => "Porta SMTP inválida",
],
"Invalid SMTP security" => [
0 => "Segurança inválida SMTP ",
],
"Invalid website mode" => [
0 => "Modo de website inválido",
],
"Invalid website content privacy mode" => [
0 => "modo de conteúdo do site privacidade inválido",
],
"Invalid homepage style" => [
0 => "Estilo da página principal inválido",
],
"Invalid URL" => [
0 => "URL inválido",
],
"Invalid upload image path" => [
0 => "Caminho para o envio de imagens inválido",
],
"Max. allowed %s" => [
0 => "Máximo permitido %s",
],
"Invalid SMTP server" => [
0 => "Servidor SMTP inválido",
],
"Invalid SMTP username" => [
0 => "Nome de usuário SMTP inválido",
],
"Dashboard" => [
0 => "Administração",
],
@ -338,21 +310,6 @@ $translation_table = [
"Image %i hosted in %w" => [
0 => "Imagem %i alojada em %w",
],
"Direct links" => [
0 => "Links Diretos",
],
"Image link" => [
0 => "Link da imagem",
],
"Image URL" => [
0 => "URL da imagem",
],
"Thumbnail URL" => [
0 => "URL Thumbnail",
],
"Medium URL" => [
0 => "URL Médio",
],
"Login needed" => [
0 => "Necessário iniciar sessão",
],
@ -363,9 +320,6 @@ $translation_table = [
"Category" => [
0 => "Categoria",
],
"IP address already banned" => [
0 => "Endereço de IP já banido",
],
"Missing values" => [
0 => "Valores em falta",
],
@ -378,6 +332,9 @@ $translation_table = [
"Username already being used" => [
0 => "Nome de utilizador já está a ser utilizado",
],
"IP address already banned" => [
0 => "Endereço de IP já banido",
],
"%s has been disconnected." => [
0 => "%s foi desconectado.",
],
@ -441,6 +398,9 @@ $translation_table = [
"User ID" => [
0 => "ID de utilizador",
],
"Images" => [
0 => "Imagens",
],
"Register date" => [
0 => "Data de registo",
],
@ -563,7 +523,7 @@ $translation_table = [
0 => "%s atrás",
],
"moments ago" => [
0 => "à momentos atrás",
0 => "há poucos segundos",
],
"Random" => [
0 => "Aleatório",
@ -619,27 +579,24 @@ $translation_table = [
"Error deleting profile background image." => [
0 => "Erro apagar imagem de fundo do perfil",
],
"Update available v%s" => [
0 => "Actualização disponível v%s",
],
"Like" => [
0 => "Gostar",
],
"Create album" => [
0 => "Criar álbum",
],
"Edit" => [
0 => "Editar",
],
"Delete" => [
0 => "Eliminar",
],
"Previous" => [
0 => "Anterior",
"Edit" => [
0 => "Editar",
],
"Like" => [
0 => "Gostar",
],
"Next" => [
0 => "Próximo",
],
"Previous" => [
0 => "Anterior",
],
"File too big." => [
0 => "Ficheiro muito grande.",
],
@ -652,9 +609,6 @@ $translation_table = [
"%s's Albums" => [
0 => "Álbuns de %s",
],
"Image edited successfully." => [
0 => "Imagem editada com sucesso.",
],
"private" => [
0 => "Privado",
],
@ -787,9 +741,6 @@ $translation_table = [
"This email was sent from %w %u" => [
0 => "Este e-mail foi enviado por %w %u",
],
"Select the images to upload" => [
0 => "Selecionar as imagens para envio",
],
"complete" => [
0 => "completo",
],
@ -829,36 +780,12 @@ $translation_table = [
"Description" => [
0 => "Descrição",
],
"Add image URLs" => [
0 => "Adicionar URLs de imagem",
],
"Add the image URLs here" => [
0 => "Adicione os URLs de imagem aqui",
],
"Error report" => [
0 => "Relatório de erro",
],
"Direct" => [
0 => "Directo",
],
"HTML Codes" => [
0 => "Códigos HTML",
],
"HTML medium linked" => [
0 => "HTML médio",
],
"HTML thumbnail linked" => [
0 => "HTML da miniatura",
],
"BBCode medium linked" => [
0 => "Código BBCode do tamanho médio",
],
"BBCode thumbnail linked" => [
0 => "Código BBCode da miniatura",
],
"Viewer links" => [
0 => "Ver links",
],
"All these words" => [
0 => "Todas estas palavras",
],
@ -991,6 +918,9 @@ $translation_table = [
"There's nothing to show here." => [
0 => "Não há nada para ver aqui.",
],
"Selection will be assigned to %t." => [
0 => "A selecção vai ser atribuída a %t.",
],
"There is no categories." => [
0 => "Não existem categorias.",
],
@ -1162,6 +1092,33 @@ $translation_table = [
"Disk used" => [
0 => "Espaço usado",
],
"Enable uploads" => [
0 => "Activar envios",
],
"Guest uploads" => [
0 => "Envios de visitantes",
],
"Enable this if you want to allow non registered users to upload." => [
0 => "Ative isto se quiser permitir que os utilizadores não registados façam envios.",
],
"Relative to Chevereto root" => [
0 => "Relativo ao root do Chevereto",
],
"Storage mode" => [
0 => "Modo de armazenamento",
],
"Datefolders creates %s structure" => [
0 => "Datefolders cria %s estrutura",
],
"File naming method" => [
0 => "Método de nomeação do arquivo",
],
"Thumb size" => [
0 => "Tamanho da miniatura",
],
"Thumbnails will be fixed to this size." => [
0 => "As miniaturas serão ajustadas para este tamanho.",
],
"Notify to email" => [
0 => "Notificar para o e-mail",
],
@ -1207,39 +1164,6 @@ $translation_table = [
"Default" => [
0 => "Padrão",
],
"Enable uploads" => [
0 => "Activar envios",
],
"Guest uploads" => [
0 => "Envios de visitantes",
],
"Enable this if you want to allow non registered users to upload." => [
0 => "Ative isto se quiser permitir que os utilizadores não registados façam envios.",
],
"Image path" => [
0 => "Caminho da imagem",
],
"Relative to Chevereto root" => [
0 => "Relativo ao root do Chevereto",
],
"Where to store the images? Relative to Chevereto root." => [
0 => "Onde alojar as imagens? Relativo ao root do Chevereto.",
],
"Storage mode" => [
0 => "Modo de armazenamento",
],
"Datefolders creates %s structure" => [
0 => "Datefolders cria %s estrutura",
],
"File naming method" => [
0 => "Método de nomeação do arquivo",
],
"Thumb size" => [
0 => "Tamanho da miniatura",
],
"Thumbnails will be fixed to this size." => [
0 => "As miniaturas serão ajustadas para este tamanho.",
],
"Expires" => [
0 => "Expira",
],
@ -1475,14 +1399,11 @@ $translation_table = [
0 => "Endereço de email",
],
"Added to %s" => [
0 => "Adicionar a %s",
0 => "Adicionado a %s",
],
"Add IP ban" => [
0 => "Adicionar banimento de IP",
],
"Upload and share your images." => [
0 => "Envie e compartilhe as suas imagens.",
],
"Sign up to unlock all the features" => [
0 => "Registre-se agora Grátis",
],

File diff suppressed because it is too large Load diff

View file

@ -9,6 +9,7 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\getCheveretoEnv;
use function Chevereto\Legacy\loaderHandler;
define('ACCESS', 'web');
@ -16,7 +17,7 @@ define('REPL', true);
require __DIR__ . '/legacy/load/loader.php';
include loaderHandler(
_cookie: [],
_env: $_ENV,
_env: getCheveretoEnv(),
_files: [],
_get: [],
_post: [],
@ -28,8 +29,7 @@ include loaderHandler(
);
return [
'startupMessage' =>
<<<EOM
'startupMessage' => <<<EOM
__ __
____/ / ___ _ _____ _______ / /____
/ __/ _ \/ -_) |/ / -_) __/ -_) __/ _ \\

View file

@ -16,36 +16,40 @@
"composer/package-versions-deprecated": true
},
"platform": {
"php": "8.0.30"
"php": "8.1.28"
}
},
"require": {
"php": "^8.0",
"php": "^8.1",
"intervention/image": "^2.6",
"jeroendesloovere/xmp-metadata-extractor": "^2.0",
"league/flysystem": "^2.0",
"jenssegers/imagehash": "^0.5.0",
"guzzlehttp/psr7": "^1.7",
"guzzlehttp/psr7": "^1.7||^2",
"phpmailer/phpmailer": "^6.5",
"psr/cache": "^1",
"psr/log": "^1",
"phpseclib/phpseclib": "^3.0",
"phpseclib/phpseclib": "^3.0.37",
"mobiledetect/mobiledetectlib": "^2.8",
"mlocati/ip-lib": "^1.17",
"composer/ca-bundle": "^1.2",
"chevere/chevere": "^2.0",
"chevere/throwable-handler": "^0.9",
"chevere/xr": "^0.7",
"chevere/xr-server": "^0.7",
"chevere/workflow": "^0.7.0",
"chevere/throwable-handler": "^1.0.2",
"xrdebug/php": "^2.0.2",
"xrdebug/xrdebug": "^2.0.2",
"chevere/workflow": "^0.9.0",
"pragmarx/google2fa": "^8.0",
"pragmarx/google2fa-qrcode": "^3.0",
"chevere/cache": "^0.4",
"phpseclib/bcmath_compat": "^2.0",
"chillerlan/php-qrcode": "^4.3",
"firebase/php-jwt": "^6.3",
"lychee-org/php-exif": "^0.7.14",
"p3k/emoji-detector": "^1.0",
"php-ds/php-ds": "^1.4",
"php-ffmpeg/php-ffmpeg": "^1.2"
"php-ffmpeg/php-ffmpeg": "^1.2",
"psy/psysh": "^0.11.8",
"chevere/cache": "^0.5.0",
"chevere/var-dump": "^2.0.x-dev",
"chevere/var-support": "^1.0"
},
"autoload": {
"files": [
@ -70,10 +74,8 @@
},
"require-dev": {
"phpunit/phpunit": "^9.2",
"symplify/easy-coding-standard": "^10.3",
"phpstan/phpstan": "^1.4",
"rector/rector": "^0.12.15",
"psy/psysh": "^0.11.8"
"symplify/easy-coding-standard": "^12.2",
"phpstan/phpstan": "^1.11"
},
"prefer-stable": true,
"scripts": {

3473
app/composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,6 @@
* file that was distributed with this source code.
*/
use Chevereto\Config\AssetConfig;
use Chevereto\Config\Config;
use Chevereto\Config\EnabledConfig;
use Chevereto\Config\HostConfig;
@ -18,19 +17,6 @@ use Chevereto\Config\SystemConfig;
use function Chevereto\Vars\env;
new Config(
asset: new AssetConfig(
accountId: env()['CHEVERETO_ASSET_STORAGE_ACCOUNT_ID'],
accountName: env()['CHEVERETO_ASSET_STORAGE_ACCOUNT_NAME'],
bucket: env()['CHEVERETO_ASSET_STORAGE_BUCKET'],
key: env()['CHEVERETO_ASSET_STORAGE_KEY'],
name: env()['CHEVERETO_ASSET_STORAGE_NAME'],
region: env()['CHEVERETO_ASSET_STORAGE_REGION'],
secret: env()['CHEVERETO_ASSET_STORAGE_SECRET'],
server: env()['CHEVERETO_ASSET_STORAGE_SERVER'],
service: env()['CHEVERETO_ASSET_STORAGE_SERVICE'],
type: env()['CHEVERETO_ASSET_STORAGE_TYPE'],
url: env()['CHEVERETO_ASSET_STORAGE_URL'],
),
enabled: new EnabledConfig(
phpPages: (bool) env()['CHEVERETO_ENABLE_PHP_PAGES'],
updateCli: (bool) env()['CHEVERETO_ENABLE_UPDATE_CLI'],

View file

@ -10,86 +10,97 @@
*/
return [
'CHEVERETO_ASSET_STORAGE_ACCOUNT_ID' => '',
'CHEVERETO_ASSET_STORAGE_ACCOUNT_NAME' => '',
'CHEVERETO_ASSET_STORAGE_BUCKET' => '',
'CHEVERETO_ASSET_STORAGE_KEY' => '',
'CHEVERETO_ASSET_STORAGE_NAME' => 'assets',
'CHEVERETO_ASSET_STORAGE_REGION' => '',
'CHEVERETO_ASSET_STORAGE_SECRET' => '',
'CHEVERETO_ASSET_STORAGE_SERVER' => '',
'CHEVERETO_ASSET_STORAGE_SERVICE' => '',
'CHEVERETO_ASSET_STORAGE_TYPE' => 'local',
'CHEVERETO_ASSET_STORAGE_URL' => '',
'CHEVERETO_CONTEXT' => '',
'CHEVERETO_DB_DRIVER' => 'mysql',
'CHEVERETO_DB_HOST' => 'localhost',
'CHEVERETO_DB_NAME' => '',
'CHEVERETO_DB_PASS' => '',
'CHEVERETO_DB_PDO_ATTRS' => '[]',
'CHEVERETO_DB_PORT' => '3306',
'CHEVERETO_DB_TABLE_PREFIX' => 'chv_',
'CHEVERETO_DB_USER' => '',
'CHEVERETO_DEBUG_LEVEL' => '1',
'CHEVERETO_ENABLE_API_GUEST' => '1',
'CHEVERETO_ENABLE_BANNERS' => '1',
'CHEVERETO_ENABLE_BULK_IMPORTER' => '1',
'CHEVERETO_ENABLE_CAPTCHA' => '1',
'CHEVERETO_ENABLE_CDN' => '1',
'CHEVERETO_ENABLE_CHECK_UPDATES' => '1',
'CHEVERETO_ENABLE_CONSENT_SCREEN' => '1',
'CHEVERETO_ENABLE_COOKIE_COMPLIANCE' => '1',
'CHEVERETO_ENABLE_EXPOSE_PAID_FEATURES' => '1',
'CHEVERETO_ENABLE_EXTERNAL_SERVICES' => '1',
'CHEVERETO_ENABLE_EXTERNAL_STORAGE' => '1',
'CHEVERETO_ENABLE_FAVICON' => '1',
'CHEVERETO_ENABLE_FOLLOWERS' => '1',
'CHEVERETO_ENABLE_HTACCESS_CHECK' => '0',
'CHEVERETO_ENABLE_IP_BANS' => '1',
'CHEVERETO_ENABLE_LANGUAGE_CHOOSER' => '1',
'CHEVERETO_ENABLE_LIKES' => '1',
'CHEVERETO_ENABLE_LOCAL_STORAGE' => '1',
'CHEVERETO_ENABLE_LOGIN_PROVIDERS' => '1',
'CHEVERETO_ENABLE_LOGO' => '1',
'CHEVERETO_ENABLE_MODERATION' => '1',
'CHEVERETO_ENABLE_NOTIFICATIONS' => '1',
'CHEVERETO_ENABLE_PAGES' => '1',
'CHEVERETO_ENABLE_PHP_PAGES' => '0',
'CHEVERETO_ENABLE_POWERED_BY_FOOTER_SITE_WIDE' => '0',
'CHEVERETO_ENABLE_ROUTING' => '1',
'CHEVERETO_ENABLE_SERVICE_AKISMET' => '1',
'CHEVERETO_ENABLE_SERVICE_MODERATECONTENT' => '1',
'CHEVERETO_ENABLE_SERVICE_PROJECTARACHNID' => '1',
'CHEVERETO_ENABLE_SERVICE_STOPFORUMSPAM' => '1',
'CHEVERETO_ENABLE_STOPWORDS' => '1',
'CHEVERETO_ENABLE_UPDATE_CLI' => '1',
'CHEVERETO_ENABLE_UPDATE_HTTP' => '1',
'CHEVERETO_ENABLE_UPLOAD_FLOOD_PROTECTION' => '1',
'CHEVERETO_ENABLE_UPLOAD_PLUGIN' => '1',
'CHEVERETO_ENABLE_UPLOAD_WATERMARK' => '1',
'CHEVERETO_ENABLE_USERS' => '1',
'CHEVERETO_ENABLE_SEO_IMAGE_URL' => '1',
'CHEVERETO_ENABLE_SEO_ALBUM_URL' => '1',
'CHEVERETO_ENCRYPTION_KEY' => '',
'CHEVERETO_ERROR_LOG' => 'php://stderr',
'CHEVERETO_HEADER_CLIENT_IP' => '',
'CHEVERETO_HOSTNAME_PATH' => '/',
'CHEVERETO_HOSTNAME' => 'localhost',
'CHEVERETO_HTTPS' => '1',
'CHEVERETO_IMAGE_FORMATS_AVAILABLE' => '["JPEG","PNG","BMP","GIF","WEBP"]',
'CHEVERETO_IMAGE_LIBRARY' => 'imagick',
'CHEVERETO_MAX_ALBUMS' => '0',
'CHEVERETO_MAX_EXECUTION_TIME_SECONDS' => '30',
'CHEVERETO_MAX_IMAGES' => '0',
'CHEVERETO_MAX_MEMORY_SIZE' => '512M',
'CHEVERETO_MAX_POST_SIZE' => '64M',
'CHEVERETO_MAX_UPLOAD_SIZE' => '64M',
'CHEVERETO_MAX_USER_ALBUMS_LIST' => '300',
'CHEVERETO_MAX_USERS' => '0',
'CHEVERETO_SERVICING' => 'server',
'CHEVERETO_SESSION_SAVE_HANDLER' => 'files',
'CHEVERETO_SESSION_SAVE_PATH' => '/tmp',
'CHEVERETO_EDITION' => 'pro',
'CHEVERETO_BINARY_FFMPEG' => 'ffmpeg',
'CHEVERETO_BINARY_FFPROBE' => 'ffprobe',
'CHEVERETO_BINARY_FFMPEG' => 'ffmpeg',
'CHEVERETO_BINARY_FFPROBE' => 'ffprobe',
'CHEVERETO_CONTEXT' => '',
'CHEVERETO_DB_DRIVER' => 'mysql',
'CHEVERETO_DB_HOST' => 'localhost',
'CHEVERETO_DB_NAME' => '',
'CHEVERETO_DB_PASS' => '',
'CHEVERETO_DB_PDO_ATTRS' => '[]',
'CHEVERETO_DB_PORT' => '3306',
'CHEVERETO_DB_TABLE_PREFIX' => 'chv_',
'CHEVERETO_DB_USER' => '',
'CHEVERETO_DEBUG_LEVEL' => '1',
'CHEVERETO_EDITION' => 'pro',
'CHEVERETO_ENABLE_API_GUEST' => '1',
'CHEVERETO_ENABLE_BANNERS' => '1',
'CHEVERETO_ENABLE_BULK_IMPORTER' => '1',
'CHEVERETO_ENABLE_CAPTCHA' => '1',
'CHEVERETO_ENABLE_CDN' => '1',
'CHEVERETO_ENABLE_CONSENT_SCREEN' => '1',
'CHEVERETO_ENABLE_COOKIE_COMPLIANCE' => '1',
'CHEVERETO_ENABLE_DEBUG' => '1',
'CHEVERETO_ENABLE_EXPOSE_PAID_FEATURES' => '1',
'CHEVERETO_ENABLE_EXTERNAL_SERVICES' => '1',
'CHEVERETO_ENABLE_EXTERNAL_STORAGE_PROVIDERS' => '1',
'CHEVERETO_ENABLE_FAVICON' => '1',
'CHEVERETO_ENABLE_FOLLOWERS' => '1',
'CHEVERETO_ENABLE_FORCE_POWERED_BY_FOOTER' => '0',
'CHEVERETO_ENABLE_HTACCESS_CHECK' => '0',
'CHEVERETO_ENABLE_IP_BANS' => '1',
'CHEVERETO_ENABLE_LANGUAGE_CHOOSER' => '1',
'CHEVERETO_ENABLE_LIKES' => '1',
'CHEVERETO_ENABLE_LOCAL_STORAGE' => '1',
'CHEVERETO_ENABLE_LOGIN_PROVIDERS' => '1',
'CHEVERETO_ENABLE_LOGO_CUSTOM' => '1',
'CHEVERETO_ENABLE_MODERATION' => '1',
'CHEVERETO_ENABLE_NEWS_CHECK' => '1',
'CHEVERETO_ENABLE_NOTIFICATIONS' => '1',
'CHEVERETO_ENABLE_PAGES' => '1',
'CHEVERETO_ENABLE_PHP_PAGES' => '0',
'CHEVERETO_ENABLE_POWERED_BY_SETTING' => '1',
'CHEVERETO_ENABLE_PUP_CUSTOM_URL' => '1',
'CHEVERETO_ENABLE_ROUTING' => '1',
'CHEVERETO_ENABLE_SEO_ALBUM_URL' => '1',
'CHEVERETO_ENABLE_SEO_IMAGE_URL' => '1',
'CHEVERETO_ENABLE_SERVICE_AKISMET' => '1',
'CHEVERETO_ENABLE_SERVICE_MODERATECONTENT' => '1',
'CHEVERETO_ENABLE_SERVICE_PROJECTARACHNID' => '1',
'CHEVERETO_ENABLE_SERVICE_STOPFORUMSPAM' => '1',
'CHEVERETO_ENABLE_STOPWORDS' => '1',
'CHEVERETO_ENABLE_UPDATE_CHECK' => '1',
'CHEVERETO_ENABLE_UPDATE_CLI' => '1',
'CHEVERETO_ENABLE_UPDATE_HTTP' => '1',
'CHEVERETO_ENABLE_UPLOAD_FLOOD_PROTECTION' => '1',
'CHEVERETO_ENABLE_UPLOAD_PLUGIN' => '1',
'CHEVERETO_ENABLE_UPLOAD_URL' => '1',
'CHEVERETO_ENABLE_UPLOAD_WATERMARK' => '1',
'CHEVERETO_ENABLE_USERS' => '1',
'CHEVERETO_ENABLE_XRDEBUG' => '0',
'CHEVERETO_ENCRYPTION_KEY' => '',
'CHEVERETO_ERROR_LOG_CLI' => '',
'CHEVERETO_ERROR_LOG_CRON' => '',
'CHEVERETO_ERROR_LOG' => 'php://stderr',
'CHEVERETO_HEADER_CLIENT_IP' => '',
'CHEVERETO_HOSTNAME_PATH' => '/',
'CHEVERETO_HOSTNAME' => 'localhost',
'CHEVERETO_HTTPS' => '1',
'CHEVERETO_IMAGE_FORMATS_AVAILABLE' => '["AVIF","JPEG","PNG","BMP","GIF","WEBP"]',
'CHEVERETO_IMAGE_LIBRARY' => 'imagick',
'CHEVERETO_MAX_ADMINS' => '0',
'CHEVERETO_MAX_ALBUMS' => '0',
'CHEVERETO_MAX_CATEGORIES' => '0',
'CHEVERETO_MAX_EXECUTION_TIME_SECONDS' => '30',
'CHEVERETO_MAX_FILES' => '0',
'CHEVERETO_MAX_LOGIN_PROVIDERS' => '0',
'CHEVERETO_MAX_MANAGERS' => '0',
'CHEVERETO_MAX_MEMORY_SIZE' => '512M',
'CHEVERETO_MAX_PAGES' => '0',
'CHEVERETO_MAX_POST_SIZE' => '100M',
'CHEVERETO_MAX_STORAGES' => '0',
'CHEVERETO_MAX_TAGS_PER_FILE' => '0',
'CHEVERETO_MAX_TAGS_PER_LISTING' => '0',
'CHEVERETO_MAX_TAGS' => '0',
'CHEVERETO_MAX_UPLOAD_SIZE' => '100M',
'CHEVERETO_MAX_USER_ALBUMS_LIST' => '500',
'CHEVERETO_MAX_USERS' => '0',
'CHEVERETO_MIN_STORAGES_ACTIVE' => '0',
'CHEVERETO_SERVICING' => 'server',
'CHEVERETO_SESSION_SAVE_HANDLER' => 'files',
'CHEVERETO_SESSION_SAVE_PATH' => '/tmp',
'CHEVERETO_XRDEBUG_HOST' => 'localhost',
'CHEVERETO_XRDEBUG_HTTPS' => '0',
'CHEVERETO_XRDEBUG_KEY' => '',
'CHEVERETO_XRDEBUG_PORT' => '27420',
];

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,8 @@
msgid ""
msgstr ""
"Project-Id-Version: VERSION\n"
"POT-Creation-Date: 2023-05-22 15:49+0000\n"
"PO-Revision-Date: 2023-05-22 15:49+0000\n"
"POT-Creation-Date: 2024-11-14 15:22+0000\n"
"PO-Revision-Date: 2024-11-14 15:22+0000\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE TEAM <EMAIL@ADDRESS>\n"
"Language: pt\n"
@ -14,21 +14,40 @@ msgstr ""
msgid "You have been forbidden to use this website."
msgstr "Foi proibido de usar este site."
msgid "Moderate"
msgstr "Moderar"
msgid "View all my images"
msgstr "Ver todas as minhas imagens"
msgid "Recent"
msgstr "Recente"
msgid "Trending"
msgstr "Popular agora"
msgid "Popular"
msgstr "Popular"
msgid "Animated"
msgstr "Animadas"
msgid "Request denied"
msgstr "Pedido negado"
msgid "terms"
msgstr "termos"
msgid "privacy policy"
msgstr "política de privacidade"
msgid "That page doesn't exist"
msgstr "Esta página não existe"
#, php-format
msgid "Page %s"
msgstr "Página %s"
msgid "Forgot password?"
msgstr "Esqueceu-se da senha?"
@ -44,11 +63,14 @@ msgstr "Adicione o seu endereço de email"
msgid "Awaiting confirmation"
msgstr "Aguardando confirmação"
msgid "Two-factor authentication"
msgstr "Autenticação de dois factores"
msgid "Email changed"
msgstr "E-mail alterado"
msgid "Invalid Username/Email"
msgstr "Nome de usuário inválido / Email"
msgstr "Nome de utilizador/Email inválido"
msgid "User doesn't have an email."
msgstr "O utilizador não tem um e-mail."
@ -59,6 +81,9 @@ msgstr "A conta precisa ser ativada antes de poder usar este recurso"
msgid "Account already activated"
msgstr "Conta activada"
msgid "Account banned"
msgstr "Conta banida"
msgid "Allow up to 15 minutes for the email. You can try again later."
msgstr "Aguarde até 15 minutos pela recepção do e-mail. Poderá tentar novamente mais tarde."
@ -86,6 +111,9 @@ msgstr "E-mail inválido"
msgid "Email already being used"
msgstr "Esse e-mail já está a ser utilizado"
msgid "Invalid code"
msgstr "Código inválido"
msgid "Check the errors in the form to continue."
msgstr "Verifique os erros no formulário para continuar."
@ -95,6 +123,9 @@ msgstr "É preciso senha"
msgid "Embed codes"
msgstr "Códigos para Incorporar"
msgid "albums"
msgstr "álbuns"
msgid "%a album hosted in %w"
msgstr "Álbum %a alojado em %w"
@ -103,12 +134,6 @@ msgid_plural "images"
msgstr[0] "imagem"
msgstr[1] "imagens"
msgid "Stats"
msgstr "Estatísticas"
msgid "Images"
msgstr "Imagens"
msgid "Album"
msgid_plural "Albums"
msgstr[0] "Álbum"
@ -134,8 +159,11 @@ msgstr "Conteúdo"
msgid "Listings"
msgstr "Resultados"
msgid "Image upload"
msgstr "Envio de imagem"
msgid "File uploads"
msgstr "Envios de ficheiros"
msgid "Semantics"
msgstr "Semântica"
msgid "Categories"
msgstr "Categorias"
@ -152,8 +180,11 @@ msgstr "Idiomas"
msgid "Email"
msgstr "E-mail"
msgid "External storage"
msgstr "Alojamento externo"
msgid "Tools"
msgstr "Ferramentas"
msgid "Logo"
msgstr "Logo"
msgid "Homepage"
msgstr "Página principal"
@ -161,11 +192,24 @@ msgstr "Página principal"
msgid "Pages"
msgstr "Páginas"
msgid "Consent screen"
msgstr "Janela de consentimento"
#, php-format
msgid "Guests %s"
msgstr "Convidados %s"
msgid "External storage"
msgstr "Alojamento externo"
msgid "Routing"
msgstr "Redireccionamento"
msgid "External services"
msgstr "Serviços externos"
msgid "Flood protection"
msgstr "Protecção contra as inundações"
msgstr "Protecção contra abuso"
msgid "IP bans"
msgstr "Banimentos por IP"
@ -173,59 +217,41 @@ msgstr "Banimentos por IP"
msgid "Watermarks"
msgstr "Marcas de água"
msgid "Documentation"
msgstr "Documentação"
msgid "Support"
msgstr "Suport"
msgid "Community"
msgstr "Comunidade"
msgstr "Suporte"
msgid "install update"
msgstr "Instalar actualização"
msgid "Stats"
msgstr "Estatísticas"
msgid "Rebuild stats"
msgstr "Estatísticas de reconstrução"
msgid "Not your IP?"
msgstr "Não é o seu IP?"
msgid "PHP version"
msgstr "Versão do PHP"
msgid "Server"
msgstr "Servidor"
msgid "MySQL version"
msgstr "Versão do MySQL"
msgid "MySQL server info"
msgstr "Informação do servidor MySQL"
msgid "File uploads"
msgstr "Envios de ficheiros"
msgid "Enabled"
msgstr "Ativado"
msgid "Disabled"
msgstr "Desactivado"
msgid "Max. execution time"
msgstr "Tempo máximo de execução"
msgid "Releases"
msgstr "Lançamentos"
#, php-format
msgid "%d second"
msgid_plural "%d seconds"
msgstr[0] "%d segundo"
msgstr[1] "%d segundos"
msgid "Community"
msgstr "Comunidade"
msgid "Memory limit"
msgstr "Limite de memória"
msgid "Cron last ran"
msgstr "Última execução do agendamento"
msgid "External"
msgstr "Externo"
msgid "PHP version"
msgstr "Versão do PHP"
msgid "Server"
msgstr "Servidor"
msgid "All"
msgstr "Todas"
@ -233,33 +259,16 @@ msgstr "Todas"
msgid "search content"
msgstr "conteúdo de pesquisa"
msgid "Before pagination"
msgstr "Antes de paginação"
msgid "After pagination"
msgstr "Depois de paginação"
msgid "Before comments"
msgstr "Antes dos comentários"
msgid "Image page"
msgstr "Página da imagem"
msgid "Inside viewer top (image page)"
msgstr "Topo da página para visualizar a imagem"
msgid "Footer (image page)"
msgstr "Rodapé (página imagem)"
msgid "User profile page"
msgstr "Página de perfil do utilizador"
msgid "After top (user profile)"
msgstr "Depois de topo (perfil do utlizador)"
msgid "Explore"
msgstr "Explorar"
#, php-format
msgid "After top (%s page)"
msgstr "Depois do topo (%s página)"
msgid "NSFW"
msgstr "18+"
msgid "Invalid website name"
msgstr "Nome da página inválido"
@ -269,6 +278,10 @@ msgstr "Idioma inválido"
msgid "Invalid timezone"
msgstr "Fuso horário inválido"
#, php-format
msgid "Invalid value: %s"
msgstr "Valor inválido: %s"
msgid "Invalid thumb width"
msgstr "largura da miniatura inválida"
@ -281,46 +294,6 @@ msgstr "Tema inválido"
msgid "Invalid value"
msgstr "Valor inválido"
msgid "Invalid theme image listing size"
msgstr "Tamanho para os resultados do tema inválido"
msgid "Invalid user id"
msgstr "ID de usuário Inválido"
msgid "Invalid email mode"
msgstr "Modo de e-mail inválido"
msgid "Invalid SMTP port"
msgstr "Porta SMTP inválida"
msgid "Invalid SMTP security"
msgstr "Segurança inválida SMTP "
msgid "Invalid website mode"
msgstr "Modo de website inválido"
msgid "Invalid website content privacy mode"
msgstr "modo de conteúdo do site privacidade inválido"
msgid "Invalid homepage style"
msgstr "Estilo da página principal inválido"
msgid "Invalid URL"
msgstr "URL inválido"
msgid "Invalid upload image path"
msgstr "Caminho para o envio de imagens inválido"
#, php-format
msgid "Max. allowed %s"
msgstr "Máximo permitido %s"
msgid "Invalid SMTP server"
msgstr "Servidor SMTP inválido"
msgid "Invalid SMTP username"
msgstr "Nome de usuário SMTP inválido"
msgid "Dashboard"
msgstr "Administração"
@ -342,21 +315,6 @@ msgstr "Imagem %i na categoria %c"
msgid "Image %i hosted in %w"
msgstr "Imagem %i alojada em %w"
msgid "Direct links"
msgstr "Links Diretos"
msgid "Image link"
msgstr "Link da imagem"
msgid "Image URL"
msgstr "URL da imagem"
msgid "Thumbnail URL"
msgstr "URL Thumbnail"
msgid "Medium URL"
msgstr "URL Médio"
msgid "Login needed"
msgstr "Necessário iniciar sessão"
@ -368,9 +326,6 @@ msgstr[1] "imagens"
msgid "Category"
msgstr "Categoria"
msgid "IP address already banned"
msgstr "Endereço de IP já banido"
msgid "Missing values"
msgstr "Valores em falta"
@ -383,6 +338,9 @@ msgstr "Papel inválido"
msgid "Username already being used"
msgstr "Nome de utilizador já está a ser utilizado"
msgid "IP address already banned"
msgstr "Endereço de IP já banido"
#, php-format
msgid "%s has been disconnected."
msgstr "%s foi desconectado."
@ -449,6 +407,9 @@ msgstr "Apagar utilizador"
msgid "User ID"
msgstr "ID de utilizador"
msgid "Images"
msgstr "Imagens"
msgid "Register date"
msgstr "Data de registo"
@ -584,7 +545,7 @@ msgid "%s ago"
msgstr "%s atrás"
msgid "moments ago"
msgstr "à momentos atrás"
msgstr "há poucos segundos"
msgid "Random"
msgstr "Aleatório"
@ -642,28 +603,24 @@ msgstr "Imagem de fundo eliminada."
msgid "Error deleting profile background image."
msgstr "Erro apagar imagem de fundo do perfil"
#, javascript-format
msgid "Update available v%s"
msgstr "Actualização disponível v%s"
msgid "Like"
msgstr "Gostar"
msgid "Create album"
msgstr "Criar álbum"
msgid "Edit"
msgstr "Editar"
msgid "Delete"
msgstr "Eliminar"
msgid "Previous"
msgstr "Anterior"
msgid "Edit"
msgstr "Editar"
msgid "Like"
msgstr "Gostar"
msgid "Next"
msgstr "Próximo"
msgid "Previous"
msgstr "Anterior"
msgid "File too big."
msgstr "Ficheiro muito grande."
@ -677,9 +634,6 @@ msgstr "Alguns arquivos não puderam ser adiccionados"
msgid "%s's Albums"
msgstr "Álbuns de %s"
msgid "Image edited successfully."
msgstr "Imagem editada com sucesso."
msgid "private"
msgstr "Privado"
@ -820,9 +774,6 @@ msgstr "Obrigado por se juntar a nós"
msgid "This email was sent from %w %u"
msgstr "Este e-mail foi enviado por %w %u"
msgid "Select the images to upload"
msgstr "Selecionar as imagens para envio"
msgid "complete"
msgstr "completo"
@ -862,36 +813,12 @@ msgstr "Assinalar como inseguro"
msgid "Description"
msgstr "Descrição"
msgid "Add image URLs"
msgstr "Adicionar URLs de imagem"
msgid "Add the image URLs here"
msgstr "Adicione os URLs de imagem aqui"
msgid "Error report"
msgstr "Relatório de erro"
msgid "Direct"
msgstr "Directo"
msgid "HTML Codes"
msgstr "Códigos HTML"
msgid "HTML medium linked"
msgstr "HTML médio"
msgid "HTML thumbnail linked"
msgstr "HTML da miniatura"
msgid "BBCode medium linked"
msgstr "Código BBCode do tamanho médio"
msgid "BBCode thumbnail linked"
msgstr "Código BBCode da miniatura"
msgid "Viewer links"
msgstr "Ver links"
msgid "All these words"
msgstr "Todas estas palavras"
@ -1024,6 +951,9 @@ msgstr "Entre com outra conta"
msgid "There's nothing to show here."
msgstr "Não há nada para ver aqui."
msgid "Selection will be assigned to %t."
msgstr "A selecção vai ser atribuída a %t."
msgid "There is no categories."
msgstr "Não existem categorias."
@ -1198,6 +1128,34 @@ msgstr "Activo"
msgid "Disk used"
msgstr "Espaço usado"
msgid "Enable uploads"
msgstr "Activar envios"
msgid "Guest uploads"
msgstr "Envios de visitantes"
msgid "Enable this if you want to allow non registered users to upload."
msgstr "Ative isto se quiser permitir que os utilizadores não registados façam envios."
msgid "Relative to Chevereto root"
msgstr "Relativo ao root do Chevereto"
msgid "Storage mode"
msgstr "Modo de armazenamento"
#, php-format
msgid "Datefolders creates %s structure"
msgstr "Datefolders cria %s estrutura"
msgid "File naming method"
msgstr "Método de nomeação do arquivo"
msgid "Thumb size"
msgstr "Tamanho da miniatura"
msgid "Thumbnails will be fixed to this size."
msgstr "As miniaturas serão ajustadas para este tamanho."
msgid "Notify to email"
msgstr "Notificar para o e-mail"
@ -1243,40 +1201,6 @@ msgstr "Branco"
msgid "Default"
msgstr "Padrão"
msgid "Enable uploads"
msgstr "Activar envios"
msgid "Guest uploads"
msgstr "Envios de visitantes"
msgid "Enable this if you want to allow non registered users to upload."
msgstr "Ative isto se quiser permitir que os utilizadores não registados façam envios."
msgid "Image path"
msgstr "Caminho da imagem"
msgid "Relative to Chevereto root"
msgstr "Relativo ao root do Chevereto"
msgid "Where to store the images? Relative to Chevereto root."
msgstr "Onde alojar as imagens? Relativo ao root do Chevereto."
msgid "Storage mode"
msgstr "Modo de armazenamento"
#, php-format
msgid "Datefolders creates %s structure"
msgstr "Datefolders cria %s estrutura"
msgid "File naming method"
msgstr "Método de nomeação do arquivo"
msgid "Thumb size"
msgstr "Tamanho da miniatura"
msgid "Thumbnails will be fixed to this size."
msgstr "As miniaturas serão ajustadas para este tamanho."
msgid "Expires"
msgstr "Expira"
@ -1514,14 +1438,11 @@ msgstr "Endereço de email"
#, php-format
msgid "Added to %s"
msgstr "Adicionar a %s"
msgstr "Adicionado a %s"
msgid "Add IP ban"
msgstr "Adicionar banimento de IP"
msgid "Upload and share your images."
msgstr "Envie e compartilhe as suas imagens."
msgid "Sign up to unlock all the features"
msgstr "Registre-se agora Grátis"

File diff suppressed because it is too large Load diff

View file

@ -14,9 +14,9 @@ use function Chevereto\Legacy\feedbackAlert;
use function Chevereto\Legacy\isSafeToExecute;
use function Chevereto\Vars\env;
if (!(bool) env()['CHEVERETO_ENABLE_BULK_IMPORTER']) {
if (! (bool) env()['CHEVERETO_ENABLE_BULK_IMPORTER']) {
feedbackAlert('Bulk importer is disabled');
die(255);
exit(255);
}
$threadID = getenv('THREAD_ID') ?: 0;
$loop = 1;
@ -26,7 +26,7 @@ do {
if ($jobs === []) {
echo "~They took our jobs!~\n";
echo "[OK] No jobs left.\n";
die(0);
exit(0);
}
$id = $jobs[0]['import_id'];
$import = new Import();
@ -34,13 +34,15 @@ do {
$import->thread = (int) $threadID;
$import->get();
if ($import->isLocked()) {
$import->edit(['status' => 'paused']);
echo "> Job locked for id #$id\n";
$import->edit([
'status' => 'paused',
]);
echo "> Job locked for id #{$id}\n";
} else {
echo "* Processing job id #$id\n";
echo "* Processing job id #{$id}\n";
$import->process();
}
$loop++;
} while (isSafeToExecute());
echo "--\n[OK] Automatic importing looped $loop times ~ /dashboard/bulk for stats\n";
die(0);
echo "--\n[OK] Automatic importing looped {$loop} times ~ /dashboard/bulk for stats\n";
exit(0);

View file

@ -35,8 +35,10 @@ $settings = Settings::get();
new EncryptionInstance($toEncryption);
foreach (Settings::ENCRYPTED_NAMES as $key) {
$value = $settings[$key] ?? '';
feedback("- $key: $value");
Settings::update([$key => $value]);
feedback("- {$key}: {$value}");
Settings::update([
$key => $value,
]);
}
feedbackSeparator();
feedbackStep($doing, 'storages');
@ -48,7 +50,7 @@ foreach ($storages as $storage) {
$values = [];
foreach (Storage::ENCRYPTED_NAMES as $key) {
$value = $storage[$key] ?? '';
feedback(" $key: $value");
feedback(" {$key}: {$value}");
$values[$key] = $value;
}
Storage::update(
@ -59,7 +61,10 @@ foreach ($storages as $storage) {
}
feedbackSeparator();
feedbackStep($doing, 'two-factor secrets');
$twoFactors = DB::get('two_factors', [], 'AND', ['field' => 'id', 'order' => 'desc']);
$twoFactors = DB::get('two_factors', [], 'AND', [
'field' => 'id',
'order' => 'desc',
]);
foreach ($twoFactors as $twoFactor) {
new EncryptionInstance($fromEncryption);
$twoFactor = TwoFactor::get($twoFactor['two_factor_id']);
@ -69,7 +74,7 @@ foreach ($twoFactors as $twoFactor) {
$values = [
'secret' => $secret,
];
feedback("- secret: $secret");
feedback("- secret: {$secret}");
TwoFactor::update(
id: $twoFactor['id'],
values: $values,
@ -85,7 +90,7 @@ foreach ($loginProviders as $name => $loginProvider) {
$values = [];
foreach (Login::ENCRYPTED_PROVIDER_NAMES as $key) {
$value = $loginProvider[$key] ?? '';
feedback(" $key: $value");
feedback(" {$key}: {$value}");
$values[$key] = $value;
}
Login::updateProvider(
@ -95,11 +100,18 @@ foreach ($loginProviders as $name => $loginProvider) {
}
feedbackSeparator();
feedbackStep($doing, 'login connection tokens');
$connections = DB::get(table: 'login_connections', values: 'all', sort: ['field' => 'id', 'order' => 'desc']);
$connections = DB::get(
table: 'login_connections',
where: 'all',
sort: [
'field' => 'id',
'order' => 'desc',
]
);
foreach ($connections as $connection) {
new EncryptionInstance($fromEncryption);
$connection = Login::getConnection($connection['login_connection_id']);
feedback("> Login connection #" . $connection['id']);
feedback('> Login connection #' . $connection['id']);
new EncryptionInstance($toEncryption);
$token = $connection['token'];
$values = [
@ -110,14 +122,14 @@ foreach ($connections as $connection) {
values: $values,
);
$tokenString = serialize($token);
feedback("- token: $tokenString");
feedback("- token: {$tokenString}");
}
feedbackSeparator();
feedbackStep($doing, 'albums password');
$albumsPassword = DB::queryFetchAll('SELECT album_id id, album_password password FROM ' . DB::getTable('albums') . ' WHERE album_password IS NOT NULL;');
foreach ($albumsPassword as $album) {
new EncryptionInstance($fromEncryption);
feedback("> Album id #" . $album['id']);
feedback('> Album id #' . $album['id']);
new EncryptionInstance($toEncryption);
$password = $album['password'];
$values = [
@ -127,5 +139,5 @@ foreach ($albumsPassword as $album) {
id: (int) $album['id'],
values: $values,
);
feedback("- password: $password");
feedback("- password: {$password}");
}

View file

@ -9,8 +9,8 @@
* file that was distributed with this source code.
*/
use Chevere\ThrowableHandler\Documents\PlainDocument;
use Chevereto\Config\Config;
use function Chevereto\Legacy\checkUpdates;
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Image;
use Chevereto\Legacy\Classes\L10n;
@ -18,6 +18,13 @@ use Chevereto\Legacy\Classes\Lock;
use Chevereto\Legacy\Classes\Queue;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\Classes\Variable;
use function Chevere\Message\message;
use function Chevere\ThrowableHandler\throwableHandler;
use function Chevere\Writer\writers;
use function Chevere\xrDebug\PHP\throwableHandler as XrDebugThrowableHandler;
use function Chevereto\Legacy\checkUpdates;
use function Chevereto\Legacy\cheveretoVersionInstalled;
use function Chevereto\Legacy\feedbackAlert;
use function Chevereto\Legacy\feedbackStep;
use function Chevereto\Legacy\G\datetime_add;
@ -30,44 +37,115 @@ use function Chevereto\Vars\env;
if (getSetting('maintenance')) {
echo "[!] Chevereto is in maintenance mode.\n";
die(255);
exit(255);
}
$jobs = ['deleteExpiredImages', 'cleanUnconfirmedUsers', 'removeDeleteLog', 'checkForNews'];
if ((bool) env()['CHEVERETO_ENABLE_EXTERNAL_STORAGE']) {
$jobs[] = 'storageDelete';
}
if ((bool) env()['CHEVERETO_ENABLE_CHECK_UPDATES']) {
$jobs = [
'deleteExpiredImages',
'cleanUnconfirmedUsers',
'removeDeleteLog',
'storageDelete',
];
if ((bool) env()['CHEVERETO_ENABLE_UPDATE_CHECK']) {
$jobs[] = 'checkForUpdates';
}
if ((bool) env()['CHEVERETO_ENABLE_NEWS_CHECK']) {
$jobs[] = 'checkForNews';
}
if (Config::enabled()->htaccessCheck()) {
$jobs[] = 'checkHtaccess';
}
shuffle($jobs);
$time_start = microtime(true);
$errors = [];
$namespace = env()['CHEVERETO_ID_HANDLE'] ?? false;
foreach ($jobs as $job) {
if (!isSafeToExecute()) {
if (! isSafeToExecute()) {
echo "[OK] Exit - (time is up)\n";
writeLastRan();
writeLastRan($time_start);
exit(0);
}
feedbackStep('Job:', $job);
$job();
try {
$job();
} catch (Throwable $throwable) {
feedbackAlert($throwable->getMessage());
$errors[$job] = $throwable->getMessage();
$publicHandler = throwableHandler($throwable);
if ($namespace) {
$publicHandler = $publicHandler
->withId($namespace . $publicHandler->id());
}
$internalHandler = $publicHandler->withIsDebug(true);
$docInternal = new PlainDocument($internalHandler);
$logMessage = '[' . $publicHandler->id() . '] '
. $docInternal->__toString()
. "\n\n";
try {
$errorLog = ini_get('error_log');
$fp = fopen($errorLog, 'a');
fwrite($fp, $logMessage);
fclose($fp);
} catch (Throwable) {
if (PHP_SAPI === 'cli') {
error_log($logMessage);
} else {
writers()->error()->write($logMessage);
}
}
$extra = <<<HTML
<div class="throwable-message"><b>Incident {$publicHandler->id()}</b></div>
<div class="throwable-message"><b>Backtrace</b></div>
HTML;
XrDebugThrowableHandler($throwable, $extra);
}
}
writeLastRan();
function writeLastRan(): void
writeLastRan($time_start);
function writeLastRan(float $time_start): void
{
$datetimegmt = datetimegmt();
Settings::update(['cron_last_ran' => datetimegmt()]);
echo "--\n✅ [DONE] Cron tasks ran @ $datetimegmt\n";
Variable::set('cron_last_ran', $datetimegmt);
$time_taken = microtime(true) - $time_start;
$ceil = ceil($time_taken);
$round = round($time_taken, 2);
echo "--\n[DONE] Cron tasks ran @ {$datetimegmt}";
echo "\n{$round}s\n--";
if (version_compare(cheveretoVersionInstalled(), '4.2.0', '>=')) {
$sql = <<<MySQL
INSERT `%table_stats%` (stat_type, stat_date_gmt, stat_cron_time, stat_cron_runs)
VALUES ("date", DATE("%date_gmt%"), %time%, 1)
ON DUPLICATE KEY
UPDATE stat_cron_time = stat_cron_time + %time%,
stat_cron_runs = stat_cron_runs + 1;
MySQL;
$sql = (string) message(
$sql,
table_stats: DB::getTable('stats'),
time: $ceil,
date_gmt: $datetimegmt,
);
try {
DB::queryExecute($sql);
} catch (Throwable $e) {
// Do nothing
}
}
exit;
}
function echoLocked(string $job): void
{
echo "* [!] Job $job is locked ~ skipping\n";
echo "* Job: {$job} [now locked]\n";
}
function storageDelete(): void
{
$job = 'storage-delete';
$lock = new Lock($job);
if ($lock->create()) {
Queue::process(['type' => $job]);
Queue::process([
'type' => $job,
]);
$lock->destroy();
return;
@ -115,7 +193,7 @@ function removeDeleteLog(): void
}
function checkForNews(): void
{
if (!checkoutUpdate('news_check_datetimegmt', 'PT4H')) {
if (! checkoutUpdate('news_check_datetimegmt', 'PT4H')) {
feedbackAlert('Skipping news check');
return;
@ -133,7 +211,7 @@ function checkForNews(): void
}
function checkForUpdates(): void
{
if (!checkoutUpdate('update_check_datetimegmt', 'P1D')) {
if (! checkoutUpdate('update_check_datetimegmt', 'P1D')) {
feedbackAlert('Skipping updates check');
return;
@ -151,8 +229,13 @@ function checkForUpdates(): void
}
function checkoutUpdate(string $datetimeSetting, string $past): bool
{
return is_null(Settings::get($datetimeSetting))
|| datetime_add(Settings::get($datetimeSetting), $past) < datetimegmt();
$get = Variable::fetch($datetimeSetting);
return $get === null
|| datetime_add(
$get,
$past
) < datetimegmt();
}
function checkHtaccess()
{

View file

@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\cheveretoVersionInstalled;
if (getSetting('chevereto_version_installed') !== null) {
if (cheveretoVersionInstalled() !== '') {
echo "[ERROR] Chevereto is already installed, try with the update command\n";
die(255);
exit(255);
}
require_once PATH_APP_LEGACY_INSTALL . 'installer.php';

View file

@ -0,0 +1,41 @@
<?php
/*
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
$workingDir = PATH_PUBLIC_CONTENT_LEGACY_THEMES_PEAFOWL_LIB;
$target = 'chevereto-all.js';
$outputFile = $workingDir . $target;
echo "* Compile JavaScript\n";
echo "---\n";
$fh = fopen($outputFile, 'w');
$files = [
'js/css_browser_detector.js',
'js/jquery.min.js',
'js/jquery-ui.min.js',
'js/hammer.min.js',
'js/peafowl.js',
'js/images-loaded.js',
'js/load-image.js',
'js/clipboard.js',
'js/chevereto.js',
];
foreach ($files as $file) {
$file = $workingDir . $file;
if (! file_exists($file)) {
echo "❌ [ERROR] Missing file: {$file}\n";
exit(1);
}
echo "Packing: {$file}\n";
fwrite($fh, file_get_contents($file) . "\n");
}
fclose($fh);
echo "---\n";
echo "💯 [OK] {$outputFile}\n";
exit(0);

View file

@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
use function Chevere\Filesystem\directoryForPath;
use Chevereto\Legacy\Classes\L10n;
use Chevereto\Legacy\G\Gettext;
use function Chevere\Filesystem\directoryForPath;
use function Chevereto\Legacy\G\unlinkIfExists;
use function Chevereto\Legacy\get_available_languages;
@ -27,20 +27,20 @@ foreach ($languages as $lang) {
$language_override_file = PATH_APP_LANGUAGES . 'overrides/' . $filename;
$language_handling = [
'base' => [
'file' => $language_file,
'cache_path' => L10n::PATH_CACHE,
'table' => [],
'file' => $language_file,
'cache_path' => L10n::PATH_CACHE,
'table' => [],
],
'override' => [
'file' => $language_override_file,
'cache_path' => L10n::PATH_CACHE_OVERRIDES,
'table' => [],
]
'file' => $language_override_file,
'cache_path' => L10n::PATH_CACHE_OVERRIDES,
'table' => [],
],
];
foreach ($language_handling as $k => $v) {
$cache_path = $v['cache_path'];
$cache_file = basename($v['file']) . '.cache.php';
if (!file_exists($v['file'])) {
if (! file_exists($v['file'])) {
continue;
}
$cache = $cache_path . $cache_file;
@ -51,12 +51,12 @@ foreach ($languages as $lang) {
'cache_header' => $k == 'base',
]);
}
echo "$lang\n";
echo "{$lang}\n";
if (file_exists($language_override_file)) {
echo "$lang [override]\n";
echo "{$lang} [override]\n";
}
}
echo "---\n";
echo L10n::LOCALES_AVAILABLE_FILEPATH . "\n";
echo "💯 [OK] Languages re-cached\n";
die(0);
exit(0);

View file

@ -9,38 +9,38 @@
* file that was distributed with this source code.
*/
use function Chevere\String\randomString;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\User;
use function Chevere\Standard\randomString;
$opts = getopt('C:u:') ?: [];
$missing = [];
if (!isset($opts['u'])) {
echo "[Error] Missing username" . "\n";
die(255);
if (! isset($opts['u'])) {
echo '[Error] Missing username' . "\n";
exit(255);
}
$password = randomString(24);
$user = User::getSingle($opts['u'], 'username');
if ($user === []) {
echo "[Error] User not found" . "\n";
die(255);
echo '[Error] User not found' . "\n";
exit(255);
}
$changed = Login::changePassword(
userId: $user['id'],
password: $password,
update_session: false
);
if (!$changed) {
if (! $changed) {
// echo "[NOTICE] User doesn't have a password" . "\n";
$added = Login::addPassword(
userId: $user['id'],
password: $password,
update_session: false
);
if (!$added) {
echo "[Error] Failed to add password" . "\n";
die(255);
if (! $added) {
echo '[Error] Failed to add password' . "\n";
exit(255);
}
}
echo $password . "\n";
die(0);
exit(0);

View file

@ -9,21 +9,21 @@
* file that was distributed with this source code.
*/
use function Chevere\Type\getType;
use Chevereto\Legacy\Classes\Settings;
use function Chevere\Parameter\getType;
$opts = getopt('C:k:t::') ?: [];
if (!isset($opts['k'])) {
if (! isset($opts['k'])) {
echo "[ERROR] Missing setting key\n";
die(255);
exit(255);
}
if (!Settings::hasKey($opts['k'])) {
if (! Settings::hasKey($opts['k'])) {
echo "[ERROR] Setting key doesn't exists\n";
die(255);
exit(255);
}
function toItalic(string $text): string
{
return "\e[3m$text\e[0m";
return "\e[3m{$text}\e[0m";
}
$value = Settings::get($opts['k']);
$echoValue = match (getType($value)) {
@ -31,9 +31,9 @@ $echoValue = match (getType($value)) {
'boolean' => toItalic($value ? 'true' : 'false'),
default => $value,
};
echo "$echoValue\n";
echo "{$echoValue}\n";
if (isset($opts['t'])) {
$typeset = Settings::getTypeset($opts['k']);
echo "%($typeset)\n";
echo "%({$typeset})\n";
}
die(0);
exit(0);

View file

@ -14,24 +14,22 @@ use Chevereto\Legacy\Classes\Settings;
$opts = getopt('C:v:k:') ?: [];
$missing = [];
foreach (['k', 'v'] as $opt) {
if (!isset($opts[$opt])) {
if (! isset($opts[$opt])) {
$missing[] = $opt;
}
}
if ($missing !== []) {
echo "[Error] Missing -" . implode(' -', $missing) . "\n";
die(255);
echo '[Error] Missing -' . implode(' -', $missing) . "\n";
exit(255);
}
if (!Settings::hasKey($opts['k'])) {
if (! Settings::hasKey($opts['k'])) {
echo "[ERROR] Setting key doesn't exists\n";
die(255);
exit(255);
}
/** @var int|string|null $value */
$value = $opts['v'] ?? null;
$typeset = Settings::getTypeset($opts['k']);
if ($typeset === 'bool') {
$value = (int) ($value == 1 || strtolower($value) === 'true');
}
Settings::update([$opts['k'] => $value]);
Settings::update([
$opts['k'] => $value,
]);
require 'setting-get.php';
die(0);
exit(0);

View file

@ -9,10 +9,10 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\cheveretoVersionInstalled;
if (getSetting('chevereto_version_installed') === null) {
if (cheveretoVersionInstalled() === '') {
echo "[ERROR] Chevereto is not installed, try with the install command.\n";
die(255);
exit(255);
}
require_once PATH_APP_LEGACY_INSTALL . 'installer.php';

View file

@ -9,44 +9,45 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\getCheveretoEnv;
use function Chevereto\Legacy\loaderHandler;
if (PHP_SAPI !== 'cli') {
header('HTTP/1.0 403 Forbidden');
die("403 Forbidden\n");
echo '403 Forbidden';
exit(255);
}
$opts = getopt('C:') ?: [];
if ($opts === []) {
echo "Missing -C command\n";
die(255);
} else {
$access = $opts['C'];
$options = [
'cron',
'update',
'encrypt-secrets',
'decrypt-secrets',
'htaccess-checksum',
'htaccess-enforce',
'bulk-importer',
'install',
'langs',
'password-reset',
'setting-get',
'setting-update',
'version'
];
if (!in_array($access, $options)) {
echo "Invalid command\n";
die(255);
}
echo 'Missing -C command' . PHP_EOL;
exit(255);
}
$access = $opts['C'];
$options = [
'cron',
'update',
'encrypt-secrets',
'decrypt-secrets',
'htaccess-checksum',
'htaccess-enforce',
'bulk-importer',
'install',
'langs',
'js',
'password-reset',
'setting-get',
'setting-update',
'version',
];
if (! in_array($access, $options, true)) {
echo 'Invalid command' . PHP_EOL;
exit(255);
}
define('ACCESS', $access);
require_once __DIR__ . '/../load/php-boot.php';
require_once __DIR__ . '/../load/loader.php';
require_once loaderHandler(
$_COOKIE,
$_ENV,
getCheveretoEnv(),
$_FILES,
$_GET,
$_POST,

View file

@ -9,6 +9,8 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\G\sanitize_path_slashes;
use function Chevereto\Legacy\getCheveretoEnv;
use function Chevereto\Legacy\loaderHandler;
define('ACCESS', 'web');
@ -16,17 +18,25 @@ define('ACCESS', 'web');
$appDir = __DIR__ . '/../..';
$loadDir = __DIR__ . '/../load';
require_once $loadDir . '/php-boot.php';
$uri = $_SERVER['REQUEST_URI'] ?? '';
$parseUri = parse_url($uri);
if (in_array($parseUri['path'] ?? null, ['/upgrading', '/upgrading/'])
$requestUri = $_SERVER['REQUEST_URI'] ?? '';
$scriptName = $_SERVER['SCRIPT_NAME'] ?? '';
$urlPath = parse_url($requestUri, PHP_URL_PATH);
if (str_ends_with($scriptName, 'index.php')) {
$relative_root = sanitize_path_slashes(
dirname($scriptName)
. '/'
);
$urlPath = preg_replace('#' . $relative_root . '#', '/', $requestUri, 1);
}
$urlPath = strtok($urlPath, '?');
if (in_array($urlPath, ['/upgrading', '/upgrading/'], true)
&& file_exists($appDir . '/.upgrading/upgrading.lock')) {
require $appDir . '/upgrading.php';
exit;
}
require_once $loadDir . '/loader.php';
require_once loaderHandler(
$_COOKIE,
$_ENV,
getCheveretoEnv(),
$_FILES,
$_GET,
$_POST,

File diff suppressed because it is too large Load diff

View file

@ -2,12 +2,12 @@
use function Chevereto\Legacy\G\get_base_url;
// @phpstan-ignore-next-line
if (!defined('ACCESS') || !ACCESS) {
die('This file cannot be directly accessed.');
if (! defined('ACCESS') || ! ACCESS) {
exit('This file cannot be directly accessed.');
} ?>
<h1><i class="far fa-check-circle"></i> Already installed</h1>
<p>Chevereto is already installed and updated.</p>
<div>
<a href="<?php echo get_base_url('dashboard'); ?>" class="action button radius"><span class="btn-icon fa-btn-icon fas fa-tachometer-alt"></span> Dashboard</a>
<a href="<?php echo get_base_url(); ?>" class="button radius"><span class="btn-icon fa-btn-icon fas fa-globe"></span> Website</a>
<a href="<?php echo get_base_url('dashboard'); ?>" class="action button radius"><span class="fas fa-tachometer-alt"></span> Dashboard</a>
<a href="<?php echo get_base_url(); ?>" class="button radius"><span class="fas fa-globe"></span> Website</a>
</div>

View file

@ -3,13 +3,20 @@ use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\get_chevereto_version;
// @phpstan-ignore-next-line
if (!defined('ACCESS') || !ACCESS) {
die('This file cannot be directly accessed.');
if (! defined('ACCESS') || ! ACCESS) {
exit('This file cannot be directly accessed.');
} ?>
<h1><i class="far fa-check-circle"></i> Installation complete</h1>
<p><?php echo strtr('Chevereto has been successfully installed. You can now continue to the <a href="%u">admin dashboard</a> and configure your website.', ['%s' => get_chevereto_version(true), '%u' => get_base_url('dashboard/?welcome')]); ?></p>
<p><?php echo strtr('Chevereto has been successfully installed. You can now continue to the <a href="%u">admin dashboard</a> and configure your website.', [
'%s' => get_chevereto_version(true),
'%u' => get_base_url('dashboard/?welcome'),
]); ?></p>
<div>
<a href="<?php echo get_base_url('dashboard/?welcome'); ?>" class="action button radius">Dashboard</a>
<a href="<?php echo get_base_url(); ?>" class="button radius">Website</a>
</div>
<script>$(document).ready(function() { CHV.fn.system.checkUpdates(); });</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
CHV.fn.system.checkUpdates();
});
</script>

View file

@ -1,50 +1,68 @@
<?php
use function Chevereto\Legacy\getSetting;
use Chevereto\Legacy\Classes\Settings;
use function Chevereto\Vars\env;
// @phpstan-ignore-next-line
if (!defined('ACCESS') || !ACCESS) {
die('This file cannot be directly accessed.');
} ?>
<h1><i class="fa fa-box-open"></i> Ready to install</h1>
<p>Fill this form with the details of the initial admin account you want to use.</p>
<p>You can change this account later on.</p>
if (! defined('ACCESS') || ! ACCESS) {
exit('This file cannot be directly accessed.');
}
$version_patch = APP_VERSION;
$explode = explode('.', $version_patch);
$version_major = $explode[0];
$version_minor = $version_major . '.' . $explode[1];
$version_link = strtr(
'https://releases.chevereto.com/%major%.X/%minor%/%patch%.html',
[
'%major%' => $version_major,
'%minor%' => $version_minor,
'%patch%' => $version_patch,
]
);
$edition = ucfirst(env()['CHEVERETO_EDITION'] ?? '');
?>
<h1><i class="fa fa-box-open"></i> Chevereto <?php echo $edition; ?> <a class="label--version" target="_blank" href="<?php echo $version_link; ?>"><?php echo APP_VERSION; ?></a></h1>
<p>Fill this form with the details of the initial admin account you want to use. You can change this account later on.</p>
<?php if ($error ?? false) { ?>
<p class="highlight padding-10"><?php echo $error_message ?? ''; ?></p>
<p class="highlight padding-10"><?php echo $error_message ?? ''; ?></p>
<?php } ?>
<form method="post">
<div>
<div class="p input-label">
<label for="username">Admin username</label>
<input type="text" name="username" id="username" class="width-100p" value="<?php echo $safe_post['username'] ?? ''; ?>" placeholder="Admin username" pattern="<?php echo getSetting('username_pattern'); ?>" title='<?php echo strtr('%i to %f characters<br>Letters, numbers and "_"', ['%i' => getSetting('username_min_length'), '%f' => getSetting('username_max_length')]); ?>' maxlength="<?php echo getSetting('username_max_length'); ?>" required>
<span class="input-warning red-warning"><?php echo $input_errors['username'] ?? ''; ?></span>
</div>
<div class="p input-label">
<label for="email">Admin email</label>
<input type="email" name="email" id="email" class="width-100p" value="<?php echo $safe_post['email'] ?? ''; ?>" placeholder="Admin email" title="Valid email address for your admin account" required>
<span class="input-warning red-warning"><?php echo $input_errors['email'] ?? ''; ?></span>
</div>
<div class="p input-label input-password">
<label for="password">Admin password</label>
<input type="password" name="password" id="password" class="width-100p" value="" placeholder="Admin password" title="Password to login" pattern="<?php echo getSetting('user_password_pattern'); ?>" autocomplete="new-password" required>
<div class="input-password-strength"><span style="width: 0%" data-content="password-meter-bar"></span></div>
<div class="input-warning red-warning" data-text="password-meter-message"><?php echo $input_errors['password'] ?? ''; ?></div>
</div>
</div>
<form method="post">
<div>
<div class="p input-label">
<label for="username">Admin username</label>
<input type="text" name="username" id="username" class="width-100p" value="<?php echo $safe_post['username'] ?? ''; ?>" placeholder="Admin username" pattern="<?php echo Settings::USERNAME_PATTERN; ?>" title='<?php echo strtr('%i to %f characters<br>Letters, numbers and "_"', [
'%i' => Settings::USERNAME_MIN_LENGTH,
'%f' => Settings::USERNAME_MAX_LENGTH,
]); ?>' maxlength="<?php echo Settings::USERNAME_MAX_LENGTH; ?>" required>
<span class="input-warning red-warning"><?php echo $input_errors['username'] ?? ''; ?></span>
</div>
<div class="p input-label">
<label for="email">Admin email</label>
<input type="email" name="email" id="email" class="width-100p" value="<?php echo $safe_post['email'] ?? ''; ?>" placeholder="Admin email" title="Valid email address for your admin account" required>
<span class="input-warning red-warning"><?php echo $input_errors['email'] ?? ''; ?></span>
</div>
<div class="p input-label input-password">
<label for="password">Admin password</label>
<input type="password" name="password" id="password" class="width-100p" value="" placeholder="Admin password" title="Password to login" pattern="<?php echo Settings::USER_PASSWORD_PATTERN; ?>" autocomplete="new-password" required>
<div class="input-password-strength"><span style="width: 0%" data-content="password-meter-bar"></span></div>
<div class="input-warning red-warning" data-text="password-meter-message"><?php echo $input_errors['password'] ?? ''; ?></div>
</div>
</div>
<?php
if ($is_2X ?? false) {
?>
<div>
<div class="p input-label">
<label for="crypt_salt">__CHV_CRYPT_SALT__</label>
<input type="text" name="crypt_salt" id="crypt_salt" class="width-100p" value="<?php echo $safe_post['crypt_salt'] ?? ''; ?>" placeholder="Example: changeme" title="As defined in includes/definitions.php" required>
<span class="input-below highlight">Value from define("__CHV_CRYPT_SALT__", "changeme");</span>
<span class="input-warning red-warning"><?php echo $input_errors['crypt_salt'] ?? ''; ?></span>
</div>
</div>
<div>
<div class="p input-label">
<label for="crypt_salt">__CHV_CRYPT_SALT__</label>
<input type="text" name="crypt_salt" id="crypt_salt" class="width-100p" value="<?php echo $safe_post['crypt_salt'] ?? ''; ?>" placeholder="Example: changeme" title="As defined in includes/definitions.php" required>
<span class="input-below highlight">Value from define("__CHV_CRYPT_SALT__", "changeme");</span>
<span class="input-warning red-warning"><?php echo $input_errors['crypt_salt'] ?? ''; ?></span>
</div>
</div>
<?php
}
?>
<div>
<button class="action radius" type="submit">Install</button>
</div>
</form>
?>
<div>
<button class="action radius" type="submit">Install</button>
</div>
</form>

View file

@ -1,8 +1,7 @@
<?php
// @phpstan-ignore-next-line
// @phpstan-ignore-next-line
if (!defined('ACCESS') || !ACCESS) {
die('This file cannot be directly accessed.');
if (! defined('ACCESS') || ! ACCESS) {
exit('This file cannot be directly accessed.');
} ?>
<h1>Update failed</h1>
<p>The update process failed. Here is the error returned:</p>

View file

@ -4,13 +4,20 @@ use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\get_chevereto_version;
// @phpstan-ignore-next-line
if (!defined('ACCESS') || !ACCESS) {
die('This file cannot be directly accessed.');
if (! defined('ACCESS') || ! ACCESS) {
exit('This file cannot be directly accessed.');
} ?>
<h1><i class="far fa-check-circle"></i> Update complete</h1>
<p><?php echo strtr('Chevereto has been successfully updated to %s. You can now continue to the <a href="%u">admin dashboard</a> and configure your website.', ['%s' => get_chevereto_version(true), '%u' => get_base_url('dashboard')]); ?></p>
<p><?php echo strtr('Chevereto has been successfully updated to %s. You can now continue to the <a href="%u">admin dashboard</a> and configure your website.', [
'%s' => get_chevereto_version(true),
'%u' => get_base_url('dashboard'),
]); ?></p>
<div>
<a href="<?php echo get_base_url('dashboard'); ?>" class="action button radius">Dashboard</a>
<a href="<?php echo get_base_url(); ?>" class="button radius">Website</a>
</div>
<script>$(document).ready(function() { CHV.fn.system.checkUpdates(); });</script>
<script>
document.addEventListener("DOMContentLoaded", function() {
CHV.fn.system.checkUpdates();
});
</script>

View file

@ -9,5 +9,5 @@
* file that was distributed with this source code.
*/
const APP_VERSION = '4.1.4';
const APP_VERSION_AKA = 'pulento';
const APP_VERSION = '4.2.4';
const APP_VERSION_AKA = 'regio';

View file

@ -13,11 +13,11 @@ namespace Chevereto\Legacy;
use Chevereto\Config\Config;
use Chevereto\Config\SystemConfig;
use Imagick;
use Throwable;
use function Chevereto\Legacy\G\absolute_to_relative;
use function Chevereto\Legacy\G\is_writable;
use function Chevereto\Vars\server;
use Imagick;
use Throwable;
function getFailingImageFormats(string $imageLibrary): array
{
@ -30,14 +30,14 @@ function getFailingImageFormats(string $imageLibrary): array
if ($imageLibrary === 'imagick') {
$imageFormats = Imagick::queryFormats();
foreach ($mustHaveFormats as $format) {
if (!in_array($format, $imageFormats)) {
if (! in_array($format, $imageFormats)) {
$failed_formats[] = $format;
}
}
} elseif ($imageLibrary === 'gd') {
$imageTypes = imagetypes();
foreach ($mustHaveFormats as $format) {
if (!($imageTypes & constant("IMG_$format"))) {
if (! ($imageTypes & constant("IMG_{$format}"))) {
$failed_formats[] = $format;
}
}
@ -51,17 +51,21 @@ function filesystemPermissionsCheck(): void
$errors = [];
$writing_paths = [CHV_PATH_IMAGES, PATH_PUBLIC_CONTENT, PATH_APP_CONTENT];
foreach ($writing_paths as $v) {
if (!file_exists($v)) {
if (! file_exists($v)) {
try {
mkdir($v);
} catch (Throwable) {
$errors[] = "<code>"
$errors[] = '<code>'
. absolute_to_relative($v)
. "</code> doesn't exists and can't be created.";
}
} else {
if (!is_writable($v)) {
$errors[] = 'No write permission for PHP user ' . get_current_user() . ' in <code>' . absolute_to_relative($v) . '</code> directory. Chevereto needs to be able to write in this directory.';
if (! is_writable($v)) {
$errors[] = 'No write permission for PHP user '
. get_current_user()
. ' in <code>'
. absolute_to_relative($v)
. '</code> directory. Chevereto needs to be able to write in this directory.';
}
}
}
@ -73,12 +77,17 @@ function phpCheck(SystemConfig $systemConfig): void
$errors = [];
$missing_tpl = '%n (<a href="http://php.net/manual/en/%t.%u.php" target="_blank">%f</a>) %t is disabled in this server. This %t must be enabled in your PHP configuration (php.ini) and/or you must add this missing %t.';
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
$errors[] = 'This server is currently running PHP version ' . PHP_VERSION . ' and Chevereto needs at least PHP 8.0.0 to run.';
$errors[] = 'This server is currently running PHP version '
. PHP_VERSION
. ' and Chevereto needs at least PHP 8.0.0 to run.';
}
if (ini_get('allow_url_fopen') !== '1' && !function_exists('curl_init')) {
if (ini_get('allow_url_fopen') !== '1' && ! function_exists('curl_init')) {
$errors[] = "cURL isn't installed and allow_url_fopen is disabled. Chevereto needs one of these to perform HTTP requests to remote servers.";
}
if (preg_match('/apache/i', server()['SERVER_SOFTWARE'] ?? '') && function_exists('apache_get_modules') && !in_array('mod_rewrite', apache_get_modules())) {
if (preg_match('/apache/i', server()['SERVER_SOFTWARE'] ?? '')
&& function_exists('apache_get_modules')
&& ! in_array('mod_rewrite', apache_get_modules())
) {
$errors[] = 'Apache <a href="http://httpd.apache.org/docs/2.1/rewrite/rewrite_intro.html" target="_blank">mod_rewrite</a> is not enabled in this server. This must be enabled to run Chevereto.';
}
$extensionsRequired = [
@ -86,13 +95,13 @@ function phpCheck(SystemConfig $systemConfig): void
'%label' => 'Exif',
'%name' => 'Exchangeable image information',
'%slug' => 'book.exif',
'%desc' => 'Exif is required to handle image metadata'
'%desc' => 'Exif is required to handle image metadata',
],
'pdo' => [
'%label' => 'PDO',
'%name' => 'PHP Data Objects',
'%slug' => 'book.pdo',
'%desc' => 'PDO is needed to perform database operations'
'%desc' => 'PDO is needed to perform database operations',
],
'pdo_mysql' => [
'%label' => 'PDO_MYSQL',
@ -119,7 +128,7 @@ function phpCheck(SystemConfig $systemConfig): void
'%name' => 'gd',
'%slug' => 'book.gd',
'%desc' => 'GD is needed for image processing',
]
],
];
$imageLibs = [
'gd' => extension_loaded('gd') && function_exists('gd_info'),
@ -136,7 +145,7 @@ function phpCheck(SystemConfig $systemConfig): void
$errors[] = 'Configured image_library ' . $systemConfigLib . ' is not present in this system.';
}
foreach ($extensionsRequired as $k => $v) {
if (!extension_loaded($k)) {
if (! extension_loaded($k)) {
$errors[] = strtr('%name (<a href="http://www.php.net/manual/%slug.php">%label</a>) is not loaded in this server. %desc.', $v);
}
}
@ -144,7 +153,11 @@ function phpCheck(SystemConfig $systemConfig): void
if ($disabled_classes !== []) {
foreach (['DirectoryIterator', 'RegexIterator', 'Pdo', 'Exception'] as $k) {
if (in_array($k, $disabled_classes)) {
$errors[] = strtr(str_replace('%t', 'class', $missing_tpl), ['%n' => $k, '%f' => $k, '%u' => str_replace('_', '-', strtolower($k))]);
$errors[] = strtr(str_replace('%t', 'class', $missing_tpl), [
'%n' => $k,
'%f' => $k,
'%u' => str_replace('_', '-', strtolower($k)),
]);
}
}
}

View file

@ -9,48 +9,50 @@
* file that was distributed with this source code.
*/
use function Chevere\Message\message;
use Chevere\Throwable\Exceptions\RuntimeException;
use function Chevere\VarDump\varDumpHtml;
use Chevere\VarDump\VarDumpInstance;
use function Chevere\Writer\streamFor;
use Chevere\Writer\StreamWriter;
use Chevere\Writer\Writers;
use Chevere\Writer\WritersInstance;
use function Chevere\VarDump\varDumpHtml;
use function Chevere\Writer\streamFor;
define('TIME_EXECUTION_START', microtime(true));
!defined('REPL') && define('REPL', false);
!defined('PACKAGING') && define('PACKAGING', false);
require_once __DIR__ . '/../../vendor/autoload.php';
new WritersInstance(
(new Writers())
->withOutput(
new StreamWriter(
streamFor('php://output', 'w')
try {
define('TIME_EXECUTION_START', microtime(true));
! defined('REPL') && define('REPL', false);
! defined('PACKAGING') && define('PACKAGING', false);
require_once __DIR__ . '/../../vendor/autoload.php';
new WritersInstance(
(new Writers())
->withOutput(
new StreamWriter(
streamFor('php://output', 'w')
)
)
)
->withError(
new StreamWriter(
streamFor('php://stderr', 'a')
->withError(
new StreamWriter(
streamFor('php://stderr', 'w')
)
)
)
);
if (PHP_SAPI !== 'cli') {
new VarDumpInstance(varDumpHtml());
}
require_once __DIR__ . '/register-handlers.php';
$posix_getuid = function_exists('posix_getuid')
? posix_getuid()
: 'unknown';
if ($posix_getuid === 0
&& !(REPL || PACKAGING)) { // @phpstan-ignore-line
$message = 'Unable to run as root (run this command as a regular user)';
if (PHP_SAPI === 'cli') {
echo "[ERROR] $message\n";
die(255);
);
if (PHP_SAPI !== 'cli') {
new VarDumpInstance(varDumpHtml());
}
require_once __DIR__ . '/register-handlers.php';
$posix_getuid = function_exists('posix_getuid')
? posix_getuid()
: 'unknown';
} catch (Throwable $e) {
$error = sprintf(
'[CHEVERETO LOAD ERROR] %s: %s %s',
$e::class,
$e->getMessage(),
$e->getFile() . ':' . $e->getLine()
);
error_log($error);
if (PHP_SAPI !== 'cli') {
http_response_code(500);
}
throw new RuntimeException(
message($message)
);
echo 'An error occurred while loading Chevereto.' . PHP_EOL;
exit(255);
}

View file

@ -9,12 +9,18 @@
* file that was distributed with this source code.
*/
if (version_compare(PHP_VERSION, '8.0.0', '<')) {
define('CHEVERETO_PHP_VERSION_REQUIRED', '8.1.28');
if (version_compare(PHP_VERSION, CHEVERETO_PHP_VERSION_REQUIRED, '<')) {
if (PHP_SAPI !== 'cli') {
http_response_code(503);
}
echo 'This server is currently running PHP ' . PHP_VERSION . ' and Chevereto needs at least PHP 8.0.0 to run.' . PHP_EOL;
die(255);
echo 'This server is running PHP '
. PHP_VERSION
. ' and Chevereto needs at least PHP '
. CHEVERETO_PHP_VERSION_REQUIRED
. PHP_EOL;
exit(255);
}
require_once __DIR__ . '/loader.php';

View file

@ -12,48 +12,162 @@
use Chevere\ThrowableHandler\Documents\ConsoleDocument;
use Chevere\ThrowableHandler\Documents\HtmlDocument;
use Chevere\ThrowableHandler\Documents\PlainDocument;
use function Chevere\ThrowableHandler\throwableHandler;
use Chevere\ThrowableHandler\ThrowableHandler;
use function Chevere\Writer\writers;
use function Chevere\Xr\throwableHandler as XrThrowableHandler;
use Chevere\VarDump\Formats\HtmlFormat;
use Chevere\VarDump\Formats\PlainFormat;
use Chevere\VarDump\Interfaces\FormatInterface;
use Chevere\VarDump\Outputs\HtmlOutput;
use Chevere\VarDump\Outputs\PlainOutput;
use Chevere\VarDump\VarDump;
use Chevereto\Config\Config;
use function Chevere\ThrowableHandler\throwableHandler;
use function Chevere\Writer\writers;
use function Chevere\xrDebug\PHP\throwableHandler as XrDebugThrowableHandler;
use function Chevereto\Legacy\isDebug;
use function Chevereto\Vars\env;
use function Chevereto\Vars\files;
use function Chevereto\Vars\get;
use function Chevereto\Vars\post;
use function Chevereto\Vars\server;
set_error_handler(ThrowableHandler::ERROR_AS_EXCEPTION);
class HeadlessHtmlOutput extends HtmlOutput
{
public function prepare(): void
{
$this->writer()->write(
'<style>' . preg_replace('/\s+/', ' ', self::CSS) . '</style>'
);
$this->writer()->write(
'<pre class="chv-dump">'
);
}
public function writeCallerFile(FormatInterface $format): void
{
//
}
}
class HeadlessPlainOutput extends PlainOutput
{
public function prepare(): void
{
}
public function finalize(): void
{
}
public function writeCallerFile(FormatInterface $format): void
{
}
}
set_error_handler(ThrowableHandler::ERROR_AS_EXCEPTION); // @phpstan-ignore-line
register_shutdown_function(ThrowableHandler::SHUTDOWN_ERROR_AS_EXCEPTION);
set_exception_handler(function (Throwable $throwable) {
$throwableHandler = throwableHandler($throwable);
$extra = '';
$publicHandler = throwableHandler($throwable);
$namespace = env()['CHEVERETO_ID_HANDLE']
?? false;
if ($namespace) {
$publicHandler = $publicHandler
->withId($namespace . $publicHandler->id());
}
if (PHP_SAPI === 'cli') {
$docInternal = new ConsoleDocument($throwableHandler);
$docInternal = new ConsoleDocument($publicHandler);
$parameters = [];
} else {
$docInternal = new PlainDocument($throwableHandler);
if (!headers_sent()) {
if (! headers_sent()) {
http_response_code(500);
}
$isDebug = isDebug();
try {
$debugLevel = Config::system()->debugLevel();
} catch (Throwable) {
$debugLevel = (int) ($_ENV['CHEVERETO_DEBUG_LEVEL'] ?? 1);
$envDebugLevel = getenv('CHEVERETO_DEBUG_LEVEL');
$debugLevel = $envDebugLevel === false
? 1
: (int) $envDebugLevel;
}
$doDebug = in_array($debugLevel, [2, 3], true) || isDebug();
$publicHandler = $publicHandler->withIsDebug($doDebug);
$internalHandler = $publicHandler->withIsDebug(true);
$method = server()['REQUEST_METHOD'] ?? '';
$uri = server()['REQUEST_URI'] ?? '';
$uri = strtok($uri, '?');
$internalHandler = $internalHandler->withPutExtra('URI', $uri);
$internalHandler = $internalHandler->withPutExtra('Method', $method);
$extra .= xrDebugExtraSection('URI', $uri);
$extra .= xrDebugExtraSection('Method', $method);
$parameters = [
'POST' => post(),
'GET' => get(),
'FILES' => files(),
];
$parameters = array_filter($parameters, fn ($value) => $value !== []);
if ($parameters !== []) {
$parametersHtml = (new VarDump(
new HtmlFormat(),
new HeadlessHtmlOutput()
))
->withVariables(...$parameters)
->export();
$internalHandler = $internalHandler
->withPutExtra('Parameters', $parametersHtml);
$extra .= xrDebugExtraSection('Parameters', $parametersHtml);
}
$docPublic = new HtmlDocument(
$throwableHandler->withIsDebug(
in_array($debugLevel, [2, 3]) || $isDebug
)
$doDebug ? $internalHandler : $publicHandler
);
writers()->output()
->write($docPublic->__toString() . "\n");
}
writers()->error()
->write($docInternal->__toString() . "\n\n");
$internalHandler = $internalHandler ?? $publicHandler;
if ($parameters !== []) {
$parametersPlain = (new VarDump(
new PlainFormat(),
new HeadlessPlainOutput()
))
->withVariables(...$parameters)
->export();
$internalHandler = $internalHandler
->withPutExtra('Parameters', $parametersPlain);
if (! isset($parametersHtml)) {
$extra .= xrDebugExtraSection('Parameters', $parametersPlain);
}
}
$docLogs = new PlainDocument($internalHandler);
$logMessage = '[' . $publicHandler->id() . '] '
. $docLogs->__toString()
. "\n\n";
XrThrowableHandler(
$throwable,
<<<HTML
<div class="throwable-message">Incident ID: {$throwableHandler->id()}</div>
HTML
);
die(255);
try {
$errorLog = ini_get('error_log');
$fp = fopen($errorLog, 'a');
fwrite($fp, $logMessage);
fclose($fp);
} catch (Throwable) {
if (PHP_SAPI === 'cli') {
error_log($logMessage);
} else {
writers()->error()->write($logMessage);
}
}
$extra .= <<<HTML
<div class="throwable-message"><b>Incident {$publicHandler->id()}</b></div>
<div class="throwable-message"><b>Backtrace</b></div>
HTML;
XrDebugThrowableHandler($throwable, $extra);
exit(255);
});
function xrDebugExtraSection(string $title, string $contents)
{
return <<<HTML
<div class="throwable-message">
<b>{$title}</b>
<div>{$contents}</div>
</div>
HTML;
}

View file

@ -10,10 +10,8 @@
*/
use Chevereto\Config\Config;
use function Chevereto\Legacy\badgePaid;
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Fonts;
use Chevereto\Legacy\Classes\Image;
use Chevereto\Legacy\Classes\IpBan;
use Chevereto\Legacy\Classes\L10n;
use Chevereto\Legacy\Classes\Login;
@ -21,20 +19,26 @@ use Chevereto\Legacy\Classes\Page;
use Chevereto\Legacy\Classes\Palettes;
use Chevereto\Legacy\Classes\RequestLog;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\Tag;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\badgePaid;
use function Chevereto\Legacy\cheveretoVersionInstalled;
use function Chevereto\Legacy\editionCombo;
use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\G\get_current_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\get_public_url;
use function Chevereto\Legacy\G\is_route_available;
use function Chevereto\Legacy\G\is_url;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\G\set_status_header;
use function Chevereto\Legacy\get_enabled_languages;
use function Chevereto\Legacy\getIdFromURLComponent;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\getSystemNotices;
use function Chevereto\Legacy\getVariable;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Legacy\headersResetCache;
use function Chevereto\Legacy\is_max_invalid_request;
use function Chevereto\Vars\cookie;
use function Chevereto\Vars\env;
@ -43,30 +47,65 @@ use function Chevereto\Vars\server;
use function Chevereto\Vars\session;
use function Chevereto\Vars\sessionVar;
if (Settings::get('chevereto_version_installed') === null) {
if (cheveretoVersionInstalled() === '') {
new Handler(
loadTemplate: !REPL, // @phpstan-ignore-line
loadTemplate: ! REPL, // @phpstan-ignore-line
before: function ($handler) {
headersNoCache();
if ($handler->request_array()[0] !== 'install') {
redirect('install');
redirect('install', 302);
}
},
);
}
$bannedIp = IpBan::getSingle();
if ($bannedIp !== []) {
is_url($bannedIp['message'])
? redirect($bannedIp['message'])
: (
die(empty($bannedIp['message'])
? _s('You have been forbidden to use this website.')
: $bannedIp['message']
)
);
headersNoCache();
// TODO: Cache until ban expires
if (is_url($bannedIp['message'] ?? false)) {
redirect($bannedIp['message'], 301);
} else {
$exitMessage = $bannedIp['message'] ?? '';
$exitMessage = match ($exitMessage) {
'' => _s('You have been forbidden to use this website.'),
default => $bannedIp['message'],
};
exit($exitMessage);
}
}
$hook_before = function (Handler $handler) {
header('Permissions-Policy: unload=()');
header('Permissions-Policy: interest-cohort=()');
header("Content-Security-Policy: frame-ancestors 'none'");
$exitEarlyRoutes = [
'webmanifest',
];
$doNotCacheRoutes = [
'login',
'signup',
'logout',
'account',
'connect',
'json',
'api',
'captcha-verify',
'oembed',
'upload',
'dashboard',
'install',
'settings',
'redirect',
];
$cache_ttl = (int) max(0, getSetting('cache_ttl') ?? 0);
if (in_array($handler->request_array()[0], $doNotCacheRoutes, true)) {
headersNoCache();
} elseif ($cache_ttl > 0) {
headersResetCache();
header("Cache-Control: private, max-age={$cache_ttl}");
}
if (in_array($handler->request_array()[0], $exitEarlyRoutes, true)) {
return;
}
$failed_access_requests = RequestLog::getCounts(['login', 'signup'], 'fail');
if (is_max_invalid_request($failed_access_requests['day'])) {
set_status_header(403);
@ -81,13 +120,14 @@ $hook_before = function (Handler $handler) {
set_status_header(403);
}
if (sessionVar()->hasKey('challenge_two_factor')
&& !in_array($handler->getRoutePath(), ['account/two-factor', 'captcha-verify', 'logout'])
&& ! in_array($handler->getRoutePath(), ['account/two-factor', 'captcha-verify', 'logout'], true)
&& $handler->request_array()[0] !== 'page'
) {
redirect('account/two-factor');
) {
headersNoCache();
redirect('account/two-factor', 302);
}
}
if (!getSetting('language_chooser_enable')) {
if (! getSetting('language_chooser_enable')) {
$user_lang = getSetting('default_language');
}
new L10n(
@ -96,25 +136,31 @@ $hook_before = function (Handler $handler) {
? false
: getSetting('auto_language')
);
if (http_response_code() == 403) {
die();
if (http_response_code() === 403) {
headersNoCache();
exit();
}
if ($handler->request_array()[0] !== 'api'
&& Settings::get('enable_uploads_url') && !Login::isAdmin()) {
&& Settings::get('enable_uploads_url') && ! Login::isAdmin()) {
Settings::setValue('enable_uploads_url', 0);
}
if (isset(get()['lang']) && array_key_exists(get()['lang'], get_enabled_languages())) {
if (Login::isLoggedUser() && Login::getUser()['language'] !== get()['lang']) {
User::update(Login::getUser()['id'], ['language' => get()['lang']]);
}
if (isset(get()['lang'])
&& array_key_exists(get()['lang'], get_enabled_languages())
) {
L10n::setCookieLang(get()['lang']);
L10n::processTranslation(get()['lang']);
define('PUSH_LANG', get()['lang']);
}
if (array_key_exists('agree-consent', get())) {
setcookie('AGREE_CONSENT', "1", time() + (60 * 60 * 24 * 30), Config::host()->hostnamePath());
setcookie(
'AGREE_CONSENT',
'1',
time() + (60 * 60 * 24 * 30),
Config::host()->hostnamePath()
);
sessionVar()->put('agree-consent', true);
redirect(get_current_url(true, ['agree-consent']));
headersNoCache();
redirect(get_current_url(true, ['agree-consent']), 302);
}
$base = $handler::baseRequest();
parse_str(server()['QUERY_STRING'] ?? '', $querystr);
@ -128,11 +174,11 @@ $hook_before = function (Handler $handler) {
$handler::setCond('manager', Login::isManager());
$showContentManager = Login::isAdmin() || Login::isManager();
$handler::setCond('content_manager', $showContentManager);
$allowed_nsfw_flagging = !getSetting('image_lock_nsfw_editing');
$allowed_nsfw_flagging = ! getSetting('image_lock_nsfw_editing');
if ($handler::cond('content_manager')) {
$moderateLink = get_base_url('moderate');
$moderateLabel = _s('Moderate');
if (!in_array('pro', editionCombo()[env()['CHEVERETO_EDITION']])) {
if (! in_array('pro', editionCombo()[env()['CHEVERETO_EDITION']], true)) {
if ((bool) env()['CHEVERETO_ENABLE_EXPOSE_PAID_FEATURES']) {
$moderateLink = 'https://chevereto.com/pricing';
$moderateLabel .= ' ' . badgePaid('pro');
@ -146,18 +192,18 @@ $hook_before = function (Handler $handler) {
}
$handler::setCond('show_content_manager', $showContentManager);
$handler::setCond('allowed_nsfw_flagging', $allowed_nsfw_flagging);
$handler::setCond('maintenance', getSetting('maintenance') and !Login::isAdmin());
$handler::setCond('maintenance', getSetting('maintenance') and ! Login::isAdmin());
$handler::setCond(
'show_consent_screen',
$base !== 'api' && (
getSetting('enable_consent_screen')
? !(Login::getUser() || isset(session()['agree-consent']) || isset(cookie()['AGREE_CONSENT']))
? ! (Login::getUser() || isset(session()['agree-consent']) || isset(cookie()['AGREE_CONSENT']))
: false
)
);
$handler::setCond('captcha_needed', getSetting('captcha') && getSetting('captcha_threshold') == 0);
$handler::setCond('show_header', !($handler::cond('maintenance') || $handler::cond('show_consent_screen')));
$handler::setCond('show_notifications', getSetting('website_mode') == 'community' && (getSetting('enable_followers') || getSetting('enable_likes')));
$handler::setCond('captcha_needed', getSetting('captcha') && getSetting('captcha_threshold') === 0);
$handler::setCond('show_header', ! ($handler::cond('maintenance') || $handler::cond('show_consent_screen')));
$handler::setCond('show_notifications', getSetting('website_mode') === 'community' && (getSetting('enable_followers') || getSetting('enable_likes')));
$handler::setCond('allowed_to_delete_content', Login::isAdmin() || getSetting('enable_user_content_delete'));
$handler::setVar('canonical', null);
$palettes = new Palettes();
@ -166,7 +212,7 @@ $hook_before = function (Handler $handler) {
$handler::setVar('fonts', $fonts);
$fontId = intval(getSetting('theme_font') ?? 0);
$handler::setVar('theme_font', $fontId);
if (in_array($handler->request_array()[0], ['login', 'signup', 'account'])) {
if (in_array($handler->request_array()[0], ['login', 'signup', 'account'], true)) {
$paletteId = 0;
} else {
$paletteId = Login::isLoggedUser()
@ -180,14 +226,21 @@ $hook_before = function (Handler $handler) {
}
$handler::setVar('theme_palette', $paletteId);
$handler::setVar('theme_palette_handle', $theme_palette_handle);
if ($handler::cond('maintenance') && $handler->request_array()[0] == 'dashboard') {
redirect('login');
if ($handler::cond('maintenance')
&& $handler->request_array()[0] === 'dashboard') {
headersNoCache();
redirect('login', 302);
}
$langLinks = [];
$langToggleUrl = get_current_url(true, ['lang']);
parse_str(server()['QUERY_STRING'] ?? '', $qs);
unset($qs['lang']);
$qs = http_build_query($qs);
$langLinks['x-default'] = [
'hreflang' => 'x-default',
'name' => 'x-default',
'url' => get_public_url($langToggleUrl),
];
$langToggleUrl = rtrim($langToggleUrl, '/') . ($qs ? '&' : '/?') . 'lang=';
foreach (get_enabled_languages() as $k => $v) {
$hreflang = strtolower($k);
@ -195,7 +248,7 @@ $hook_before = function (Handler $handler) {
$langLinks[$k] = [
'hreflang' => $hreflang,
'name' => $v['name'],
'url' => $langUrl,
'url' => get_public_url($langUrl),
];
}
$handler::setVar('langLinks', $langLinks);
@ -210,46 +263,46 @@ $hook_before = function (Handler $handler) {
$consent_accept_url
);
}
if (!Login::getUser()) {
if (! Login::getUser()) {
if (getSetting('captcha') && $failed_access_requests['day'] >= getSetting('captcha_threshold')) {
$handler::setCond('captcha_needed', true);
}
}
if (getSetting('website_mode') == 'personal') {
if (getSetting('website_mode') === 'personal') {
$userMapPaths = ['search'];
$userMapPaths[] = getSetting('user_profile_view') == 'files'
$userMapPaths[] = getSetting('user_profile_view') === 'files'
? 'albums'
: 'files';
if ($handler->request_array()[0] == '/'
&& getSetting('website_mode_personal_routing') == '/'
&& in_array(key($querystr), ['random'])
if ($handler->request_array()[0] === '/'
&& getSetting('website_mode_personal_routing') === '/'
&& in_array(key($querystr), ['random'], true)
) {
$handler->mapRoute('index');
} elseif ($handler->request_array()[0] == 'search'
&& in_array($handler->request_array()[1] ?? [], ['images', 'albums', 'users'])
} elseif ($handler->request_array()[0] === 'search'
&& in_array($handler->request_array()[1] ?? [], ['images', 'albums', 'users'], true)
) {
$handler->mapRoute('search');
} elseif ($handler->request_array()[0] == getSetting('website_mode_personal_routing')
|| (getSetting('website_mode_personal_routing') == '/'
&& in_array($handler->request_array()[0], $userMapPaths))
} elseif ($handler->request_array()[0] === getSetting('website_mode_personal_routing')
|| (getSetting('website_mode_personal_routing') === '/'
&& in_array($handler->request_array()[0], $userMapPaths, true))
) {
$handler->mapRoute('user', [
'id' => getSetting('website_mode_personal_uid'),
]);
}
if ($handler->request_array()[0] == '/'
&& !in_array(key($querystr), ['random', 'lang'])
&& !$handler::cond('mapped_route')
if ($handler->request_array()[0] === '/'
&& ! in_array(key($querystr), ['random', 'lang'], true)
&& ! $handler::cond('mapped_route')
) {
$personal_mode_user = User::getSingle(getSetting('website_mode_personal_uid'));
if ($personal_mode_user !== []) {
if (Settings::get('homepage_cta_html') == null) {
if (Settings::get('homepage_cta_html') === null) {
Settings::setValue('homepage_cta_html', _s('View all my images'));
}
if (Settings::get('homepage_title_html') == null) {
if (Settings::get('homepage_title_html') === null) {
Settings::setValue('homepage_title_html', $personal_mode_user['name']);
}
if (Settings::get('homepage_paragraph_html') == null) {
if (Settings::get('homepage_paragraph_html') === null) {
Settings::setValue('homepage_paragraph_html', _s('Feel free to browse and discover all my shared images and albums.'));
}
if (Settings::get('homepage_cta_fn') !== 'cta-link') {
@ -262,13 +315,13 @@ $hook_before = function (Handler $handler) {
}
}
} else {
if ($base !== 'index' and !is_route_available($handler->request_array()[0])) {
if ($base !== 'index' and ! is_route_available($handler->request_array()[0])) {
$mapTo = getSetting('root_route');
$handler->mapRoute($mapTo);
}
}
$virtualizable_routes = ['image', 'album', 'user'];
if (in_array($handler->request_array()[0], $virtualizable_routes)) {
$virtual_routes = ['image', 'album', 'user', 'video', 'audio'];
if (in_array($handler->request_array()[0], $virtual_routes, true)) {
$virtual_route = getSetting('route_' . $handler->request_array()[0]);
if ($handler->request_array()[0] !== $virtual_route) {
$virtualized_url = str_replace(
@ -276,21 +329,21 @@ $hook_before = function (Handler $handler) {
get_base_url($virtual_route),
get_current_url()
);
redirect($virtualized_url);
redirect($virtualized_url, 301);
return;
}
}
if ($base !== 'index' && !is_route_available($handler->request_array()[0])) {
foreach ($virtualizable_routes as $k) {
if ($handler->request_array()[0] == getSetting('route_' . $k)) {
if ($base !== 'index' && ! is_route_available($handler->request_array()[0])) {
foreach ($virtual_routes as $k) {
if ($handler->request_array()[0] === getSetting('route_' . $k)) {
$handler->mapRoute($k);
}
}
}
if (getSetting('website_privacy_mode') == 'private' && !Login::getUser()) {
if (getSetting('website_privacy_mode') === 'private' && ! Login::getUser()) {
$allowed_requests = ['api', 'login', 'logout', 'page', 'account', 'connect', 'json', 'captcha-verify'];
foreach ($virtualizable_routes as $v) {
foreach ($virtual_routes as $v) {
$v = getSetting('route_' . $v);
if (isset($v)) {
$allowed_requests[] = $v;
@ -299,13 +352,28 @@ $hook_before = function (Handler $handler) {
if (getSetting('enable_signups')) {
$allowed_requests[] = 'signup';
}
if (!in_array($handler->request_array()[0], $allowed_requests)) {
redirect('login');
if (! in_array($handler->request_array()[0], $allowed_requests, true)) {
headersNoCache();
redirect('login', 302);
}
}
$handler::setCond('private_gate', getSetting('website_privacy_mode') == 'private' and !Login::getUser());
$handler::setCond('forced_private_mode', (getSetting('website_privacy_mode') == 'private' and getSetting('website_content_privacy_mode') !== 'default'));
$handler::setCond('explore_enabled', $handler::cond('content_manager') ?: (getSetting('website_explore_page') ? ((bool) Login::isLoggedUser() ?: getSetting('website_explore_page_guest')) : false));
$handler::setCond(
'private_gate',
getSetting('website_privacy_mode') === 'private'
&& ! Login::getUser()
);
$handler::setCond(
'forced_private_mode',
getSetting('website_privacy_mode') === 'private'
&& getSetting('website_content_privacy_mode') !== 'default'
);
$handler::setCond(
'explore_enabled',
$handler::cond('content_manager')
?: (getSetting('website_explore_page')
? ((bool) Login::isLoggedUser() ?: getSetting('website_explore_page_guest'))
: false)
);
$handler::setCond(
'search_enabled',
$handler::cond('content_manager')
@ -316,47 +384,60 @@ $hook_before = function (Handler $handler) {
);
$handler::setCond(
'random_enabled',
$handler::cond('content_manager')
?: (
getSetting('website_random')
&& (Login::isLoggedUser() ?: getSetting('website_random_guest'))
)
getSetting('website_random')
&& (Login::isLoggedUser() ?: getSetting('website_random_guest'))
);
$moderate_uploads = false;
switch (getSetting('moderate_uploads')) {
case 'all':
$moderate_uploads = !$handler::cond('content_manager');
$moderate_uploads = ! $handler::cond('content_manager');
break;
break;
case 'guest':
$moderate_uploads = !Login::isLoggedUser();
$moderate_uploads = ! Login::isLoggedUser();
break;
break;
}
$handler::setCond('moderate_uploads', $moderate_uploads);
$categories = [];
if ($handler::cond('explore_enabled') || $base == 'dashboard') {
$tags_top = [];
if ($handler::cond('explore_enabled') || $base === 'dashboard') {
try {
$categories_db = DB::queryFetchAll('SELECT * FROM ' . DB::getTable('categories') . ' ORDER BY category_name ASC;');
if (count($categories_db) > 0) {
foreach ($categories_db as $k => $v) {
$key = $v['category_id'];
$categories[$key] = $v;
$categories[$key]['category_url'] = get_base_url('category/' . $v['category_url_key']);
$categories[$key] = DB::formatRow($categories[$key]);
}
$categories_db = DB::queryFetchAll(
'SELECT * FROM '
. DB::getTable('categories')
. ' ORDER BY category_name ASC;'
);
foreach ($categories_db as $k => $v) {
$key = $v['category_id'];
$categories[$key] = $v;
$categories[$key]['category_url'] = get_base_url('category/' . $v['category_url_key']);
$categories[$key] = DB::formatRow($categories[$key]);
}
} catch (Throwable) {
}
try {
$tagsTable = DB::getTable('tags');
$tags_db = DB::queryFetchAll(
<<<MYSQL
SELECT t.tag_name name, t.tag_id id, t.tag_files files, t.tag_views views
FROM `{$tagsTable}` t
ORDER BY `tag_files` DESC, `tag_name` ASC
LIMIT 30;
MYSQL
);
foreach ($tags_db as $k => $v) {
$tag = array_merge($v, Tag::row($v['name']));
$tags_top[] = $tag;
}
} catch (Throwable) {
}
}
if ($handler::cond('explore_enabled')
&& $categories === []
&& !(bool) env()['CHEVERETO_ENABLE_USERS']
) {
$handler::setCond('explore_enabled', false);
}
$handler::setVar('categories', $categories);
$explore_semantics = [
$handler::setVar('tags_top', $tags_top);
$explore_discovery = [
'recent' => [
'label' => _s('Recent'),
'icon' => 'fas fa-history',
@ -369,127 +450,188 @@ $hook_before = function (Handler $handler) {
'label' => _s('Popular'),
'icon' => 'fas fa-heart',
],
];
$explore_content = [
'images' => [
'label' => _n('Image', 'Images', 20),
'icon' => 'fas fa-image',
],
'videos' => [
'label' => _s('Videos'),
'label' => _n('Video', 'Videos', 20),
'icon' => 'fas fa-video',
],
'animated' => [
'label' => _s('Animated'),
'icon' => 'fas fa-play',
],
'tags' => [
'label' => _n('Tag', 'Tags', 20),
'icon' => 'fas fa-tags',
],
'albums' => [
'label' => _n('Album', 'Albums', 20),
'icon' => 'fas fa-photo-film',
],
'users' => [
'label' => _n('User', 'Users', 20),
'icon' => 'fas fa-users',
],
];
if (!(bool) env()['CHEVERETO_ENABLE_USERS']) {
$explore_semantics = [];
if (Login::isLoggedUser() && getSetting('enable_followers')) {
$explore_discovery['following'] = [
'label' => _s('Following'),
'icon' => 'fas fa-rss',
'url' => get_base_url('following'),
];
}
if (!getSetting('enable_likes')) {
unset($explore_semantics['popular']);
if (! getSetting('enable_likes')) {
unset($explore_discovery['popular']);
}
if (!in_array('gif', Image::getEnabledImageExtensions())) {
unset($explore_semantics['animated']);
foreach ($explore_discovery as $k => &$v) {
$v['url'] = get_base_url('explore/' . $k);
}
foreach ($explore_semantics as $k => &$v) {
foreach ($explore_content as $k => &$v) {
$v['url'] = get_base_url('explore/' . $k);
}
unset($v);
$handler::setVar('explore_semantics', $explore_semantics);
if (version_compare(Settings::get('chevereto_version_installed'), '3.6.7', '>=')) {
$pages_visible_db = Page::getAll(['is_active' => 1, 'is_link_visible' => 1], ['field' => 'sort_display', 'order' => 'ASC']);
$pageHandle = version_compare(Settings::get('chevereto_version_installed'), '3.12.4', '>=') ? 'internal' : 'url_key';
$handler::setVar('page_tos', Page::getSingle('tos', $pageHandle));
$handler::setVar('page_privacy', Page::getSingle('privacy', $pageHandle));
}
$handler::setVar('explore_discovery', $explore_discovery);
$handler::setVar('explore_content', $explore_content);
$versionInstalled = cheveretoVersionInstalled();
$pages_visible = [];
if (version_compare($versionInstalled, '3.6.7', '>=')) {
$pages_visible_db = Page::getAll(
args: [
'is_active' => '1',
'is_link_visible' => '1',
],
sort: [
'field' => 'sort_display',
'order' => 'ASC',
]
);
$pos_page_tos = array_search('tos', array_column($pages_visible_db, 'internal'));
$pos_page_privacy = array_search('privacy', array_column($pages_visible_db, 'internal'));
$page_tos = $pos_page_tos === false
? null
: $pages_visible_db[$pos_page_tos];
$page_privacy = $pos_page_privacy === false
? null
: $pages_visible_db[$pos_page_privacy];
$handler::setVar('page_tos', $page_tos);
$handler::setVar('page_privacy', $page_privacy);
}
if ((bool) env()['CHEVERETO_ENABLE_PAGES']) {
foreach ($pages_visible_db as $k => $v) {
if (!($v['is_active'] ?? false) && !($v['is_link_visible'] ?? false)) {
foreach ($pages_visible_db ?? [] as $k => $v) {
if (! ($v['is_active'] ?? false) && ! ($v['is_link_visible'] ?? false)) {
continue;
}
$pages_visible[$v['id']] = $v;
}
if (getSetting('enable_plugin_route')) {
$plugin_page = [
'type' => 'link',
'link_url' => get_base_url('plugin'),
'icon' => 'fas fa-code',
'title' => _s('Plugin'),
'is_active' => 1,
'is_link_visible' => 1,
'attr_target' => '_self',
'sort_display' => 999,
];
Page::fill($plugin_page);
$pages_visible[] = $plugin_page;
}
}
$api_page = [
'type' => 'link',
'link_url' => get_base_url('api-v1'),
'icon' => 'fas fa-project-diagram',
'title' => 'API',
'is_active' => 1,
'is_link_visible' => 1,
'attr_target' => '_self',
'sort_display' => -2,
];
Page::fill($api_page);
$pages_visible[] = $api_page;
if (getSetting('enable_plugin_route')) {
$plugin_page = [
'type' => 'link',
'link_url' => get_base_url('plugin'),
'icon' => 'fas fa-plug-circle-plus',
'title' => _s('Plugin'),
'is_active' => 1,
'is_link_visible' => 1,
'attr_target' => '_self',
'sort_display' => -1,
];
Page::fill($plugin_page);
$pages_visible[] = $plugin_page;
}
uasort($pages_visible, function ($a, $b) {
return $a['sort_display'] - $b['sort_display'];
});
$handler::setVar('pages_link_visible', $pages_visible);
$upload_enabled = Login::isAdmin() ?: getSetting('enable_uploads');
$upload_allowed = $upload_enabled;
if (!Login::getUser()) {
if (!getSetting('guest_uploads') || getSetting('website_privacy_mode') == 'private' || $handler::cond('maintenance')) {
if (! Login::getUser()) {
if (! getSetting('guest_uploads') || getSetting('website_privacy_mode') === 'private' || $handler::cond('maintenance')) {
$upload_allowed = false;
}
} elseif (!Login::isAdmin() && getSetting('website_mode') == 'personal' && getSetting('website_mode_personal_uid') !== Login::getUser()['id']) {
} elseif (! Login::isAdmin() && getSetting('website_mode') === 'personal' && getSetting('website_mode_personal_uid') !== Login::getUser()['id']) {
$upload_allowed = false;
}
if (!Login::getUser() && $upload_allowed && getSetting('upload_max_filesize_mb_guest')) {
if ((! (bool) env()['CHEVERETO_ENABLE_LOCAL_STORAGE']) && getVariable('storages_active')->nullInt() === 0) {
$upload_enabled = false;
$upload_allowed = false;
}
if (! Login::getUser() && $upload_allowed && getSetting('upload_max_filesize_mb_guest')) {
Settings::setValue('upload_max_filesize_mb_bak', getSetting('upload_max_filesize_mb'));
Settings::setValue('upload_max_filesize_mb', getSetting('upload_max_filesize_mb_guest'));
}
if ($upload_allowed && in_array($handler->request_array()[0], ['login', 'signup', 'account'])) {
if ($upload_allowed
&& in_array($handler->request_array()[0], ['login', 'signup', 'account'], true)
) {
$upload_allowed = false;
}
$handler::setCond('upload_enabled', $upload_enabled); // System allows to upload?
$handler::setCond('upload_allowed', $upload_allowed); // Target peer can upload?
$handler::setCond('upload_allowed', $upload_allowed); // Current user can upload?
if ($handler::cond('maintenance') || $handler::cond('show_consent_screen')) {
$handler::setCond('private_gate', true);
$allowed_requests = ['login', 'account', 'connect', 'captcha-verify', 'oembed'];
if (!in_array($handler->request_array()[0], $allowed_requests)) {
if (! in_array($handler->request_array()[0], $allowed_requests, true)) {
$handler->preventRoute($handler::cond('show_consent_screen') ? 'consent-screen' : 'maintenance');
}
}
if ($handler->request_array()[0] == getSetting('route_image')) {
$id = getIdFromURLComponent($handler->request()[0] ?? '');
if ($id !== 0) {
$image = Image::getSingle($id, false, true, $handler::var('logged_user'));
$userNotBanned = ($image['user']['status'] ?? '') != 'banned';
if ($image !== [] && $image['is_approved'] && $userNotBanned && !in_array($image['album']['privacy'] ?? '', ['private', 'custom'])) {
$image_safe_html = safe_html($image);
$handler::setVar('oembed', [
'title' => ($image_safe_html['title'] ?? ($image_safe_html['name'] . '.' . $image['extension'])) . ' hosted at ' . getSetting('website_name'),
'url' => $image['url_viewer']
]);
}
}
}
$handler::setVar('system_notices', Login::isAdmin() ? getSystemNotices() : []);
if (!in_array($handler->request_array()[0], ['login', 'signup', 'account', 'connect', 'logout', 'json', 'api', 'captcha-verify'])) {
$excludeLastUrl = [
'login',
'signup',
'account',
'connect',
'logout',
'json',
'api',
'captcha-verify',
'webmanifest',
'tag-autocomplete',
];
if (! in_array($handler->request_array()[0], $excludeLastUrl, true)) {
sessionVar()->put('last_url', get_current_url());
}
$detect = new Mobile_Detect();
$isMobile = $detect->isMobile();
$handler::setCond('mobile_device', (bool) $isMobile);
$handler::setCond('show_viewer_zero', false);
if ($handler->template() == 'request-denied') {
$handler::setVar('doctitle', _s("Request denied") . ' (403) - ' . getSetting('website_name'));
if ($handler->template() === 'request-denied') {
$handler::setVar('doctitle', _s('Request denied') . ' (403) - ' . getSetting('website_name'));
$handler->preventRoute('request-denied');
}
$handler::setVar('tos_privacy_agreement', _s('I agree to the %terms_link and %privacy_link', [
'%terms_link' => '<a ' . ($handler::var('page_tos')['link_attr'] ?? '') . '>' . _s('terms') . '</a>',
'%privacy_link' => '<a ' . ($handler::var('page_privacy')['link_attr'] ?? '') . '>' . _s('privacy policy') . '</a>'
'%privacy_link' => '<a ' . ($handler::var('page_privacy')['link_attr'] ?? '') . '>' . _s('privacy policy') . '</a>',
]));
$poweredBySiteWide = (bool) env()['CHEVERETO_ENABLE_POWERED_BY_FOOTER_SITE_WIDE'];
$show_powered_by_footer = $poweredBySiteWide
?: ($handler->getRoutePath() === 'index' && getSetting('enable_powered_by'));
if (in_array($handler->getRoutePath(false), ['settings', 'dashboard'])) {
$show_powered_by_footer = false;
$show_powered_by_footer = getSetting('enable_powered_by');
if (array_key_exists('CHEVERETO_ENABLE_FORCE_POWERED_BY_FOOTER', env())) {
if ((bool) env()['CHEVERETO_ENABLE_FORCE_POWERED_BY_FOOTER']) {
$show_powered_by_footer = true;
}
}
$handler::setCond('show_powered_by_footer', $show_powered_by_footer);
};
$hook_after = function (Handler $handler) {
if (array_key_exists('deleted', get()) && in_array($handler->template(), ['user', 'album'])) {
if (array_key_exists('deleted', get())
&& in_array($handler->template(), ['user', 'album'], true)
) {
set_status_header(303);
}
if ($handler->template() == '404') {
if ($handler->template() === '404') {
if (sessionVar()->hasKey('last_url')) {
sessionVar()->remove('last_url');
}
@ -502,14 +644,19 @@ $hook_after = function (Handler $handler) {
if (defined('PUSH_LANG')) {
$handler::setVar('doctitle', $handler::var('doctitle') . ' (' . get_enabled_languages()[PUSH_LANG]['name'] . ')');
}
$handler::setVar('safe_html_website_name', safe_html(getSetting('website_name')));
$handler::setVar('safe_html_website_name', getSetting('website_name', true));
$handler::setVar('safe_html_doctitle', safe_html($handler::var('doctitle')));
if ($handler::var('pre_doctitle')) {
$handler::setVar('safe_html_pre_doctitle', safe_html($handler::var('pre_doctitle')));
}
$handler::setVar('safe_html_meta_description', safe_html($handler::var('meta_description')));
if ($handler::var('meta_description')) {
$handler::setVar('safe_html_meta_description', safe_html($handler::var('meta_description')));
}
if ($handler::var('meta_keywords')) {
$handler::setVar('safe_html_meta_keywords', safe_html($handler::var('meta_keywords')));
}
sessionVar()->put('REQUEST_REFERER', get_current_url());
header('X-Powered-By: Chevereto 4');
};
// @phpstan-ignore-next-line
new Handler(loadTemplate: !REPL, before: $hook_before, after: $hook_after, );
new Handler(loadTemplate: ! REPL, before: $hook_before, after: $hook_after);

View file

@ -10,8 +10,6 @@
*/
use Chevereto\Config\Config;
use function Chevereto\Legacy\captcha_check;
use function Chevereto\Legacy\check_hashed_token;
use Chevereto\Legacy\Classes\Confirmation;
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Login;
@ -19,12 +17,14 @@ use Chevereto\Legacy\Classes\RequestLog;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\TwoFactor;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\captcha_check;
use function Chevereto\Legacy\check_hashed_token;
use function Chevereto\Legacy\decodeID;
use function Chevereto\Legacy\G\datetime;
use function Chevereto\Legacy\G\datetime_diff;
use function Chevereto\Legacy\G\datetimegmt;
use function Chevereto\Legacy\G\get_public_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\generate_hashed_token;
use function Chevereto\Legacy\get_email_body_str;
@ -43,73 +43,82 @@ return function (Handler $handler) {
$handler->setTemplate('404');
$route = $handler->requestArray()[0];
$doing = $handler->request()[0] ?? false;
if (!$doing || !in_array($doing, ['activate', 'password-reset', 'change-email-confirm', 'two-factor']) && $handler->isRequestLevel(3)) {
if (! $doing
|| ! in_array($doing, ['activate', 'password-reset', 'change-email-confirm', 'two-factor'], true)
&& $handler->isRequestLevel(3)
) {
$handler->issueError(404);
return;
}
if (!Settings::get('enable_signups') && in_array($doing, ['awaiting-confirmation', 'activate', 'email-changed'])) {
if (! Settings::get('enable_signups')
&& in_array($doing, ['awaiting-confirmation', 'activate', 'email-changed'], true)
) {
$handler->issueError(403);
return;
}
$logged_user = Login::getUser();
$loggedStatus = $logged_user['status'] ?? '';
if (Login::isLoggedUser() && $doing !== 'email-needed' && $loggedStatus == 'awaiting-email') {
redirect('account/email-needed');
if (Login::isLoggedUser() && $doing !== 'email-needed' && $loggedStatus === 'awaiting-email') {
redirect('account/email-needed', 302);
}
switch ($doing) {
case 'email-needed':
if (Login::isLoggedUser() && $loggedStatus !== 'awaiting-email') {
redirect($logged_user['url']);
if (Login::isLoggedUser()) {
if ($loggedStatus !== 'awaiting-email') {
redirect($logged_user['url'], 302);
}
} else {
redirect('login', 302);
}
break;
case 'resend-activation':
case 'activate':
if (Login::isLoggedUser() && $loggedStatus !== 'awaiting-confirmation') {
redirect($logged_user['url'] ?? '');
redirect($logged_user['url'] ?? '', 302);
}
break;
case 'two-factor':
if (!Login::isLoggedUser()) {
redirect('');
if (! Login::isLoggedUser()) {
redirect('login', 302);
}
if (!TwoFactor::hasFor($logged_user['id'])) {
redirect('settings/security');
if (! TwoFactor::hasFor($logged_user['id'])) {
redirect('settings/security', 302);
}
if (!sessionVar()->hasKey('challenge_two_factor')) {
redirect($logged_user['url'] ?? '');
if (! sessionVar()->hasKey('challenge_two_factor')) {
redirect($logged_user['url'] ?? '', 302);
}
break;
}
$captcha_needed = false;
$request_to_db = [
'activate' => 'account-activate',
'change-email-confirm' => 'account-change-email',
'email-needed' => 'account-email-needed',
'password-forgot' => 'account-password-forgot',
'password-reset' => 'account-password-forgot',
'resend-activation' => 'account-activate',
'activate' => 'account-activate',
'email-needed' => 'account-email-needed',
'change-email-confirm' => 'account-change-email',
'two-factor' => 'account-two-factor',
];
$request_db_field = $request_to_db[$doing] ?? '';
$pre_doctitles = [
'awaiting-confirmation' => _s('Awaiting confirmation'),
'email-changed' => _s('Email changed'),
'email-needed' => _s('Add your email address'),
'password-forgot' => _s('Forgot password?'),
'password-reset' => _s('Reset password'),
'resend-activation' => _s('Resend account activation'),
'email-needed' => _s('Add your email address'),
'awaiting-confirmation' => _s('Awaiting confirmation'),
'two-factor' => _s('Two-factor authentication'),
'email-changed' => _s('Email changed'),
];
$keysToCheck = $request_to_db;
unset($keysToCheck['change-email-confirm']);
$keysToCheck = array_keys($keysToCheck);
if (in_array($doing, $keysToCheck)) {
if (in_array($doing, $keysToCheck, true)) {
$request_log = RequestLog::getCounts($request_db_field, 'fail');
$captcha_needed = (getSetting('captcha') ?? false)
? must_use_captcha($request_log['day'])
@ -119,9 +128,9 @@ return function (Handler $handler) {
$is_error = false;
$error_message = null;
$input_errors = [];
if ($captcha_needed && !empty($POST)) {
if ($captcha_needed && ! empty($POST)) {
$captcha = captcha_check();
if (!$captcha->is_valid) {
if (! $captcha->is_valid) {
$is_error = true;
$error_message = _s('%s says you are a robot', 'CAPTCHA');
}
@ -130,33 +139,32 @@ return function (Handler $handler) {
switch ($doing) {
case 'password-forgot':
case 'resend-activation':
if ($doing == 'password-forgot' && $loggedStatus == 'valid' || $doing == 'resend-activation' && $loggedStatus == 'awaiting-confirmation') {
if ($doing === 'password-forgot' && $loggedStatus === 'valid' || $doing === 'resend-activation' && $loggedStatus === 'awaiting-confirmation') {
$POST['user-subject'] = $logged_user['username'];
$is_error = false;
}
if ($POST !== [] && !$is_error) {
if ($POST !== [] && ! $is_error) {
$subject_type = filter_var($POST['user-subject'] ?? '', FILTER_VALIDATE_EMAIL)
? 'email'
: 'username';
if (trim($POST['user-subject']) == '') {
if (trim($POST['user-subject']) === '') {
$is_error = true;
$input_errors['user-subject'] = _s('Invalid Username/Email');
}
if (!$is_error) {
if (! $is_error) {
$user = User::getSingle($POST['user-subject'], $subject_type);
if ($user !== []) {
if (!filter_var($user['email'], FILTER_VALIDATE_EMAIL)) {
if (! filter_var($user['email'], FILTER_VALIDATE_EMAIL)) {
$error_message = _s("User doesn't have an email.");
$is_error = true;
}
if ($doing == 'password-forgot') {
if ($doing === 'password-forgot') {
switch ($user['status']) {
case 'banned':
$handler->issueError(403);
return;
break;
case 'awaiting-email':
case 'awaiting-confirmation':
$is_error = true;
@ -178,11 +186,11 @@ return function (Handler $handler) {
break;
}
}
if ($handler->template() == '403') {
if ($handler->template() === '403') {
RequestLog::insert([
'type' => $request_db_field,
'result' => 'fail',
'user_id' => $user['id']
'user_id' => $user['id'],
]);
return;
@ -191,15 +199,24 @@ return function (Handler $handler) {
$is_error = true;
$input_errors['user-subject'] = _s('Invalid Username/Email');
}
if (!$is_error) {
$confirmation_db = Confirmation::get(['user_id' => $user['id'], 'type' => $request_db_field, 'status' => 'active'], ['field' => 'date', 'order' => 'desc'], 1);
if (! $is_error) {
$confirmation_db = Confirmation::get([
'user_id' => $user['id'],
'type' => $request_db_field,
'status' => 'active',
], [
'field' => 'date',
'order' => 'desc',
], 1);
if ($confirmation_db !== false) {
$minute_diff = $confirmation_db['confirmation_date_gmt'] ? datetime_diff($confirmation_db['confirmation_date_gmt'], null, 'm') : 15 + 1;
$minute_diff = $confirmation_db['confirmation_date_gmt']
? datetime_diff($confirmation_db['confirmation_date_gmt'], null, 'm')
: 15 + 1;
if ($minute_diff < 15) { // Mimic for the already submitted
$is_error = true;
$is_process_done = false;
$activation_email = $user['email'];
if ($subject_type == 'username') { // We won't disclose this email address
if ($subject_type === 'username') { // We won't disclose this email address
$activation_email = preg_replace('/(?<=.).(?=.*@)/u', '*', $activation_email);
$explode = explode('@', $activation_email);
while (strlen($explode[0]) < 4) {
@ -210,11 +227,14 @@ return function (Handler $handler) {
$handler::setVar('resend_activation_email', $activation_email);
$error_message = _s('Allow up to 15 minutes for the email. You can try again later.');
} else {
Confirmation::delete(['user_id' => $user['id'], 'type' => $request_db_field]);
Confirmation::delete([
'user_id' => $user['id'],
'type' => $request_db_field,
]);
}
}
}
if (!$is_error) {
if (! $is_error) {
$hashed_token = generate_hashed_token((int) $user['id']);
$array_values = [
'type' => $request_db_field,
@ -222,35 +242,40 @@ return function (Handler $handler) {
'date_gmt' => datetimegmt(),
'token_hash' => $hashed_token['hash'],
];
if (!isset($user['confirmation_id'])) {
if (! isset($user['confirmation_id'])) {
$array_values['user_id'] = $user['id'];
$confirmation_db_query = Confirmation::insert($array_values);
} else {
$confirmation_db_query = Confirmation::update($user['confirmation_id'], $array_values);
}
if ($confirmation_db_query) {
$recovery_link = get_public_url('account/' . ($doing == 'password-forgot' ? 'password-reset' : 'activate') . '/?token=' . $hashed_token['public_token_format']);
$recovery_link = get_public_url('account/' . ($doing === 'password-forgot' ? 'password-reset' : 'activate') . '/?token=' . $hashed_token['public_token_format']);
global $theme_mail;
$theme_mail = [
'user' => $user,
'link' => $recovery_link,
];
if ($doing == 'password-forgot') {
$mail['subject'] = _s('Reset your password at %s', getSettings()['website_name']);
if ($doing === 'password-forgot') {
$mail['subject'] = _s(
'Reset your password at %s',
getSetting('website_name')
);
} else {
$mail['subject'] = _s('Confirmation required at %s', getSettings()['website_name']);
$mail['subject'] = _s(
'Confirmation required at %s',
getSetting('website_name')
);
}
$mail['message'] = get_email_body_str('mails/account-' . ($doing == 'password-forgot' ? 'password-reset' : 'confirm'));
xr($mail);
$mail['message'] = get_email_body_str('mails/account-' . ($doing === 'password-forgot' ? 'password-reset' : 'confirm'));
if (send_mail($user['email'], $mail['subject'], $mail['message'])) {
$is_process_done = true;
}
if ($doing == 'resend-activation') {
if ($doing === 'resend-activation') {
Login::setSignup([
'status' => 'awaiting-confirmation',
'email' => $user['email'],
]);
redirect('account/awaiting-confirmation');
redirect('account/awaiting-confirmation', 302);
}
$handler::setVar('password_forgot_email', $user['email']);
} else {
@ -262,14 +287,14 @@ return function (Handler $handler) {
RequestLog::insert([
'result' => 'fail',
'type' => $request_db_field,
'user_id' => $user['id'] ?? null
'user_id' => $user['id'] ?? null,
]);
if ((getSetting('captcha') ?? false)
&& isset($request_log)
&& must_use_captcha($request_log['day'] + 1)) {
$captcha_needed = true;
}
if (!$error_message) {
if (! $error_message) {
$error_message = _s('Invalid Username/Email');
}
}
@ -277,14 +302,12 @@ return function (Handler $handler) {
break;
case 'awaiting-confirmation':
if (!Login::hasSignup()) {
if (! Login::hasSignup()) {
$handler->issueError(403);
return;
break;
}
if (Login::getSignup()['status'] != 'awaiting-confirmation') {
if (Login::getSignup()['status'] !== 'awaiting-confirmation') {
$handler->issueError(403);
return;
@ -310,7 +333,7 @@ return function (Handler $handler) {
RequestLog::insert([
'type' => $request_db_field,
'result' => 'fail',
'user_id' => null
'user_id' => null,
]);
$handler->issueError(403);
@ -318,7 +341,10 @@ return function (Handler $handler) {
}
$user_id = decodeID($get_token_array[0]);
$get_token = hashed_token_info(get()['token']);
$confirmation_db = Confirmation::get(['type' => $request_db_field, 'user_id' => $get_token['id']]);
$confirmation_db = Confirmation::get([
'user_id' => $get_token['id'],
'type' => $request_db_field,
]);
if ($confirmation_db === false) {
$handler->issueError(403);
@ -326,14 +352,16 @@ return function (Handler $handler) {
}
$hash_match = check_hashed_token($confirmation_db['confirmation_token_hash'], get()['token']);
if (datetime_diff($confirmation_db['confirmation_date_gmt'], null, 'h') > 48) {
Confirmation::delete(['id' => $confirmation_db['confirmation_id']]);
Confirmation::delete([
'id' => $confirmation_db['confirmation_id'],
]);
$confirmation_db = false;
}
if (!$hash_match || !$confirmation_db) {
if (! $hash_match || ! $confirmation_db) {
RequestLog::insert([
'type' => $request_db_field,
'result' => 'fail',
'user_id' => $user_id
'user_id' => $user_id,
]);
$handler->issueError(403);
@ -341,39 +369,49 @@ return function (Handler $handler) {
}
switch ($doing) {
case 'activate':
User::update($confirmation_db['confirmation_user_id'], ['status' => 'valid']);
Confirmation::delete(['id' => $confirmation_db['confirmation_id']]);
User::update($confirmation_db['confirmation_user_id'], [
'status' => 'valid',
]);
Confirmation::delete([
'id' => $confirmation_db['confirmation_id'],
]);
$logged_user = Login::login($confirmation_db['confirmation_user_id']);
Login::insertCookie('cookie', $logged_user['id']);
global $theme_mail;
$theme_mail = [
'user' => $logged_user,
];
$mail['subject'] = _s('Welcome to %s', getSettings()['website_name']);
$mail['subject'] = _s('Welcome to %s', getSetting('website_name'));
$mail['message'] = get_email_body_str('mails/account-welcome');
if (send_mail($logged_user['email'], $mail['subject'], $mail['message'])) {
$is_process_done = true;
}
Login::unsetSignup();
redirect($logged_user !== [] ? User::getUrl($logged_user) : null);
$redirectTo = $logged_user !== []
? User::getUrl($logged_user)
: '';
redirect($redirectTo, 302);
break;
case 'password-reset':
if ($POST !== []) {
if (!preg_match('/' . getSetting('user_password_pattern') . '/', $POST['new-password'] ?? '')) {
if (! preg_match('/' . Settings::USER_PASSWORD_PATTERN . '/', $POST['new-password'] ?? '')) {
$input_errors['new-password'] = _s('Invalid password');
}
if ($POST['new-password'] !== $POST['new-password-confirm']) {
$input_errors['new-password-confirm'] = _s("Passwords don't match");
}
if (count($input_errors) == 0) {
if (count($input_errors) === 0) {
if (Login::hasPassword($user_id)) {
$is_process_done = Login::changePassword($user_id, $POST['new-password']);
} else {
$is_process_done = Login::addPassword($user_id, $POST['new-password']);
}
if ($is_process_done) {
Confirmation::delete(['type' => $request_db_field, 'user_id' => $user_id]);
Confirmation::delete([
'type' => $request_db_field,
'user_id' => $user_id,
]);
} else {
throw new Exception('Unexpected error', 400);
}
@ -385,50 +423,70 @@ return function (Handler $handler) {
break;
case 'change-email-confirm':
$email_candidate = $confirmation_db['confirmation_extra'];
$email_db = DB::get('users', ['email' => $email_candidate]);
if ($email_db !== []) {
if ($email_db['user_status'] == 'valid') {
Confirmation::delete(['id' => $confirmation_db['confirmation_id']]);
$email_db = DB::get(
table: 'users',
where: [
'email' => $email_candidate,
],
limit: 1
);
if (! $email_db) {
if ($email_db['user_status'] === 'valid') {
Confirmation::delete([
'id' => $confirmation_db['confirmation_id'],
]);
RequestLog::insert([
'type' => $request_db_field,
'result' => 'fail',
'user_id' => $user_id
'user_id' => $user_id,
]);
$handler->issueError(403);
return;
} else {
DB::delete('users', ['id' => $email_db['user_id']]);
Confirmation::delete(['type' => 'account-change-email', 'user_id' => $email_db['user_id']]);
}
DB::delete('users', [
'id' => $email_db['user_id'],
]);
Confirmation::delete([
'type' => 'account-change-email',
'user_id' => $email_db['user_id'],
]);
}
Confirmation::delete(['type' => 'account-change-email', 'user_id' => $user_id]);
Confirmation::delete([
'type' => 'account-change-email',
'user_id' => $user_id,
]);
sessionVar()->put('change-email-confirm', true);
User::update($user_id, ['email' => $email_candidate]);
User::update($user_id, [
'email' => $email_candidate,
]);
Login::login($user_id);
redirect('account/email-changed');
redirect('account/email-changed', 302);
break;
}
break;
case 'email-needed':
if ($POST !== [] && !$is_error) {
if (!filter_var($POST['email'], FILTER_VALIDATE_EMAIL)) {
if ($POST !== [] && ! $is_error) {
if (! filter_var($POST['email'], FILTER_VALIDATE_EMAIL)) {
$is_error = true;
$input_errors['email'] = _s('Invalid email');
}
if (!$is_error) {
if (! $is_error) {
$user = User::getSingle($POST['email'], 'email');
if ($user !== []) {
$is_error = true;
$input_errors['email'] = _s('Email already being used');
}
}
if (!$is_error) {
User::update($logged_user['id'], ['status' => getSetting('require_user_email_confirmation') ? 'awaiting-confirmation' : 'valid', 'email' => trim($POST['email'])]);
if (!getSetting('require_user_email_confirmation')) {
redirect($logged_user['url']);
if (! $is_error) {
User::update($logged_user['id'], [
'status' => getSetting('require_user_email_confirmation') ? 'awaiting-confirmation' : 'valid',
'email' => trim($POST['email']),
]);
if (! getSetting('require_user_email_confirmation')) {
redirect($logged_user['url'], 302);
}
$hashed_token = generate_hashed_token((int) $logged_user['id']);
$array_values = [
@ -445,7 +503,7 @@ return function (Handler $handler) {
'user' => $logged_user,
'link' => $activation_link,
];
$mail['subject'] = _s('Confirmation required at %s', getSettings()['website_name']);
$mail['subject'] = _s('Confirmation required at %s', getSettings('website_name'));
$mail['message'] = get_email_body_str('mails/account-confirm');
if (send_mail($POST['email'], $mail['subject'], $mail['message'])) {
$is_process_done = true;
@ -454,13 +512,13 @@ return function (Handler $handler) {
'status' => 'awaiting-confirmation',
'email' => $POST['email'],
]);
redirect('account/awaiting-confirmation');
redirect('account/awaiting-confirmation', 302);
} else {
RequestLog::insert(
[
'result' => 'fail',
'type' => $request_db_field,
'user_id' => $user['id'] ?? null
'user_id' => $user['id'] ?? null,
]
);
if ((getSetting('captcha') ?? false)
@ -476,7 +534,7 @@ return function (Handler $handler) {
break;
case 'email-changed':
if (!isset(session()['change-email-confirm'])) {
if (! isset(session()['change-email-confirm'])) {
$handler->issueError(404);
return;
@ -486,20 +544,20 @@ return function (Handler $handler) {
break;
case 'two-factor':
$handler->setTemplate($route . '/' . 'two-factor');
if (!is_null($POST['user-two-factor'] ?? null) && !$is_error) {
if (null !== ($POST['user-two-factor'] ?? null) && ! $is_error) {
$twoFactor = (new TwoFactor())->withSecret(
TwoFactor::getSecretFor(intval($logged_user['id']))
);
if ($twoFactor->verify($POST['user-two-factor'])) {
sessionVar()->remove('challenge_two_factor');
redirect($logged_user['url']);
redirect($logged_user['url'], 302);
} else {
$is_error = true;
$input_errors['user-two-factor'] = _s('Invalid code');
RequestLog::insert([
'type' => $request_db_field,
'result' => 'fail',
'user_id' => $logged_user['id']
'user_id' => $logged_user['id'],
]);
if ((getSetting('captcha') ?? false)
&& isset($request_log)

View file

@ -9,14 +9,18 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\captcha_check;
use Chevereto\Legacy\Classes\Album;
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\RequestLog;
use Chevereto\Legacy\Classes\Tag;
use Chevereto\Legacy\Classes\User;
use function Chevereto\Legacy\G\get_current_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\captcha_check;
use function Chevereto\Legacy\encodeID;
use function Chevereto\Legacy\G\get_current_url;
use function Chevereto\Legacy\G\get_public_url;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\G\starts_with;
@ -24,10 +28,11 @@ use function Chevereto\Legacy\G\url_to_relative;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Legacy\getIdFromURLComponent;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Legacy\is_max_invalid_request;
use function Chevereto\Legacy\isShowEmbedContent;
use function Chevereto\Legacy\must_use_captcha;
use function Chevereto\Legacy\redirectIfRouting;
use function Chevereto\Legacy\virtualRouteHandleRedirect;
use function Chevereto\Vars\env;
use function Chevereto\Vars\get;
use function Chevereto\Vars\post;
@ -37,7 +42,7 @@ use function Chevereto\Vars\session;
use function Chevereto\Vars\sessionVar;
return function (Handler $handler) {
redirectIfRouting('album', $handler->requestArray()[0]);
virtualRouteHandleRedirect('album', $handler->requestArray()[0]);
$albumIndex = getSetting('root_route') === 'album'
? 0
: 1;
@ -60,19 +65,21 @@ return function (Handler $handler) {
return;
}
if (isset($request_handle[1]) && !in_array($request_handle[1], ['embeds', 'sub', 'info'])) {
if (isset($request_handle[1])
&& ! in_array($request_handle[1], ['embeds', 'sub', 'info'])
) {
$handler->issueError(404);
return;
}
$logged_user = Login::getUser();
User::statusRedirect($logged_user['status'] ?? null);
if (!isset(session()['album_view_stock'])) {
if (! isset(session()['album_view_stock'])) {
sessionVar()->put('album_view_stock', []);
}
$album = Album::getSingle(
id: $id,
sumview: !in_array($id, session()['album_view_stock']),
sumView: ! in_array($id, session()['album_view_stock']),
requester: $logged_user
);
if ($album === []) {
@ -80,26 +87,23 @@ return function (Handler $handler) {
return;
}
if (!(bool) env()['CHEVERETO_ENABLE_USERS']
if (! (bool) env()['CHEVERETO_ENABLE_USERS']
&& ($album['user']['id'] ?? 'not-found') != getSetting('website_mode_personal_uid')) {
$handler->issueError(404);
return;
}
if (!starts_with($album['url'], get_current_url())) {
if (! starts_with($album['url'], get_public_url(get_current_url()))) {
if (server()['QUERY_STRING'] ?? false) {
$redirect = rtrim($album['url'], '/') . '/?' . server()['QUERY_STRING'];
} else {
$redirect = $album['url'];
}
redirect($redirect);
redirect($redirect, 302);
}
$handler::setVar(
'canonical',
isset(get()['page']) ? null : $album['url']
);
$banned = isset($album['user']['status']) && $album['user']['status'] === 'banned';
if (!$handler::cond('content_manager') && ($album == false || $banned)) {
if (! $handler::cond('content_manager') && ($album == false || $banned)) {
$handler->issueError(404);
return;
@ -109,11 +113,14 @@ return function (Handler $handler) {
if ($handler::cond('forced_private_mode')) {
$album['privacy'] = getSetting('website_content_privacy_mode');
}
if (!Login::getUser() && $album['privacy'] != 'private_but_link') {
redirect('login');
if (! Login::getUser()
&& $album['privacy'] != 'private_but_link'
) {
headersNoCache();
redirect('login', 302);
}
}
if (!$handler::cond('content_manager') && !$is_owner && $album['privacy'] == 'password' && isset($album['password'])) {
if (! $handler::cond('content_manager') && ! $is_owner && $album['privacy'] == 'password' && isset($album['password'])) {
$is_error = false;
$error_message = null;
$failed_access_requests = RequestLog::getCounts('content-password', 'fail');
@ -125,21 +132,22 @@ return function (Handler $handler) {
$captcha_needed = $handler::cond('captcha_needed');
if ($captcha_needed && (post()['content-password'] ?? false)) {
$captcha = captcha_check();
if (!$captcha->is_valid) {
if (! $captcha->is_valid) {
$is_error = true;
$error_message = _s('%s says you are a robot', 'CAPTCHA');
}
}
if (!$is_error) {
if (! $is_error) {
if (isset(post()['content-password']) && hash_equals($album['password'], post()['content-password'])) {
Album::storeUserPassword($album['id'], post()['content-password']);
} elseif (!Album::checkSessionPassword($album)) {
} elseif (! Album::checkSessionPassword($album)) {
$is_error = true;
if (isset(post()['content-password'])) {
RequestLog::insert([
'type' => 'content-password',
'user_id' => ($logged_user['id'] ?? null),
'content_id' => $album['id'], 'result' => 'fail'
'content_id' => $album['id'],
'result' => 'fail',
]);
$error_message = _s('Invalid password');
}
@ -156,28 +164,77 @@ return function (Handler $handler) {
$handler::setVar('pre_doctitle', _s('Password required'));
return;
} else {
$redirect_password = session()['redirect_password_to'] ?? null;
if (isset($redirect_password)) {
sessionVar()->remove('redirect_password_to');
redirect($redirect_password);
}
}
$redirect_password = session()['redirect_password_to'] ?? null;
if (isset($redirect_password)) {
sessionVar()->remove('redirect_password_to', null);
headersNoCache();
redirect($redirect_password, 302);
}
}
if ($album['user']['is_private'] == 1
&& !$handler::cond('content_manager')
&& $album["user"]["id"] != ($logged_user['id'] ?? null)
&& ! $handler::cond('content_manager')
&& $album['user']['id'] != ($logged_user['id'] ?? null)
) {
unset($album['user']);
$album['user'] = User::getPrivate();
}
if (!$handler::cond('content_manager') && in_array($album['privacy'], ['private', 'custom']) && !$is_owner) {
if (! $handler::cond('content_manager')
&& in_array($album['privacy'], ['private', 'custom'])
&& ! $is_owner
) {
$handler->issueError(404);
return;
}
$tags_id = [];
$tags_active = [];
$isDisplayUsedTags = true;
if ((get()['tag'] ?? '') !== '') {
$tags = Tag::get(get()['tag']);
if ($tags !== []) {
$tags_active = array_column($tags, 'name');
$tags_id = array_column($tags, 'id');
$tags_id_encoded = array_map(function ($id): string {
return encodeID($id);
}, $tags_id);
$params_hidden['tag_id'] = implode(',', $tags_id_encoded);
}
}
$tag_string = implode(', ', $tags_active);
$tag_string_no_spaces = implode(',', $tags_active);
$tagsTable = DB::getTable('tags');
$tagsAlbumsTable = DB::getTable('tags_albums');
$userId = (int) $album['user']['id'];
$albumId = (int) $album['id'];
$base_album_url = url_to_relative($album['url']);
$tags_display = [];
if ($isDisplayUsedTags) {
$tagsSql = <<<MySQL
SELECT t.tag_name name, ta.tag_album_count count
FROM `{$tagsTable}` t
INNER JOIN `{$tagsAlbumsTable}` ta
ON ta.tag_album_tag_id=t.tag_id
AND ta.tag_album_album_id={$albumId}
AND ta.tag_album_count > 0
AND ta.tag_album_user_id={$userId}
ORDER BY `tag_album_count` DESC, `tag_name` ASC
LIMIT 20;
MySQL;
$tags_display = DB::queryFetchAll($tagsSql);
foreach ($tags_display as &$tag) {
$base_tag_filter_url = $base_album_url . '/?tag=';
$tag = Tag::row($tag['name'], $base_tag_filter_url . '%s');
Tag::addUrlFilters($tag, $base_album_url, $tags_active);
}
}
$safe_html_album = safe_html($album);
$safe_html_album['description'] = preg_replace('/[ \t]+/', ' ', preg_replace('/\s*$^\s*/m', "\n", $safe_html_album['description'] ?? ''));
$safe_html_album['description'] = preg_replace(
'/[ \t]+/',
' ',
preg_replace('/\s*$^\s*/m', "\n", $safe_html_album['description'] ?? '')
);
$getParams = Listing::getParams(request());
$handler::setVar('list_params', $getParams);
$type = 'images';
@ -200,11 +257,13 @@ return function (Handler $handler) {
$listing->setLimit($getParams['limit']); // how many results?
$listing->setSortType($getParams['sort'][0]); // date | size | views
$listing->setSortOrder($getParams['sort'][1]); // asc | desc
$listing->setOwner((int) $album["user"]["id"]);
$listing->setOwner((int) $album['user']['id']);
$listing->setTagsIds(...$tags_id);
$listing->setTagsString($tag_string_no_spaces);
$listing->setRequester(Login::getUser());
$listing->setWhere($where);
$listing->setPrivacy($album["privacy"]);
$listing->bind(":image_album_id", $album["id"]);
$listing->setPrivacy($album['privacy']);
$listing->bind(':image_album_id', $album['id']);
$listing->setOutputTpl($output_tpl);
if ($is_owner || $handler::cond('content_manager')) {
$listing->setTools(true);
@ -215,8 +274,17 @@ return function (Handler $handler) {
$tabs = Listing::getTabs([
'listing' => 'images',
'basename' => $baseUrl,
'params_hidden' => ['list' => 'images', 'from' => 'album', 'albumid' => $album['id_encoded']],
'tools_available' => $album['user']['id'] ? [] : ['album' => false]
'params_hidden' => [
'list' => 'images',
'from' => 'album',
'albumid' => $album['id_encoded'],
],
'tools_available' => $album['user']['id']
? []
: [
'album' => false,
],
'tag' => rawurldecode($tag_string_no_spaces),
]);
if (isShowEmbedContent()) {
$tabs[] = [
@ -228,18 +296,28 @@ return function (Handler $handler) {
'id' => 'tab-embeds',
];
}
$tabsSubAlbum = Listing::getTabs([
'listing' => 'albums',
'basename' => $baseUrl . '/sub',
'params_hidden' => ['list' => 'albums', 'from' => 'album', 'albumid' => $album['id_encoded']],
'tools_available' => $album['user']['id'] ? [] : ['album' => false]
'params_hidden' => [
'list' => 'albums',
'from' => 'album',
'albumid' => $album['id_encoded'],
],
'tools_available' => $album['user']['id']
? []
: [
'album' => false,
],
], $getParams);
foreach ($tabsSubAlbum as $array) {
if ($array['label'] == 'AZ') {
$array['label'] = _s('Sub %s', _s('albums'));
$array['id'] = 'tab-sub';
$array['url'] = $album['url'] . '/sub';
$array = array_merge($array, [
'icon' => 'fas fa-folder-tree',
'label' => _s('Sub %s', _s('albums')),
'id' => 'tab-sub',
'url' => $album['url'] . '/sub',
]);
$tabs[] = $array;
break;
@ -252,9 +330,10 @@ return function (Handler $handler) {
'tools' => false,
'label' => _s('Info'),
'id' => 'tab-info',
'url' => $album['url'] . '/info'
'url' => $album['url'] . '/info',
];
}
$currentKey = 0;
$handler::setVar('current_tab', 0);
foreach ($tabs as $k => &$v) {
if (isset($request_handle[1])) {
@ -262,11 +341,12 @@ return function (Handler $handler) {
}
if (isset($v['current']) && $v['current'] === true) {
$handler::setVar('current_tab', $v['id']);
$currentKey = $k;
}
if (!isset($v['params'])) {
if (! isset($v['params'])) {
continue;
}
$class_tabs[$k]['disabled'] = $album['image_count'] == 0 ? !$v['current'] : false;
$class_tabs[$k]['disabled'] = $album['image_count'] == 0 ? ! $v['current'] : false;
}
$handler::setCond('owner', $is_owner);
$handler::setVars([
@ -275,27 +355,68 @@ return function (Handler $handler) {
'album_safe_html' => $safe_html_album,
'tabs' => $tabs,
'list' => $listing,
'owner' => $album['user']
'owner' => $album['user'],
]);
if (isset($album['description'])) {
$meta_description = $album['description'];
} else {
$meta_description = _s('%a album hosted in %w', ['%a' => $album['name'], '%w' => getSetting('website_name')]);
$meta_description = _s('%a album hosted in %w', [
'%a' => $album['name'],
'%w' => getSetting('website_name'),
]);
}
$handler::setVar('meta_description', htmlspecialchars($meta_description));
$handler::setVar('meta_description', $meta_description);
if ($handler::cond('content_manager') || $is_owner) {
$handler::setVar('user_items_editor', [
"user_albums" => User::getAlbums((int) $album["user"]["id"]),
"type" => "images"
'user_albums' => User::getAlbums((int) $album['user']['id']),
'type' => $type,
]);
}
$share_element = [
"HTML" => '<a href="__url__" title="__title__">__title__ (' . $album['image_count'] . ' ' . _n('image', 'images', $album['user']['image_count_display']) . ')</a>'
'HTML' => '<a href="__url__" title="__title__">__title__ ('
. $album['image_count']
. ' '
. _n('image', 'images', $album['user']['image_count_display'])
. ')</a>',
];
$share_links_array = get_share_links($share_element);
$handler::setVar('share_links_array', $share_links_array);
$handler::setVar('privacy', $album['privacy']);
$addValue = session()['album_view_stock'];
$addValue[] = $id;
sessionVar()->put('album_view_stock', $addValue);
$sessionValue = session()['album_view_stock'];
$sessionValue[] = $id;
sessionVar()->put('album_view_stock', $sessionValue);
$handler::setVar('tags_display', $tags_display);
$handler::setVar('tags_active', $tags_active);
if ($tag_string !== '') {
$handler::setVar('meta_keywords', $tag_string);
}
$canonical = get_public_url($tabs[$currentKey]['url']);
$handler::setVar('canonical', $canonical);
$ancestors = [];
$breadcrumbs = [];
if (isset($album['parent_id'])) {
$safe_breadcrumbs_limit = 8;
try {
$ancestors = Album::getAncestors(
$album['id'],
$logged_user,
$safe_breadcrumbs_limit + 1
);
} catch (Throwable $e) {
$ancestors = [];
}
if (count($ancestors) > $safe_breadcrumbs_limit - 1) {
$ancestors[count($ancestors) - 1]['name_html'] = '...';
}
foreach ($ancestors as $ancestor) {
$breadcrumbs[] = [
'url' => $ancestor['url'],
'name_html' => $ancestor['name_html'],
];
}
$breadcrumbs = array_reverse($breadcrumbs);
}
$handler::setVar('ancestors', $ancestors);
$handler::setVar('breadcrumbs', $breadcrumbs);
};

View file

@ -0,0 +1,21 @@
<?php
/*
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Chevereto\Legacy\G\Handler;
return function (Handler $handler) {
if ($handler->isRequestLevel(2)) {
$handler->issueError(404);
return;
}
$handler::setVar('pre_doctitle', _s('API version %s', '1.1'));
};

View file

@ -23,17 +23,21 @@ use Chevereto\Legacy\Classes\Akismet;
use Chevereto\Legacy\Classes\ApiKey;
use Chevereto\Legacy\Classes\Image;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\Upload;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\decodeID;
use function Chevereto\Legacy\encodeID;
use function Chevereto\Legacy\G\get_mimetype;
use function Chevereto\Legacy\G\getQsParams;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\is_image_url;
use function Chevereto\Legacy\G\is_url;
use function Chevereto\Legacy\G\json_document_output;
use function Chevereto\Legacy\G\json_error;
use function Chevereto\Legacy\G\json_output;
use function Chevereto\Legacy\G\mime_to_extension;
use function Chevereto\Legacy\G\random_string;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\getVariable;
use function Chevereto\Vars\env;
use function Chevereto\Vars\files;
use function Chevereto\Vars\request;
@ -46,106 +50,126 @@ return function (Handler $handler) {
$FILES = files();
$SERVER = server();
$format = $REQUEST['format'] ?? 'json';
$version = $handler->request()[0] ?? null;
$action = $handler->request()[1] ?? null;
$key = $SERVER['HTTP_X_API_KEY'] ?? $REQUEST['key'] ?? null;
$version = strval($handler->request()[0] ?? '');
$action = strval($handler->request()[1] ?? '');
$key = strval($SERVER['HTTP_X_API_KEY'] ?? $REQUEST['key'] ?? '');
foreach (['version', 'action', 'key'] as $var) {
if (${$var} === null) {
throw new Exception("No $var provided", 100);
if (${$var} === '') {
throw new Exception("No {$var} provided", 100);
}
}
if (!in_array($version, ['1'])) {
if (! in_array($version, ['1'], true)) {
throw new Exception('Invalid API version.', 110);
}
$verify = ApiKey::verify($key);
if ($verify === []) {
if (!(bool) env()['CHEVERETO_ENABLE_API_GUEST']) {
throw new Exception("Guest API is disabled.", 400);
if (! (bool) env()['CHEVERETO_ENABLE_API_GUEST']) {
throw new Exception('Invalid API key.', 100);
}
$apiV1Key = (string) (getSetting('api_v1_key') ?? '');
if ($apiV1Key == '') {
throw new Exception("API V1 public key can't be null. Go to your dashboard and set the Guest API key.", 0);
if ($apiV1Key === '') {
throw new Exception("API V1 public key can't be null. Go to /dashboard and set the Guest API key.", 0);
}
// @var string $key
if (!hash_equals($apiV1Key, $key)) {
throw new Exception("Invalid guest API key.", 100);
if (! hash_equals($apiV1Key, $key)) {
throw new Exception('Invalid API key.', 100);
}
} else {
$user = User::getSingle($verify['user_id']);
}
$isAdmin = boolval(($user['is_admin'] ?? false));
if (Settings::get('enable_uploads_url') && !$isAdmin) {
Settings::setValue('enable_uploads_url', 0);
}
$upload_enabled = $isAdmin ?: getSetting('enable_uploads');
$upload_allowed = $upload_enabled;
if ($user === []) {
if (!getSetting('guest_uploads')
|| getSetting('website_privacy_mode') == 'private'
if (! getSetting('guest_uploads')
|| getSetting('website_privacy_mode') === 'private'
|| $handler::cond('maintenance')
) {
$upload_allowed = false;
}
} elseif (!$user['is_admin']
&& getSetting('website_mode') == 'personal'
&& getSetting('website_mode_personal_uid') !== $user['id']
} elseif (! $isAdmin
&& getSetting('website_mode') === 'personal'
&& getSetting('website_mode_personal_uid') !== ($user['id'] ?? 0)
) {
$upload_allowed = false;
}
if (!$upload_allowed) {
if ((! (bool) env()['CHEVERETO_ENABLE_LOCAL_STORAGE'])
&& getVariable('storages_active')->nullInt() === 0
) {
$upload_enabled = false;
$upload_allowed = false;
}
if ($user === []
&& $upload_allowed
&& getSetting('upload_max_filesize_mb_guest')
) {
Settings::setValue('upload_max_filesize_mb_bak', getSetting('upload_max_filesize_mb'));
Settings::setValue('upload_max_filesize_mb', getSetting('upload_max_filesize_mb_guest'));
}
$handler::setCond('upload_enabled', $upload_enabled);
$handler::setCond('upload_allowed', $upload_allowed);
if (Settings::get('enable_uploads_url') && ! $isAdmin) {
Settings::setValue('enable_uploads_url', 0);
}
if (! $handler::cond('upload_allowed')) {
throw new Exception(_s('Request denied'), 401);
}
$version_to_actions = [
'1' => ['upload']
];
if (!in_array($action, $version_to_actions[$version])) {
throw new Exception('Invalid API action.', 120);
'1' => ['upload'],
];
if (! in_array($action, $version_to_actions[$version], true)) {
throw new Exception('Invalid API action', 120);
}
$source = $FILES['source']
?? $REQUEST['source']
?? $REQUEST['image']
?? null;
if (is_null($source)) {
throw new Exception('Empty upload source.', 130);
if ($source === null) {
throw new Exception('Empty upload source', 130);
}
switch (true) {
case isset($FILES['source'], $FILES['source']['tmp_name']):
$source = $FILES['source'];
break;
break;
case is_image_url($source) || is_url($source):
if (($SERVER['REQUEST_METHOD'] ?? '') === 'GET') {
$sourceQs = urldecode(getQsParams()['source']);
}
$source = $sourceQs ?? $source;
break;
break;
default:
if (($SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
throw new Exception('Upload using base64 source must be done using POST method.', 130);
}
$source = trim(preg_replace('/\s+/', '', $source));
$base64source = base64_encode(base64_decode($source));
if (!hash_equals($base64source, $source)) {
throw new Exception('Invalid base64 string.', 120);
$base64source = base64_encode(base64_decode($source, true));
if (! hash_equals($base64source, $source)) {
throw new Exception('Invalid base64 string', 120);
}
$api_temp_file = tempnam(sys_get_temp_dir(), 'chvtemp');
if (!$api_temp_file || !is_writable($api_temp_file)) {
throw new Exception("Can't get a tempnam.", 200);
if ($source === '') {
throw new Exception('Empty source', 130);
}
try {
$api_temp_file = Upload::getTempNam();
} catch (Exception $e) {
throw new Exception("Can't get a tempnam", 200);
}
$fh = fopen($api_temp_file, 'w');
stream_filter_append($fh, 'convert.base64-decode', STREAM_FILTER_WRITE);
fwrite($fh, $source);
fclose($fh);
$mimetype = get_mimetype($api_temp_file);
$source = [
'name' => random_string(12) . '.jpg',
'type' => 'image/jpeg',
'name' => random_string(12) . '.' . mime_to_extension($mimetype),
'type' => $mimetype,
'tmp_name' => $api_temp_file,
'error' => 'UPLOAD_ERR_OK',
'size' => '1'
'size' => filesize($api_temp_file),
];
break;
break;
}
$isImgBBSpec = array_key_exists('image', $REQUEST);
$albumId = $REQUEST['album_id'] ?? null;
@ -153,8 +177,8 @@ return function (Handler $handler) {
$albumId = decodeID($albumId);
}
$expiration = $REQUEST['expiration'] ?? null;
if (!is_null($expiration) && ctype_digit($expiration)) {
$expiration = Image::getExpirationFromSeconds($expiration);
if ($expiration !== null && ctype_digit($expiration)) {
$expiration = (int) $expiration;
}
$params = [
'album_id' => $albumId,
@ -162,25 +186,38 @@ return function (Handler $handler) {
'description' => $REQUEST['description'] ?? null,
'nsfw' => $REQUEST['nsfw'] ?? null,
'title' => $REQUEST['title'] ?? $REQUEST['name'] ?? null,
'tags' => $REQUEST['tags'] ?? null,
'width' => $REQUEST['width'] ?? null,
'expiration' => $expiration,
'mimetype' => $REQUEST['mimetype'] ?? 'image/jpeg',
'use_file_date' => $isAdmin
? ($REQUEST['use_file_date'] ?? false)
: false,
];
$params = array_filter($params);
if (!$handler::cond('content_manager') && getSetting('akismet')) {
if (! $handler::cond('content_manager') && getSetting('akismet')) {
$user_source_db = [
'user_name' => $user['name'] ?? null,
'user_username' => $user['username'] ?? null,
'user_email' => $user['email'] ?? null,
];
Akismet::checkImage($params['title'] ?? null, $params['description'] ?? null, $user_source_db);
Akismet::checkImage(
title: $params['title'] ?? null,
description: $params['description'] ?? null,
tags: $params['tags'] ?? null,
source_db: $user_source_db
);
}
$uploadToWebsite = Image::uploadToWebsite($source, $user, $params);
$uploaded_id = intval($uploadToWebsite[0]);
$image = Image::formatArray(Image::getSingle($uploaded_id), true);
$image['delete_url'] = Image::getDeleteUrl(encodeID($uploaded_id), $uploadToWebsite[1]);
$image['delete_url'] = Image::getDeleteUrl(
type: $image['type'],
idEncoded: encodeID($uploaded_id),
password: $uploadToWebsite[1]
);
unset($image['user'], $image['album']);
if (!$image['is_approved']) {
if (! $image['is_approved']) {
unset($image['image']['url'], $image['thumb']['url'], $image['medium']['url'], $image['url'], $image['display_url']);
}
$json_array = [];
@ -189,49 +226,51 @@ return function (Handler $handler) {
$json_array['status'] = $json_array['status_code'];
$image['id'] = $image['id_encoded'];
}
$json_array['success'] = ['message' => 'file uploaded', 'code' => 200];
$json_array['success'] = [
'message' => 'file uploaded',
'code' => 200,
];
$json_array[$isImgBBSpec ? 'data' : 'image'] = $image;
if ($version == 1) {
if ($version === '1') {
switch ($format) {
default:
case 'json':
json_output($json_array);
json_document_output($json_array);
break;
break;
case 'txt':
echo $image['url'];
break;
break;
case 'redirect':
if ($json_array['status_code'] === 200) {
$redirect_url = $image['path_viewer'];
header("Location: $redirect_url");
header("Location: {$redirect_url}");
} else {
die($json_array['status_code']);
exit($json_array['status_code']);
}
break;
break;
}
die();
} else {
json_output($json_array);
exit();
}
json_document_output($json_array);
} catch (Exception $e) {
$json_array = json_error($e);
if ($version == 1) {
if ($version === '1') {
switch ($format) {
default:
case 'json':
json_output($json_array);
json_document_output($json_array);
break;
case 'txt':
case 'redirect':
die($json_array['error']['message']);
exit($json_array['error']['message']);
}
} else {
json_output($json_array);
json_document_output($json_array);
}
}
};

View file

@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\fetch_url;
use function Chevereto\Legacy\G\get_client_ip;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Vars\get;
@ -20,7 +20,7 @@ use function Chevereto\Vars\sessionVar;
return function (Handler $handler) {
$key = getSetting('captcha_secret') ?? '';
if ($key === '') {
redirect();
redirect('', 302);
}
try {
@ -35,7 +35,7 @@ return function (Handler $handler) {
$params = [
'secret' => getSetting('captcha_secret'),
'response' => get()['token'] ?? '',
'remoteip' => get_client_ip()
'remoteip' => get_client_ip(),
];
$fetch = fetch_url(
url: $endpoint,
@ -47,9 +47,9 @@ return function (Handler $handler) {
$object = json_decode($fetch);
$isSuccess = (bool) $object->success;
sessionVar()->put('isHuman', $isSuccess);
sessionVar()->put('isBot', !$isSuccess);
die($fetch);
sessionVar()->put('isBot', ! $isSuccess);
exit($fetch);
} catch (Exception) {
}
die();
exit();
};

View file

@ -11,14 +11,18 @@
use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use function Chevereto\Legacy\G\get_route_name;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\get_route_name;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Vars\request;
return function (Handler $handler) {
if (!$handler::cond('explore_enabled')) {
if (! $handler::cond('explore_enabled')) {
$handler->issueError(404);
return;
}
if ($handler->isRequestLevel(3)) {
$handler->issueError(404);
return;
@ -26,29 +30,33 @@ return function (Handler $handler) {
$category = null;
$categories = $handler::var('categories');
$category_url_key = $handler->request()[0] ?? false;
if (!$category_url_key) {
redirect('explore');
}
if ($category_url_key) {
foreach ($categories as $v) {
if ($v['url_key'] == $category_url_key) {
$category = $v;
if (! $category_url_key) {
$handler->issueError(404);
break;
}
}
if (!$category) {
$handler->issueError(404);
return;
}
$handler::setVar('pre_doctitle', $category['name']);
return;
}
$category_url_key = urldecode($category_url_key);
foreach ($categories as $v) {
if ($v['url_key'] == $category_url_key) {
$category = $v;
break;
}
}
if (! $category) {
$handler->issueError(404);
return;
}
$handler::setVar('pre_doctitle', $category['name']);
$getParams = Listing::getParams(request());
$tabs = Listing::getTabs([
'listing' => 'images',
'basename' => get_route_name() . '/' . $category['url_key'],
'params_hidden' => ['category_id' => $category['id'], 'hide_banned' => 1],
'params_hidden' => [
'category_id' => $category['id'],
'hide_banned' => 1,
],
], $getParams);
$handler::setVar('list_params', $getParams);
$listing = new Listing();
@ -67,10 +75,9 @@ return function (Handler $handler) {
$listing->setRequester(Login::getUser());
$listing->exec();
$meta_description = $category['description'] ?? '';
$handler::setVar('meta_description', htmlspecialchars($meta_description));
$handler::setVar('meta_description', $meta_description);
$handler::setVar('category', $category);
$handler::setVar('tabs', $tabs);
$handler::setVar('listing', $listing);
$handler->setTemplate('explore');
$handler::setVar('share_links_array', get_share_links());
};

View file

@ -9,28 +9,29 @@
* file that was distributed with this source code.
*/
use function Chevere\Message\message;
use Chevereto\Legacy\Classes\HybridauthSession;
use Chevereto\Legacy\Classes\L10n;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\User;
use function Chevereto\Legacy\G\get_public_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\getSetting;
use Hybridauth\Exception\InvalidAuthorizationStateException;
use Hybridauth\Hybridauth;
use function Chevere\Message\message;
use function Chevereto\Legacy\cheveretoVersionInstalled;
use function Chevereto\Legacy\G\get_public_url;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\getSetting;
return function (Handler $handler) {
if (!version_compare(Settings::get('chevereto_version_installed') ?? '', '4.0.0-beta.11', '>=')) {
if (! version_compare(cheveretoVersionInstalled(), '4.0.0-beta.11', '>=')) {
echo 'Route not available until the system update gets installed.';
die();
exit();
}
$doing = $handler->request()[0] ?? '';
$providersEnabled = Login::getProviders('enabled');
$doable = array_keys($providersEnabled);
if (!in_array($doing, $doable)) {
if (! in_array($doing, $doable)) {
$handler->issueError(404);
return;
@ -43,7 +44,7 @@ return function (Handler $handler) {
if ($validate['valid']
&& in_array($validate['id'], Login::getSession()['login_cookies'] ?? [])
) {
redirect('settings/connections#' . $doing);
redirect('settings/connections#' . $doing, 302);
return;
}
@ -58,7 +59,7 @@ return function (Handler $handler) {
'keys' => [
'id' => $provider['key_id'],
'secret' => $provider['key_secret'],
]
],
];
}
$session = new HybridauthSession();
@ -66,13 +67,12 @@ return function (Handler $handler) {
$adapter = $hybridauth->getAdapter($doing);
try {
if (!$adapter->isConnected()) {
if (! $adapter->isConnected()) {
$adapter->authenticate();
} else {
}
} catch (InvalidAuthorizationStateException) {
$session->clear();
redirect('connect/' . $doing);
redirect('connect/' . $doing, 302);
}
if ($adapter->isConnected()) {
$user = $logged_user;
@ -87,11 +87,11 @@ return function (Handler $handler) {
}
if ($connectedUserId != ($user['id'] ?? 0)) {
Login::logout();
redirect('connect/' . $doing);
redirect('connect/' . $doing, 302);
}
}
if ($user === []) {
if (!Settings::get('enable_signups')) {
if (! Settings::get('enable_signups')) {
$handler->issueError(403);
return;
@ -101,11 +101,11 @@ return function (Handler $handler) {
foreach ($user_matches[0] as $match) {
$username .= $match;
}
$baseUsername = substr(strtolower($username), 0, (int) getSetting('username_max_length'));
$baseUsername = substr(strtolower($username), 0, (int) Settings::USERNAME_MAX_LENGTH);
$username = $baseUsername;
$j = 1;
while (!User::isValidUsername($username)) {
if (strlen($username) > getSetting('username_max_length')) {
while (! User::isValidUsername($username)) {
if (strlen($username) > Settings::USERNAME_MAX_LENGTH) {
$username = substr($baseUsername, 0, -strlen(strval($j))) . $j;
} else {
$username .= $j;
@ -114,7 +114,7 @@ return function (Handler $handler) {
}
$i = 1;
while (User::getSingle($username, 'username', false)) {
if (strlen($username) > getSetting('username_max_length')) {
if (strlen($username) > Settings::USERNAME_MAX_LENGTH) {
$username = substr($baseUsername, 0, -strlen(strval($i))) . $i;
} else {
$username .= $i;
@ -132,9 +132,6 @@ return function (Handler $handler) {
'language' => L10n::getLocale(),
];
$insert_user_values = array_filter($insert_user_values);
// if (in_array($doing, ['twitter', 'facebook'])) {
// $insert_user_values[$doing . '_username'] = $connectProfile->displayName;
// }
$inserted_user = User::insert($insert_user_values);
$user = User::getSingle($inserted_user, 'id', true);
}
@ -169,10 +166,10 @@ return function (Handler $handler) {
? $user['url']
: 'settings/connections#' . $doing
);
redirect($redirectTo);
redirect($redirectTo, 302);
}
redirect('');
redirect('', 302);
die();
exit();
};

File diff suppressed because it is too large Load diff

View file

@ -12,34 +12,41 @@
use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\G\get_current_url;
use function Chevereto\Legacy\G\get_public_url;
use function Chevereto\Legacy\G\get_route_name;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\str_replace_first;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Vars\request;
return function (Handler $handler) {
$logged_user = Login::getUser();
if (!$handler::cond('explore_enabled') && !($logged_user['is_content_manager'] ?? false)) {
if (! $handler::cond('explore_enabled') && ! ($logged_user['is_content_manager'] ?? false)) {
$handler->issueError(404);
return;
}
$doing = $handler->request()[0] ?? null;
$baseUrlRouteName = get_base_url(get_route_name());
if (!isset($doing)
if (! isset($doing)
&& getSetting('homepage_style') == 'route_explore'
&& str_contains(get_current_url(), $baseUrlRouteName)
) {
$redirect = str_replace_first($baseUrlRouteName, get_base_url(), get_current_url());
redirect($redirect);
$redirect = str_replace_first(
$baseUrlRouteName,
get_base_url(),
get_current_url()
);
headersNoCache();
redirect($redirect, 302);
}
$explore_semantics = $handler::var('explore_semantics');
if (isset($doing) && !array_key_exists($doing, $explore_semantics)) {
$explore_discovery = $handler::var('explore_discovery') + $handler::var('explore_content');
if (isset($doing) && ! array_key_exists($doing, $explore_discovery)) {
$handler->issueError(404);
return;
@ -55,30 +62,58 @@ return function (Handler $handler) {
if ($doing) {
$basename .= ($basename ? '/' : '') . $doing;
}
$list = isset($doing) ? $explore_semantics[$doing] : ['label' => _s('Explore'), 'icon' => 'fas fa-images'];
$list['list'] = is_null($doing) ? get_route_name() : $doing;
$list = isset($doing) ? $explore_discovery[$doing] : [
'label' => _s('Explore'),
'icon' => 'fas fa-compass',
];
$list['list'] = $doing === null
? get_route_name()
: $doing;
$doing ??= 'images';
$listingParams = [
'listing' => $list['list'],
'basename' => $basename,
'params_hidden' => [
'hide_empty' => 1,
'hide_banned' => 1,
'album_min_image_count' => getSetting('explore_albums_min_image_count'),
],
];
if ($listingParams['listing'] === 'albums') {
$listingParams['params_hidden']['album_min_image_count'] = getSetting('explore_albums_min_image_count');
}
if ($doing == 'animated') {
$listingParams['params_hidden']['is_animated'] = 1;
$listingParams['params_hidden'] = array_merge($listingParams['params_hidden'], [
'is_animated' => 1,
'is_image' => 1,
'is_video' => 0,
]);
}
if ($doing == 'videos') {
$listingParams['params_hidden']['is_video'] = 1;
$listingParams['params_hidden'] = array_merge($listingParams['params_hidden'], [
'is_image' => 0,
'is_video' => 1,
]);
}
$getParams = Listing::getParams(request());
if ($doing == 'images' && $basename !== '') {
$listingParams['params_hidden'] = array_merge($listingParams['params_hidden'], [
'is_image' => 1,
'is_video' => 0,
]);
}
$request = request();
$getParams = Listing::getParams(
request: $request,
type: $request['list'] ?? $doing
);
$tabs = Listing::getTabs($listingParams, $getParams, true);
$currentKey = $tabs['currentKey'];
$type = $tabs['tabs'][$currentKey]['type'];
$tabs = $tabs['tabs'];
parse_str($tabs[$currentKey]['params'], $tabs_params);
$getParams['sort'] = explode('_', $tabs_params['sort']); // Hack this stuff
parse_str($tabs[$currentKey]['params'], $tab_params);
$fix_sort = explode('_', $tab_params['sort']);
if (count($fix_sort) == 2) {
$getParams['sort'] = $fix_sort;
}
$handler::setVar('list_params', $getParams);
$listing = new Listing();
$listing->setType($type);
@ -109,4 +144,6 @@ return function (Handler $handler) {
$handler::setVar('user_items_editor', false);
}
$handler::setVar('share_links_array', get_share_links());
$canonical = get_public_url($tabs[$currentKey]['url']);
$handler::setVar('canonical', $canonical);
};

View file

@ -11,22 +11,27 @@
use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use function Chevereto\Legacy\encodeID;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\cheveretoVersionInstalled;
use function Chevereto\Legacy\encodeID;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Vars\request;
return function (Handler $handler) {
if (version_compare(getSetting('chevereto_version_installed'), '3.7.0', '<') || !getSetting('enable_followers')) {
if (version_compare(cheveretoVersionInstalled(), '3.7.0', '<')
|| ! getSetting('enable_followers')
) {
$handler->issueError(404);
return;
}
$logged_user = Login::getUser();
if ($logged_user === []) {
redirect('login');
headersNoCache();
redirect('login', 302);
}
if ($handler->isRequestLevel(2)) {
$handler->issueError(404);
@ -37,7 +42,9 @@ return function (Handler $handler) {
$tabs = Listing::getTabs([
'listing' => 'images',
'exclude_criterias' => ['most-oldest'],
'params_hidden' => ['follow_user_id' => encodeID((int) $logged_user['id'])],
'params_hidden' => [
'follow_user_id' => encodeID((int) $logged_user['id']),
],
], $getParams);
$where = 'WHERE follow_user_id=:user_id';
$handler::setVar('list_params', $getParams);
@ -55,7 +62,7 @@ return function (Handler $handler) {
$listing->setSortOrder($getParams['sort'][1]); // asc | desc
$listing->setRequester(Login::getUser());
$listing->setWhere($where);
$listing->bind(":user_id", $logged_user['id']);
$listing->bind(':user_id', $logged_user['id']);
$listing->exec();
$handler::setVar('pre_doctitle', _s('Following'));
$handler::setVar('tabs', $tabs);

View file

@ -14,29 +14,32 @@ use Chevereto\Legacy\Classes\Image;
use Chevereto\Legacy\Classes\IpBan;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\encodeID;
use function Chevereto\Legacy\flatten_array;
use function Chevereto\Legacy\G\get_current_url;
use function Chevereto\Legacy\G\get_global;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\include_theme_file;
use function Chevereto\Legacy\G\is_animated_image;
use function Chevereto\Legacy\G\get_route_name;
use function Chevereto\Legacy\G\get_route_path;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\require_theme_file;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\G\str_replace_first;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Legacy\getComments;
use function Chevereto\Legacy\getFriendlyExif;
use function Chevereto\Legacy\getIdFromURLComponent;
use function Chevereto\Legacy\getIpButtonsArray;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Legacy\isShowEmbedContent;
use function Chevereto\Legacy\redirectIfRouting;
use function Chevereto\Legacy\virtualRouteHandleRedirect;
use function Chevereto\Vars\env;
use function Chevereto\Vars\session;
use function Chevereto\Vars\sessionVar;
return function (Handler $handler) {
redirectIfRouting('image', $handler->requestArray()[0]);
virtualRouteHandleRedirect('image', $handler->requestArray()[0]);
$imageIndex = getSetting('root_route') === 'image'
? 0
: 1;
@ -54,18 +57,23 @@ return function (Handler $handler) {
return;
}
if (!isset(session()['image_view_stock'])) {
if (! isset(session()['image_view_stock'])) {
sessionVar()->put('image_view_stock', []);
}
$logged_user = Login::getUser();
User::statusRedirect($logged_user['status'] ?? null);
$image = Image::getSingle($id, !in_array($id, session()['image_view_stock']), true, $logged_user);
if ($image === [] || !isset($image['url'])) {
$image = Image::getSingle(
$id,
! in_array($id, session()['image_view_stock']),
true,
$logged_user
);
if ($image === [] || ! isset($image['url'])) {
$handler->issueError(404);
return;
}
if (!(bool) env()['CHEVERETO_ENABLE_USERS']
if (! (bool) env()['CHEVERETO_ENABLE_USERS']
&& ($image['user']['id'] ?? 'not-found') != getSetting('website_mode_personal_uid')) {
$handler->issueError(404);
@ -76,7 +84,7 @@ return function (Handler $handler) {
$password = $request_handle[2] ?? '';
if (Image::verifyPassword($id, $password)) {
Image::delete($id);
redirect($image['path_viewer'] . '?deleted');
redirect($image['path_viewer'] . '?deleted', 301);
}
}
@ -84,56 +92,65 @@ return function (Handler $handler) {
return;
}
if (!$image['is_approved'] && (!($logged_user['is_manager'] ?? false) && !($logged_user['is_admin'] ?? false))) {
if (! $image['is_approved']
&& (! ($logged_user['is_manager'] ?? false) && ! ($logged_user['is_admin'] ?? false))
) {
$handler->issueError(403);
return;
}
if ($image['path_viewer'] != get_current_url(true, ['lang'])) {
redirect($image['path_viewer']);
redirect($image['path_viewer'], 302);
}
$handler::setVar('canonical', $image['url_viewer']);
if ((!$handler::cond('content_manager')
if ((! $handler::cond('content_manager')
&& ($image['user']['status'] ?? null) == 'banned')
) {
) {
$handler->issueError(404);
return;
}
sessionVar()->put('last_viewed_image', encodeID((int) $id));
if ($image['file_resource']['type'] == 'path' && (!$image['is_animated'] && isset($image['file_resource']['chain']['image']) && is_animated_image($image['file_resource']['chain']['image']))) {
Image::update($id, ['is_animated' => 1]);
$image['is_animated'] = 1;
}
$is_owner = isset($image['user']['id']) ? ($image['user']['id'] == ($logged_user['id'] ?? null)) : false;
if (getSetting('website_privacy_mode') == 'private') {
if ($handler::cond('forced_private_mode')) {
$image['album']['privacy'] = getSetting('website_content_privacy_mode');
}
if (!Login::getUser() && ($image['album']['privacy'] ?? null) != 'private_but_link') {
redirect('login');
if (! Login::getUser()
&& ($image['album']['privacy'] ?? null) != 'private_but_link'
) {
headersNoCache();
redirect('login', 302);
}
}
if (!$handler::cond('content_manager') && !$is_owner && ($image['album']['privacy'] ?? null) == 'password' && !Album::checkSessionPassword($image['album'])) {
if (! $handler::cond('content_manager')
&& ! $is_owner
&& ($image['album']['privacy'] ?? null) == 'password'
&& ! Album::checkSessionPassword($image['album'])
) {
sessionVar()->put('redirect_password_to', $image['path_viewer']);
redirect($image['album']['url']);
headersNoCache();
redirect($image['album']['url'], 302);
}
if (isset($image['user']['is_private'])
&& $image['user']['is_private'] == 1
&& !$handler::cond('content_manager')
&& ! $handler::cond('content_manager')
&& $image['user']['id'] != ($logged_user['id'] ?? null)
) {
unset($image['user']);
$image['user'] = User::getPrivate();
}
if (!$handler::cond('content_manager') && in_array($image['album']['privacy'] ?? null, ['private', 'custom']) && !$is_owner) {
if (! $handler::cond('content_manager')
&& in_array($image['album']['privacy'] ?? null, ['private', 'custom'])
&& ! $is_owner
) {
$handler->issueError(404);
return;
}
if (isset($image['user']['id'])) {
$image['user']['albums'] = User::getAlbums((int) $image["user"]["id"]);
if (isset($image['user']['id'])
&& ($handler::cond('content_manager') || $is_owner)) {
$image['user']['albums'] = User::getAlbums((int) $image['user']['id']);
}
$is_album_cover = false;
if (isset($image['album']['id'])) {
@ -145,22 +162,34 @@ return function (Handler $handler) {
$handler::setCond('album_cover', $is_album_cover);
$image_safe_html = safe_html($image);
$image['alt'] = $image_safe_html['description'] ?? ($image_safe_html['title'] ?? $image_safe_html['name']);
$hostedAt = _s('%f hosted at %w', [
'%f' => $image_safe_html['name'] . '.' . $image['extension'],
'%w' => getSetting('website_name'),
]);
$pre_doctitle = isset($image['title'])
? strip_tags($image['title'])
: $image_safe_html['name'] . '.' . $image['extension'] . ' hosted at ' . getSetting('website_name');
: $hostedAt;
$tabs = [];
$tabs[] = [
'icon' => 'fas fa-list-ul',
'label' => _s('About'),
'id' => 'tab-about',
'current' => true,
'url' => '#about',
];
$comments = getComments();
$commentsArgs = [
'url' => $image['url_short'],
'id' => $image['type'] . ':' . $image['id_encoded'],
'title' => $image['title_truncated_html'],
];
// $commentsArgs['id'] = str_replace_first(get_route_path(), get_route_name(), get_route_path(true)); // Legacy fix
$comments = getComments(...$commentsArgs);
if ($comments !== '') {
$tabs[] = [
'icon' => 'fas fa-comments',
'label' => _s('Comments'),
'id' => 'tab-comments',
'url' => '#comments',
];
}
$handler::setVar('comments', $comments);
@ -169,20 +198,37 @@ return function (Handler $handler) {
'icon' => 'fas fa-code',
'label' => _s('Embed codes'),
'id' => 'tab-embeds',
'url' => '#embeds',
];
}
$image_exif = [];
if (getSetting('theme_show_exif_data')) {
$image_exif = getFriendlyExif($image['original_exifdata']) ?? [];
if ($image_exif !== []) {
$tabs[] = [
'icon' => 'fas fa-camera',
'label' => _s('EXIF data'),
'id' => 'tab-exif',
'url' => '#exif',
];
}
}
$handler::setVar('image_exif', $image_exif);
if ($handler::cond('content_manager')) {
if ($handler::cond('admin')) {
$tabs[] = [
'icon' => 'fas fa-info-circle',
'label' => _s('Info'),
'id' => 'tab-info',
'url' => '#info',
];
}
$bannedIp = IpBan::getSingle(['ip' => $image['uploader_ip']]);
$bannedIp = IpBan::getSingle([
'ip' => $image['uploader_ip'],
]);
$image_admin_list_values = [
[
'label' => _s('Image ID'),
'label' => _s('File ID'),
'content' => $image['id'] . ' (' . $image['id_encoded'] . ')',
],
getIpButtonsArray($bannedIp, $image['uploader_ip']),
@ -192,19 +238,18 @@ return function (Handler $handler) {
],
[
'label' => '',
'content' => $image['date_gmt'] . ' (GMT)',
'content' => $image['date_gmt'] . ' (UTC)',
],
];
$handler::setVar('content_ip', $image['uploader_ip']);
$handler::setVar('image_admin_list_values', $image_admin_list_values);
$handler::setCond('banned_ip', $bannedIp !== []);
}
// tab-embeds, tab-about, tab-info
$firstTabSetting = getSetting('image_first_tab');
if (!$handler::cond('admin') && $firstTabSetting == 'info') {
if (! $handler::cond('admin') && $firstTabSetting == 'info') {
$firstTabSetting = 'embeds';
}
if (!isShowEmbedContent() && $firstTabSetting == 'embeds') {
if (! isShowEmbedContent() && $firstTabSetting == 'embeds') {
$firstTabSetting = 'about';
}
if ($comments === '' && $firstTabSetting == 'comments') {
@ -247,14 +292,14 @@ return function (Handler $handler) {
$meta_description = $image['description'];
} else {
$image_tr = [
'%i' => $image[is_null($image['title']) ? 'filename' : 'title'],
'%i' => $image[$image['title'] === null ? 'filename' : 'title'],
'%a' => $image['album']['name'] ?? '',
'%w' => getSetting('website_name'),
'%c' => $image['category']['name'] ?? '',
];
if (isset($image['album']['id'])
|| (
!((bool) ($image['user']['is_private'] ?? false)) && isset($image['album']['name'])
! ((bool) ($image['user']['is_private'] ?? false)) && isset($image['album']['name'])
)) {
$meta_description = _s('Image %i in %a album', $image_tr);
} elseif (isset($image['category']['id'])) {
@ -263,7 +308,7 @@ return function (Handler $handler) {
$meta_description = _s('Image %i hosted in %w', $image_tr);
}
}
$handler::setVar('meta_description', htmlspecialchars($meta_description ?? ''));
$handler::setVar('meta_description', $meta_description ?? '');
if ($handler::cond('content_manager') || $is_owner) {
$handler::setVar('user_items_editor', [
'user_albums' => $image['user']['albums'] ?? null,
@ -274,7 +319,7 @@ return function (Handler $handler) {
}
$handler::setVar('share_links_array', get_share_links());
$handler::setVar('privacy', $image['album']['privacy'] ?? '');
include_theme_file('snippets/embed');
require_theme_file('snippets/embed');
$embed_share_tpl = get_global('embed_share_tpl');
$sharing = [];
foreach (flatten_array($image) as $imageKey => $imageValue) {
@ -291,7 +336,7 @@ return function (Handler $handler) {
$groupLabel = $group['label'];
foreach ($group['options'] as $option => $optionValue) {
foreach ($hasSizes as $sizeKey => $sizeValue) {
if (!$sizeValue && str_starts_with($option, $sizeKey . '-')) {
if (! $sizeValue && str_starts_with($option, $sizeKey . '-')) {
continue 2;
}
}
@ -309,19 +354,32 @@ return function (Handler $handler) {
$label = $optionValue['label'];
$label = str_ireplace($groupLabel, '', $label);
$label = ucfirst(trim($label));
$entries[] = [
$entry = [
'label' => $label,
'value' => $value,
'id' => $option
'id' => $option,
];
if ($code === 'links'
&& ! in_array($option, ['viewer-links', 'delete-links'])
) {
$entry['url_download'] = $value;
}
$entries[] = $entry;
}
$embed[$code] = [
'label' => $group['label'],
'entries' => $entries
'entries' => $entries,
];
}
$handler::setVar('oembed', [
'title' => $handler::var('pre_doctitle'),
'url' => $image['url_viewer'],
]);
$handler::setVar('embed', $embed);
$addValue = session()['image_view_stock'] ?? [];
$addValue[] = $id;
sessionVar()->put('image_view_stock', $addValue);
if ($image['tags_string'] !== '') {
$handler::setVar('meta_keywords', $image['tags_string']);
}
};

View file

@ -14,7 +14,7 @@ use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\G\Handler;
return function (Handler $handler) {
if (!Login::isAdmin()) {
if (! Login::isAdmin()) {
$handler->issueError(403);
return;
@ -25,18 +25,18 @@ return function (Handler $handler) {
return;
}
if (is_null($handler->request()[0] ?? null) || is_null($handler->request()[1] ?? null)) {
if (null === ($handler->request()[0] ?? null) || null === ($handler->request()[1] ?? null)) {
$handler->issueError(404);
return;
}
$filepath = Import::PATH_JOBS . sprintf('%1$s/%2$s.txt', $handler->request()[0], $handler->request()[1]);
if (!file_exists($filepath)) {
if (! file_exists($filepath)) {
$handler->issueError(404);
return;
}
if (!headers_sent()) {
if (! headers_sent()) {
header('Content-Type: text/plain');
}
readfile($filepath);

View file

@ -15,16 +15,17 @@ use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\decodeID;
use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\G\get_current_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\random_values;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\starts_with;
use function Chevereto\Legacy\G\str_replace_first;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Vars\env;
use function Chevereto\Vars\get;
use function Chevereto\Vars\request;
@ -34,7 +35,9 @@ use function Chevereto\Vars\sessionVar;
return function (Handler $handler) {
parse_str(server()['QUERY_STRING'] ?? '', $querystr);
if (key($querystr) != 'random' && starts_with('route_', Settings::get('homepage_style'))) {
if (key($querystr) !== 'random'
&& starts_with('route_', Settings::get('homepage_style'))
) {
$route = str_replace_first('route_', '', Settings::get('homepage_style'));
$handler->mapRoute($route);
$routeCallable = include PATH_APP_LEGACY_ROUTES . $route . '.php';
@ -46,25 +49,27 @@ return function (Handler $handler) {
if (server()['QUERY_STRING'] ?? false) {
switch (key($querystr)) {
case 'random':
if (!$handler::cond('random_enabled')) {
redirect('/');
headersNoCache();
if (! $handler::cond('random_enabled')) {
redirect('', 302);
}
$tables = DB::getTables();
$db = DB::getInstance();
$db->query('SELECT MIN(image_id) as min, MAX(image_id) as max FROM ' . $tables['images']);
$limit = $db->fetchSingle();
$random_ids = random_values((int) $limit['min'], (int) $limit['max'], 100);
if (count($random_ids) == 1) {
if (count($random_ids) === 1) {
$random_ids[] = $random_ids[0];
}
if ($limit['min'] !== $limit['max']) {
$last_viewed_image = decodeID(session()['last_viewed_image'] ?? '');
if (($key = array_search($last_viewed_image, $random_ids)) !== false) {
$key = array_search($last_viewed_image, $random_ids, true);
if ($key !== false) {
unset($random_ids[$key]);
}
}
$query = 'SELECT image_id FROM ' . $tables['images'] . ' LEFT JOIN ' . $tables['albums'] . ' ON ' . $tables['images'] . '.image_album_id = ' . $tables['albums'] . '.album_id WHERE image_is_approved = 1 AND image_id IN (' . implode(',', $random_ids) . ") AND (album_privacy = 'public' OR album_privacy IS NULL) ";
if (!getSetting('show_nsfw_in_random_mode')) {
if (! getSetting('show_nsfw_in_random_mode')) {
if ($logged_user) {
$query .= 'AND (' . $tables['images'] . '.image_nsfw = 0 OR ' . $tables['images'] . '.image_user_id = ' . $logged_user['id'] . ') ';
} else {
@ -74,24 +79,24 @@ return function (Handler $handler) {
if ($handler::cond('forced_private_mode')) {
$query .= 'AND ' . $tables['images'] . '.image_user_id = ' . $logged_user['id'] . ' ';
}
if (!(bool) env()['CHEVERETO_ENABLE_USERS']) {
if (! (bool) env()['CHEVERETO_ENABLE_USERS']) {
$query .= 'AND ' . $tables['images'] . '.image_user_id=' . (getSetting('website_mode_personal_uid') ?? 0) . ' ';
}
$query .= 'ORDER BY RAND() LIMIT 1';
$db->query($query);
$fetch = $db->fetchSingle();
if (!$fetch) {
if (! $fetch) {
$image = false;
} else {
$imageId = (int) $fetch['image_id'];
$image = Image::getSingle(id: $imageId, pretty: true);
if (!isset($image['file_resource']['chain']['image'])) {
if (! isset($image['file_resource']['chain']['image'])) {
$image = false;
}
}
if (!$image) {
if (! $image) {
if ((session()['random_failure'] ?? 0) > 3) {
redirect();
redirect('', 302);
} else {
sessionVar()->put('random_failure', (session()['random_failure'] ?? 0) + 1);
}
@ -100,21 +105,23 @@ return function (Handler $handler) {
sessionVar()->remove('random_failure');
}
}
redirect(
$image
? $image['path_viewer']
: '?random'
);
$redirectTo = $image
? $image['path_viewer']
: '?random';
redirect($redirectTo, 302);
return;
case 'v':
if (preg_match('{^\w*\.jpg|png|gif$}', get()['v'] ?? '')) {
$explode = array_filter(explode('.', get()['v']));
if (count($explode) == 2) {
$image = DB::get('images', ['name' => $explode[0], 'extension' => $explode[1]], 'AND', [], 1) ?: [];
if (count($explode) === 2) {
$image = DB::get('images', [
'name' => $explode[0],
'extension' => $explode[1],
], 'AND', [], 1) ?: [];
if ($image !== []) {
$image = Image::formatArray($image);
redirect($image['path_viewer']);
redirect($image['path_viewer'], 301);
}
}
}
@ -122,7 +129,6 @@ return function (Handler $handler) {
return;
break;
case 'list':
$handler->setTemplate('index');
@ -138,7 +144,7 @@ return function (Handler $handler) {
break;
}
}
if (Settings::get('homepage_style') == 'split') {
if (Settings::get('homepage_style') === 'split') {
$tabs = [
[
'tools' => true,
@ -147,22 +153,28 @@ return function (Handler $handler) {
'type' => 'image',
],
];
$home_uids = getSetting('homepage_uids');
$home_uid_is_null = ($home_uids == '' || $home_uids == '0');
$home_uid_arr = $home_uid_is_null ? false : explode(',', $home_uids);
$home_uids = getSetting('homepage_uids') ?? '';
$home_uids = trim($home_uids);
$home_uid_is_null = $home_uids === '' || $home_uids === '0';
$home_uid_arr = $home_uid_is_null
? false
: explode(',', $home_uids);
if (is_array($home_uid_arr)) {
$home_uid_arr = array_filter($home_uid_arr);
$home_uid_bind = [];
foreach ($home_uid_arr as $k => $v) {
$home_uid_bind[] = ':user_id_' . $k;
if ($v == 0) {
$home_uid_is_null = true;
if (! is_numeric($v)) {
continue;
}
$home_uid_bind[] = ':user_id_' . $k;
}
$home_uid_bind = implode(',', $home_uid_bind);
}
$doing = is_array($home_uid_arr) ? 'recent' : 'trending';
$explore_semantics = $handler::var('explore_semantics');
$list = $explore_semantics[$doing];
$doing = is_array($home_uid_arr)
? 'recent'
: 'trending';
$explore_discovery = $handler::var('explore_discovery');
$list = $explore_discovery[$doing];
$list['list'] = $doing;
$getParams = Listing::getParams(request());
$listing = new Listing();
@ -187,7 +199,7 @@ return function (Handler $handler) {
$listing->setParamsHidden($listingParams['params_hidden']);
if (is_array($home_uid_arr)) {
foreach ($tabs as $k => &$v) {
if ($v['type'] == 'users') {
if ($v['type'] === 'users') {
unset($tabs[$k]);
}
}
@ -227,26 +239,29 @@ return function (Handler $handler) {
$handler::setVar('user_items_editor', false);
}
$handler::setVar('share_links_array', get_share_links());
$button_color = Settings::get('homepage_cta_color') ?: 'accent';
if (getSetting('homepage_cta_outline')) {
$button_color .= ' outline';
}
$homepage_cta = [
'<a',
getSetting('homepage_cta_fn') == 'cta-upload'
getSetting('homepage_cta_fn') === 'cta-upload'
? (
getSetting('upload_gui') == 'js' && Handler::cond('upload_allowed')
getSetting('upload_gui') === 'js' && Handler::cond('upload_allowed')
? 'data-trigger="anywhere-upload-input"'
: 'href="' . get_base_url('upload') . '"'
)
: 'href="'
. getSetting('homepage_cta_fn_extra')
. '"',
(getSetting('homepage_cta_fn') == 'cta-upload' && !getSetting('guest_uploads'))
(getSetting('homepage_cta_fn') === 'cta-upload' && ! getSetting('guest_uploads'))
? 'data-login-needed="true"'
: '',
'class="btn btn-big accent ' . getSetting('homepage_cta_color') . '">'
'class="btn btn-big ' . $button_color . '">'
. (getSetting('homepage_cta_html')
?: '<i class="fas fa-cloud-upload-alt"></i><span class="btn-text">'
. _s('Start uploading') . '</span>')
. '</a>'
. '</a>',
];
$handler::setVar('homepage_cta', join(' ', $homepage_cta));
$handler::setVar('homepage_cta', implode(' ', $homepage_cta));
};

View file

@ -9,11 +9,11 @@
* file that was distributed with this source code.
*/
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\cheveretoVersionInstalled;
return function (Handler $handler) {
if (Settings::get('chevereto_version_installed') !== null) {
if (cheveretoVersionInstalled() !== '') {
$handler->issueError(404);
return;

File diff suppressed because it is too large Load diff

View file

@ -9,12 +9,12 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\captcha_check;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\RequestLog;
use Chevereto\Legacy\Classes\TwoFactor;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\captcha_check;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\must_use_captcha;
@ -25,7 +25,7 @@ use function Chevereto\Vars\session;
use function Chevereto\Vars\sessionVar;
return function (Handler $handler) {
if (post() !== [] && !$handler::checkAuthToken(request()['auth_token'] ?? '')) {
if (post() !== [] && ! $handler::checkAuthToken(request()['auth_token'] ?? '')) {
$handler->issueError(403);
return;
@ -38,27 +38,30 @@ return function (Handler $handler) {
$logged_user = Login::getUser();
User::statusRedirect($logged_user['status'] ?? null);
if ($logged_user) {
redirect(User::getUrl($logged_user));
redirect(User::getUrl($logged_user), 302);
}
$request_log_insert = ['type' => 'login', 'user_id' => null];
$request_log_insert = [
'type' => 'login',
'user_id' => null,
];
$failed_access_requests = $handler::var('failed_access_requests');
$SAFE_POST = $handler::var('safe_post');
$is_error = false;
$captcha_needed = $handler::cond('captcha_needed');
$error_message = null;
if ($captcha_needed && !empty(post())) {
if ($captcha_needed && ! empty(post())) {
$captcha = captcha_check();
if (!$captcha->is_valid) {
if (! $captcha->is_valid) {
$is_error = true;
$error_message = _s('%s says you are a robot', 'CAPTCHA');
}
}
if (post() !== [] && !$is_error) {
if (post() !== [] && ! $is_error) {
$login_by = filter_var(post()['login-subject'], FILTER_VALIDATE_EMAIL) ? 'email' : 'username';
if (trim(post()['login-subject']) == '' || trim(post()['password']) == '') {
$is_error = true;
}
if (!$is_error) {
if (! $is_error) {
$user = User::getSingle(
trim(post()['login-subject']),
$login_by,
@ -71,9 +74,9 @@ return function (Handler $handler) {
case 'awaiting-confirmation':
Login::setSignup([
'status' => 'awaiting-confirmation',
'email' => $user['email']
'email' => $user['email'],
]);
redirect('account/awaiting-confirmation');
redirect('account/awaiting-confirmation', 302);
break;
case 'banned':
@ -81,7 +84,7 @@ return function (Handler $handler) {
return;
}
$is_login = !(bool) env()['CHEVERETO_ENABLE_USERS'] && getSetting('website_mode_personal_uid') != $user['id']
$is_login = ! (bool) env()['CHEVERETO_ENABLE_USERS'] && getSetting('website_mode_personal_uid') != $user['id']
? false
: Login::checkPassword($user['id'], post()['password']);
}
@ -90,7 +93,7 @@ return function (Handler $handler) {
RequestLog::insert($request_log_insert);
$logged_user = Login::login($user['id']);
Login::insertCookie('cookie', $user['id']);
$redirect_to = User::getUrl(Login::getUser());
$redirect_to = User::getUrl(Login::getUser(), true);
if (TwoFactor::hasFor($user['id'])) {
sessionVar()->put('challenge_two_factor', $user['id']);
$redirect_to = 'account/two-factor';
@ -101,7 +104,7 @@ return function (Handler $handler) {
$redirect_to = 'account/email-needed';
}
redirect($redirect_to);
redirect($redirect_to, 302);
} else {
$is_error = true;
}

View file

@ -14,7 +14,7 @@ use Chevereto\Legacy\G\Handler;
use function Chevereto\Vars\request;
return function (Handler $handler) {
if (!$handler::checkAuthToken(request()['auth_token'] ?? '')) {
if (! $handler::checkAuthToken(request()['auth_token'] ?? '')) {
$handler->issueError(403);
return;

View file

@ -11,24 +11,27 @@
use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use function Chevereto\Legacy\G\get_route_name;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\get_route_name;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Vars\env;
use function Chevereto\Vars\request;
return function (Handler $handler) {
if (!$handler::cond('content_manager')) {
if (! $handler::cond('content_manager')) {
$handler->issueError(404);
return;
}
if (!(bool) env()['CHEVERETO_ENABLE_MODERATION']) {
if (! (bool) env()['CHEVERETO_ENABLE_MODERATION']) {
$handler->issueError(403);
return;
}
$list = ['label' => _s('Moderate'), 'icon' => 'fas fa-check-double'];
$list = [
'label' => _s('Moderate'),
'icon' => 'fas fa-check-double',
];
$list['list'] = get_route_name();
$listingParams = [
'listing' => $list['list'],
@ -40,7 +43,7 @@ return function (Handler $handler) {
'album_min_image_count' => 0,
],
'exclude_criterias' => ['most-viewed', 'most-liked'],
'order' => ['most-oldest', 'most-recent']
'order' => ['most-oldest', 'most-recent'],
];
$getParams = Listing::getParams(request());
$tabs = Listing::getTabs($listingParams, $getParams, true);

View file

@ -12,14 +12,14 @@
use Chevereto\Legacy\Classes\Image;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\User;
use function Chevereto\Legacy\G\get_public_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\json_output;
use function Chevereto\Legacy\G\get_public_url;
use function Chevereto\Legacy\G\json_document_output;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\G\set_status_header;
use function Chevereto\Legacy\G\str_replace_first;
use function Chevereto\Legacy\G\str_replace_last;
use function Chevereto\Legacy\G\xml_output;
use function Chevereto\Legacy\G\xml_document_output;
use function Chevereto\Legacy\getIdFromURLComponent;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Vars\get;
@ -30,32 +30,32 @@ return function (Handler $handler) {
return;
}
$viewer = Image::getUrlViewer('%id');
$viewer = str_replace('/', '\/', $viewer);
$regex = str_replace_last('%id', '(.*)', $viewer);
$viewerImage = Image::getUrlViewer(type: 'image', id_encoded: '%id');
$viewerImage = str_replace('/', '\/', $viewerImage);
$regex = str_replace_last('%id', '(.*)', $viewerImage);
$regex = str_replace_first('https:', 'https?:', $regex);
$regex = str_replace_first('http:', 'https?:', $regex);
if (!preg_match('#^' . $regex . '$#', get()['url'] ?? '', $matches)) {
if (! preg_match('#^' . $regex . '$#', get()['url'] ?? '', $matches)) {
set_status_header(403);
die();
exit();
}
$id = getIdFromURLComponent($matches[1]);
if ($id == 0) {
set_status_header(404);
die();
exit();
}
$image = Image::getSingle(id: $id, pretty: true);
if ($image === []) {
set_status_header(404);
die();
exit();
}
if (!$image['is_approved']) {
if (! $image['is_approved']) {
set_status_header(403);
die();
exit();
}
if (in_array($image['album']['privacy'] ?? '', ['password', 'private', 'custom'])) {
set_status_header(401);
die();
exit();
}
if (($image['user']['is_private'] ?? false) == 1) {
unset($image['user']);
@ -72,7 +72,15 @@ return function (Handler $handler) {
];
switch ($image['type']) {
case 'video':
$data['html'] = '<video src="' . $image['url'] . '" width="' . $image['width'] . '" height="' . $image['height'] . '" controls poster="' . $image['url_frame'] . '"></video>';
$data['html'] = '<video src="'
. $image['url']
. '" width="'
. $image['width']
. '" height="'
. $image['height']
. '" controls poster="'
. $image['url_frame']
. '"></video>';
$data['type'] = 'video';
break;
@ -113,9 +121,16 @@ return function (Handler $handler) {
'thumbnail_height' => $display_height,
]);
}
match (get()['format'] ?? '') {
'xml' => xml_output(['oembed' => $data]),
default => json_output($data),
};
die();
$format = get()['format'] ?? '';
if ($format === 'xml') {
if (isset($data['html'])) {
$data['html'] = htmlentities($data['html']);
}
xml_document_output([
'oembed' => $data,
]);
} else {
json_document_output($data);
}
exit();
};

View file

@ -10,29 +10,29 @@
*/
use Chevereto\Legacy\Classes\Page;
use function Chevereto\Legacy\G\add_ending_slash;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\add_ending_slash;
use function Chevereto\Vars\env;
return function (Handler $handler) {
if (!(bool) env()['CHEVERETO_ENABLE_PAGES']) {
$this->issueError(404);
if (! (bool) env()['CHEVERETO_ENABLE_PAGES']) {
$handler->issueError(404);
return;
}
$request_url_key = implode('/', $handler->request());
$page = Page::getSingle($request_url_key);
if (!$page || !$page['is_active'] || $page['type'] !== 'internal') {
if (! $page || ! $page['is_active'] || $page['type'] !== 'internal') {
$handler->issueError(404);
return;
}
if (!$page['file_path_absolute']) {
if (! $page['file_path_absolute']) {
$handler->issueError(404);
return;
}
if (!file_exists($page['file_path_absolute'])) {
if (! file_exists($page['file_path_absolute'])) {
$handler->issueError(404);
return;
@ -43,7 +43,7 @@ return function (Handler $handler) {
$page_metas = [
'pre_doctitle' => $page['title'],
'meta_description' => htmlspecialchars($page['description'] ?? ''),
'meta_keywords' => htmlspecialchars($page['keywords'] ?? '')
'meta_keywords' => htmlspecialchars($page['keywords'] ?? ''),
];
foreach ($page_metas as $k => $v) {
if ($v === null) {

View file

@ -10,22 +10,27 @@
*/
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\get_global;
use function Chevereto\Legacy\G\get_public_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\include_theme_file;
use function Chevereto\Legacy\G\require_theme_file;
use function Chevereto\Legacy\G\str_replace_first;
use function Chevereto\Legacy\getSetting;
return function (Handler $handler) {
if (!getSetting('enable_plugin_route') && !Login::isAdmin()) {
if (! getSetting('enable_plugin_route') && ! Login::isAdmin()) {
$handler->issueError(404);
return;
}
if ($handler->isRequestLevel(2)) {
$handler->issueError(404);
return;
}
$src = getSetting('sdk_pup_url') ?: get_public_url('sdk/pup.js');
$src = str_replace_first('https:', '', $src);
include_theme_file('snippets/embed');
require_theme_file('snippets/embed');
$embed_share_tpl = get_global('embed_share_tpl');
$embed = [];
foreach ($embed_share_tpl as $vGroup) {
@ -39,7 +44,7 @@ return function (Handler $handler) {
$tagAttrs = [
'async' => '',
'src' => $src,
'data-url' => get_public_url('upload')
'data-url' => get_public_url('upload'),
];
$tagCode = '<script';
foreach ($tagAttrs as $k => $v) {
@ -71,7 +76,7 @@ return function (Handler $handler) {
'Vanilla Forums',
'vBulletin',
'WoltLab',
'XenForo'
'XenForo',
],
'palettes' => [
'default' => ['#ececec', '#000', '#2980b9', '#fff'],
@ -85,7 +90,7 @@ return function (Handler $handler) {
'orange' => ['#d35400', '#fff', '#e67e22', '#fff'],
'red' => ['#c0392b', '#fff', '#e74c3c', '#fff'],
'grey' => ['#ececec', '#000', '#e0e0e0', '#000'],
'black' => ['#333', '#fff', '#666', '#fff']
'black' => ['#333', '#fff', '#666', '#fff'],
],
'button' => '<div class="%cClass"><button id="pup-preview" class="%bClass %bClass--palette-default"><span class="%iClass">%iconSvg</span><span class="%tClass">' . _s('Upload images') . '</span></button></div>',
'baseCss' => '.%cClass{display:inline-block;margin-top:5px;margin-bottom:5px}.%bClass{-webkit-transition:all .2s;-o-transition:all .2s;transition:all .2s;outline:0;border:none;cursor:pointer;border:1px solid rgba(0,0,0,.05);border-radius:.2em;padding:.5em 1em;font-size:12px;font-weight:700;text-shadow:none}.%bClass:hover{border-top-color:rgba(255,255,255,.1);border-right-color:rgba(0,0,0,.05);border-bottom-color:rgba(0,0,0,.1);border-left-color:rgba(0,0,0,.05);}.%iClass{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-ms-flex-item-align:center;align-self:center;position:relative;height:1em;width:1em;margin-right:.25em}.%iClass img,.%iClass svg{width:1em;height:1em;bottom:-.125em;position:absolute}.%iClass svg{fill:currentColor}',
@ -101,7 +106,7 @@ return function (Handler $handler) {
}
$palette_css_rules .= strtr($plugin['paletteCss'], $paletteTable);
}
foreach (['button', 'baseCss'] as $v) {
foreach (['button', 'baseCss'] as $v) {
$plugin[$v] = strtr($plugin[$v], $plugin['table']);
}
$plugin['stylesheet'] = '<style type="text/css" id="chevereto-pup-style">' . $plugin['baseCss'] . $palette_css_rules . '</style>';

View file

@ -9,8 +9,8 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\decryptString;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\decryptString;
use function Chevereto\Legacy\G\is_url_web;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Vars\get;
@ -34,7 +34,7 @@ return function (Handler $handler) {
$url = decryptString($encrypted);
$validations = [
is_url_web($url),
$handler::checkAuthToken(get()['auth_token'] ?? '')
$handler::checkAuthToken(get()['auth_token'] ?? ''),
];
if (in_array(false, $validations)) {
$handler->issueError(404);

View file

@ -13,27 +13,20 @@ use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Search;
use Chevereto\Legacy\Classes\User;
use function Chevereto\Legacy\G\check_value;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Vars\env;
use function Chevereto\Vars\post;
use function Chevereto\Vars\request;
return function (Handler $handler) {
if (!(bool) env()['CHEVERETO_ENABLE_USERS']) {
$handler->issueError(403);
return;
}
if ($handler::cond('search_enabled') == false) {
$handler->issueError(404);
return;
}
if (post() !== [] && !$handler::checkAuthToken(request()['auth_token'] ?? '')) {
if (post() !== [] && ! $handler::checkAuthToken(request()['auth_token'] ?? '')) {
$handler->issueError(403);
return;
@ -43,14 +36,14 @@ return function (Handler $handler) {
return;
} // Allow only 3 levels
if (is_null($handler->request()[0] ?? null)) {
if (null === ($handler->request()[0] ?? null)) {
$handler->issueError(404);
return;
}
$logged_user = Login::getUser();
User::statusRedirect($logged_user['status'] ?? null);
if (!in_array($handler->request()[0], ['images', 'albums', 'users'])) {
if (! in_array($handler->request()[0], ['images', 'albums', 'users'])) {
$handler->issueError(404);
return;
@ -61,8 +54,8 @@ return function (Handler $handler) {
$search->request = request();
$search->requester = Login::getUser();
$search->build();
if (!check_value($search->q)) {
redirect();
if ($search->q === '') {
redirect('', 302);
return;
}
@ -97,7 +90,10 @@ return function (Handler $handler) {
$tabs = Listing::getTabs([
'listing' => 'search',
'basename' => 'search',
'params' => ['q' => $safe_html_search['q'], 'page' => '1'],
'params' => [
'q' => $safe_html_search['q'],
'page' => '1',
],
'params_remove_keys' => ['sort'],
], $getParams);
foreach ($tabs as &$v) {
@ -106,17 +102,23 @@ return function (Handler $handler) {
$meta_description = '';
switch ($search->type) {
case 'images':
$meta_description = _s('%t search results for %s', ['%t' => _n('Image', 'Images', 1)]);
$meta_description = _s('%t search results for %s', [
'%t' => _n('Image', 'Images', 1),
]);
break;
break;
case 'albums':
$meta_description = _s('%t search results for %s', ['%t' => _n('Album', 'Albums', 1)]);
$meta_description = _s('%t search results for %s', [
'%t' => _n('Album', 'Albums', 1),
]);
break;
break;
case 'users':
$meta_description = _s('%t search results for %s', ['%t' => _n('User', 'Users', 1)]);
$meta_description = _s('%t search results for %s', [
'%t' => _n('User', 'Users', 1),
]);
break;
break;
}
$handler::setVar('pre_doctitle', $search->q . ' - ' . _s('Search'));
$handler::setVar('meta_description', sprintf($meta_description, $safe_html_search['q']));
@ -127,4 +129,5 @@ return function (Handler $handler) {
$handler::setVar('user_items_editor', false);
}
$handler::setVar('share_links_array', get_share_links());
$handler::setVar('meta_robots', 'noindex, follow');
};

View file

@ -21,12 +21,12 @@ use Chevereto\Legacy\Classes\RequestLog;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\TwoFactor;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\array_filter_array;
use function Chevereto\Legacy\G\dateinterval;
use function Chevereto\Legacy\G\datetime_diff;
use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\G\get_public_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\is_url_web;
use function Chevereto\Legacy\G\nullify_string;
use function Chevereto\Legacy\G\redirect;
@ -45,27 +45,44 @@ use function Chevereto\Vars\sessionVar;
return function (Handler $handler) {
$POST = post();
if ($POST !== [] and !$handler::checkAuthToken(request()['auth_token'] ?? '')) {
if ($POST !== [] and ! $handler::checkAuthToken(request()['auth_token'] ?? '')) {
$handler->issueError(403);
return;
}
$logged_user = Login::getUser();
if ($logged_user === []) {
redirect('login');
redirect('login', 302);
}
User::statusRedirect($logged_user['status'] ?? null);
$handler->setTemplate('settings');
$is_dashboard_user = $handler::cond('dashboard_user');
if (!$is_dashboard_user) {
if (! $is_dashboard_user) {
RequestLog::getCounts('account-edit', 'fail');
}
$allowed_to_edit = ['name', 'username', 'email', 'avatar_filename', 'website', 'background_filename', 'timezone', 'language', 'image_keep_exif', 'image_expiration', 'newsletter_subscribe', 'bio', 'show_nsfw_listings', 'is_private', 'status'];
$allowed_to_edit = [
'name',
'username',
'email',
'avatar_filename',
'website',
'background_filename',
'timezone',
'language',
'image_keep_exif',
'file_meta_tag_camera_model',
'image_expiration',
'newsletter_subscribe',
'bio',
'show_nsfw_listings',
'is_private',
'status',
];
if ($is_dashboard_user) {
$allowed_to_edit = array_merge($allowed_to_edit, ['is_admin', 'is_manager']);
}
if (!getSetting('enable_expirable_uploads')) {
$key = array_search('image_expiration', $allowed_to_edit);
if (! getSetting('enable_expirable_uploads')) {
$key = array_search('image_expiration', $allowed_to_edit, true);
unset($allowed_to_edit[$key]);
}
$user = $is_dashboard_user
@ -76,16 +93,16 @@ return function (Handler $handler) {
return;
}
$is_owner = $user['id'] == Login::getUser()['id'];
if ($is_dashboard_user && $user['is_content_manager'] && Login::isAdmin() == false) {
$is_owner = $user['id'] === Login::getUser()['id'];
if ($is_dashboard_user && $user['is_content_manager'] && Login::isAdmin() === false) {
$handler->issueError(404);
return;
}
if (in_array('language', $allowed_to_edit)
if (in_array('language', $allowed_to_edit, true)
&& isset($POST['language'])
&& $logged_user['language'] !== $POST['language']
&& $logged_user['id'] == $user['id']
&& $logged_user['id'] === $user['id']
&& array_key_exists($POST['language'], L10n::getEnabledLanguages())
) {
L10n::processTranslation($POST['language']);
@ -112,15 +129,18 @@ return function (Handler $handler) {
];
$default_route = 'account';
$route_homepage = false;
if (getSetting('website_mode') == 'personal' and getSetting('website_mode_personal_routing') !== '/' and $logged_user['id'] == getSetting('website_mode_personal_uid')) {
if (getSetting('website_mode') === 'personal'
&& getSetting('website_mode_personal_routing') !== '/'
&& $logged_user['id'] === getSetting('website_mode_personal_uid')
) {
$route_homepage = true;
}
$is_email_required = (bool) getSetting('require_user_email_confirmation');
if ($handler::cond('content_manager') && $is_owner == false) {
if ($handler::cond('content_manager') && $is_owner === false) {
$is_email_required = false;
}
$providersEnabled = Login::getProviders('enabled');
if ($is_email_required && getSetting('require_user_email_social_signup') == false) {
if ($is_email_required && getSetting('require_user_email_social_signup') === false) {
foreach (array_keys($providersEnabled) as $k) {
if (array_key_exists($k, $user['login'])) {
$is_email_required = false;
@ -131,22 +151,26 @@ return function (Handler $handler) {
}
$doing_level = $is_dashboard_user ? 2 : 0;
$doing = $handler->request()[$doing_level] ?? $default_route;
if (!$user || isset($handler->request()[$doing_level + 1]) || (!is_null($doing) and !array_key_exists($doing, $routes))) {
if (isset($handler->request()[$doing_level + 1])
|| ($doing != null && ! array_key_exists($doing, $routes))
) {
$handler->issueError(404);
return;
}
if ($doing == '') {
if ($doing === '') { // @phpstan-ignore-line
$doing = $default_route;
}
$tabs = [];
foreach ($routes as $route => $label) {
$aux = str_replace('_', '-', $route);
$handler::setCond('settings_' . $aux, $doing == $aux);
$handler::setCond('settings_' . $aux, $doing === $aux);
if ($handler::cond('settings_' . $aux)) {
$handler::setVar('setting', $aux);
}
if ($aux == 'homepage' and !$route_homepage) {
if ($aux === 'homepage' and ! $route_homepage) {
unset($routes[$aux]);
continue;
}
$tabs[$aux] = [
@ -154,18 +178,18 @@ return function (Handler $handler) {
'label' => $label,
'url' => get_base_url(
($is_dashboard_user ? ('dashboard/user/' . $user['id']) : 'settings')
. ($route == $default_route ? '' : '/' . $route)
. ($route === $default_route ? '' : '/' . $route)
),
'current' => $handler::cond('settings_' . $aux)
'current' => $handler::cond('settings_' . $aux),
];
}
if (count($providersEnabled) == 0 || ($is_dashboard_user && Login::isAdmin() == false)) {
if (count($providersEnabled) === 0 || ($is_dashboard_user && Login::isAdmin() === false)) {
unset($routes['connections']);
$tabs = array_filter_array($tabs, ['connections'], 'rest');
}
$handler::setVar('tabs', $tabs);
if (!array_key_exists($doing, $routes)) {
if (! array_key_exists($doing, $routes)) {
$handler->issueError(404);
return;
@ -189,63 +213,85 @@ return function (Handler $handler) {
case 'account':
$checkboxes = ['upload_image_exif', 'newsletter_subscribe', 'show_nsfw_listings', 'is_private'];
foreach ($checkboxes as $k) {
if (!isset($POST[$k])) {
if (! isset($POST[$k])) {
continue;
}
$POST[$k] = in_array($POST[$k], ['On', 1]) ? 1 : 0;
$POST[$k] = in_array($POST[$k], ['On', 1], false)
? 1
: 0;
}
nullify_string($POST['image_expiration']);
$__post = [];
$__safe_post = [];
foreach (['username', 'email'] as $v) {
if (isset($POST[$v])) {
$POST[$v] = $v == 'email' ? trim($POST[$v]) : strtolower(trim($POST[$v]));
$POST[$v] = $v === 'email'
? trim($POST[$v])
: strtolower(trim($POST[$v]));
$__post[$v] = $POST[$v];
$__safe_post[$v] = safe_html($POST[$v]);
}
}
$handler::updateVar('post', $__post);
$handler::updateVar('safe_post', $__safe_post);
if (!User::isValidUsername($POST['username'])) {
if (! User::isValidUsername($POST['username'])) {
$input_errors['username'] = _s('Invalid username');
}
if ($is_email_required and !filter_var($POST['email'], FILTER_VALIDATE_EMAIL)) {
if ($is_email_required and ! filter_var($POST['email'], FILTER_VALIDATE_EMAIL)) {
$input_errors['email'] = _s('Invalid email');
}
if (getSetting('enable_expirable_uploads')) {
if ($POST['image_expiration'] !== null && (!dateinterval($POST['image_expiration']) || !array_key_exists($POST['image_expiration'], Image::getAvailableExpirations()))) {
if (isset($POST['image_expiration'])
&& (
! dateinterval($POST['image_expiration'])
|| ! array_key_exists($POST['image_expiration'], Image::getAvailableExpirations())
)
) {
$input_errors['image_expiration'] = _s('Invalid image expiration: %s', $POST['image_expiration']);
}
}
if (getSetting('language_chooser_enable') && !array_key_exists($POST['language'], get_available_languages())) {
$POST['language'] = getSetting('default_language');
if (getSetting('language_chooser_enable')) {
if (isset($POST['language'])
&& ! array_key_exists($POST['language'], get_available_languages())
) {
$POST['language'] = getSetting('default_language');
}
}
if (!in_array($POST['timezone'], timezone_identifiers_list())) {
if (! in_array($POST['timezone'], timezone_identifiers_list(), false)) {
$POST['timezone'] = date_default_timezone_get();
}
if (is_array($input_errors) && count($input_errors) > 0) {
$is_error = true;
}
if (!$is_error) {
$user_db = DB::get('users', ['username' => $POST['username'], 'email' => $POST['email']], 'OR', []);
if (! $is_error) {
$user_db = DB::get('users', [
'username' => $POST['username'],
'email' => $POST['email'],
], 'OR', []);
if ($user_db) {
foreach ($user_db as $row) {
if ($row['user_id'] == $user['id']) {
if ($row['user_id'] === $user['id']) {
continue;
} // Same guy?
if (!in_array($row['user_status'], ['valid', 'banned'])) { // Don't touch the valid and banned users
if (! in_array($row['user_status'], ['valid', 'banned'], true)) { // Don't touch the valid and banned users
$must_delete_old_user = false;
$confirmation_db = Confirmation::get(['user_id' => $row['user_id']]);
$confirmation_db = Confirmation::get([
'user_id' => $row['user_id'],
]);
if ($confirmation_db !== false) {
if (datetime_diff($confirmation_db['confirmation_date_gmt'], null, 'h') > 48) {
Confirmation::delete(['id' => $confirmation_db['confirmation_id']]);
Confirmation::delete([
'id' => $confirmation_db['confirmation_id'],
]);
$must_delete_old_user = true;
}
} else {
$must_delete_old_user = true;
}
if ($must_delete_old_user) {
DB::delete('users', ['id' => $row['user_id']]);
DB::delete('users', [
'id' => $row['user_id'],
]);
continue;
}
@ -255,7 +301,7 @@ return function (Handler $handler) {
) {
$input_errors['username'] = 'Username already being used';
}
if (!empty($POST['email'])
if (! empty($POST['email'])
&& hash_equals((string) $row['user_email'], (string) $POST['email'])
&& $user['email'] !== $row['user_email']
) {
@ -267,22 +313,25 @@ return function (Handler $handler) {
}
}
}
if (!$is_error
if (! $is_error
&& $is_email_required
&& !empty($POST['email'])
&& !hash_equals(
&& ! empty($POST['email'])
&& ! hash_equals(
(string) ($user['email'] ?? ''),
(string) $POST['email']
)
) {
Confirmation::delete(['type' => 'account-change-email', 'user_id' => $user['id']]);
Confirmation::delete([
'type' => 'account-change-email',
'user_id' => $user['id'],
]);
$hashed_token = generate_hashed_token((int) $user['id']);
Confirmation::insert([
'type' => 'account-change-email',
'user_id' => $user['id'],
'token_hash' => $hashed_token['hash'],
'status' => 'active',
'extra' => $POST['email']
'extra' => $POST['email'],
]);
$email_confirm_link = get_public_url(
'account/change-email-confirm/?token='
@ -292,13 +341,13 @@ return function (Handler $handler) {
global $theme_mail;
$theme_mail = [
'user' => $user,
'link' => $email_confirm_link
'link' => $email_confirm_link,
];
ob_start();
require_once PATH_PUBLIC_LEGACY_THEME . 'mails/account-change-email.php';
$mail_body = ob_get_contents();
ob_end_clean();
$mail['subject'] = _s('Confirmation required at %s', getSettings()['website_name']);
$mail['subject'] = _s('Confirmation required at %s', getSettings('website_name'));
$mail['message'] = $mail_body;
send_mail($POST['email'], $mail['subject'], $mail['message']);
unset($POST['email']);
@ -306,15 +355,15 @@ return function (Handler $handler) {
break;
case 'profile':
if (!preg_match('/^.{1,60}$/', $POST['name'] ?? '')) {
if (! preg_match('/^.{1,60}$/', $POST['name'] ?? '')) {
$input_errors['name'] = _s('Invalid name');
}
if (!empty($POST['website'])) {
if (!is_url_web($POST['website'])) {
if (! empty($POST['website'])) {
if (! is_url_web($POST['website'])) {
$input_errors['website'] = _s('Invalid website');
}
}
if (!$handler::cond('content_manager') && getSetting('akismet')) {
if (! $handler::cond('content_manager') && getSetting('akismet')) {
$akismet = new Akismet();
$isSpam = $akismet->isSpam($POST['bio'], $POST['name'], $user['email'], $POST['website']);
$is_error = $isSpam;
@ -324,18 +373,20 @@ return function (Handler $handler) {
break;
case 'password':
if (!$is_dashboard_user) {
if (! $is_dashboard_user) {
if (isset($POST['current-password'])) {
if (!Login::checkPassword($user['id'], $POST['current-password'])) {
if (! Login::checkPassword($user['id'], $POST['current-password'])) {
$input_errors['current-password'] = _s('Wrong password');
}
if ($POST['current-password'] == ($POST['new-password'] ?? null)) {
if ($POST['current-password'] === ($POST['new-password'] ?? null)) {
$input_errors['new-password'] = _s('Use a new password');
$handler::updateVar('safe_post', ['current-password' => null]);
$handler::updateVar('safe_post', [
'current-password' => null,
]);
}
}
}
if (!preg_match('/' . getSetting('user_password_pattern') . '/', $POST['new-password'] ?? '')) {
if (! preg_match('/' . Settings::USER_PASSWORD_PATTERN . '/', $POST['new-password'] ?? '')) {
$input_errors['new-password'] = _s('Invalid password');
}
if ($POST['new-password'] !== $POST['new-password-confirm']) {
@ -345,11 +396,11 @@ return function (Handler $handler) {
break;
case 'security':
if (!TwoFactor::hasFor($user['id']) && sessionVar()->hasKey('two_factor_secret')) {
if (! TwoFactor::hasFor($user['id']) && sessionVar()->hasKey('two_factor_secret')) {
$twoFactor = new TwoFactor();
$twoFactor = $twoFactor->withSecret(session()['two_factor_secret']);
sessionVar()->remove('two_factor_secret');
if (!$twoFactor->verify($POST['two-factor-code'])) {
if (! $twoFactor->verify($POST['two-factor-code'])) {
$input_errors['two-factor-code'] = _s('Invalid code');
} else {
$twoFactor->insert($user['id']);
@ -359,7 +410,7 @@ return function (Handler $handler) {
break;
case 'homepage':
if (!array_key_exists($doing, $routes)) {
if (! array_key_exists($doing, $routes)) {
$handler->issueError(404);
return;
@ -368,7 +419,7 @@ return function (Handler $handler) {
$editing_array = array_filter_array($POST, $allowed_to_edit, 'exclusion');
$update_settings = [];
foreach ($allowed_to_edit as $k) {
if (!array_key_exists($k, Settings::get()) or Settings::get($k) == $editing_array[$k]) {
if (! array_key_exists($k, Settings::get()) or Settings::get($k) == $editing_array[$k]) {
continue;
}
$update_settings[$k] = $editing_array[$k];
@ -396,14 +447,12 @@ return function (Handler $handler) {
$handler->issueError(404);
return;
break;
}
if (is_array($input_errors) && count($input_errors) > 0) {
$is_error = true;
}
if (!$is_error) {
if (in_array($doing, [null, 'account', 'profile'])) {
if (! $is_error) {
if (in_array($doing, [null, 'account', 'profile'], false)) {
foreach ($POST as $k => $v) {
if (($user[$k] ?? null) !== $v) {
$is_changed = true;
@ -411,10 +460,10 @@ return function (Handler $handler) {
}
if ($is_changed) {
$editing_array = array_filter_array($POST, $allowed_to_edit, 'exclusion');
if (!$is_dashboard_user) {
if (! $is_dashboard_user) {
unset($editing_array['status'], $editing_array['is_admin'], $editing_array['is_manager']);
} else {
if (!in_array($editing_array['status'] ?? null, ['valid', 'banned', 'awaiting-confirmation', 'awaiting-email'])) {
if (! in_array($editing_array['status'] ?? null, ['valid', 'banned', 'awaiting-confirmation', 'awaiting-email'], true)) {
unset($editing_array['status']);
}
if ($logged_user['is_manager']) {
@ -435,13 +484,13 @@ return function (Handler $handler) {
break;
}
if ($user['is_admin'] != $is_admin) {
$handler::setCond('admin', (bool) $is_admin);
$pushAdmin = true;
$editing_array['is_admin'] = $is_admin;
}
if ($user['is_manager'] != $is_manager) {
$editing_array['is_manager'] = $is_manager;
}
if ($POST['role'] == 'admin') {
if ($POST['role'] === 'admin') {
$editing_array['status'] = 'valid';
}
unset($POST['role']);
@ -449,14 +498,25 @@ return function (Handler $handler) {
if (empty($POST['email'])) {
unset($editing_array['email']);
}
if (User::update($user['id'], $editing_array)) {
try {
$userUpdate = User::update($user['id'], $editing_array);
} catch (Throwable $e) {
$userUpdate = false;
$is_error = true;
$is_changed = false;
$error_message = $e->getMessage();
}
if ($userUpdate) {
if (isset($isAdmin) && ($pushAdmin ?? false)) {
$handler::setCond('admin', (bool) $is_admin);
}
$user = array_merge($user, $editing_array);
$handler::updateVar('safe_post', [
'name' => safe_html($user['name']),
]);
}
if (!$is_dashboard_user) {
if (! $is_dashboard_user) {
$logged_user = User::getSingle($user['id']);
} else {
$user = User::getSingle($user['id'], 'id');
@ -464,38 +524,38 @@ return function (Handler $handler) {
$changed_message = _s('Changes have been saved.');
}
}
if ($doing == 'password') {
if ($doing === 'password') {
if (Login::hasPassword($user['id'])) {
Login::deleteCookies('cookie', ['user_id' => $user['id']]);
Login::deleteCookies('session', ['user_id' => $user['id']]);
$is_changed = Login::changePassword((int) $user['id'], $POST['new-password']); // This inserts the session login
$changed_message = _s('Password has been changed');
} else {
$is_changed = Login::addPassword((int) $user['id'], $POST['new-password']);
$changed_message = _s('Password has been created.');
if (!$is_dashboard_user || $logged_user['id'] == $user['id']) {
if (! $is_dashboard_user || $logged_user['id'] === $user['id']) {
$logged_user = Login::login($user['id']);
}
}
if (!$is_dashboard_user) {
if (! $is_dashboard_user) {
Login::insertCookie('cookie', $user['id']);
}
$unsets = ['current-password', 'new-password', 'new-password-confirm'];
foreach ($unsets as $unset) {
$handler::updateVar('safe_post', [$unset => null]);
$handler::updateVar('safe_post', [
$unset => null,
]);
}
}
} else {
if (in_array($doing, ['', 'account']) && !$is_dashboard_user) {
if (in_array($doing, ['', 'account'], false) && ! $is_dashboard_user) {
RequestLog::insert([
'type' => 'account-edit',
'result' => 'fail'
'result' => 'fail',
]);
$error_message = _s('Wrong Username/Email values');
}
}
}
if ($doing == 'connections') {
if ($doing === 'connections') {
$connections = Login::getUserConnections($user['id']);
$has_password = Login::hasPassword($user['id']);
$handler::setCond('has_password', $has_password);
@ -503,7 +563,7 @@ return function (Handler $handler) {
$handler::setVar('providers_enabled', $providersEnabled);
}
if ($doing === 'api') {
if (!ApiKey::has(intval($user['id']))) {
if (! ApiKey::has(intval($user['id']))) {
$apiCreated = ApiKey::insert(intval($user['id']));
$handler::setVar('api_v1_key', $apiCreated);
}
@ -512,7 +572,7 @@ return function (Handler $handler) {
$handler::setVar('api_v1_date_created', $apiPub['date_gmt']);
}
$hasTwoFactor = TwoFactor::hasFor($user['id']);
if ($doing === 'security' && !$hasTwoFactor) {
if ($doing === 'security' && ! $hasTwoFactor) {
$twoFactor = new TwoFactor();
$twoFactorArgs = [
'company' => Settings::get('website_name') . ' ' . env()['CHEVERETO_HOSTNAME'],
@ -542,36 +602,38 @@ return function (Handler $handler) {
$handler::setVar('user', $is_dashboard_user ? $user : $logged_user);
$handler::setVar('safe_html_user', safe_html($handler::var('user')));
if ($doing === 'account') {
$bannedIp = IpBan::getSingle(['ip' => $handler::var('user')['registration_ip']]);
$bannedIp = IpBan::getSingle([
'ip' => $handler::var('user')['registration_ip'],
]);
$user_list_values = [
[
'label' => _s('Username'),
'content' => '<a href="' . $handler::var('user')['url'] . '" class="btn btn-small default"><span class="icon fas fa-user-circle"></span><span class="margin-left-5">' . $handler::var('user')['username'] . '</span></a>' . (
$handler::cond('dashboard_user')
? (' <a class="btn btn-small default" data-confirm="' . _s("Do you really want to delete this %s?", _n('user', 'users', 1)) . ' ' . _s("This can't be undone.") . '" data-submit-fn="CHV.fn.user.delete.submit" data-ajax-deferred="CHV.fn.complete_resource_delete" data-ajax-url="' . get_base_url("json") . '"><span class="icon fas fa-trash-alt"></span><span class="phone-hide margin-left-5">' . _s('Delete user') . '</span></a>')
? (' <a class="btn btn-small default" data-confirm="' . _s('Do you really want to delete this %s?', _n('user', 'users', 1)) . ' ' . _s("This can't be undone.") . '" data-submit-fn="CHV.fn.user.delete.submit" data-ajax-deferred="CHV.fn.complete_resource_delete" data-ajax-url="' . get_base_url('json') . '"><span class="icon fas fa-trash-alt"></span><span class="phone-hide margin-left-5">' . _s('Delete user') . '</span></a>')
: ''
)
),
],
[
'label' => _s('User ID'),
'content' => $handler::var('user')['id'] . ' (' . $handler::var('user')['id_encoded'] . ')'
'content' => $handler::var('user')['id'] . ' (' . $handler::var('user')['id_encoded'] . ')',
],
[
'label' => _s('Images'),
'content' => $handler::var('user')['image_count']
'content' => $handler::var('user')['image_count'],
],
[
'label' => _n('Album', 'Albums', 20),
'content' => $handler::var('user')['album_count']
'content' => $handler::var('user')['album_count'],
],
[
'label' => _s('Register date'),
'content' => $handler::var('user')['date']
'content' => $handler::var('user')['date'],
],
[
'label' => '<span class="visibility-hidden">' . _s('Register date') . '</span>',
'content' => $handler::var('user')['date_gmt'] . ' (GMT)'
]
'content' => $handler::var('user')['date_gmt'] . ' (UTC)',
],
];
if ($handler::var('user')['registration_ip']) {
$user_list_values[] = getIpButtonsArray($bannedIp, $handler::var('user')['registration_ip']);

View file

@ -9,24 +9,24 @@
* file that was distributed with this source code.
*/
use function Chevereto\Legacy\captcha_check;
use Chevereto\Legacy\Classes\Confirmation;
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\L10n;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\RequestLog;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\StopForumSpam;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\captcha_check;
use function Chevereto\Legacy\G\datetime_diff;
use function Chevereto\Legacy\G\get_client_ip;
use function Chevereto\Legacy\G\get_public_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\generate_hashed_token;
use function Chevereto\Legacy\get_email_body_str;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\getSettings;
use function Chevereto\Legacy\must_use_captcha;
use function Chevereto\Legacy\send_mail;
use function Chevereto\Vars\post;
@ -35,12 +35,12 @@ use function Chevereto\Vars\request;
return function (Handler $handler) {
$POST = post();
$SAFE_POST = $handler::var('safe_post');
if (!getSetting('enable_signups')) {
if (! getSetting('enable_signups')) {
$handler->issueError(404);
return;
}
if ($POST !== [] && !$handler::checkAuthToken(request()['auth_token'] ?? '')) {
if ($POST !== [] && ! $handler::checkAuthToken(request()['auth_token'] ?? '')) {
$handler->issueError(403);
return;
@ -52,12 +52,12 @@ return function (Handler $handler) {
} // Allow only 1 level
if (Login::hasSignup()) {
$SAFE_POST['email'] = Login::getSignup()['email'];
redirect('account/awaiting-confirmation');
redirect('account/awaiting-confirmation', 302);
}
$logged_user = Login::getUser();
User::statusRedirect($logged_user['status'] ?? null);
if ($logged_user) {
redirect(User::getUrl($logged_user));
redirect(User::getUrl($logged_user), 302);
}
$failed_access_requests = $handler::var('failed_access_requests');
$is_error = false;
@ -66,13 +66,13 @@ return function (Handler $handler) {
$captcha_needed = $handler::cond('captcha_needed');
if ($captcha_needed && $POST !== []) {
$captcha = captcha_check();
if (!$captcha->is_valid) {
if (! $captcha->is_valid) {
$is_error = true;
$error_message = _s('%s says you are a robot', 'CAPTCHA');
}
}
$handler::setCond('show_resend_activation', false);
if ($POST !== [] && !$is_error && !Login::hasSignup()) {
if ($POST !== [] && ! $is_error && ! Login::hasSignup()) {
$__post = [];
$__safe_post = [];
foreach (['username', 'email'] as $v) {
@ -84,22 +84,22 @@ return function (Handler $handler) {
}
$handler::updateVar('post', $__post);
$handler::updateVar('safe_post', $__safe_post);
if (!filter_var($POST['email'], FILTER_VALIDATE_EMAIL)) {
if (! filter_var($POST['email'] ?? '', FILTER_VALIDATE_EMAIL)) {
$input_errors['email'] = _s('Invalid email');
}
if (!User::isValidUsername($POST['username'])) {
if (! User::isValidUsername($POST['username'] ?? '')) {
$input_errors['username'] = _s('Invalid username');
}
if (!preg_match('/' . getSetting('user_password_pattern') . '/', $POST['password'] ?? '')) {
if (! preg_match('/' . Settings::USER_PASSWORD_PATTERN . '/', $POST['password'] ?? '')) {
$input_errors['password'] = _s('Invalid password');
}
if (!filter_var($POST['email'], FILTER_VALIDATE_EMAIL)) {
if (! filter_var($POST['email'] ?? '', FILTER_VALIDATE_EMAIL)) {
$input_errors['email'] = _s('Invalid email');
}
if ($POST['signup-accept-terms-policies'] != 1) {
if (($POST['signup-accept-terms-policies'] ?? 0) != 1) {
$input_errors['signup-accept-terms-policies'] = _s('You must agree to the terms and privacy policy');
}
if (getSetting('user_minimum_age') > 0 && !isset($POST['minimum-age-signup'])) {
if (getSetting('user_minimum_age') > 0 && ! isset($POST['minimum-age-signup'])) {
$input_errors['minimum-age-signup'] = _s('You must be at least %s years old to use this website.', getSetting('user_minimum_age'));
}
if (count($input_errors) > 0) {
@ -111,26 +111,35 @@ return function (Handler $handler) {
$error_message = _s('Spam detected');
}
}
if (!$is_error) {
$user_db = DB::get('users', ['username' => $POST['username'], 'email' => $POST['email']], 'OR', []);
if (! $is_error) {
$user_db = DB::get('users', [
'username' => $POST['username'],
'email' => $POST['email'],
], 'OR', []);
if ($user_db !== []) {
$is_error = true;
$show_resend_activation = false;
foreach ($user_db as $row) {
if (!in_array($row['user_status'], ['valid', 'banned'])) { // Don't touch the valid and banned users
if (! in_array($row['user_status'], ['valid', 'banned'])) { // Don't touch the valid and banned users
$must_delete_old_user = false;
$confirmation_db = Confirmation::get(['user_id' => $row['user_id']]);
$confirmation_db = Confirmation::get([
'user_id' => $row['user_id'],
]);
if ($confirmation_db !== false) {
// 24x2 = 48 tic tac tic tac
if (datetime_diff($confirmation_db['confirmation_date_gmt'], null, 'h') > 48) {
Confirmation::delete(['id' => $confirmation_db['confirmation_id']]);
Confirmation::delete([
'id' => $confirmation_db['confirmation_id'],
]);
$must_delete_old_user = true;
}
} else {
$must_delete_old_user = true;
}
if ($must_delete_old_user) {
DB::delete('users', ['id' => $row['user_id']]);
DB::delete('users', [
'id' => $row['user_id'],
]);
continue;
}
@ -141,7 +150,7 @@ return function (Handler $handler) {
if (hash_equals((string) $row['user_email'], (string) $POST['email'])) {
$input_errors['email'] = _s('Email already being used');
}
if (!$show_resend_activation) {
if (! $show_resend_activation) {
$show_resend_activation = $row['user_status'] == 'awaiting-confirmation';
}
}
@ -152,7 +161,7 @@ return function (Handler $handler) {
'email' => $POST['email'],
'timezone' => getSetting('default_timezone'),
'language' => L10n::getLocale(),
'status' => getSetting('require_user_email_confirmation') ? 'awaiting-confirmation' : 'valid'
'status' => getSetting('require_user_email_confirmation') ? 'awaiting-confirmation' : 'valid',
];
try {
@ -166,14 +175,14 @@ return function (Handler $handler) {
$is_error = true;
$error_message = $e->getMessage();
} else {
throw new Exception($e, $e->getCode(), $e);
throw new Exception($e, (int) $e->getCode(), $e);
}
}
if (!$is_error) {
if (! $is_error) {
if ($inserted_user !== 0) {
$insert_password = Login::addPassword($inserted_user, $POST['password']);
}
if (!$inserted_user || !$insert_password) {
if (! $inserted_user || ! $insert_password) {
throw new Exception("Can't insert user to the DB", 400);
} elseif (getSetting('require_user_email_confirmation')) {
$hashed_token = generate_hashed_token($inserted_user);
@ -181,7 +190,7 @@ return function (Handler $handler) {
'user_id' => $inserted_user,
'type' => 'account-activate',
'token_hash' => $hashed_token['hash'],
'status' => 'active'
'status' => 'active',
]);
$activation_link = get_public_url(
'account/activate/?token='
@ -190,9 +199,12 @@ return function (Handler $handler) {
global $theme_mail;
$theme_mail = [
'user' => $user_array,
'link' => $activation_link
'link' => $activation_link,
];
$mail['subject'] = _s('Confirmation required at %s', getSettings()['website_name']);
$mail['subject'] = _s(
'Confirmation required at %s',
getSetting('website_name')
);
$mail['message'] = get_email_body_str('mails/account-confirm');
send_mail($POST['email'], $mail['subject'], $mail['message']);
} else {
@ -210,20 +222,20 @@ return function (Handler $handler) {
send_mail($logged_user['email'], $mail['subject'], $mail['message']);
} catch (Exception) {
} // Silence
redirect($user['url']);
redirect($user['url'], 302);
}
Login::setSignup([
'status' => 'awaiting-confirmation',
'email' => $SAFE_POST['email']
'email' => $SAFE_POST['email'],
]);
redirect('account/awaiting-confirmation');
redirect('account/awaiting-confirmation', 302);
}
}
}
if ($is_error) {
RequestLog::insert([
'type' => 'signup',
'result' => 'fail'
'result' => 'fail',
]);
$error_message ??= _s('Check the errors in the form to continue.');
if ((getSetting('captcha') ?? false) && must_use_captcha($failed_access_requests['day'] + 1)) {

View file

@ -0,0 +1,46 @@
<?php
/*
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Chevereto\Legacy\Classes\Tag;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\json_output;
use function Chevereto\Vars\get;
use function Chevereto\Vars\request;
return function (Handler $handler) {
header('Content-type: application/json; charset=UTF-8');
if (! $handler::checkAuthToken(request()['auth_token'] ?? '')) {
json_output(401, [
'error' => [
'error_msg' => _s('Request denied'),
],
]);
}
if ($handler->isRequestLevel(2)) {
json_output(404);
return;
}
$q = get()['q'] ?? '';
$q = trim($q);
if ($q === ''
|| str_contains($q, ',')
) {
json_output(400);
return;
}
$array = [
'items' => Tag::autocomplete($q),
];
json_output(200, $array);
};

160
app/legacy/routes/tag.php Normal file
View file

@ -0,0 +1,160 @@
<?php
/*
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Tag;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\encodeID;
use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\G\get_route_name;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Vars\env;
use function Chevereto\Vars\get;
use function Chevereto\Vars\request;
use function Chevereto\Vars\server;
use function Chevereto\Vars\session;
use function Chevereto\Vars\sessionVar;
return function (Handler $handler) {
if (! $handler::cond('explore_enabled')) {
$handler->issueError(404);
return;
}
$tagKey = $handler->request()[0] ?? '';
$tagKey = rawurldecode($tagKey);
if ($tagKey === '') {
$handler->issueError(404);
return;
}
$tagsPathAsIs = explode(',', $tagKey);
$tagsParsed = Tag::parse($tagKey);
if ($tagsParsed === []) {
$handler->issueError(404);
return;
}
if (count($tagsParsed) !== count($tagsPathAsIs)) {
$handler->issueError(404);
return;
}
if (! in_array(get()['match'] ?? '', ['', 'all'])) {
$handler->issueError(400);
return;
}
if (env()['CHEVERETO_MAX_TAGS_PER_LISTING'] !== '0'
&& count($tagsParsed) > (int) env()['CHEVERETO_MAX_TAGS_PER_LISTING']
) {
$handler->issueError(403);
return;
}
$tags = Tag::get($tagKey, 'id', 'name', 'description');
if (count($tags) !== count($tagsPathAsIs)) {
$handler->issueError(404);
return;
}
if (! $tags) {
$handler->issueError(404);
return;
}
if (! isset(session()['tag_view_stock'])) {
sessionVar()->put('tag_view_stock', []);
}
$sessionValue = session()['tag_view_stock'];
$sumViews = [];
foreach ($tags as &$tag) {
$tag = array_merge($tag, Tag::row($tag['name']));
if (! in_array($tag['id'], session()['tag_view_stock'])) {
$sessionValue[] = $tag['id'];
$sumViews[] = $tag['id'];
}
}
$tags_names = array_column($tags, 'name');
$tag_string = implode(', ', $tags_names);
$tag_string_no_spaces = implode(',', $tags_names);
$tags_id = array_column($tags, 'id');
$tags_id_encoded = array_map(function ($id): string {
return encodeID($id);
}, $tags_id);
$tags_key_display = $tag_string;
$tags_key_url = $tag_string_no_spaces;
$tags_basename = get_route_name() . '/' . rawurlencode($tags_key_url);
$canonical = get_base_url($tags_basename, true);
$queryString = server()['QUERY_STRING'] ?? '';
$tags_descriptions = array_column($tags, 'description');
$tags_descriptions = array_filter($tags_descriptions);
if ($queryString !== '') {
parse_str($queryString, $parse);
unset($parse['lang']);
$queryString = http_build_query($parse ?? []);
if ($queryString !== '') {
$canonical .= '/?' . $queryString;
}
}
$handler::setVar('canonical', $canonical);
$handler::setVar('pre_doctitle', $tags_key_display);
$getParams = Listing::getParams(request());
$tabs = Listing::getTabs([
'listing' => 'images',
'basename' => $tags_basename,
'params_hidden' => [
'tag_id' => implode(',', $tags_id_encoded),
'tag_match' => get()['match'] ?? 'any',
'hide_banned' => 1,
],
], $getParams);
$handler::setVar('list_params', $getParams);
$listing = new Listing();
$listing->setType('images');
if (isset($getParams['reverse'])) {
$listing->setReverse($getParams['reverse']);
}
if (isset($getParams['seek'])) {
$listing->setSeek($getParams['seek']);
}
$listing->setOffset($getParams['offset']);
$listing->setLimit($getParams['limit']); // how many results?
$listing->setSortType($getParams['sort'][0]); // date | size | views
$listing->setSortOrder($getParams['sort'][1]); // asc | desc
$listing->setTagsIds(...$tags_id);
$listing->setTagsString($tag_string_no_spaces);
$listing->setTagsMatch(get()['match'] ?? 'any');
$listing->setRequester(Login::getUser());
$listing->exec();
$tags_descriptions = implode(' — ', $tags_descriptions);
$handler::setVar('tags_descriptions', $tags_descriptions);
$handler::setVar('meta_description', $tags_descriptions);
$handler::setVar('tags', $tags);
$handler::setVar('tabs', $tabs);
$handler::setVar('listing', $listing);
$handler::setVar('share_links_array', get_share_links());
if ($sumViews !== []) {
$tagsTable = DB::getTable('tags');
$tagsIds = implode(',', $sumViews);
$sumViewsSql = <<<MySQL
UPDATE {$tagsTable} SET `tag_views` = `tag_views` + 1 WHERE `tag_id` IN ({$tagsIds});
MySQL;
$db = DB::getInstance();
$db->query($sumViewsSql);
$db->exec();
sessionVar()->put('tag_view_stock', $sessionValue);
}
$handler::setVar('meta_keywords', $tag_string);
};

View file

@ -10,19 +10,19 @@
*/
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\cheveretoVersionInstalled;
use function Chevereto\Vars\env;
return function (Handler $handler) {
if (!(bool) env()['CHEVERETO_ENABLE_UPDATE_HTTP']
|| Settings::get('chevereto_version_installed') === null
if (! (bool) env()['CHEVERETO_ENABLE_UPDATE_HTTP']
|| cheveretoVersionInstalled() === ''
) {
$handler->issueError(404);
return;
}
if (!Login::isAdmin()) {
if (! Login::isAdmin()) {
$handler->issueError(403);
return;

View file

@ -13,22 +13,21 @@ use Chevereto\Legacy\Classes\Album;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Settings;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\decodeID;
use function Chevereto\Legacy\G\get_base_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Vars\get;
return function (Handler $handler) {
if (!$handler::cond('upload_allowed')) {
if (! $handler::cond('upload_allowed')) {
if (Login::isLoggedUser()) {
$handler->issueError(403);
return;
} else {
redirect('login');
}
redirect('login', 302);
}
$logged_user = Login::getUser();
User::statusRedirect($logged_user['status'] ?? null);
@ -37,7 +36,7 @@ return function (Handler $handler) {
$toAlbumId = decodeID(get()['toAlbum']);
$album = Album::getSingle(id: $toAlbumId, requester: $logged_user);
$is_owner = isset($album['user']['id']) && $album['user']['id'] == $logged_user['id'];
if (!$is_owner) {
if (! $is_owner) {
$album = [];
}
}

View file

@ -0,0 +1,85 @@
<?php
/*
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\User;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\getSettings;
use function Chevereto\Legacy\json_output;
use function Chevereto\Vars\env;
use function Chevereto\Vars\get;
use function Chevereto\Vars\request;
return function (Handler $handler) {
header('Content-type: application/json; charset=UTF-8');
json_output(404);
if (! $handler::checkAuthToken(request()['auth_token'] ?? '')) {
json_output(401, [
'error' => [
'error_msg' => _s('Request denied'),
],
]);
}
if ($handler->isRequestLevel(2)) {
json_output(404);
return;
}
$q = get()['q'] ?? '';
$q = trim($q);
if ($q === ''
|| str_contains($q, ',')
) {
json_output(400);
return;
}
$logged_user = Login::getUser();
if ($logged_user === []) {
json_output(401);
return;
}
$user = User::getSingle($q, 'username', false);
$user = DB::formatRow($user);
$user['url'] = User::getUrl($user);
if (! $user
|| ($user['status'] ?? '') !== 'valid'
&& ($logged_user === [] || ! $handler::cond('content_manager'))
) {
json_output(404);
return;
}
$is_owner = false;
if (isset($user['id'], $logged_user['id'])) {
$is_owner = $user['id'] === $logged_user['id'];
}
if (! $is_owner
&& ! $handler::cond('content_manager')
&& (bool) $user['is_private']
) {
json_output(404);
return;
}
if (! (bool) env()['CHEVERETO_ENABLE_USERS']
&& $user['id'] !== getSettings('website_mode_personal_uid')
) {
json_output(404);
return;
}
$array = User::getAlbums($user);
json_output(200, $array);
};

View file

@ -9,27 +9,33 @@
* file that was distributed with this source code.
*/
use Chevere\String\ModifyString;
use Chevereto\Legacy\Classes\DB;
use Chevereto\Legacy\Classes\Follow;
use Chevereto\Legacy\Classes\Listing;
use Chevereto\Legacy\Classes\Login;
use Chevereto\Legacy\Classes\Tag;
use Chevereto\Legacy\Classes\User;
use function Chevereto\Legacy\G\get_current_url;
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\encodeID;
use function Chevereto\Legacy\G\get_current_url;
use function Chevereto\Legacy\G\get_public_url;
use function Chevereto\Legacy\G\redirect;
use function Chevereto\Legacy\G\safe_html;
use function Chevereto\Legacy\G\str_replace_first;
use function Chevereto\Legacy\get_share_links;
use function Chevereto\Legacy\getSetting;
use function Chevereto\Legacy\redirectIfRouting;
use function Chevereto\Legacy\headersNoCache;
use function Chevereto\Legacy\virtualRouteHandleRedirect;
use function Chevereto\Vars\env;
use function Chevereto\Vars\get;
use function Chevereto\Vars\request;
use function Chevereto\Vars\server;
return function (Handler $handler) {
$currentUrl = get_current_url();
redirectIfRouting('user', $handler->requestArray()[0]);
virtualRouteHandleRedirect('user', $handler->requestArray()[0]);
$userIndex = (getSetting('root_route') === 'user'
|| getSetting('website_mode') == 'personal')
|| getSetting('website_mode') === 'personal')
? 0
: 1;
if ($handler->isRequestLevel($handler::cond('mapped_route') ? 4 : 5)) {
@ -41,14 +47,14 @@ return function (Handler $handler) {
? $handler->requestArray()
: $handler->request();
$userMapPaths = ['search', 'following', 'followers'];
$userMapPaths[] = getSetting('user_profile_view') == 'files'
$userMapPaths[] = getSetting('user_profile_view') === 'files'
? 'albums'
: 'files';
if (getSetting('website_mode') == 'personal'
&& getSetting('website_mode_personal_routing') == '/'
if (getSetting('website_mode') === 'personal'
&& getSetting('website_mode_personal_routing') === '/'
&& $request_handle[0] !== '/'
) {
if (!in_array($request_handle[0], $userMapPaths)) {
if (! in_array($request_handle[0], $userMapPaths, true)) {
$handler->issueError(404);
return;
@ -56,12 +62,14 @@ return function (Handler $handler) {
$personal_mode_user = User::getSingle(getSetting('website_mode_personal_uid'));
if ($personal_mode_user !== []) {
$request_handle = [
0 => $personal_mode_user['username'],
1 => $request_handle[0]
];
0 => $personal_mode_user['username'],
1 => $request_handle[0],
];
}
}
if ($request_handle[0] === getSetting('route_user') && getSetting('root_route') !== 'user') {
if (($request_handle[0] ?? false) === getSetting('route_user')
&& getSetting('root_route') !== 'user'
) {
array_shift($request_handle);
}
$username = $request_handle[0] ?? null;
@ -71,7 +79,7 @@ return function (Handler $handler) {
if (isset($mapped_args['id'])) {
$id = $handler::mappedArgs()['id'];
}
if (!isset($username) && isset($id)) {
if (! isset($username) && isset($id)) {
$handler->issueError(404);
return;
@ -83,31 +91,32 @@ return function (Handler $handler) {
?? User::getSingle(${$userHandle}, $userHandle);
$is_owner = false;
if (isset($user['id'], $logged_user['id'])) {
$is_owner = $user['id'] == $logged_user['id'];
$is_owner = $user['id'] === $logged_user['id'];
}
if (!$user
if (! $user
|| ($user['status'] ?? '') !== 'valid'
&& ($logged_user === [] || !$handler::cond('content_manager'))) {
&& ($logged_user === [] || ! $handler::cond('content_manager'))) {
$handler->issueError(404);
return;
}
if (!$is_owner && !$handler::cond('content_manager') && (bool) $user['is_private']) {
if (! $is_owner && ! $handler::cond('content_manager') && (bool) $user['is_private']) {
$handler->issueError(404);
return;
}
if (!(bool) env()['CHEVERETO_ENABLE_USERS'] && $user['id'] != getSetting('website_mode_personal_uid')) {
if (! (bool) env()['CHEVERETO_ENABLE_USERS'] && $user['id'] !== getSetting('website_mode_personal_uid')) {
$handler->issueError(404);
return;
}
if (getSetting('website_mode') == 'personal' && getSetting('website_mode_personal_routing') === '/') {
if (getSetting('website_mode') === 'personal'
&& getSetting('website_mode_personal_routing') === '/'
) {
if (str_starts_with($currentUrl, '/' . $user['username'])) {
$redirectTo = (new ModifyString($currentUrl))
->withReplaceFirst('/' . $user['username'], '')
->__toString();
redirect($redirectTo);
$redirectTo = str_replace_first('/' . $user['username'], '', $currentUrl);
headersNoCache();
redirect($redirectTo, 302);
}
}
$pre_doctitle = '';
@ -118,16 +127,18 @@ return function (Handler $handler) {
$user_views = [
'files' => [
'title' => _s(
"%t by %s",
'%t by %s',
[
'%t' => _n('File', 'Files', 20)
'%t' => _n('File', 'Files', 20),
]
),
'title_short' => _s("Images"),
'title_short' => _s('Files'),
],
'albums' => [
'title' => _s("%t by %s", ['%t' => _n('Album', 'Albums', 20)]),
'title_short' => _s("Albums"),
'title' => _s('%t by %s', [
'%t' => _n('Album', 'Albums', 20),
]),
'title_short' => _s('Albums'),
],
'search' => [
'title' => _s('Search'),
@ -135,7 +146,7 @@ return function (Handler $handler) {
],
];
foreach (array_keys($user_views) as $k) {
$user_routes[] = $k == $userHome
$user_routes[] = $k === $userHome
? $username
: $k;
}
@ -143,18 +154,22 @@ return function (Handler $handler) {
// images: admin, albums, search
if (getSetting('enable_likes')) {
$user_views['liked'] = [
'title' => _s("Liked by %s"),
'title_short' => _s("Liked"),
'title' => _s('Liked by %s'),
'title_short' => _s('Liked'),
];
$user_routes[] = 'liked';
}
if (getSetting('enable_followers')) {
$user_views['following'] = [
'title' => _s("%t followed by %s", ['%t' => _n('User', 'Users', 20)]),
'title' => _s('%t followed by %s', [
'%t' => _n('User', 'Users', 20),
]),
'title_short' => _s('Following'),
];
$user_views['followers'] = [
'title' => _s("%t following %s", ['%t' => _n('User', 'Users', 20)]),
'title' => _s('%t following %s', [
'%t' => _n('User', 'Users', 20),
]),
'title_short' => _s('Followers'),
];
$user_routes[] = 'following';
@ -164,33 +179,37 @@ return function (Handler $handler) {
$user_views[$k]['current'] = false;
}
if (isset($request_handle[1])) {
if ($request_handle[1] == 'search') {
if (!$handler::cond('search_enabled')) {
if ($request_handle[1] === 'search') {
if (! $handler::cond('search_enabled')) {
$handler->issueError(404);
return;
}
if (!(request()['q'] ?? false)) {
redirect($user['url']);
if (! (request()['q'] ?? false)) {
redirect($user['url'], 302);
}
$user['search'] = [
'type' => empty(request()['list']) ? 'images' : request()['list'],
'q' => request()['q'],
'd' => strlen(request()['q']) >= 25 ? (substr(request()['q'], 0, 22) . '...') : request()['q']
'd' => strlen(request()['q']) >= 25 ? (substr(request()['q'], 0, 22) . '...') : request()['q'],
];
}
if ($request_handle[1] !== server()['QUERY_STRING'] && !in_array($request_handle[1], $user_routes)) {
if ($request_handle[1] !== server()['QUERY_STRING']
&& ! in_array($request_handle[1], $user_routes, true)
) {
$handler->issueError(404);
return;
}
if ($request_handle[1] == 'search') {
if (!server()['QUERY_STRING']) {
if ($request_handle[1] === 'search') {
if (! server()['QUERY_STRING']) {
$handler->issueError(404);
return;
}
if (!empty(request()['list']) && !in_array(request()['list'], ['images', 'albums', 'users'])) {
if (! empty(request()['list'])
&& ! in_array(request()['list'], ['images', 'albums', 'users'], true)
) {
$handler->issueError(404);
return;
@ -204,64 +223,93 @@ return function (Handler $handler) {
}
$user['followed'] = false;
$show_follow_button = false;
if (getSetting('website_mode') != 'personal') {
if (getSetting('website_mode') !== 'personal') {
$user['followed'] = false;
$show_follow_button = false;
if ($logged_user !== []) {
$user['followed'] = ($user['id'] == $logged_user['id'])
$user['followed'] = ($user['id'] === $logged_user['id'])
? false
: Follow::doesFollow(
(int) $logged_user['id'],
(int) $user['id']
);
$show_follow_button = $user['id'] != $logged_user['id']
$show_follow_button = $user['id'] !== $logged_user['id']
&& $logged_user['is_private'] == 0;
}
}
$handler::setCond('show_follow_button', $show_follow_button);
$base_user_url = $user['url'];
$type = $userHome;
$current_view = $type;
$current_view = $userHome;
$tools = false;
foreach ($user_views as $k => $v) {
$handler::setCond('user_' . $k, (bool) $v['current']);
if ($v['current']) {
$current_view = $k;
if ($current_view !== $userHome) {
$base_user_url .= "/$k";
$base_user_url .= "/{$k}";
}
}
}
$type = match ($current_view) {
'files' => 'images',
default => $current_view
};
$currentKey = 0;
$safe_html_user = safe_html($user);
$sub_tabs = [];
if ($current_view === 'liked') {
$type = (get()['list'] ?? '') === 'albums'
? 'albums'
: 'images';
$sub_tabs = [
[
'icon' => 'fas fa-photo-film',
'label' => _s('Files'),
'url' => $base_user_url . '/?list=images',
'current' => $type === 'images',
],
[
'icon' => 'fas fa-images',
'label' => _s('Albums'),
'url' => $base_user_url . '/?list=albums',
'current' => $type === 'albums',
],
];
}
if ($type === 'files') {
$type = 'images';
}
switch ($current_view) {
case 'files':
case 'liked':
$type = "images";
$tools = $is_owner || $handler::cond('content_manager');
if ($current_view == 'liked') {
$tools_available = $handler::cond('content_manager') ? ['delete', 'category', 'flag'] : ['embed'];
if ($current_view === 'liked') {
$tools_available = $handler::cond('content_manager')
? ['delete', 'category', 'flag']
: ['embed'];
}
break;
break;
case 'following':
case 'followers':
$type = 'users';
$tools = false;
$params_hidden = [$current_view . '_user_id' => $user['id_encoded']];
$params_hidden = [
$current_view . '_user_id' => $user['id_encoded'],
];
$params_remove_keys = ['list'];
break;
break;
case 'albums':
$icon = 'fas fa-images';
$type = "albums";
$type = 'albums';
$tools = true;
break;
break;
case 'search':
$icon = 'fas fa-search';
$type = $user['search']['type'];
$currentKey = (isset(request()['list']) && request()['list'] == 'images') || !isset(request()['list'])
$currentKey = (isset(request()['list']) && request()['list'] === 'images') || ! isset(request()['list'])
? 0 : 1;
$tabs = [
[
@ -277,7 +325,7 @@ return function (Handler $handler) {
'label' => _n('Album', 'Albums', 20),
'id' => 'list-user-albums',
'current' => $currentKey === 1,
]
],
];
foreach ($tabs as $k => $v) {
$params = [
@ -290,7 +338,7 @@ return function (Handler $handler) {
$tabs[$k]['url'] = $base_user_url . '/?' . $tabs[$k]['params'];
}
break;
break;
}
$icon = [
'files' => 'fas fa-photo-film',
@ -303,34 +351,91 @@ return function (Handler $handler) {
if ($user_views['albums']['current']) {
$params_hidden['list'] = 'albums';
}
$params_hidden[$current_view == 'liked' ? 'like_user_id' : 'userid'] = $user['id_encoded'];
$params_hidden[$current_view === 'liked' ? 'like_user_id' : 'userid'] = $user['id_encoded'];
$params_hidden['from'] = 'user';
if (!isset($tabs)) {
$tags_id = [];
$tags_active = [];
$isDisplayUsedTags = in_array($current_view, ['files', 'albums']);
if (in_array($type, ['images', 'albums'])
&& $isDisplayUsedTags
&& (get()['tag'] ?? '') !== ''
) {
$tags = Tag::get(get()['tag']);
if ($tags !== []) {
$tags_active = array_column($tags, 'name');
$tags_id = array_column($tags, 'id');
$tags_id_encoded = array_map(function ($id): string {
return encodeID($id);
}, $tags_id);
$params_hidden['tag_id'] = implode(',', $tags_id_encoded);
}
}
$tag_string = implode(', ', $tags_active);
$tag_string_no_spaces = implode(',', $tags_active);
$tagsTable = DB::getTable('tags');
$tagsUsersTable = DB::getTable('tags_users');
$tagsAlbumsTable = DB::getTable('tags_albums');
$userId = (int) $user['id'];
$tags_display = [];
if ($isDisplayUsedTags) {
$tagsSql = <<<MySQL
SELECT DISTINCT t.tag_name name, tu.tag_user_count count
FROM `{$tagsTable}` t
INNER JOIN `{$tagsUsersTable}` tu
ON tu.tag_user_tag_id=t.tag_id
AND tu.tag_user_user_id={$userId}
AND tu.tag_user_count > 0
ORDER BY `tag_user_count` DESC, `tag_name` ASC
LIMIT 20;
MySQL;
if ($type === 'albums') {
$tagsSql = <<<MySQL
SELECT DISTINCT t.tag_name name, ta.tag_album_count count
FROM `{$tagsTable}` t
INNER JOIN `{$tagsAlbumsTable}` ta
ON ta.tag_album_tag_id=t.tag_id
AND ta.tag_album_user_id={$userId}
AND ta.tag_album_count > 0
ORDER BY `tag_album_count` DESC, `tag_name` ASC
LIMIT 20;
MySQL;
}
$tags_display = DB::queryFetchAll($tagsSql);
foreach ($tags_display as &$tag) {
$base_tag_filter_url = $base_user_url . '/?tag=';
$tag = Tag::row($tag['name'], $base_tag_filter_url . '%s');
Tag::addUrlFilters($tag, $base_user_url, $tags_active);
}
}
if (! isset($tabs)) {
$tabs = Listing::getTabs([
'listing' => $type,
'basename' => $base_user_url,
'tools' => $tools,
'tools_available' => $tools_available ?? null,
'tools_available' => $tools_available ?? [],
'params_hidden' => $params_hidden,
'params_remove_keys' => $params_remove_keys ?? null,
'tag' => rawurldecode($tag_string_no_spaces),
], [], true);
$currentKey = $tabs['currentKey'];
$tabs = $tabs['tabs'];
}
foreach ($tabs as $k => &$v) {
if (!array_key_exists('params_hidden', $tabs)) {
if (! array_key_exists('params_hidden', $tabs)) {
$tabs[$k]['params_hidden'] = http_build_query($params_hidden);
}
$v['disabled'] = $user[($user_views['files']['current'] ? 'image' : 'album') . '_count'] == 0 ? !$v['current'] : false;
$v['disabled'] = $user[($user_views['files']['current'] ? 'image' : 'album') . '_count'] === 0 ? ! $v['current'] : false;
}
$listing = new Listing();
if ($user["image_count"] > 0
|| $user["album_count"] > 0
|| in_array($current_view, ['liked', 'following', 'followers'])) {
if ($user['image_count'] > 0
|| $user['album_count'] > 0
|| in_array($current_view, ['liked', 'following', 'followers'], true)) {
$getParams = Listing::getParams(request());
Listing::fillCurrentTabPeekSeek($tabs, $currentKey, $getParams);
$handler::setVar('list_params', $getParams);
if ($getParams['sort'][0] == 'likes' && !getSetting('enable_likes')) {
if ($getParams['sort'][0] === 'likes' && ! getSetting('enable_likes')) {
$handler->issueError(404);
return;
@ -339,31 +444,39 @@ return function (Handler $handler) {
switch ($current_view) {
case 'liked':
$where = 'WHERE like_user_id=:user_id';
$tpl = 'liked';
$tpl = 'liked/' . match ($type) {
'images' => 'image',
'albums' => 'album',
};
break;
break;
case 'following':
$where = 'WHERE follow_user_id=:user_id';
break;
break;
case 'followers':
$where = 'WHERE follow_followed_user_id=:user_id';
break;
break;
default:
$where = $type == 'images'
$where = $type === 'images'
? 'WHERE image_user_id=:user_id'
: 'WHERE album_user_id=:user_id AND album_parent_id IS NULL';
: 'WHERE album_user_id=:user_id';
// if ($type === 'albums' && $tags_active === []) {
// $where .= ' AND album_parent_id IS NULL';
// }
break;
break;
}
$output_tpl = 'user/' . $tpl;
if ($user_views['search']['current']) {
$type = $user["search"]["type"];
$where = $user["search"]["type"] == "images" ? "WHERE image_user_id=:user_id AND MATCH(image_name, image_title, image_description, image_original_filename) AGAINST (:q)" : "WHERE album_user_id=:user_id AND MATCH(album_name, album_description) AGAINST (:q)";
$type = $user['search']['type'];
$where = $user['search']['type'] === 'images'
? 'WHERE image_user_id=:user_id AND MATCH(image_name, image_title, image_description, image_original_filename) AGAINST (:q)'
: 'WHERE album_user_id=:user_id AND MATCH(album_name, album_description) AGAINST (:q)';
}
$show_user_items_editor = Login::isLoggedUser();
if ($type == 'albums') {
if ($type === 'albums') {
$show_user_items_editor = false;
}
@ -381,15 +494,17 @@ return function (Handler $handler) {
$listing->setSortType($getParams['sort'][0]); // date | size | views | likes
$listing->setSortOrder($getParams['sort'][1]); // asc | desc
$listing->setWhere($where);
$listing->setOwner((int) $user["id"]);
$listing->setOwner((int) $user['id']);
$listing->setTagsIds(...$tags_id);
$listing->setTagsString($tag_string_no_spaces);
$listing->setRequester(Login::getUser());
if ($is_owner || $handler::cond('content_manager')) {
if ($type == 'users') {
if ($type === 'users') {
$listing->setTools(false);
$show_user_items_editor = false;
} elseif ($current_view == 'liked') {
} elseif ($current_view === 'liked') {
$listing->setTools(
$user['id'] == $logged_user['id']
$user['id'] === $logged_user['id']
? ['embed']
: false
);
@ -397,8 +512,9 @@ return function (Handler $handler) {
$listing->setTools(true);
}
}
$listing->bind(":user_id", $user["id"]);
if ($user_views['search']['current'] && !empty($user['search']['q'])) {
$listing->bind(':user_id', $user['id']);
if ($user_views['search']['current'] && ! empty($user['search']['q'])) {
$handler::setVar('meta_robots', 'noindex, follow');
$listing->bind(':q', $user['search']['q']);
}
$listing->setOutputTpl($output_tpl);
@ -413,7 +529,7 @@ return function (Handler $handler) {
$pre_doctitle .= $user['search']['d'] . ' - ';
}
$pre_doctitle .= sprintf($user_views[$current_view]['title'], $user['name_html']);
if (getSetting('website_mode') == 'community' || $user['id'] !== getSetting('website_mode_personal_uid')) {
if (getSetting('website_mode') === 'community' || $user['id'] !== getSetting('website_mode_personal_uid')) {
$pre_doctitle .= ' (' . $user['username'] . ')';
}
$handler::setVar('pre_doctitle', $pre_doctitle);
@ -433,12 +549,24 @@ return function (Handler $handler) {
} else {
$meta_description = _s('%n (%u) on %w');
}
$handler::setVar('meta_description', strtr($meta_description, ['%n' => $user['name'], '%u' => $user['username'], '%w' => getSetting('website_name')]));
$handler::setVar('meta_description', strtr($meta_description, [
'%n' => $user['name'],
'%u' => $user['username'],
'%w' => getSetting('website_name'),
]));
if ($handler::cond('content_manager') || $is_owner) {
$handler::setVar('user_items_editor', [
"user_albums" => User::getAlbums($user),
"type" => $user_views['albums']['current'] ? "albums" : "images"
'user_albums' => User::getAlbums($user),
'type' => $user_views['albums']['current'] ? 'albums' : 'images',
]);
}
$handler::setVar('share_links_array', get_share_links());
$handler::setVar('tags_display', $tags_display);
$handler::setVar('tags_active', $tags_active);
if ($tag_string !== '') {
$handler::setVar('meta_keywords', $tag_string);
}
$canonical = get_public_url($tabs[$currentKey]['url']);
$handler::setVar('canonical', $canonical);
$handler::setVar('sub_tabs', $sub_tabs);
};

View file

@ -0,0 +1,22 @@
<?php
/*
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\virtualRouteHandleRedirect;
return function (Handler $handler) {
$route = 'image';
virtualRouteHandleRedirect($route, $handler->requestArray()[0], 'video');
$handler->mapRoute($route);
$routeCallable = include PATH_APP_LEGACY_ROUTES . $route . '.php';
return $routeCallable($handler);
};

View file

@ -0,0 +1,38 @@
<?php
/*
* This file is part of Chevereto.
*
* (c) Rodolfo Berrios <rodolfo@chevereto.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Chevereto\Legacy\G\Handler;
use function Chevereto\Legacy\G\get_base_url;
use function Chevereto\Legacy\getSetting;
return function (Handler $handler) {
if ($handler->isRequestLevel(2)) {
$handler->issueError(404);
return;
}
header('Content-Type: application/json');
$manifest = [
'name' => getSetting('website_doctitle'),
'short_name' => getSetting('website_name'),
'description' => getSetting('website_description'),
// 'lang' => 'en-US',
// 'dir' => 'ltr',
'display' => 'standalone',
'scope' => get_base_url(''),
'id' => get_base_url('?_pwa=1'),
'start_url' => get_base_url('?_pwa=1'),
// 'background_color' => '#FFFFFF',
// 'theme_color' => '#FFFFFF',
];
echo json_encode($manifest, JSON_PRETTY_PRINT);
exit();
};

View file

@ -4,6 +4,7 @@ parameters:
- phpstan-bootstrap.php
paths:
- bin
- legacy
- src/Legacy
- src/Encryption
- ../content/

View file

@ -7,16 +7,16 @@ CREATE TABLE `%table_prefix%albums` (
`album_date_gmt` datetime NOT NULL,
`album_creation_ip` varchar(255) NOT NULL,
`album_privacy` enum('public','password','private','private_but_link','custom') DEFAULT 'public',
`album_privacy_extra` mediumtext,
`album_password` mediumtext,
`album_privacy_extra` text,
`album_password` text,
`album_image_count` bigint(32) NOT NULL DEFAULT '0',
`album_description` mediumtext,
`album_description` text,
`album_likes` bigint(32) NOT NULL DEFAULT '0',
`album_views` bigint(32) NOT NULL DEFAULT '0',
`album_cover_id` bigint(32) DEFAULT NULL,
`album_parent_id` bigint(32) DEFAULT NULL,
`album_cta_enable` tinyint(1) NOT NULL DEFAULT '0',
`album_cta` longtext,
`album_cta` text,
PRIMARY KEY (`album_id`),
KEY `album_name` (`album_name`),
KEY `album_user_id` (`album_user_id`),

View file

@ -4,7 +4,7 @@ CREATE TABLE `%table_prefix%api_keys` (
`api_key_user_id` bigint(32) DEFAULT NULL,
`api_key_name` varchar(100) DEFAULT NULL,
`api_key_date_gmt` datetime NOT NULL,
`api_key_hash` mediumtext NOT NULL,
`api_key_hash` text NOT NULL,
PRIMARY KEY (`api_key_id`),
KEY `api_key_user_id` (`api_key_user_id`),
KEY `api_key_name` (`api_key_name`),

View file

@ -8,7 +8,6 @@ CREATE TABLE `%table_prefix%assets` (
`asset_blob` blob,
PRIMARY KEY (`asset_id`),
UNIQUE KEY `key` (`asset_key`(191)) USING BTREE,
KEY `md5` (`asset_md5`),
KEY `filename` (`asset_filename`),
KEY `file_path` (`asset_file_path`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -2,8 +2,8 @@ DROP TABLE IF EXISTS `%table_prefix%categories`;
CREATE TABLE `%table_prefix%categories` (
`category_id` bigint(32) NOT NULL AUTO_INCREMENT,
`category_name` varchar(32) NOT NULL,
`category_url_key` varchar(32) NOT NULL,
`category_description` mediumtext,
`category_url_key` varchar(32) COLLATE utf8mb4_bin NOT NULL,
`category_description` text,
PRIMARY KEY (`category_id`),
UNIQUE KEY `url_key` (`category_url_key`) USING BTREE
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -8,5 +8,8 @@ CREATE TABLE `%table_prefix%confirmations` (
`confirmation_token_hash` varchar(255) NOT NULL,
`confirmation_status` enum('active','valid','invalid') NOT NULL,
`confirmation_extra` mediumtext,
PRIMARY KEY (`confirmation_id`)
PRIMARY KEY (`confirmation_id`),
KEY `confirmation_user` (`confirmation_user_id`),
KEY `confirmation_user_type` (`confirmation_user_id`, `confirmation_type`),
KEY `confirmation_user_type_status_date` (`confirmation_user_id`, `confirmation_type`, `confirmation_status`, `confirmation_date_gmt`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

View file

@ -9,7 +9,7 @@ CREATE TABLE `%table_prefix%images` (
`image_date` datetime NOT NULL,
`image_date_gmt` datetime NOT NULL,
`image_title` varchar(100) DEFAULT NULL,
`image_description` mediumtext,
`image_description` text,
`image_nsfw` tinyint(1) NOT NULL DEFAULT '0',
`image_user_id` bigint(32) DEFAULT NULL,
`image_album_id` bigint(32) DEFAULT NULL,
@ -20,7 +20,7 @@ CREATE TABLE `%table_prefix%images` (
`image_md5` varchar(32) NOT NULL,
`image_source_md5` varchar(32) DEFAULT NULL,
`image_original_filename` varchar(255) NOT NULL,
`image_original_exifdata` longtext,
`image_original_exifdata` mediumtext,
`image_views` bigint(32) NOT NULL DEFAULT '0',
`image_category_id` bigint(32) DEFAULT NULL,
`image_chain` tinyint(3) NOT NULL,
@ -34,10 +34,10 @@ CREATE TABLE `%table_prefix%images` (
`image_is_360` tinyint(1) NOT NULL DEFAULT '0',
`image_duration` int(11) NOT NULL DEFAULT '0',
`image_type` tinyint(3) UNSIGNED as (case
when `image_extension` in ('pdf', 'doc', 'md') then 4
when `image_extension` in ('mp3', 'm4a', 'wav') then 3
when `image_extension` in ('mp4', 'webm') then 2
when `image_extension` in ('jpg', 'jpeg', 'gif', 'png', 'webp') then 1
when `image_extension` in ('pdf','doc','md') then 4
when `image_extension` in ('mp3','m4a','wav') then 3
when `image_extension` in ('mp4','webm','mov') then 2
when `image_extension` in ('avif','jpg','jpeg','gif','png','webp') then 1
else 0 end) stored,
PRIMARY KEY (`image_id`),
KEY `image_name` (`image_name`),

View file

@ -4,7 +4,7 @@ CREATE TABLE `%table_prefix%importing` (
`importing_import_id` bigint(32) NOT NULL,
`importing_path` varchar(4096) NOT NULL,
`importing_content_type` enum('user','album','image') NOT NULL,
`importing_content_id` bigint(32) NOT NULL DEFAULT '0',
`importing_content_id` bigint(32) DEFAULT NULL,
PRIMARY KEY (`importing_id`),
UNIQUE KEY `importing_path` (`importing_path`(191))
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -5,8 +5,8 @@ CREATE TABLE `%table_prefix%login_connections` (
`login_connection_provider_id` bigint(32) NOT NULL,
`login_connection_date_gmt` datetime NOT NULL,
`login_connection_resource_id` varchar(255) NOT NULL,
`login_connection_resource_name` mediumtext,
`login_connection_token` mediumtext NOT NULL COMMENT 'Ciphertext',
`login_connection_resource_name` text,
`login_connection_token` text NOT NULL COMMENT 'Ciphertext',
PRIMARY KEY (`login_connection_id`),
UNIQUE KEY `login_connection_unique` (`login_connection_user_id`,`login_connection_provider_id`),
KEY `login_connection_user_id` (`login_connection_user_id`),

View file

@ -5,8 +5,8 @@ CREATE TABLE `%table_prefix%login_cookies` (
`login_cookie_connection_id` bigint(32) DEFAULT 0,
`login_cookie_date_gmt` datetime NOT NULL,
`login_cookie_ip` varchar(255) DEFAULT NULL,
`login_cookie_user_agent` mediumtext NOT NULL,
`login_cookie_hash` mediumtext NOT NULL,
`login_cookie_user_agent` text NOT NULL,
`login_cookie_hash` text NOT NULL,
PRIMARY KEY (`login_cookie_id`),
UNIQUE KEY `login_cookie_unique` (`login_cookie_user_id`,`login_cookie_connection_id`,`login_cookie_date_gmt`),
KEY `login_cookie_user_id_date_gmt` (`login_cookie_user_id`, `login_cookie_date_gmt`),

View file

@ -3,7 +3,7 @@ CREATE TABLE `%table_prefix%login_passwords` (
`login_password_id` bigint(32) NOT NULL AUTO_INCREMENT,
`login_password_user_id` bigint(32) NOT NULL,
`login_password_date_gmt` datetime NOT NULL,
`login_password_hash` mediumtext NOT NULL,
`login_password_hash` text NOT NULL,
PRIMARY KEY (`login_password_id`),
UNIQUE KEY `login_password_user_id` (`login_password_user_id`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -3,8 +3,8 @@ CREATE TABLE `%table_prefix%login_providers` (
`login_provider_id` bigint(32) NOT NULL AUTO_INCREMENT,
`login_provider_name` varchar(255) DEFAULT NULL,
`login_provider_label` varchar(255) DEFAULT NULL,
`login_provider_key_id` mediumtext DEFAULT NULL,
`login_provider_key_secret` mediumtext DEFAULT NULL,
`login_provider_key_id` text DEFAULT NULL,
`login_provider_key_secret` text DEFAULT NULL,
`login_provider_is_enabled` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`login_provider_id`),
UNIQUE KEY `login_provider_name` (`login_provider_name`(191)),

View file

@ -4,15 +4,15 @@ CREATE TABLE `%table_prefix%logins` (
`login_user_id` bigint(32) NOT NULL,
`login_type` enum('password','session','cookie','facebook','twitter','google','vk','cookie_facebook','cookie_twitter','cookie_google','cookie_vk') NOT NULL,
`login_ip` varchar(255) DEFAULT NULL,
`login_hostname` mediumtext,
`login_hostname` text,
`login_date` datetime NOT NULL,
`login_date_gmt` datetime NOT NULL,
`login_resource_id` varchar(255) DEFAULT NULL,
`login_resource_name` mediumtext,
`login_resource_avatar` mediumtext,
`login_resource_url` mediumtext,
`login_secret` mediumtext DEFAULT NULL COMMENT 'The secret part',
`login_token_hash` mediumtext COMMENT 'Hashed complement to secret if needed',
`login_resource_name` text,
`login_resource_avatar` text,
`login_resource_url` text,
`login_secret` text DEFAULT NULL COMMENT 'The secret part',
`login_token_hash` text COMMENT 'Hashed complement to secret if needed',
PRIMARY KEY (`login_id`),
KEY `login_user_id` (`login_user_id`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -4,18 +4,18 @@ CREATE TABLE `%table_prefix%pages` (
`page_url_key` varchar(32) DEFAULT NULL,
`page_type` enum('internal','link') NOT NULL DEFAULT 'internal',
`page_file_path` varchar(255) DEFAULT NULL,
`page_link_url` mediumtext,
`page_link_url` text,
`page_icon` varchar(255) DEFAULT NULL,
`page_title` varchar(255) NOT NULL,
`page_description` mediumtext,
`page_keywords` mediumtext,
`page_description` text,
`page_keywords` text,
`page_is_active` tinyint(1) NOT NULL DEFAULT '1',
`page_is_link_visible` tinyint(1) NOT NULL DEFAULT '1',
`page_attr_target` enum('_self','_blank') DEFAULT '_self',
`page_attr_rel` varchar(255) DEFAULT NULL,
`page_sort_display` int(11) DEFAULT NULL,
`page_internal` varchar(255) DEFAULT NULL,
`page_code` mediumtext,
`page_code` text,
PRIMARY KEY (`page_id`),
UNIQUE KEY `page_internal` (`page_internal`(191)),
KEY `page_url_key` (`page_url_key`),

View file

@ -3,7 +3,7 @@ CREATE TABLE `%table_prefix%queues` (
`queue_id` bigint(32) NOT NULL AUTO_INCREMENT,
`queue_type` enum('storage-delete') NOT NULL,
`queue_date_gmt` datetime NOT NULL,
`queue_args` longtext NOT NULL,
`queue_args` text NOT NULL,
`queue_join` bigint(32) NOT NULL,
`queue_attempts` varchar(255) DEFAULT '0',
`queue_status` enum('pending','failed') NOT NULL DEFAULT 'pending',

View file

@ -2,9 +2,9 @@ DROP TABLE IF EXISTS `%table_prefix%settings`;
CREATE TABLE `%table_prefix%settings` (
`setting_id` int(11) NOT NULL AUTO_INCREMENT,
`setting_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`setting_value` mediumtext,
`setting_default` mediumtext,
`setting_value` text,
`setting_default` text,
`setting_typeset` enum('string','bool') DEFAULT 'string',
PRIMARY KEY (`setting_id`),
KEY `setting_name` (`setting_name`)
UNIQUE KEY `setting_name` (`setting_name`) USING BTREE
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -3,16 +3,19 @@ CREATE TABLE `%table_prefix%stats` (
`stat_id` bigint(32) NOT NULL AUTO_INCREMENT,
`stat_type` enum('total','date') NOT NULL,
`stat_date_gmt` date DEFAULT NULL,
`stat_users` bigint(32) NOT NULL DEFAULT '0',
`stat_images` bigint(32) NOT NULL DEFAULT '0',
`stat_albums` bigint(32) NOT NULL DEFAULT '0',
`stat_image_views` bigint(32) NOT NULL DEFAULT '0',
`stat_album_views` bigint(32) NOT NULL DEFAULT '0',
`stat_image_likes` bigint(32) NOT NULL DEFAULT '0',
`stat_album_likes` bigint(32) NOT NULL DEFAULT '0',
`stat_disk_used` bigint(32) NOT NULL DEFAULT '0',
`stat_users` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_images` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_albums` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_tags` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_cron_runs` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_cron_time` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_image_views` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_album_views` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_image_likes` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_album_likes` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
`stat_disk_used` bigint(32) UNSIGNED NOT NULL DEFAULT '0',
PRIMARY KEY (`stat_id`),
UNIQUE KEY `stat_date_gmt` (`stat_date_gmt`) USING BTREE,
KEY `stat_type` (`stat_type`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
INSERT INTO `%table_prefix%stats` VALUES ('1', 'total', NULL, '0', '0', '0', '0', '0', '0', '0', '0');
INSERT INTO `%table_prefix%stats` (stat_id, stat_type) VALUES (1, 'total');

View file

@ -10,14 +10,17 @@ CREATE TABLE `%table_prefix%storages` (
`storage_server` varchar(255) DEFAULT NULL,
`storage_account_id` varchar(255) DEFAULT NULL,
`storage_account_name` varchar(255) DEFAULT NULL,
`storage_key` mediumtext,
`storage_secret` mediumtext,
`storage_key` text,
`storage_secret` text,
`storage_is_https` tinyint(1) NOT NULL DEFAULT '0',
`storage_is_active` tinyint(1) NOT NULL DEFAULT '0',
`storage_capacity` bigint(32) DEFAULT NULL,
`storage_space_used` bigint(32) DEFAULT '0',
`storage_type_chain` tinyint(3) NOT NULL DEFAULT '1',
`storage_use_path_style_endpoint` tinyint(1) NOT NULL DEFAULT '0',
`storage_deleted_at` DATETIME NULL DEFAULT NULL,
PRIMARY KEY (`storage_id`),
KEY `storage_api_id` (`storage_api_id`),
KEY `storage_is_active` (`storage_is_active`)
KEY `storage_is_active` (`storage_is_active`),
KEY `storage_deleted_at` (`storage_deleted_at`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -0,0 +1,19 @@
DROP TABLE IF EXISTS `%table_prefix%tags`;
CREATE TABLE `%table_prefix%tags` (
`tag_id` bigint(32) NOT NULL AUTO_INCREMENT,
`tag_name` varchar(32) COLLATE utf8mb4_bin NOT NULL,
`tag_description` text,
`tag_user_id` bigint(32) NOT NULL,
`tag_date_gmt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`tag_files` bigint(32) NOT NULL DEFAULT 0,
`tag_views` bigint(32) NOT NULL DEFAULT 0,
PRIMARY KEY (`tag_id`),
UNIQUE KEY `tag_name` (`tag_name`) USING BTREE,
KEY `tag_user_id` (`tag_user_id`),
KEY `tag_date_gmt` (`tag_date_gmt`),
KEY `tag_files` (`tag_files`),
KEY `tag_views` (`tag_views`),
KEY `tag_user_id_date_gmt` (`tag_user_id`,`tag_date_gmt`),
KEY `tag_user_id_files` (`tag_user_id`,`tag_files`),
KEY `tag_user_id_views` (`tag_user_id`,`tag_views`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

View file

@ -0,0 +1,14 @@
DROP TABLE IF EXISTS `%table_prefix%tags_albums`;
CREATE TABLE `%table_prefix%tags_albums` (
`tag_album_tag_id` bigint(32) NOT NULL,
`tag_album_album_id` bigint(32) NOT NULL,
`tag_album_user_id` bigint(32) NOT NULL,
`tag_album_count` int(11) NOT NULL DEFAULT 0,
`tag_album_last_used_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tag_album_tag_id) REFERENCES `%table_prefix%tags` (tag_id) ON DELETE CASCADE,
FOREIGN KEY (tag_album_album_id) REFERENCES `%table_prefix%albums` (album_id) ON DELETE CASCADE,
FOREIGN KEY (tag_album_user_id) REFERENCES `%table_prefix%users` (user_id) ON DELETE CASCADE,
UNIQUE INDEX `tag_album_UNIQUE` (`tag_album_tag_id` ASC, `tag_album_album_id` ASC, `tag_album_user_id` ASC),
KEY `tag_album_count` (`tag_album_count`),
KEY `tag_album_last_used_datetime` (`tag_album_last_used_datetime`)
) ENGINE=%table_engine% DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

Some files were not shown because too many files have changed in this diff Show more