Added URL registry attributes.

This commit is contained in:
flash 2023-09-10 00:04:53 +00:00
parent 7db43a2acd
commit 3e49f6e503
15 changed files with 262 additions and 213 deletions

View file

@ -125,6 +125,8 @@ CSRF::init(
($authInfo->isLoggedIn() ? $sessionInfo->getToken() : $_SERVER['REMOTE_ADDR']) ($authInfo->isLoggedIn() ? $sessionInfo->getToken() : $_SERVER['REMOTE_ADDR'])
); );
// order for these two currently matters i think: it shouldn't.
$router = $msz->createRouting();
$msz->startTemplating(); $msz->startTemplating();
$mszRequestPath = $request->getPath(); $mszRequestPath = $request->getPath();
@ -144,5 +146,4 @@ if(!empty($mszLegacyPath) && str_starts_with($mszLegacyPath, $mszLegacyPathPrefi
} }
} }
$msz->startRouter(); $router->dispatch($request);
$msz->dispatchRouter($request);

View file

@ -15,6 +15,7 @@ use Misuzu\Feeds\Feed;
use Misuzu\Feeds\FeedItem; use Misuzu\Feeds\FeedItem;
use Misuzu\Feeds\AtomFeedSerializer; use Misuzu\Feeds\AtomFeedSerializer;
use Misuzu\Feeds\RssFeedSerializer; use Misuzu\Feeds\RssFeedSerializer;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry; use Misuzu\URLs\URLRegistry;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;
@ -34,6 +35,7 @@ final class ChangelogRoutes extends RouteHandler {
} }
#[Route('GET', '/changelog')] #[Route('GET', '/changelog')]
#[URLInfo('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>'])]
public function getIndex($response, $request) { public function getIndex($response, $request) {
$filterDate = (string)$request->getParam('date'); $filterDate = (string)$request->getParam('date');
$filterUser = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT); $filterUser = (string)$request->getParam('user', FILTER_SANITIZE_NUMBER_INT);
@ -98,6 +100,8 @@ final class ChangelogRoutes extends RouteHandler {
} }
#[Route('GET', '/changelog/change/:id')] #[Route('GET', '/changelog/change/:id')]
#[URLInfo('changelog-change', '/changelog/change/<change>')]
#[URLInfo('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments')]
public function getChange($response, $request, string $changeId) { public function getChange($response, $request, string $changeId) {
try { try {
$changeInfo = $this->changelog->getChange($changeId); $changeInfo = $this->changelog->getChange($changeId);
@ -145,12 +149,14 @@ final class ChangelogRoutes extends RouteHandler {
} }
#[Route('GET', '/changelog.rss')] #[Route('GET', '/changelog.rss')]
#[URLInfo('changelog-feed-rss', '/changelog.rss')]
public function getFeedRSS($response) { public function getFeedRSS($response) {
$response->setContentType('application/rss+xml; charset=utf-8'); $response->setContentType('application/rss+xml; charset=utf-8');
return (new RssFeedSerializer)->serializeFeed($this->createFeed('rss')); return (new RssFeedSerializer)->serializeFeed($this->createFeed('rss'));
} }
#[Route('GET', '/changelog.atom')] #[Route('GET', '/changelog.atom')]
#[URLInfo('changelog-feed-atom', '/changelog.atom')]
public function getFeedAtom($response) { public function getFeedAtom($response) {
$response->setContentType('application/atom+xml; charset=utf-8'); $response->setContentType('application/atom+xml; charset=utf-8');
return (new AtomFeedSerializer)->serializeFeed($this->createFeed('atom')); return (new AtomFeedSerializer)->serializeFeed($this->createFeed('atom'));

View file

@ -16,6 +16,7 @@ use Misuzu\Comments\Comments;
use Misuzu\Config\IConfig; use Misuzu\Config\IConfig;
use Misuzu\Counters\Counters; use Misuzu\Counters\Counters;
use Misuzu\News\News; use Misuzu\News\News;
use Misuzu\URLs\URLInfo;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;
class HomeRoutes extends RouteHandler { class HomeRoutes extends RouteHandler {
@ -154,6 +155,7 @@ class HomeRoutes extends RouteHandler {
} }
#[Route('GET', '/')] #[Route('GET', '/')]
#[URLInfo('index', '/')]
public function getIndex(...$args) { public function getIndex(...$args) {
return $this->authInfo->isLoggedIn() return $this->authInfo->isLoggedIn()
? $this->getHome(...$args) ? $this->getHome(...$args)

View file

@ -5,6 +5,7 @@ use Index\Routing\Route;
use Index\Routing\RouteHandler; use Index\Routing\RouteHandler;
use Misuzu\Template; use Misuzu\Template;
use Misuzu\Parsers\Parser; use Misuzu\Parsers\Parser;
use Misuzu\URLs\URLInfo;
class InfoRoutes extends RouteHandler { class InfoRoutes extends RouteHandler {
private const DOCS_PATH = MSZ_ROOT . '/docs'; private const DOCS_PATH = MSZ_ROOT . '/docs';
@ -22,11 +23,14 @@ class InfoRoutes extends RouteHandler {
} }
#[Route('GET', '/info')] #[Route('GET', '/info')]
#[URLInfo('info-index', '/info')]
public function getIndex() { public function getIndex() {
return Template::renderRaw('info.index'); return Template::renderRaw('info.index');
} }
#[Route('GET', '/info/:name')] #[Route('GET', '/info/:name')]
#[URLInfo('info', '/info/<title>')]
#[URLInfo('info-doc', '/info/<title>')]
public function getDocsPage($response, $request, string $name) { public function getDocsPage($response, $request, string $name) {
if(!self::checkName($name)) if(!self::checkName($name))
return 404; return 404;
@ -75,6 +79,7 @@ class InfoRoutes extends RouteHandler {
} }
#[Route('GET', '/info/:project/:name')] #[Route('GET', '/info/:project/:name')]
#[URLInfo('info-project-doc', '/info/<project>/<title>')]
public function getProjectPage($response, $request, string $project, string $name) { public function getProjectPage($response, $request, string $project, string $name) {
if(!array_key_exists($project, self::PROJECT_PATHS)) if(!array_key_exists($project, self::PROJECT_PATHS))
return 404; return 404;

View file

@ -3,13 +3,127 @@ namespace Misuzu;
use Index\Routing\Route; use Index\Routing\Route;
use Index\Routing\RouteHandler; use Index\Routing\RouteHandler;
use Misuzu\URLs\IURLSource;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry; use Misuzu\URLs\URLRegistry;
class LegacyRoutes extends RouteHandler { class LegacyRoutes extends RouteHandler implements IURLSource {
public function __construct( public function __construct(
private URLRegistry $urls private URLRegistry $urls
) {} ) {}
public function registerURLs(URLRegistry $urls): void {
// eventually this should be handled by context classes
$urls->register('search-index', '/search.php');
$urls->register('search-query', '/search.php', ['q' => '<query>'], '<section>');
$urls->register('auth-login', '/auth/login.php', ['username' => '<username>', 'redirect' => '<redirect>']);
$urls->register('auth-login-welcome', '/auth/login.php', ['welcome' => '1', 'username' => '<username>']);
$urls->register('auth-register', '/auth/register.php');
$urls->register('auth-forgot', '/auth/password.php');
$urls->register('auth-reset', '/auth/password.php', ['user' => '<user>']);
$urls->register('auth-logout', '/auth/logout.php', ['csrf' => '<csrf>']);
$urls->register('auth-resolve-user', '/auth/login.php', ['resolve' => '1', 'name' => '<username>']);
$urls->register('auth-two-factor', '/auth/twofactor.php', ['token' => '<token>']);
$urls->register('auth-revert', '/auth/revert.php', ['csrf' => '<csrf>']);
$urls->register('forum-index', '/forum');
$urls->register('forum-leaderboard', '/forum/leaderboard.php', ['id' => '<id>', 'mode' => '<mode>']);
$urls->register('forum-mark-global', '/forum/index.php', ['m' => 'mark']);
$urls->register('forum-mark-single', '/forum/index.php', ['m' => 'mark', 'f' => '<forum>']);
$urls->register('forum-topic-new', '/forum/posting.php', ['f' => '<forum>']);
$urls->register('forum-reply-new', '/forum/posting.php', ['t' => '<topic>']);
$urls->register('forum-category', '/forum/forum.php', ['f' => '<forum>', 'p' => '<page>']);
$urls->register('forum-category-root', '/forum/index.php', fragment: '<forum>');
$urls->register('forum-topic', '/forum/topic.php', ['t' => '<topic>', 'page' => '<page>']);
$urls->register('forum-topic-create', '/forum/posting.php', ['f' => '<forum>']);
$urls->register('forum-topic-bump', '/forum/topic.php', ['t' => '<topic>', 'm' => 'bump', 'csrf' => '<csrf>']);
$urls->register('forum-topic-lock', '/forum/topic.php', ['t' => '<topic>', 'm' => 'lock', 'csrf' => '<csrf>']);
$urls->register('forum-topic-unlock', '/forum/topic.php', ['t' => '<topic>', 'm' => 'unlock', 'csrf' => '<csrf>']);
$urls->register('forum-topic-delete', '/forum/topic.php', ['t' => '<topic>', 'm' => 'delete', 'csrf' => '<csrf>']);
$urls->register('forum-topic-restore', '/forum/topic.php', ['t' => '<topic>', 'm' => 'restore', 'csrf' => '<csrf>']);
$urls->register('forum-topic-nuke', '/forum/topic.php', ['t' => '<topic>', 'm' => 'nuke', 'csrf' => '<csrf>']);
$urls->register('forum-post', '/forum/topic.php', ['p' => '<post>'], 'p<post>');
$urls->register('forum-post-create', '/forum/posting.php', ['t' => '<topic>']);
$urls->register('forum-post-delete', '/forum/post.php', ['p' => '<post>', 'm' => 'delete']);
$urls->register('forum-post-restore', '/forum/post.php', ['p' => '<post>', 'm' => 'restore']);
$urls->register('forum-post-nuke', '/forum/post.php', ['p' => '<post>', 'm' => 'nuke']);
$urls->register('forum-post-quote', '/forum/posting.php', ['q' => '<post>']);
$urls->register('forum-post-edit', '/forum/posting.php', ['p' => '<post>', 'm' => 'edit']);
$urls->register('user-list', '/members.php', ['r' => '<role>', 'ss' => '<sort>', 'sd' => '<direction>', 'p' => '<page>']);
$urls->register('user-profile', '/profile.php', ['u' => '<user>']);
$urls->register('user-profile-forum-topics', '/profile.php', ['u' => '<user>', 'm' => 'forum-topics']);
$urls->register('user-profile-forum-posts', '/profile.php', ['u' => '<user>', 'm' => 'forum-posts']);
$urls->register('user-profile-edit', '/profile.php', ['u' => '<user>', 'edit' => '1']);
$urls->register('user-account-standing', '/profile.php', ['u' => '<user>'], 'account-standing');
$urls->register('settings-index', '/settings');
$urls->register('settings-account', '/settings/account.php');
$urls->register('settings-sessions', '/settings/sessions.php', ['p' => '<page>']);
$urls->register('settings-logs', '/settings/logs.php');
$urls->register('settings-logs-logins', '/settings/logs.php', ['ap' => '<account-page>', 'hp' => '<page>'], 'login-history');
$urls->register('settings-logs-account', '/settings/logs.php', ['hp' => '<logins-page>', 'ap' => '<page>'], 'account-log');
$urls->register('settings-data', '/settings/data.php');
$urls->register('comment-create', '/comments.php', ['m' => 'create', 'return' => '<return>']);
$urls->register('comment-vote', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'vote', 'v' => '<vote>', 'return' => '<return>']);
$urls->register('comment-delete', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'delete', 'return' => '<return>']);
$urls->register('comment-restore', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'restore', 'return' => '<return>']);
$urls->register('comment-pin', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'pin', 'return' => '<return>']);
$urls->register('comment-unpin', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'unpin', 'return' => '<return>']);
$urls->register('manage-general-overview', '/manage/general');
$urls->register('manage-general-logs', '/manage/general/logs.php', ['p' => '<page>']);
$urls->register('manage-general-emoticons', '/manage/general/emoticons.php');
$urls->register('manage-general-emoticon', '/manage/general/emoticon.php', ['e' => '<emote>']);
$urls->register('manage-general-emoticon-order-up', '/manage/general/emoticons.php', ['emote' => '<emote>', 'order' => 'd', 'csrf' => '<csrf>']);
$urls->register('manage-general-emoticon-order-down', '/manage/general/emoticons.php', ['emote' => '<emote>', 'order' => 'i', 'csrf' => '<csrf>']);
$urls->register('manage-general-emoticon-delete', '/manage/general/emoticons.php', ['emote' => '<emote>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-general-emoticon-alias', '/manage/general/emoticons.php', ['emote' => '<emote>', 'alias' => '<string>', 'csrf' => '<csrf>']);
$urls->register('manage-general-settings', '/manage/general/settings.php');
$urls->register('manage-general-setting', '/manage/general/setting.php', ['name' => '<name>', 'type' => '<type>']);
$urls->register('manage-general-setting-delete', '/manage/general/setting-delete.php', ['name' => '<name>']);
$urls->register('manage-forum-categories', '/manage/forum/index.php');
$urls->register('manage-forum-category', '/manage/forum/category.php', ['f' => '<forum>']);
$urls->register('manage-forum-topic-redirs', '/manage/forum/redirs.php', ['p' => '<page>']);
$urls->register('manage-forum-topic-redirs-create', '/manage/forum/redirs.php');
$urls->register('manage-forum-topic-redirs-nuke', '/manage/forum/redirs.php', ['m' => 'explode', 't' => '<topic>', 'csrf' => '<csrf>']);
$urls->register('manage-changelog-changes', '/manage/changelog', ['p' => '<page>']);
$urls->register('manage-changelog-change', '/manage/changelog/change.php', ['c' => '<change>']);
$urls->register('manage-changelog-change-delete', '/manage/changelog/change.php', ['c' => '<change>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-changelog-tags', '/manage/changelog/tags.php');
$urls->register('manage-changelog-tag', '/manage/changelog/tag.php', ['t' => '<tag>']);
$urls->register('manage-changelog-tag-delete', '/manage/changelog/tag.php', ['t' => '<tag>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-news-categories', '/manage/news/categories.php', ['p' => '<page>']);
$urls->register('manage-news-category', '/manage/news/category.php', ['c' => '<category>']);
$urls->register('manage-news-category-delete', '/manage/news/category.php', ['c' => '<category>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-news-posts', '/manage/news/posts.php', ['p' => '<page>']);
$urls->register('manage-news-post', '/manage/news/post.php', ['p' => '<post>']);
$urls->register('manage-news-post-delete', '/manage/news/post.php', ['p' => '<post>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-users', '/manage/users', ['p' => '<page>']);
$urls->register('manage-user', '/manage/users/user.php', ['u' => '<user>']);
$urls->register('manage-users-warnings', '/manage/users/warnings.php', ['u' => '<user>', 'p' => '<page>']);
$urls->register('manage-users-warning', '/manage/users/warning.php', ['u' => '<user>']);
$urls->register('manage-users-warning-delete', '/manage/users/warning.php', ['w' => '<warning>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-users-notes', '/manage/users/notes.php', ['u' => '<user>', 'p' => '<page>']);
$urls->register('manage-users-note', '/manage/users/note.php', ['n' => '<note>', 'u' => '<user>']);
$urls->register('manage-users-note-delete', '/manage/users/note.php', ['n' => '<note>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-users-bans', '/manage/users/bans.php', ['u' => '<user>', 'p' => '<page>']);
$urls->register('manage-users-ban', '/manage/users/ban.php', ['u' => '<user>']);
$urls->register('manage-users-ban-delete', '/manage/users/ban.php', ['b' => '<ban>', 'delete' => '1', 'csrf' => '<csrf>']);
$urls->register('manage-roles', '/manage/users/roles.php', ['p' => '<page>']);
$urls->register('manage-role', '/manage/users/role.php', ['r' => '<role>']);
}
#[Route('GET', '/index.php')] #[Route('GET', '/index.php')]
public function getIndexPHP($response): void { public function getIndexPHP($response): void {
$response->redirect($this->urls->format('index'), true); $response->redirect($this->urls->format('index'), true);
@ -151,6 +265,7 @@ class LegacyRoutes extends RouteHandler {
} }
#[Route('GET', '/manage')] #[Route('GET', '/manage')]
#[URLInfo('manage-index', '/manage')]
public function getManageIndex($response): void { public function getManageIndex($response): void {
$response->redirect($this->urls->format('manage-general-overview')); $response->redirect($this->urls->format('manage-general-overview'));
} }

View file

@ -6,9 +6,6 @@ use Index\Data\IDbConnection;
use Index\Data\Migration\IDbMigrationRepo; use Index\Data\Migration\IDbMigrationRepo;
use Index\Data\Migration\DbMigrationManager; use Index\Data\Migration\DbMigrationManager;
use Index\Data\Migration\FsDbMigrationRepo; use Index\Data\Migration\FsDbMigrationRepo;
use Index\Http\HttpFx;
use Index\Http\HttpRequest;
use Index\Routing\IRouter;
use Sasae\SasaeEnvironment; use Sasae\SasaeEnvironment;
use Misuzu\Template; use Misuzu\Template;
use Misuzu\Auth\AuthContext; use Misuzu\Auth\AuthContext;
@ -43,18 +40,14 @@ use Misuzu\Users\Assets\AssetsRoutes;
class MisuzuContext { class MisuzuContext {
private IDbConnection $dbConn; private IDbConnection $dbConn;
private IConfig $config; private IConfig $config;
private HttpFx $router;
private SasaeEnvironment $templating; private SasaeEnvironment $templating;
private URLRegistry $urls;
private AuditLog $auditLog; private AuditLog $auditLog;
private Counters $counters; private Counters $counters;
private Emotes $emotes; private Emotes $emotes;
private Changelog $changelog; private Changelog $changelog;
private News $news; private News $news;
private Comments $comments; private Comments $comments;
private AuthContext $authCtx; private AuthContext $authCtx;
@ -67,13 +60,13 @@ class MisuzuContext {
private AuthInfo $authInfo; private AuthInfo $authInfo;
private SiteInfo $siteInfo; private SiteInfo $siteInfo;
// this probably shouldn't be available
private URLRegistry $urls;
public function __construct(IDbConnection $dbConn, IConfig $config) { public function __construct(IDbConnection $dbConn, IConfig $config) {
$this->dbConn = $dbConn; $this->dbConn = $dbConn;
$this->config = $config; $this->config = $config;
$this->urls = new URLRegistry;
$this->registerURLs();
$this->perms = new Permissions($dbConn); $this->perms = new Permissions($dbConn);
$this->authInfo = new AuthInfo($this->perms); $this->authInfo = new AuthInfo($this->perms);
$this->siteInfo = new SiteInfo($config->scopeTo('site')); $this->siteInfo = new SiteInfo($config->scopeTo('site'));
@ -116,10 +109,6 @@ class MisuzuContext {
return $this->config; return $this->config;
} }
public function getRouter(): IRouter {
return $this->router;
}
public function getEmotes(): Emotes { public function getEmotes(): Emotes {
return $this->emotes; return $this->emotes;
} }
@ -227,40 +216,13 @@ class MisuzuContext {
Template::init($this->templating); Template::init($this->templating);
} }
public function startRouter(): void { public function createRouting(): RoutingContext {
$this->router = new HttpFx; $routingCtx = new RoutingContext();
$this->router->use('/', function($response) {
$response->setPoweredBy('Misuzu');
});
$this->registerErrorPages(); $this->urls = $routingCtx->getURLs();
$this->registerHttpRoutes(); $routingCtx->registerDefaultErrorPages();
}
public function dispatchRouter(?HttpRequest $request = null): void { $routingCtx->register(new HomeRoutes(
$this->router->dispatch($request);
}
private function registerErrorPages(): void {
$this->router->addErrorHandler(400, function($response) {
$response->setContent(Template::renderRaw('errors.400'));
});
$this->router->addErrorHandler(403, function($response) {
$response->setContent(Template::renderRaw('errors.403'));
});
$this->router->addErrorHandler(404, function($response) {
$response->setContent(Template::renderRaw('errors.404'));
});
$this->router->addErrorHandler(500, function($response) {
$response->setContent(file_get_contents(MSZ_TEMPLATES . '/500.html'));
});
$this->router->addErrorHandler(503, function($response) {
$response->setContent(file_get_contents(MSZ_TEMPLATES . '/503.html'));
});
}
private function registerHttpRoutes(): void {
$this->router->register(new HomeRoutes(
$this->config, $this->config,
$this->dbConn, $this->dbConn,
$this->siteInfo, $this->siteInfo,
@ -272,15 +234,15 @@ class MisuzuContext {
$this->usersCtx $this->usersCtx
)); ));
$this->router->register(new AssetsRoutes( $routingCtx->register(new AssetsRoutes(
$this->authInfo, $this->authInfo,
$this->urls, $this->urls,
$this->usersCtx $this->usersCtx
)); ));
$this->router->register(new InfoRoutes); $routingCtx->register(new InfoRoutes);
$this->router->register(new NewsRoutes( $routingCtx->register(new NewsRoutes(
$this->siteInfo, $this->siteInfo,
$this->authInfo, $this->authInfo,
$this->urls, $this->urls,
@ -289,7 +251,7 @@ class MisuzuContext {
$this->comments $this->comments
)); ));
$this->router->register(new ChangelogRoutes( $routingCtx->register(new ChangelogRoutes(
$this->siteInfo, $this->siteInfo,
$this->urls, $this->urls,
$this->changelog, $this->changelog,
@ -298,7 +260,7 @@ class MisuzuContext {
$this->comments $this->comments
)); ));
$this->router->register(new SharpChatRoutes( $routingCtx->register(new SharpChatRoutes(
$this->config->scopeTo('sockChat'), $this->config->scopeTo('sockChat'),
$this->urls, $this->urls,
$this->usersCtx, $this->usersCtx,
@ -308,148 +270,15 @@ class MisuzuContext {
$this->authInfo $this->authInfo
)); ));
$this->router->register(new SatoriRoutes( $routingCtx->register(new SatoriRoutes(
$this->config->scopeTo('satori'), $this->config->scopeTo('satori'),
$this->usersCtx, $this->usersCtx,
$this->forumCtx, $this->forumCtx,
$this->profileFields $this->profileFields
)); ));
$this->router->register(new LegacyRoutes($this->urls)); $routingCtx->register(new LegacyRoutes($this->urls));
}
public function registerURLs(): void { return $routingCtx;
// eventually this should be handled by context classes
$this->urls->register('index', '/');
$this->urls->register('info', '/info/<title>');
$this->urls->register('search-index', '/search.php');
$this->urls->register('search-query', '/search.php', ['q' => '<query>'], '<section>');
$this->urls->register('auth-login', '/auth/login.php', ['username' => '<username>', 'redirect' => '<redirect>']);
$this->urls->register('auth-login-welcome', '/auth/login.php', ['welcome' => '1', 'username' => '<username>']);
$this->urls->register('auth-register', '/auth/register.php');
$this->urls->register('auth-forgot', '/auth/password.php');
$this->urls->register('auth-reset', '/auth/password.php', ['user' => '<user>']);
$this->urls->register('auth-logout', '/auth/logout.php', ['csrf' => '<csrf>']);
$this->urls->register('auth-resolve-user', '/auth/login.php', ['resolve' => '1', 'name' => '<username>']);
$this->urls->register('auth-two-factor', '/auth/twofactor.php', ['token' => '<token>']);
$this->urls->register('auth-revert', '/auth/revert.php', ['csrf' => '<csrf>']);
$this->urls->register('changelog-index', '/changelog', ['date' => '<date>', 'user' => '<user>', 'tags' => '<tags>', 'p' => '<page>']);
$this->urls->register('changelog-feed-rss', '/changelog.rss');
$this->urls->register('changelog-feed-atom', '/changelog.atom');
$this->urls->register('changelog-change', '/changelog/change/<change>');
$this->urls->register('changelog-change-comments', '/changelog/change/<change>', fragment: 'comments');
$this->urls->register('news-index', '/news', ['p' => '<page>']);
$this->urls->register('news-category', '/news/<category>', ['p' => '<page>']);
$this->urls->register('news-post', '/news/post/<post>');
$this->urls->register('news-post-comments', '/news/post/<post>', fragment: 'comments');
$this->urls->register('news-feed-rss', '/news.rss');
$this->urls->register('news-category-feed-rss', '/news/<category>.rss');
$this->urls->register('news-feed-atom', '/news.atom');
$this->urls->register('news-category-feed-atom', '/news/<category>.atom');
$this->urls->register('forum-index', '/forum');
$this->urls->register('forum-leaderboard', '/forum/leaderboard.php', ['id' => '<id>', 'mode' => '<mode>']);
$this->urls->register('forum-mark-global', '/forum/index.php', ['m' => 'mark']);
$this->urls->register('forum-mark-single', '/forum/index.php', ['m' => 'mark', 'f' => '<forum>']);
$this->urls->register('forum-topic-new', '/forum/posting.php', ['f' => '<forum>']);
$this->urls->register('forum-reply-new', '/forum/posting.php', ['t' => '<topic>']);
$this->urls->register('forum-category', '/forum/forum.php', ['f' => '<forum>', 'p' => '<page>']);
$this->urls->register('forum-category-root', '/forum/index.php', fragment: '<forum>');
$this->urls->register('forum-topic', '/forum/topic.php', ['t' => '<topic>', 'page' => '<page>']);
$this->urls->register('forum-topic-create', '/forum/posting.php', ['f' => '<forum>']);
$this->urls->register('forum-topic-bump', '/forum/topic.php', ['t' => '<topic>', 'm' => 'bump', 'csrf' => '<csrf>']);
$this->urls->register('forum-topic-lock', '/forum/topic.php', ['t' => '<topic>', 'm' => 'lock', 'csrf' => '<csrf>']);
$this->urls->register('forum-topic-unlock', '/forum/topic.php', ['t' => '<topic>', 'm' => 'unlock', 'csrf' => '<csrf>']);
$this->urls->register('forum-topic-delete', '/forum/topic.php', ['t' => '<topic>', 'm' => 'delete', 'csrf' => '<csrf>']);
$this->urls->register('forum-topic-restore', '/forum/topic.php', ['t' => '<topic>', 'm' => 'restore', 'csrf' => '<csrf>']);
$this->urls->register('forum-topic-nuke', '/forum/topic.php', ['t' => '<topic>', 'm' => 'nuke', 'csrf' => '<csrf>']);
$this->urls->register('forum-post', '/forum/topic.php', ['p' => '<post>'], 'p<post>');
$this->urls->register('forum-post-create', '/forum/posting.php', ['t' => '<topic>']);
$this->urls->register('forum-post-delete', '/forum/post.php', ['p' => '<post>', 'm' => 'delete']);
$this->urls->register('forum-post-restore', '/forum/post.php', ['p' => '<post>', 'm' => 'restore']);
$this->urls->register('forum-post-nuke', '/forum/post.php', ['p' => '<post>', 'm' => 'nuke']);
$this->urls->register('forum-post-quote', '/forum/posting.php', ['q' => '<post>']);
$this->urls->register('forum-post-edit', '/forum/posting.php', ['p' => '<post>', 'm' => 'edit']);
$this->urls->register('user-list', '/members.php', ['r' => '<role>', 'ss' => '<sort>', 'sd' => '<direction>', 'p' => '<page>']);
$this->urls->register('user-profile', '/profile.php', ['u' => '<user>']);
$this->urls->register('user-profile-forum-topics', '/profile.php', ['u' => '<user>', 'm' => 'forum-topics']);
$this->urls->register('user-profile-forum-posts', '/profile.php', ['u' => '<user>', 'm' => 'forum-posts']);
$this->urls->register('user-profile-edit', '/profile.php', ['u' => '<user>', 'edit' => '1']);
$this->urls->register('user-account-standing', '/profile.php', ['u' => '<user>'], 'account-standing');
$this->urls->register('user-avatar', '/assets/avatar/<user>', ['res' => '<res>']);
$this->urls->register('user-background', '/assets/profile-background/<user>');
$this->urls->register('settings-index', '/settings');
$this->urls->register('settings-account', '/settings/account.php');
$this->urls->register('settings-sessions', '/settings/sessions.php', ['p' => '<page>']);
$this->urls->register('settings-logs', '/settings/logs.php');
$this->urls->register('settings-logs-logins', '/settings/logs.php', ['ap' => '<account-page>', 'hp' => '<page>'], 'login-history');
$this->urls->register('settings-logs-account', '/settings/logs.php', ['hp' => '<logins-page>', 'ap' => '<page>'], 'account-log');
$this->urls->register('settings-data', '/settings/data.php');
$this->urls->register('comment-create', '/comments.php', ['m' => 'create', 'return' => '<return>']);
$this->urls->register('comment-vote', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'vote', 'v' => '<vote>', 'return' => '<return>']);
$this->urls->register('comment-delete', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'delete', 'return' => '<return>']);
$this->urls->register('comment-restore', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'restore', 'return' => '<return>']);
$this->urls->register('comment-pin', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'pin', 'return' => '<return>']);
$this->urls->register('comment-unpin', '/comments.php', ['c' => '<comment>', 'csrf' => '<csrf>', 'm' => 'unpin', 'return' => '<return>']);
$this->urls->register('manage-index', '/manage');
$this->urls->register('manage-general-overview', '/manage/general');
$this->urls->register('manage-general-logs', '/manage/general/logs.php', ['p' => '<page>']);
$this->urls->register('manage-general-emoticons', '/manage/general/emoticons.php');
$this->urls->register('manage-general-emoticon', '/manage/general/emoticon.php', ['e' => '<emote>']);
$this->urls->register('manage-general-emoticon-order-up', '/manage/general/emoticons.php', ['emote' => '<emote>', 'order' => 'd', 'csrf' => '<csrf>']);
$this->urls->register('manage-general-emoticon-order-down', '/manage/general/emoticons.php', ['emote' => '<emote>', 'order' => 'i', 'csrf' => '<csrf>']);
$this->urls->register('manage-general-emoticon-delete', '/manage/general/emoticons.php', ['emote' => '<emote>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-general-emoticon-alias', '/manage/general/emoticons.php', ['emote' => '<emote>', 'alias' => '<string>', 'csrf' => '<csrf>']);
$this->urls->register('manage-general-settings', '/manage/general/settings.php');
$this->urls->register('manage-general-setting', '/manage/general/setting.php', ['name' => '<name>', 'type' => '<type>']);
$this->urls->register('manage-general-setting-delete', '/manage/general/setting-delete.php', ['name' => '<name>']);
$this->urls->register('manage-forum-categories', '/manage/forum/index.php');
$this->urls->register('manage-forum-category', '/manage/forum/category.php', ['f' => '<forum>']);
$this->urls->register('manage-forum-topic-redirs', '/manage/forum/redirs.php', ['p' => '<page>']);
$this->urls->register('manage-forum-topic-redirs-create', '/manage/forum/redirs.php');
$this->urls->register('manage-forum-topic-redirs-nuke', '/manage/forum/redirs.php', ['m' => 'explode', 't' => '<topic>', 'csrf' => '<csrf>']);
$this->urls->register('manage-changelog-changes', '/manage/changelog', ['p' => '<page>']);
$this->urls->register('manage-changelog-change', '/manage/changelog/change.php', ['c' => '<change>']);
$this->urls->register('manage-changelog-change-delete', '/manage/changelog/change.php', ['c' => '<change>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-changelog-tags', '/manage/changelog/tags.php');
$this->urls->register('manage-changelog-tag', '/manage/changelog/tag.php', ['t' => '<tag>']);
$this->urls->register('manage-changelog-tag-delete', '/manage/changelog/tag.php', ['t' => '<tag>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-news-categories', '/manage/news/categories.php', ['p' => '<page>']);
$this->urls->register('manage-news-category', '/manage/news/category.php', ['c' => '<category>']);
$this->urls->register('manage-news-category-delete', '/manage/news/category.php', ['c' => '<category>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-news-posts', '/manage/news/posts.php', ['p' => '<page>']);
$this->urls->register('manage-news-post', '/manage/news/post.php', ['p' => '<post>']);
$this->urls->register('manage-news-post-delete', '/manage/news/post.php', ['p' => '<post>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-users', '/manage/users', ['p' => '<page>']);
$this->urls->register('manage-user', '/manage/users/user.php', ['u' => '<user>']);
$this->urls->register('manage-users-warnings', '/manage/users/warnings.php', ['u' => '<user>', 'p' => '<page>']);
$this->urls->register('manage-users-warning', '/manage/users/warning.php', ['u' => '<user>']);
$this->urls->register('manage-users-warning-delete', '/manage/users/warning.php', ['w' => '<warning>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-users-notes', '/manage/users/notes.php', ['u' => '<user>', 'p' => '<page>']);
$this->urls->register('manage-users-note', '/manage/users/note.php', ['n' => '<note>', 'u' => '<user>']);
$this->urls->register('manage-users-note-delete', '/manage/users/note.php', ['n' => '<note>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-users-bans', '/manage/users/bans.php', ['u' => '<user>', 'p' => '<page>']);
$this->urls->register('manage-users-ban', '/manage/users/ban.php', ['u' => '<user>']);
$this->urls->register('manage-users-ban-delete', '/manage/users/ban.php', ['b' => '<ban>', 'delete' => '1', 'csrf' => '<csrf>']);
$this->urls->register('manage-roles', '/manage/users/roles.php', ['p' => '<page>']);
$this->urls->register('manage-role', '/manage/users/role.php', ['r' => '<role>']);
} }
} }

View file

@ -19,6 +19,7 @@ use Misuzu\Feeds\FeedItem;
use Misuzu\Feeds\AtomFeedSerializer; use Misuzu\Feeds\AtomFeedSerializer;
use Misuzu\Feeds\RssFeedSerializer; use Misuzu\Feeds\RssFeedSerializer;
use Misuzu\Parsers\Parser; use Misuzu\Parsers\Parser;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry; use Misuzu\URLs\URLRegistry;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;
@ -91,6 +92,7 @@ class NewsRoutes extends RouteHandler {
} }
#[Route('GET', '/news')] #[Route('GET', '/news')]
#[URLInfo('news-index', '/news', ['p' => '<page>'])]
public function getIndex() { public function getIndex() {
$categories = $this->news->getCategories(hidden: false); $categories = $this->news->getCategories(hidden: false);
@ -108,16 +110,19 @@ class NewsRoutes extends RouteHandler {
} }
#[Route('GET', '/news.rss')] #[Route('GET', '/news.rss')]
#[URLInfo('news-feed-rss', '/news.rss')]
public function getFeedRss($response) { public function getFeedRss($response) {
return $this->getFeed($response, 'rss'); return $this->getFeed($response, 'rss');
} }
#[Route('GET', '/news.atom')] #[Route('GET', '/news.atom')]
#[URLInfo('news-feed-atom', '/news.atom')]
public function getFeedAtom($response) { public function getFeedAtom($response) {
return $this->getFeed($response, 'atom'); return $this->getFeed($response, 'atom');
} }
#[Route('GET', '/news/:category')] #[Route('GET', '/news/:category')]
#[URLInfo('news-category', '/news/<category>', ['p' => '<page>'])]
public function getCategory($response, $request, string $fileName) { public function getCategory($response, $request, string $fileName) {
$categoryId = pathinfo($fileName, PATHINFO_FILENAME); $categoryId = pathinfo($fileName, PATHINFO_FILENAME);
$type = pathinfo($fileName, PATHINFO_EXTENSION); $type = pathinfo($fileName, PATHINFO_EXTENSION);
@ -148,15 +153,19 @@ class NewsRoutes extends RouteHandler {
]); ]);
} }
#[URLInfo('news-category-feed-rss', '/news/<category>.rss')]
private function getCategoryFeedRss($response, $request, NewsCategoryInfo $categoryInfo) { private function getCategoryFeedRss($response, $request, NewsCategoryInfo $categoryInfo) {
return $this->getFeed($response, 'rss', $categoryInfo); return $this->getFeed($response, 'rss', $categoryInfo);
} }
#[URLInfo('news-category-feed-atom', '/news/<category>.atom')]
private function getCategoryFeedAtom($response, $request, NewsCategoryInfo $categoryInfo) { private function getCategoryFeedAtom($response, $request, NewsCategoryInfo $categoryInfo) {
return $this->getFeed($response, 'atom', $categoryInfo); return $this->getFeed($response, 'atom', $categoryInfo);
} }
#[Route('GET', '/news/post/:id')] #[Route('GET', '/news/post/:id')]
#[URLInfo('news-post', '/news/post/<post>')]
#[URLInfo('news-post-comments', '/news/post/<post>', fragment: 'comments')]
public function getPost($response, $request, string $postId) { public function getPost($response, $request, string $postId) {
try { try {
$postInfo = $this->news->getPost($postId); $postInfo = $this->news->getPost($postId);

60
src/RoutingContext.php Normal file
View file

@ -0,0 +1,60 @@
<?php
namespace Misuzu;
use Index\Http\HttpFx;
use Index\Http\HttpRequest;
use Index\Routing\IRouter;
use Index\Routing\IRouteHandler;
use Misuzu\URLs\IURLSource;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry;
class RoutingContext {
private URLRegistry $urls;
private HttpFx $router;
public function __construct() {
$this->urls = new URLRegistry;
$this->router = new HttpFx;
$this->router->use('/', fn($resp) => $resp->setPoweredBy('Misuzu'));
}
public function getURLs(): URLRegistry {
return $this->urls;
}
public function getRouter(): IRouter {
return $this->router;
}
public function registerDefaultErrorPages(): void {
$this->router->addErrorHandler(400, fn($resp) => $resp->setContent(Template::renderRaw('errors.400')));
$this->router->addErrorHandler(403, fn($resp) => $resp->setContent(Template::renderRaw('errors.403')));
$this->router->addErrorHandler(404, fn($resp) => $resp->setContent(Template::renderRaw('errors.404')));
$this->router->addErrorHandler(500, fn($resp) => $resp->setContent(file_get_contents(MSZ_TEMPLATES . '/500.html')));
$this->router->addErrorHandler(503, fn($resp) => $resp->setContent(file_get_contents(MSZ_TEMPLATES . '/503.html')));
}
public static function registerSimpleErrorPages(IRouter $router, string $path): void {
if($router instanceof HttpFx)
$router->use($path, function() use($router) {
$router->addErrorHandler(400, fn($resp) => $resp->setContent('HTTP 400'));
$router->addErrorHandler(403, fn($resp) => $resp->setContent('HTTP 403'));
$router->addErrorHandler(404, fn($resp) => $resp->setContent('HTTP 404'));
$router->addErrorHandler(500, fn($resp) => $resp->setContent('HTTP 500'));
$router->addErrorHandler(503, fn($resp) => $resp->setContent('HTTP 503'));
});
}
public function register(IRouteHandler|IURLSource $handler): void {
if($handler instanceof IRouteHandler)
$this->router->register($handler);
if($handler instanceof IURLSource)
$handler->registerURLs($this->urls);
URLInfo::handleAttributes($this->urls, $handler);
}
public function dispatch(?HttpRequest $request = null): void {
$this->router->dispatch($request);
}
}

View file

@ -7,7 +7,7 @@ use Index\Routing\IRouter;
use Index\Routing\IRouteHandler; use Index\Routing\IRouteHandler;
use Index\Routing\Route; use Index\Routing\Route;
use Misuzu\Pagination; use Misuzu\Pagination;
use Misuzu\Tools; use Misuzu\RoutingContext;
use Misuzu\Config\IConfig; use Misuzu\Config\IConfig;
use Misuzu\Forum\ForumContext; use Misuzu\Forum\ForumContext;
use Misuzu\Profile\ProfileFields; use Misuzu\Profile\ProfileFields;
@ -22,7 +22,7 @@ final class SatoriRoutes implements IRouteHandler {
) {} ) {}
public function registerRoutes(IRouter $router): void { public function registerRoutes(IRouter $router): void {
Tools::simplifyErrorPages($router, '/_satori'); RoutingContext::registerSimpleErrorPages($router, '/_satori');
Route::handleAttributes($router, $this); Route::handleAttributes($router, $this);
} }

View file

@ -6,7 +6,7 @@ use Index\Colour\Colour;
use Index\Routing\IRouter; use Index\Routing\IRouter;
use Index\Routing\IRouteHandler; use Index\Routing\IRouteHandler;
use Index\Routing\Route; use Index\Routing\Route;
use Misuzu\Tools; use Misuzu\RoutingContext;
use Misuzu\Auth\AuthContext; use Misuzu\Auth\AuthContext;
use Misuzu\Auth\AuthInfo; use Misuzu\Auth\AuthInfo;
use Misuzu\Auth\Sessions; use Misuzu\Auth\Sessions;
@ -33,7 +33,7 @@ final class SharpChatRoutes implements IRouteHandler {
} }
public function registerRoutes(IRouter $router): void { public function registerRoutes(IRouter $router): void {
Tools::simplifyErrorPages($router, '/_sockchat'); RoutingContext::registerSimpleErrorPages($router, '/_sockchat');
Route::handleAttributes($router, $this); Route::handleAttributes($router, $this);
} }

View file

@ -68,17 +68,6 @@ final class Tools {
return $day <= $days; return $day <= $days;
} }
public static function simplifyErrorPages(IRouter $router, string $path): void {
if($router instanceof HttpFx)
$router->use($path, function() use($router) {
$router->addErrorHandler(400, fn($resp) => $resp->setContent('HTTP 400'));
$router->addErrorHandler(403, fn($resp) => $resp->setContent('HTTP 403'));
$router->addErrorHandler(404, fn($resp) => $resp->setContent('HTTP 404'));
$router->addErrorHandler(500, fn($resp) => $resp->setContent('HTTP 500'));
$router->addErrorHandler(503, fn($resp) => $resp->setContent('HTTP 503'));
});
}
// for your own sanity and the sanity of others, keep this one at the bottom // for your own sanity and the sanity of others, keep this one at the bottom
public static function countryName(string $code): string { public static function countryName(string $code): string {
return match(strtoupper($code)) { return match(strtoupper($code)) {

6
src/URLs/IURLSource.php Normal file
View file

@ -0,0 +1,6 @@
<?php
namespace Misuzu\URLs;
interface IURLSource {
public function registerURLs(URLRegistry $urls): void;
}

View file

@ -1,13 +1,23 @@
<?php <?php
namespace Misuzu\URLs; namespace Misuzu\URLs;
use Attribute;
use InvalidArgumentException;
use ReflectionObject;
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
class URLInfo { class URLInfo {
public function __construct( public function __construct(
private string $name, private string $name,
private string $path, private string $path,
private array $query, private array $query = [],
private string $fragment private string $fragment = ''
) {} ) {
if($path === '')
throw new InvalidArgumentException('$path may not be empty.');
if($path[0] !== '/')
throw new InvalidArgumentException('$path must begin with /.');
}
public function getName(): string { public function getName(): string {
return $this->name; return $this->name;
@ -32,4 +42,15 @@ class URLInfo {
public function getFragment(): string { public function getFragment(): string {
return $this->fragment; return $this->fragment;
} }
public static function handleAttributes(URLRegistry $urls, object $source): void {
$objectInfo = new ReflectionObject($source);
$methodInfos = $objectInfo->getMethods();
foreach($methodInfos as $methodInfo) {
$attrInfos = $methodInfo->getAttributes(URLInfo::class);
foreach($attrInfos as $attrInfo)
$urls->registerInfo($attrInfo->newInstance());
}
}
} }

View file

@ -9,14 +9,17 @@ class URLRegistry {
public function register(string $name, string $path, array $query = [], string $fragment = ''): void { public function register(string $name, string $path, array $query = [], string $fragment = ''): void {
if(array_key_exists($name, $this->infos)) if(array_key_exists($name, $this->infos))
throw new InvalidArgumentException('A URL with $name has already been registered.'); throw new InvalidArgumentException('A URL with $name has already been registered.');
if($path === '')
throw new InvalidArgumentException('$path may not be empty.');
if($path[0] !== '/')
throw new InvalidArgumentException('$path must begin with /.');
$this->infos[$name] = new URLInfo($name, $path, $query, $fragment); $this->infos[$name] = new URLInfo($name, $path, $query, $fragment);
} }
public function registerInfo(URLInfo $info): void {
if(array_key_exists($info->getName(), $this->infos))
throw new InvalidArgumentException('A URL with $name has already been registered.');
$this->infos[$info->getName()] = $info;
}
public function format(string $name, array $vars = [], bool $spacesAsPlus = false): string { public function format(string $name, array $vars = [], bool $spacesAsPlus = false): string {
if(!array_key_exists($name, $this->infos)) if(!array_key_exists($name, $this->infos))
return ''; return '';

View file

@ -7,6 +7,7 @@ use Index\Routing\Route;
use Index\Routing\RouteHandler; use Index\Routing\RouteHandler;
use Misuzu\Perm; use Misuzu\Perm;
use Misuzu\Auth\AuthInfo; use Misuzu\Auth\AuthInfo;
use Misuzu\URLs\URLInfo;
use Misuzu\URLs\URLRegistry; use Misuzu\URLs\URLRegistry;
use Misuzu\Users\UsersContext; use Misuzu\Users\UsersContext;
use Misuzu\Users\UserInfo; use Misuzu\Users\UserInfo;
@ -30,6 +31,7 @@ class AssetsRoutes extends RouteHandler {
#[Route('GET', '/assets/avatar')] #[Route('GET', '/assets/avatar')]
#[Route('GET', '/assets/avatar/:filename')] #[Route('GET', '/assets/avatar/:filename')]
#[URLInfo('user-avatar', '/assets/avatar/<user>', ['res' => '<res>'])]
public function getAvatar($response, $request, string $fileName = '') { public function getAvatar($response, $request, string $fileName = '') {
$userId = pathinfo($fileName, PATHINFO_FILENAME); $userId = pathinfo($fileName, PATHINFO_FILENAME);
$assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC); $assetInfo = new StaticUserImageAsset(MSZ_PUBLIC . '/images/no-avatar.png', MSZ_PUBLIC);
@ -52,6 +54,7 @@ class AssetsRoutes extends RouteHandler {
#[Route('GET', '/assets/profile-background')] #[Route('GET', '/assets/profile-background')]
#[Route('GET', '/assets/profile-background/:filename')] #[Route('GET', '/assets/profile-background/:filename')]
#[URLInfo('user-background', '/assets/profile-background/<user>')]
public function getProfileBackground($response, $request, string $fileName = '') { public function getProfileBackground($response, $request, string $fileName = '') {
$userId = pathinfo($fileName, PATHINFO_FILENAME); $userId = pathinfo($fileName, PATHINFO_FILENAME);