appwrite/app/init.php

394 lines
14 KiB
PHP
Raw Normal View History

2019-05-09 06:54:39 +00:00
<?php
2022-05-23 14:54:50 +00:00
if (\file_exists(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
2019-07-31 20:35:42 +00:00
}
2019-05-09 06:54:39 +00:00
2024-03-06 17:34:21 +00:00
use Ahc\Jwt\JWT;
2024-10-01 14:30:47 +00:00
use Appwrite\Auth\Authentication;
use Appwrite\Auth\MFA\Type\TOTP;
use Appwrite\Event\Audit;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Build;
use Appwrite\Event\Certificate;
use Appwrite\Event\Database as EventDatabase;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Delete;
2020-06-27 19:42:38 +00:00
use Appwrite\Event\Event;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Func;
use Appwrite\Event\Mail;
use Appwrite\Event\Messaging;
2024-03-06 17:34:21 +00:00
use Appwrite\Event\Migration;
use Appwrite\Event\Usage;
use Appwrite\Extend\Exception;
use Appwrite\GraphQL\Promises\Adapter\Swoole;
2023-05-23 13:43:03 +00:00
use Appwrite\GraphQL\Schema;
2024-03-06 17:34:21 +00:00
use Appwrite\Hooks\Hooks;
2024-10-01 14:30:47 +00:00
use Appwrite\URL\URL;
use Appwrite\Utopia\Queue\Connections;
use Appwrite\Utopia\Response\Models;
2024-03-06 17:34:21 +00:00
use MaxMind\Db\Reader;
use PHPMailer\PHPMailer\PHPMailer;
2024-10-01 14:30:47 +00:00
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Database\RedisConfig;
use Swoole\Database\RedisPool;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\Database\TimeLimit;
use Utopia\Cache\Adapter\Redis as CacheRedis;
2024-03-06 17:34:21 +00:00
use Utopia\Cache\Adapter\Sharding;
2022-07-13 09:34:56 +00:00
use Utopia\Cache\Cache;
2024-03-06 17:34:21 +00:00
use Utopia\CLI\Console;
2023-05-23 13:43:03 +00:00
use Utopia\Config\Config;
2024-03-06 17:34:21 +00:00
use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Adapter\MySQL;
use Utopia\Database\Adapter\SQL;
2021-08-21 15:09:08 +00:00
use Utopia\Database\Database;
2023-05-23 13:43:03 +00:00
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
2024-10-01 14:30:47 +00:00
use Utopia\DI\Container;
use Utopia\Domains\Domain;
2024-03-06 17:34:21 +00:00
use Utopia\Domains\Validator\PublicDomain;
2023-05-23 13:43:03 +00:00
use Utopia\DSN\DSN;
2024-10-01 14:30:47 +00:00
use Utopia\Http\Http;
use Utopia\Http\Request;
use Utopia\Http\Validator\Hostname;
2024-03-06 17:34:21 +00:00
use Utopia\Locale\Locale;
2024-07-03 13:29:35 +00:00
use Utopia\Logger\Adapter\AppSignal;
use Utopia\Logger\Adapter\LogOwl;
use Utopia\Logger\Adapter\Raygun;
use Utopia\Logger\Adapter\Sentry;
2024-03-06 17:34:21 +00:00
use Utopia\Logger\Log;
use Utopia\Logger\Logger;
use Utopia\Queue;
use Utopia\Registry\Registry;
2021-12-13 07:34:15 +00:00
use Utopia\Storage\Device\Local;
2024-04-01 11:08:46 +00:00
use Utopia\System\System;
2024-10-01 14:30:47 +00:00
use Utopia\VCS\Adapter\Git\GitHub;
2024-02-20 12:06:35 +00:00
2024-10-01 14:30:47 +00:00
require_once __DIR__ . '/init/constants.php';
require_once __DIR__ . '/init/config.php';
require_once __DIR__ . '/init/locale.php';
require_once __DIR__ . '/init/database/filters.php';
require_once __DIR__ . '/init/database/formats.php';
2024-02-20 12:06:35 +00:00
2024-10-01 14:30:47 +00:00
ini_set('memory_limit', '-1');
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
ini_set('default_socket_timeout', -1);
error_reporting(E_ALL);
2024-09-17 08:45:07 +00:00
2024-10-01 14:30:47 +00:00
global $http, $container, $registry;
2019-05-09 06:54:39 +00:00
2024-10-01 14:30:47 +00:00
Http::setMode(System::getEnv('_APP_ENV', Http::MODE_TYPE_PRODUCTION));
2020-06-19 00:04:09 +00:00
2024-10-01 14:30:47 +00:00
if (!Http::isProduction()) {
2024-01-08 20:11:48 +00:00
// Allow specific domains to skip public domain validation in dev environment
// Useful for existing tests involving webhooks
PublicDomain::allow(['request-catcher']);
}
2019-05-09 06:54:39 +00:00
2024-10-01 14:30:47 +00:00
$container = new Container();
$registry = new Registry();
2023-11-14 08:37:52 +00:00
2024-10-01 14:30:47 +00:00
$registry->set('logger', function () {
2022-06-24 09:48:55 +00:00
// Register error logger
2024-04-01 11:02:47 +00:00
$providerName = System::getEnv('_APP_LOGGING_PROVIDER', '');
$providerConfig = System::getEnv('_APP_LOGGING_CONFIG', '');
try {
$loggingProvider = new DSN($providerConfig ?? '');
$providerName = $loggingProvider->getScheme();
$providerConfig = match ($providerName) {
2024-07-03 15:51:58 +00:00
'sentry' => ['key' => $loggingProvider->getPassword(), 'projectId' => $loggingProvider->getUser() ?? '', 'host' => 'https://' . $loggingProvider->getHost()],
'logowl' => ['ticket' => $loggingProvider->getUser() ?? '', 'host' => $loggingProvider->getHost()],
default => ['key' => $loggingProvider->getHost()],
};
} catch (Throwable $th) {
Console::warning('Using deprecated logging configuration. Please update your configuration to use DSN format.' . $th->getMessage());
2024-10-01 14:30:47 +00:00
// Fallback for older Appwrite versions up to 1.5.x that use _APP_LOGGING_PROVIDER and _APP_LOGGING_CONFIG environment variables
$configChunks = \explode(";", $providerConfig);
$providerConfig = match ($providerName) {
2024-10-01 14:30:47 +00:00
'sentry' => ['key' => $configChunks[0], 'projectId' => $configChunks[1] ?? '', 'host' => '',],
'logowl' => ['ticket' => $configChunks[0] ?? '', 'host' => ''],
default => ['key' => $providerConfig],
};
}
2022-05-23 14:54:50 +00:00
if (empty($providerName) || empty($providerConfig)) {
2024-03-06 17:34:21 +00:00
return;
}
2022-05-23 14:54:50 +00:00
if (!Logger::hasProvider($providerName)) {
2022-08-14 05:35:25 +00:00
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Logging provider not supported. Logging is disabled");
}
try {
$adapter = match ($providerName) {
'sentry' => new Sentry($providerConfig['projectId'], $providerConfig['key'], $providerConfig['host']),
'logowl' => new LogOwl($providerConfig['ticket'], $providerConfig['host']),
'raygun' => new Raygun($providerConfig['key']),
'appsignal' => new AppSignal($providerConfig['key']),
default => null
};
} catch (Throwable $th) {
$adapter = null;
}
if ($adapter === null) {
Console::error("Logging provider not supported. Logging is disabled");
return;
}
2024-10-01 14:30:47 +00:00
$logger = new Logger($adapter);
$logger->setSample(0.4);
return $logger;
});
2024-10-01 14:30:47 +00:00
$registry->set('geodb', function () {
/**
* @disregard P1009 Undefined type
*/
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2024-09.mmdb');
});
2022-11-22 07:17:56 +00:00
2024-10-01 14:30:47 +00:00
$registry->set('hooks', function () {
return new Hooks();
});
2024-10-01 14:30:47 +00:00
$registry->set(
'pools',
(function () {
$fallbackForDB = 'db_main=' . URL::unparse([
'scheme' => 'mariadb',
'host' => System::getEnv('_APP_DB_HOST', 'mariadb'),
'port' => System::getEnv('_APP_DB_PORT', '3306'),
'user' => System::getEnv('_APP_DB_USER', ''),
'pass' => System::getEnv('_APP_DB_PASS', ''),
'path' => System::getEnv('_APP_DB_SCHEMA', ''),
]);
$fallbackForRedis = 'redis_main=' . URL::unparse([
'scheme' => 'redis',
'host' => System::getEnv('_APP_REDIS_HOST', 'redis'),
'port' => System::getEnv('_APP_REDIS_PORT', '6379'),
'user' => System::getEnv('_APP_REDIS_USER', ''),
'pass' => System::getEnv('_APP_REDIS_PASS', ''),
]);
2019-05-09 06:54:39 +00:00
2024-10-01 14:30:47 +00:00
$connections = [
'console' => [
'type' => 'database',
'dsns' => System::getEnv('_APP_CONNECTIONS_DB_CONSOLE', $fallbackForDB),
'multiple' => false,
'schemes' => ['mariadb', 'mysql'],
],
'database' => [
'type' => 'database',
'dsns' => System::getEnv('_APP_CONNECTIONS_DB_PROJECT', $fallbackForDB),
'multiple' => true,
'schemes' => ['mariadb', 'mysql'],
],
'queue' => [
'type' => 'queue',
'dsns' => System::getEnv('_APP_CONNECTIONS_QUEUE', $fallbackForRedis),
'multiple' => false,
'schemes' => ['redis'],
],
'pubsub' => [
'type' => 'pubsub',
'dsns' => System::getEnv('_APP_CONNECTIONS_PUBSUB', $fallbackForRedis),
'multiple' => false,
'schemes' => ['redis'],
],
'cache' => [
'type' => 'cache',
'dsns' => System::getEnv('_APP_CONNECTIONS_CACHE', $fallbackForRedis),
'multiple' => true,
'schemes' => ['redis'],
],
];
2024-10-01 14:30:47 +00:00
$pools = [];
$poolSize = (int)System::getEnv('_APP_POOL_SIZE', 64);
2024-10-01 14:30:47 +00:00
foreach ($connections as $key => $connection) {
$dsns = $connection['dsns'] ?? '';
$multiple = $connection['multiple'] ?? false;
$schemes = $connection['schemes'] ?? [];
$dsns = explode(',', $connection['dsns'] ?? '');
$config = [];
2024-10-01 14:30:47 +00:00
foreach ($dsns as &$dsn) {
$dsn = explode('=', $dsn);
$name = ($multiple) ? $key . '_' . $dsn[0] : $key;
$config[] = $name;
$dsn = $dsn[1] ?? '';
2024-10-01 14:30:47 +00:00
if (empty($dsn)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Missing value for DSN connection in {$key}");
}
2023-12-08 17:33:35 +00:00
2024-10-01 14:30:47 +00:00
$dsn = new DSN($dsn);
$dsnHost = $dsn->getHost();
$dsnPort = $dsn->getPort();
$dsnUser = $dsn->getUser();
$dsnPass = $dsn->getPassword();
$dsnScheme = $dsn->getScheme();
$dsnDatabase = $dsn->getPath();
2024-10-01 14:30:47 +00:00
if (!in_array($dsnScheme, $schemes)) {
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid console database scheme");
}
2022-10-19 08:35:30 +00:00
2024-10-01 14:30:47 +00:00
/**
* Get Resource
*
* Creation could be reused accross connection types like database, cache, queue, etc.
*
* Resource assignment to an adapter will happen below.
*/
switch ($dsnScheme) {
case 'mysql':
case 'mariadb':
$pool = new PDOPool(
(new PDOConfig())
->withHost($dsnHost)
->withPort($dsnPort)
->withDbName($dsnDatabase)
->withCharset('utf8mb4')
->withUsername($dsnUser)
->withPassword($dsnPass)
->withOptions([
// No need to set PDO::ATTR_ERRMODE it is overwitten in PDOProxy
// PDO::ATTR_TIMEOUT => 3, // Seconds
// PDO::ATTR_PERSISTENT => true,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => true,
PDO::ATTR_STRINGIFY_FETCHES => true,
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
]),
$poolSize
);
2022-11-15 16:03:42 +00:00
break;
2024-10-01 14:30:47 +00:00
case 'redis':
$pool = new RedisPool(
(new RedisConfig())
->withHost($dsnHost)
->withPort((int)$dsnPort)
->withAuth($dsnPass ?? ''),
$poolSize
);
2022-10-16 22:49:53 +00:00
break;
2022-10-19 08:35:30 +00:00
2022-10-16 22:49:53 +00:00
default:
2024-10-01 14:30:47 +00:00
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Invalid scheme");
2022-10-16 22:49:53 +00:00
}
2022-10-19 08:35:30 +00:00
2024-10-01 14:30:47 +00:00
$pools['pools-' . $key . '-' . $name] = [
'pool' => $pool,
'dsn' => $dsn,
];
}
2024-10-01 14:30:47 +00:00
Config::setParam('pools-' . $key, $config);
}
2022-10-15 14:14:17 +00:00
2024-10-01 14:30:47 +00:00
return function () use ($pools): array {
return $pools;
};
})()
);
2023-08-20 12:29:43 +00:00
2024-10-01 14:30:47 +00:00
$registry->set('smtp', function () {
2019-08-08 21:49:46 +00:00
$mail = new PHPMailer(true);
2019-05-09 06:54:39 +00:00
2019-08-08 21:49:46 +00:00
$mail->isSMTP();
2019-05-09 06:54:39 +00:00
2024-04-01 11:02:47 +00:00
$username = System::getEnv('_APP_SMTP_USERNAME');
$password = System::getEnv('_APP_SMTP_PASSWORD');
2019-08-08 21:49:46 +00:00
2019-10-01 04:57:41 +00:00
$mail->XMailer = 'Appwrite Mailer';
2024-04-01 11:02:47 +00:00
$mail->Host = System::getEnv('_APP_SMTP_HOST', 'smtp');
$mail->Port = System::getEnv('_APP_SMTP_PORT', 25);
2023-08-30 04:56:08 +00:00
$mail->SMTPAuth = !empty($username) && !empty($password);
2019-10-01 04:57:41 +00:00
$mail->Username = $username;
$mail->Password = $password;
2024-04-01 11:02:47 +00:00
$mail->SMTPSecure = System::getEnv('_APP_SMTP_SECURE', '');
2020-01-11 13:58:02 +00:00
$mail->SMTPAutoTLS = false;
2020-06-12 16:49:56 +00:00
$mail->CharSet = 'UTF-8';
2019-08-08 21:49:46 +00:00
2024-04-01 11:02:47 +00:00
$from = \urldecode(System::getEnv('_APP_SYSTEM_EMAIL_NAME', APP_NAME . ' Server'));
$email = System::getEnv('_APP_SYSTEM_EMAIL_ADDRESS', APP_EMAIL_TEAM);
$mail->setFrom($email, $from);
$mail->addReplyTo($email, $from);
2019-05-09 06:54:39 +00:00
2019-08-08 21:49:46 +00:00
$mail->isHTML(true);
2019-09-28 01:48:50 +00:00
2019-08-08 21:49:46 +00:00
return $mail;
2019-05-09 06:54:39 +00:00
});
2023-10-19 04:21:11 +00:00
2024-10-01 14:30:47 +00:00
$registry->set('promiseAdapter', function () {
return new Swoole();
2022-08-10 13:49:56 +00:00
});
2023-05-23 13:43:03 +00:00
2024-10-01 14:30:47 +00:00
$registry->set('db', function () {
// This is usually for our workers or CLI commands scope
$dbHost = System::getEnv('_APP_DB_HOST', '');
$dbPort = System::getEnv('_APP_DB_PORT', '');
$dbUser = System::getEnv('_APP_DB_USER', '');
$dbPass = System::getEnv('_APP_DB_PASS', '');
$dbScheme = System::getEnv('_APP_DB_SCHEMA', '');
2023-05-23 13:43:03 +00:00
2024-10-01 14:30:47 +00:00
return new PDO(
"mysql:host={$dbHost};port={$dbPort};dbname={$dbScheme};charset=utf8mb4",
$dbUser,
$dbPass,
SQL::getPDOAttributes()
2023-05-23 13:43:03 +00:00
);
2023-08-29 18:25:00 +00:00
});
2023-04-26 08:21:10 +00:00
2024-10-01 14:30:47 +00:00
// Autoload
class_exists(JWT::class, true);
class_exists(DSN::class, true);
class_exists(Log::class, true);
class_exists(TOTP::class, true);
class_exists(Mail::class, true);
class_exists(Func::class, true);
class_exists(Cache::class, true);
class_exists(Abuse::class, true);
class_exists(MySQL::class, true);
class_exists(Event::class, true);
class_exists(Audit::class, true);
class_exists(Usage::class, true);
class_exists(Local::class, true);
class_exists(Build::class, true);
class_exists(Locale::class, true);
class_exists(Delete::class, true);
class_exists(GitHub::class, true);
class_exists(Schema::class, true);
class_exists(Domain::class, true);
class_exists(Console::class, true);
class_exists(Request::class, true);
class_exists(MariaDB::class, true);
class_exists(Document::class, true);
class_exists(Sharding::class, true);
class_exists(Database::class, true);
class_exists(Hostname::class, true);
class_exists(TimeLimit::class, true);
class_exists(Migration::class, true);
class_exists(Messaging::class, true);
class_exists(CacheRedis::class, true);
class_exists(Connections::class, true);
class_exists(Certificate::class, true);
class_exists(EventDatabase::class, true);
class_exists(Authorization::class, true);
class_exists(Authentication::class, true);
class_exists(Queue\Connection\Redis::class, true);
require_once __DIR__ . '/init/resources.php';
Models::init();