2017-12-16 19:17:29 +00:00
|
|
|
<?php
|
|
|
|
namespace Misuzu;
|
|
|
|
|
2018-09-16 19:45:40 +00:00
|
|
|
define('MSZ_STARTUP', microtime(true));
|
|
|
|
define('MSZ_DEBUG', file_exists(__DIR__ . '/.debug'));
|
|
|
|
|
2018-09-16 21:03:56 +00:00
|
|
|
error_reporting(MSZ_DEBUG ? -1 : 0);
|
|
|
|
ini_set('display_errors', MSZ_DEBUG ? 'On' : 'Off');
|
|
|
|
|
2018-05-27 23:24:16 +00:00
|
|
|
date_default_timezone_set('UTC');
|
2018-09-15 21:55:26 +00:00
|
|
|
mb_internal_encoding('UTF-8');
|
2018-05-27 23:24:16 +00:00
|
|
|
|
2018-04-30 21:39:43 +00:00
|
|
|
require_once __DIR__ . '/vendor/autoload.php';
|
2018-08-23 18:13:37 +00:00
|
|
|
|
2018-09-16 21:03:56 +00:00
|
|
|
$errorHandler = new \Whoops\Run;
|
|
|
|
$errorHandler->pushHandler(
|
|
|
|
MSZ_DEBUG
|
|
|
|
? (
|
2018-08-23 18:13:37 +00:00
|
|
|
PHP_SAPI === 'cli'
|
|
|
|
? new \Whoops\Handler\PlainTextHandler
|
|
|
|
: new \Whoops\Handler\PrettyPageHandler
|
2018-09-16 21:03:56 +00:00
|
|
|
)
|
|
|
|
: ($errorReporter = new WhoopsReporter)
|
|
|
|
);
|
|
|
|
$errorHandler->register();
|
2018-08-23 18:13:37 +00:00
|
|
|
|
2018-07-17 17:17:57 +00:00
|
|
|
require_once __DIR__ . '/src/audit_log.php';
|
2018-07-06 01:28:06 +00:00
|
|
|
require_once __DIR__ . '/src/changelog.php';
|
2018-04-30 21:39:43 +00:00
|
|
|
require_once __DIR__ . '/src/colour.php';
|
2018-07-10 21:24:00 +00:00
|
|
|
require_once __DIR__ . '/src/comments.php';
|
|
|
|
require_once __DIR__ . '/src/general.php';
|
2018-07-10 16:37:13 +00:00
|
|
|
require_once __DIR__ . '/src/git.php';
|
2018-07-07 23:24:34 +00:00
|
|
|
require_once __DIR__ . '/src/manage.php';
|
2018-07-08 19:24:59 +00:00
|
|
|
require_once __DIR__ . '/src/news.php';
|
2018-07-07 23:24:34 +00:00
|
|
|
require_once __DIR__ . '/src/perms.php';
|
2018-08-15 01:12:58 +00:00
|
|
|
require_once __DIR__ . '/src/tpl.php';
|
2018-04-30 21:39:43 +00:00
|
|
|
require_once __DIR__ . '/src/zalgo.php';
|
2018-05-23 01:41:57 +00:00
|
|
|
require_once __DIR__ . '/src/Forum/forum.php';
|
2018-08-17 16:34:02 +00:00
|
|
|
require_once __DIR__ . '/src/Forum/perms.php';
|
2018-05-23 01:41:57 +00:00
|
|
|
require_once __DIR__ . '/src/Forum/post.php';
|
|
|
|
require_once __DIR__ . '/src/Forum/topic.php';
|
|
|
|
require_once __DIR__ . '/src/Forum/validate.php';
|
2018-05-16 02:58:21 +00:00
|
|
|
require_once __DIR__ . '/src/Users/login_attempt.php';
|
2018-05-27 00:20:35 +00:00
|
|
|
require_once __DIR__ . '/src/Users/profile.php';
|
|
|
|
require_once __DIR__ . '/src/Users/role.php';
|
|
|
|
require_once __DIR__ . '/src/Users/session.php';
|
|
|
|
require_once __DIR__ . '/src/Users/user.php';
|
2018-05-16 02:58:21 +00:00
|
|
|
require_once __DIR__ . '/src/Users/validation.php';
|
2018-01-02 19:37:13 +00:00
|
|
|
|
2018-09-16 19:45:40 +00:00
|
|
|
$app = new Application(__DIR__ . '/config/config.ini');
|
2018-09-16 21:03:56 +00:00
|
|
|
|
|
|
|
if (!empty($errorReporter)) {
|
|
|
|
$errorReporter->setReportInfo(...$app->getReportInfo());
|
|
|
|
}
|
|
|
|
|
2018-01-03 21:39:01 +00:00
|
|
|
$app->startDatabase();
|
2018-03-14 01:39:02 +00:00
|
|
|
|
2018-07-11 20:30:17 +00:00
|
|
|
if (PHP_SAPI === 'cli') {
|
|
|
|
if ($argv[0] === basename(__FILE__)) {
|
|
|
|
switch ($argv[1] ?? null) {
|
|
|
|
case 'cron':
|
|
|
|
// Ensure main role exists.
|
2018-07-15 22:59:14 +00:00
|
|
|
Database::exec("
|
2018-07-11 20:30:17 +00:00
|
|
|
INSERT IGNORE INTO `msz_roles`
|
|
|
|
(`role_id`, `role_name`, `role_hierarchy`, `role_colour`, `role_description`, `created_at`)
|
|
|
|
VALUES
|
|
|
|
(1, 'Member', 1, 1073741824, NULL, NOW())
|
|
|
|
");
|
|
|
|
|
|
|
|
// Ensures all users are in the main role.
|
2018-07-15 22:59:14 +00:00
|
|
|
Database::exec('
|
2018-07-11 20:30:17 +00:00
|
|
|
INSERT INTO `msz_user_roles`
|
|
|
|
(`user_id`, `role_id`)
|
|
|
|
SELECT `user_id`, 1 FROM `msz_users` as u
|
|
|
|
WHERE NOT EXISTS (
|
|
|
|
SELECT 1
|
|
|
|
FROM `msz_user_roles` as ur
|
|
|
|
WHERE `role_id` = 1
|
|
|
|
AND u.`user_id` = ur.`user_id`
|
|
|
|
)
|
|
|
|
');
|
|
|
|
|
|
|
|
// Ensures all display_role values are correct with `msz_user_roles`
|
2018-07-15 22:59:14 +00:00
|
|
|
Database::exec('
|
2018-07-11 20:30:17 +00:00
|
|
|
UPDATE `msz_users` as u
|
|
|
|
SET `display_role` = (
|
|
|
|
SELECT ur.`role_id`
|
|
|
|
FROM `msz_user_roles` as ur
|
|
|
|
LEFT JOIN `msz_roles` as r
|
|
|
|
ON r.`role_id` = ur.`role_id`
|
|
|
|
WHERE ur.`user_id` = u.`user_id`
|
|
|
|
ORDER BY `role_hierarchy` DESC
|
|
|
|
LIMIT 1
|
|
|
|
)
|
|
|
|
WHERE NOT EXISTS (
|
|
|
|
SELECT 1
|
|
|
|
FROM `msz_user_roles` as ur
|
|
|
|
WHERE ur.`role_id` = u.`display_role`
|
|
|
|
AND `ur`.`user_id` = u.`user_id`
|
|
|
|
)
|
|
|
|
');
|
2018-07-17 17:55:28 +00:00
|
|
|
|
|
|
|
// Deletes expired sessions
|
|
|
|
Database::exec('
|
|
|
|
DELETE FROM `msz_sessions`
|
|
|
|
WHERE `expires_on` < NOW()
|
|
|
|
');
|
|
|
|
|
2018-07-21 23:54:12 +00:00
|
|
|
// Remove old password reset records, left for a week for possible review
|
|
|
|
Database::exec('
|
|
|
|
DELETE FROM `msz_users_password_resets`
|
|
|
|
WHERE `reset_requested` < NOW() - INTERVAL 1 WEEK
|
|
|
|
');
|
|
|
|
|
2018-07-17 17:55:28 +00:00
|
|
|
// Cleans up the login history table
|
|
|
|
Database::exec('
|
|
|
|
DELETE FROM `msz_login_attempts`
|
|
|
|
WHERE `created_at` < NOW() - INTERVAL 1 YEAR
|
|
|
|
');
|
|
|
|
|
|
|
|
// Cleans up the audit log table
|
|
|
|
Database::exec('
|
|
|
|
DELETE FROM `msz_audit_log`
|
|
|
|
WHERE `log_created` < NOW() - INTERVAL 1 YEAR
|
|
|
|
');
|
2018-07-11 20:30:17 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'migrate':
|
|
|
|
$migrationTargets = [
|
2018-08-06 22:19:35 +00:00
|
|
|
'mysql-main' => __DIR__ . '/database',
|
2018-07-11 20:30:17 +00:00
|
|
|
];
|
|
|
|
$doRollback = !empty($argv[2]) && $argv[2] === 'rollback';
|
|
|
|
$targetDb = isset($argv[$doRollback ? 3 : 2]) ? $argv[$doRollback ? 3 : 2] : null;
|
|
|
|
|
|
|
|
if ($targetDb !== null && !array_key_exists($targetDb, $migrationTargets)) {
|
|
|
|
echo 'Invalid target database connection.' . PHP_EOL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($migrationTargets as $db => $path) {
|
|
|
|
echo "Creating migration manager for '{$db}'..." . PHP_EOL;
|
|
|
|
$migrationManager = new DatabaseMigrationManager(Database::connection($db), $path);
|
|
|
|
$migrationManager->setLogger(function ($log) {
|
|
|
|
echo $log . PHP_EOL;
|
|
|
|
});
|
|
|
|
|
|
|
|
if ($doRollback) {
|
|
|
|
echo "Rolling back last migrations for '{$db}'..." . PHP_EOL;
|
|
|
|
$migrationManager->rollback();
|
|
|
|
} else {
|
|
|
|
echo "Running migrations for '{$db}'..." . PHP_EOL;
|
|
|
|
$migrationManager->migrate();
|
|
|
|
}
|
|
|
|
|
|
|
|
$errors = $migrationManager->getErrors();
|
|
|
|
$errorCount = count($errors);
|
|
|
|
|
|
|
|
if ($errorCount < 1) {
|
|
|
|
echo 'Completed with no errors!' . PHP_EOL;
|
|
|
|
} else {
|
|
|
|
echo PHP_EOL . "There were {$errorCount} errors during the migrations..." . PHP_EOL;
|
|
|
|
|
|
|
|
foreach ($errors as $error) {
|
|
|
|
echo $error . PHP_EOL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-07-18 03:06:27 +00:00
|
|
|
case 'new-mig':
|
|
|
|
if (empty($argv[2])) {
|
|
|
|
echo 'Specify a migration name.' . PHP_EOL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!preg_match('#^([a-z_]+)$#', $argv[2])) {
|
|
|
|
echo 'Migration name may only contain alpha and _ characters.' . PHP_EOL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$filename = date('Y_m_d_His_') . trim($argv[2], '_') . '.php';
|
|
|
|
$filepath = __DIR__ . '/database/' . $filename;
|
|
|
|
$namespace = snake_to_camel($argv[2]);
|
|
|
|
$template = <<<MIG
|
|
|
|
<?php
|
|
|
|
namespace Misuzu\DatabaseMigrations\\$namespace;
|
|
|
|
|
|
|
|
use PDO;
|
|
|
|
|
|
|
|
function migrate_up(PDO \$conn): void
|
|
|
|
{
|
|
|
|
\$conn->exec('
|
|
|
|
CREATE TABLE ...
|
|
|
|
');
|
|
|
|
}
|
|
|
|
|
|
|
|
function migrate_down(PDO \$conn): void
|
|
|
|
{
|
|
|
|
\$conn->exec('DROP TABLE ...');
|
|
|
|
}
|
|
|
|
|
|
|
|
MIG;
|
|
|
|
|
|
|
|
file_put_contents($filepath, $template);
|
|
|
|
|
|
|
|
echo "Template for '{$namespace}' has been created." . PHP_EOL;
|
|
|
|
break;
|
|
|
|
|
2018-07-11 20:30:17 +00:00
|
|
|
default:
|
|
|
|
echo 'Unknown command.' . PHP_EOL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2018-09-16 19:45:40 +00:00
|
|
|
if (!MSZ_DEBUG) {
|
2018-07-21 00:56:47 +00:00
|
|
|
ob_start('ob_gzhandler');
|
|
|
|
}
|
|
|
|
|
|
|
|
// we're running this again because ob_clean breaks gzip otherwise
|
|
|
|
ob_start();
|
2018-07-14 17:57:21 +00:00
|
|
|
|
2018-09-16 00:21:13 +00:00
|
|
|
if (!$app->canAccessStorage()) {
|
2018-03-24 04:31:42 +00:00
|
|
|
echo 'Cannot access storage directory.';
|
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2018-07-15 22:39:39 +00:00
|
|
|
$app->startCache();
|
2018-09-16 19:45:40 +00:00
|
|
|
|
|
|
|
tpl_init(['debug' => MSZ_DEBUG]);
|
|
|
|
|
|
|
|
tpl_var('globals', $app->getSiteInfo());
|
|
|
|
|
|
|
|
tpl_add_function('json_decode', true);
|
|
|
|
tpl_add_function('byte_symbol', true);
|
|
|
|
tpl_add_function('html_link', true);
|
|
|
|
tpl_add_function('html_colour', true);
|
|
|
|
tpl_add_function('url_construct', true);
|
|
|
|
tpl_add_function('country_name', true, 'get_country_name');
|
|
|
|
tpl_add_function('flip', true, 'array_flip');
|
|
|
|
tpl_add_function('first_paragraph', true);
|
|
|
|
tpl_add_function('colour_get_css', true);
|
|
|
|
tpl_add_function('colour_get_css_contrast', true);
|
|
|
|
tpl_add_function('colour_get_inherit', true);
|
|
|
|
tpl_add_function('colour_get_red', true);
|
|
|
|
tpl_add_function('colour_get_green', true);
|
|
|
|
tpl_add_function('colour_get_blue', true);
|
|
|
|
tpl_add_function('parse_line', true);
|
|
|
|
tpl_add_function('parse_text', true);
|
|
|
|
tpl_add_function('asset_url', true);
|
|
|
|
tpl_add_function('vsprintf', true);
|
|
|
|
tpl_add_function('perms_check', true);
|
|
|
|
|
|
|
|
tpl_add_function('git_commit_hash');
|
|
|
|
tpl_add_function('git_branch');
|
|
|
|
tpl_add_function('csrf_token', false, 'tmp_csrf_token');
|
|
|
|
tpl_add_function('startup_time', false, function (float $time = MSZ_STARTUP) {
|
|
|
|
return microtime(true) - $time;
|
|
|
|
});
|
2018-09-16 19:51:14 +00:00
|
|
|
tpl_add_function('sql_query_count', false, [Database::class, 'queryCount']);
|
2018-08-15 01:12:58 +00:00
|
|
|
|
|
|
|
tpl_add_path(__DIR__ . '/templates');
|
2018-07-07 23:24:34 +00:00
|
|
|
|
2018-09-15 23:27:12 +00:00
|
|
|
if ($app->underLockdown()) {
|
2018-03-31 22:28:32 +00:00
|
|
|
http_response_code(503);
|
2018-08-15 01:12:58 +00:00
|
|
|
echo tpl_render('auth/lockdown');
|
2018-03-31 22:28:32 +00:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isset($_COOKIE['msz_uid'], $_COOKIE['msz_sid'])) {
|
|
|
|
$app->startSession((int)$_COOKIE['msz_uid'], $_COOKIE['msz_sid']);
|
2018-04-17 21:01:49 +00:00
|
|
|
|
2018-05-16 02:58:21 +00:00
|
|
|
if ($app->hasActiveSession()) {
|
2018-07-15 22:59:14 +00:00
|
|
|
$bumpUserLast = Database::prepare('
|
2018-05-16 02:58:21 +00:00
|
|
|
UPDATE `msz_users` SET
|
|
|
|
`last_seen` = NOW(),
|
|
|
|
`last_ip` = INET6_ATON(:last_ip)
|
|
|
|
WHERE `user_id` = :user_id
|
|
|
|
');
|
|
|
|
$bumpUserLast->bindValue('last_ip', Net\IPAddress::remote()->getString());
|
|
|
|
$bumpUserLast->bindValue('user_id', $app->getUserId());
|
|
|
|
$bumpUserLast->execute();
|
|
|
|
|
2018-07-15 22:59:14 +00:00
|
|
|
$getUserDisplayInfo = Database::prepare('
|
2018-05-16 02:58:21 +00:00
|
|
|
SELECT
|
|
|
|
u.`user_id`, u.`username`,
|
2018-08-06 22:19:35 +00:00
|
|
|
COALESCE(u.`user_colour`, r.`role_colour`) as `user_colour`
|
2018-05-16 02:58:21 +00:00
|
|
|
FROM `msz_users` as u
|
|
|
|
LEFT JOIN `msz_roles` as r
|
|
|
|
ON u.`display_role` = r.`role_id`
|
|
|
|
WHERE `user_id` = :user_id
|
|
|
|
');
|
|
|
|
$getUserDisplayInfo->bindValue('user_id', $app->getUserId());
|
|
|
|
$userDisplayInfo = $getUserDisplayInfo->execute() ? $getUserDisplayInfo->fetch() : [];
|
2018-08-15 01:12:58 +00:00
|
|
|
tpl_var('current_user', $userDisplayInfo);
|
2018-04-17 21:01:49 +00:00
|
|
|
}
|
2018-03-31 22:28:32 +00:00
|
|
|
}
|
|
|
|
|
2018-07-07 23:24:34 +00:00
|
|
|
$inManageMode = starts_with($_SERVER['REQUEST_URI'], '/manage');
|
2018-08-18 02:31:46 +00:00
|
|
|
$hasManageAccess = perms_check(perms_get_user(MSZ_PERMS_GENERAL, $app->getUserId()), MSZ_PERM_GENERAL_CAN_MANAGE);
|
2018-08-15 01:12:58 +00:00
|
|
|
tpl_var('has_manage_access', $hasManageAccess);
|
2018-03-28 00:35:37 +00:00
|
|
|
|
2018-07-07 23:24:34 +00:00
|
|
|
if ($inManageMode) {
|
|
|
|
if (!$hasManageAccess) {
|
2018-05-26 20:33:05 +00:00
|
|
|
echo render_error(403);
|
2018-03-28 00:35:37 +00:00
|
|
|
exit;
|
|
|
|
}
|
|
|
|
|
2018-08-15 01:12:58 +00:00
|
|
|
tpl_var('manage_menu', manage_get_menu($app->getUserId()));
|
2018-03-28 00:35:37 +00:00
|
|
|
}
|
2018-03-14 01:39:02 +00:00
|
|
|
}
|