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 = " "; foreach ($this->debug as $key => $array) { ++$key; $return .= ""; $return .= ""; foreach ($array as $value) { $return .= ""; } $return .= ""; } $total_time = array_sum($this->time_array); $return .= "
N Q M C T
$key$value
# Name Query Mode Cache $total_time
"; if (defined('CAPTURE_CACHE_STATS') && CAPTURE_CACHE_STATS) { // ======== Add cache table $cacheDebug = $memcached->toArray(); $return .= " "; $return .= " "; foreach ($cacheDebug['log'] as $key => $cacheLogRow) { $return .= " "; } $total_time = array_sum($this->time_array); $return .= "
Method Time (s) Key Result Call Stack
Hits: {$cacheDebug['stats']['hit']}, Misses: {$cacheDebug['stats']['miss']}, Sets: {$cacheDebug['stats']['set']}, Deletes: {$cacheDebug['stats']['delete']}
$key $cacheLogRow[method] $cacheLogRow[time] $cacheLogRow[key] ".$memcached->getResultString($cacheLogRow['result'])."
  • ".implode("
  • ",$cacheLogRow['call_stack'])."
# 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());