SENTRY_SAMPLE_RATE,
'curl_method' => SENTRY_CURL_METHOD,
'timeout' => SENTRY_TIMEOUT
]);
try {
$sentry->install();
} catch (\Raven_Exception $e) {
// This should land in the logfiles at least but not block script execution
trigger_error('Failed to install Sentry client: '.$e->getMessage(), E_USER_WARNING);
}
}
//database stuff
$host = DB_HOST;
$db = DB_NAME;
$charset = 'utf8mb4';
$dsn_master = "mysql:host=$host;dbname=$db;charset=$charset";
$dsn_slaves = [];
foreach (DB_READ_HOSTS ?? [] AS $slave_host) {
$slave_db = DB_READ_NAME;
$slave_port = 3306;
if (strpos($slave_host, ':') !== false) {
[$slave_host, $slave_port] = explode(':', $slave_host, 2);
}
$dsn_slaves[] = "mysql:host=$slave_host;port=$slave_port;dbname=$slave_db;charset=$charset";
}
$opt = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_PERSISTENT => defined('DB_PERSISTENT') ? (bool)DB_PERSISTENT : false,
];
class SQL extends PDO {
private $debug = [];
private $time_array = [];
/** @var \PDO */
private $slave_sql;
private $credentials = [];
private $isConnected = false;
public function __construct(string $dsn_master, array $dsn_slaves, $username = null, $passwd = null, $options = null)
{
$this->credentials = [
'dsn_master' => $dsn_master,
'dsn_slaves' => $dsn_slaves,
'username' => $username,
'passwd' => $passwd,
'options' => $options,
];
}
private function ensureConnected(): void
{
if (!$this->isConnected) {
$dsn_master = $this->credentials['dsn_master'];
$dsn_slaves = $this->credentials['dsn_slaves'];
$username = $this->credentials['username'];
$passwd = $this->credentials['passwd'];
$options = $this->credentials['options'];
$this->credentials = [];
// Establish connection with master
parent::__construct($dsn_master, $username, $passwd, $options);
$this->isConnected = true;
// Randomize pick order
shuffle($dsn_slaves);
while (!empty($dsn_slaves)) {
$dsn_slave = array_pop($dsn_slaves);
$error = 'Slave failed with unknown reason';
try {
$this->slave_sql = new \PDO($dsn_slave, DB_READ_USER, DB_READ_PASSWORD, $options);
// Try a ping
if (false === $this->slave_sql->query('SELECT 1')) {
throw new \RuntimeException('Ping on slave failed!');
}
// Connection successful
return;
} catch (\PDOException $e) {
$error = sprintf('Slave failed with error code %s', $e->getCode());
} catch (\Throwable $e) {
$error = sprintf('Unexpected exception: %s', $e->getMessage());
}
// A slave failed, report warning to sentry
trigger_error($error, E_USER_WARNING);
}
// Fall back to master
$this->slave_sql = $this;
}
}
public function query_read($name, $query, $fetch, $pdo_mode, $expiry = 0) {
global $memcached;
$name = str_replace(' ', '_', $name);
if ($expiry < 0) {
$memcached->delete($name);
}
$start = microtime(true);
$cache = $memcached->get($name);
$from_cache = 'Y';
if ($cache === FALSE) {
$this->ensureConnected();
if ($fetch === 'fetchAll') {
$cache = $this->slave_sql->query($query)->fetchAll($pdo_mode);
}
elseif ($fetch === 'fetchColumn') {
$cache = $this->slave_sql->query($query)->fetchColumn();
}
else {
$cache = $this->slave_sql->query($query)->fetch($pdo_mode);
}
if ($expiry >= 0) {
$memcached->set($name, $cache, $expiry);
}
$from_cache = 'N';
}
$time_taken = round((microtime(true) - $start) * 1000, 2);
$this->time_array[] = $time_taken;
$this->debug[] = [$name, nl2br(trim($query)), $fetch, $from_cache, $time_taken];
return $cache;
}
public function prep($name, $query, $bind, $fetch, $pdo_mode = '', $expiry = 0, $force_master = false) {
global $memcached;
$name = str_replace(' ', '_', $name);
if ($expiry < 0) {
$memcached->delete($name);
}
$start = microtime(true);
$cache = $memcached->get($name);
$from_cache = 'Y';
if ($cache === FALSE) {
$this->ensureConnected();
$stmt = $force_master ? $this->prepare($query) : $this->slave_sql->prepare($query);
$stmt->execute($bind);
switch ($fetch) {
case 'fetch':
$cache = $stmt->fetch($pdo_mode);
break;
case 'fetchColumn':
$cache = $stmt->fetchColumn();
break;
default:
$cache = $stmt->fetchAll($pdo_mode);
break;
}
if ($expiry >= 0) {
$memcached->set($name, $cache, $expiry);
}
$from_cache = 'N';
}
$time_taken = round((microtime(true) - $start) * 1000, 2);
$this->time_array[] = $time_taken;
$query = preg_replace(array_fill(0, count($bind), '/\?/'), array_fill(0, count($bind), "~"), $query, 1);
$query = preg_replace(array_fill(0, count($bind), '/~/'), $bind, $query, 1);
$this->debug[] = [$name, nl2br(trim($query)), $fetch, $from_cache, $time_taken];
return $cache;
}
public function modify($name, $query, $bind) {
$name = str_replace(' ', '_', $name);
$start = microtime(true);
$from_cache = '/';
$this->ensureConnected();
$stmt = $this->prepare($query);
$stmt->execute($bind);
$time_taken = round((microtime(true) - $start) * 1000, 2);
$this->time_array[] = $time_taken;
$query = preg_replace(array_fill(0, count($bind), '/\?/'), array_fill(0, count($bind), "~"), $query, 1);
$query = preg_replace(array_fill(0, count($bind), '/~/'), $bind, $query, 1);
$this->debug[] = [$name, nl2br(trim($query)), 'modify', $from_cache, $time_taken];
return $this->lastInsertId();
}
public function debug() {
global $memcached;
// ======== Add sql table
$return = "
|
N |
Q |
M |
C |
T |
";
foreach ($this->debug as $key => $array) {
++$key;
$return .= "";
$return .= "$key | ";
foreach ($array as $value) {
$return .= "$value | ";
}
$return .= "
";
}
$total_time = array_sum($this->time_array);
$return .= "
# |
Name |
Query |
Mode |
Cache |
$total_time |
";
if (defined('CAPTURE_CACHE_STATS') && CAPTURE_CACHE_STATS) {
// ======== Add cache table
$cacheDebug = $memcached->toArray();
$return .= "
|
Method |
Time (s) |
Key |
Result |
Call Stack |
";
$return .= "
Hits: {$cacheDebug['stats']['hit']}, Misses: {$cacheDebug['stats']['miss']}, Sets: {$cacheDebug['stats']['set']}, Deletes: {$cacheDebug['stats']['delete']} |
";
foreach ($cacheDebug['log'] as $key => $cacheLogRow) {
$return .= "
$key |
$cacheLogRow[method] |
$cacheLogRow[time] |
$cacheLogRow[key] |
".$memcached->getResultString($cacheLogRow['result'])." |
- ".implode("
- ",$cacheLogRow['call_stack'])."
|
";
}
$total_time = array_sum($this->time_array);
$return .= "
# |
Method |
Time (s) |
Key |
Result |
$cacheDebug[time] |
";
}
$return .= "
";
return $return;
}
}
try {
$sql = new SQL($dsn_master, $dsn_slaves, DB_USER, DB_PASSWORD, $opt);
} catch (\PDOException $e) {
print file_get_contents(ABSPATH . '/dberror.html');
// Send to sentry
trigger_error('DB is down: '.$e->getMessage(), E_USER_ERROR);
die();
}
//cache
require_once ABSPATH . '/scripts/classes/cache.class.req.php';
if (defined('CAPTURE_CACHE_STATS') && CAPTURE_CACHE_STATS) {
$memcached = new Cache();
} else {
$memcached = new Synced_Memcached();
}
$memcached->addServer(MEMCACHED_HOST, 11211);
//including files
require_once (ABSPATH . '/scripts/functions.req.php');
foreach (read_dir('scripts/classes') as $file) {
$file = str_replace(['..', '/', '\\', '`', 'ยด', '"', "'"], '', $file);
require_once (ABSPATH . "/scripts/classes/$file");
} //require every file in classes
require_once (ABSPATH . '/scripts/display.req.php');
//set vars
$ip = substr($_SERVER['HTTP_CF_CONNECTING_IP'] ?? $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? 'cli', 0, 45);
if (\strpos($ip, ',') !== false) {
$_tmp = explode(',', $ip);
$ip = reset($_tmp);
unset($_tmp);
}
define('_IP', $ip);
$ipService = new \Mangadex\Model\IpLocator();
$mdAtHomeClient = new Mangadex\Model\MdexAtHomeClient();
$hentai_toggle = max(0,min(2, $_COOKIE['mangadex_h_toggle'] ?? 0));
$theme_cookie = (int)($_COOKIE['mangadex_theme'] ?? 1);
$display_lang_cookie = (int)($_COOKIE['mangadex_display_lang'] ?? 0);
$filter_langs_cookie = $_COOKIE['mangadex_filter_langs'] ?? '';
$title_mode_cookie = (int)($_COOKIE['mangadex_title_mode'] ?? 0);
$_GET['page'] = $_GET['page'] ?? '';
$timestamp = time();
//require other stuff
require_once (ABSPATH . '/scripts/JBBCode/Parser.php');
$parser = new JBBCode\Parser();
$parser->addCodeDefinitionSet(new JBBCode\DefaultCodeDefinitionSet());