mirror of
https://github.com/holo-gfx/mangadex.git
synced 2024-11-28 18:28:57 -05:00
1034 lines
35 KiB
PHP
1034 lines
35 KiB
PHP
<?php
|
||
/* mysql_escape_mimic($inp)
|
||
* rand_string($length)
|
||
* get_time_ago($string)
|
||
* number_format_mod($number)
|
||
* format_filesize($bytes)
|
||
* reArrayFiles(&$file_post)
|
||
* scrape_torrent($scraper, $external, $announce_url, $info_hash_array)
|
||
* decode_torrent($torrent, $torrent_hash)
|
||
* calc_total_transfer($completed, $size)
|
||
* update_stats($db, $s, $l, $c, $id)
|
||
*/
|
||
|
||
/*************************************
|
||
* General functions
|
||
*************************************/
|
||
function is_banned_asn($ip) {
|
||
$ch = curl_init();
|
||
// IMPORTANT: the below line is a security risk, read https://paragonie.com/blog/2017/10/certainty-automated-cacert-pem-management-for-php-software
|
||
// in most cases, you should set it to true
|
||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($ch, CURLOPT_URL, "https://api.iptoasn.com/v1/as/ip/$ip");
|
||
$result = curl_exec($ch);
|
||
curl_close($ch);
|
||
|
||
$obj = json_decode($result);
|
||
|
||
if (in_array($obj->as_number, BANNED_ASNS))
|
||
return TRUE;
|
||
else
|
||
return FALSE;
|
||
}
|
||
|
||
function bayesian_average($ratings_array, $average_no_ratings_per_title, $average_rating, $site_average_rating) {
|
||
$w = count($ratings_array) / (count($ratings_array) + $average_no_ratings_per_title);
|
||
return $w * $average_rating + (1 - $w) * $site_average_rating;
|
||
}
|
||
|
||
function get_browser_lang($server) {
|
||
$lang_header = $server['HTTP_ACCEPT_LANGUAGE'] ?? 'en-GB';
|
||
if (!preg_match('#[a-zA-Z-_]+#', $lang_header))
|
||
$lang_header = 'en-GB';
|
||
$array = explode('-', $lang_header);
|
||
return $array[0];
|
||
}
|
||
|
||
|
||
|
||
function get_country_code($ip = null) {
|
||
if (!isset($ip))
|
||
$ip = _IP;
|
||
|
||
global $ipService;
|
||
|
||
$locationRecord = $ipService->getCountryRecord($ip);
|
||
|
||
if (isset($locationRecord) && is_object($locationRecord)) {
|
||
$countryCode = ($locationRecord->country ?? $locationRecord->registeredCountry ?? $locationRecord->representedCountry)->isoCode ?? '??';
|
||
} else {
|
||
$countryCode = '??';
|
||
}
|
||
|
||
return strtolower($countryCode);
|
||
}
|
||
|
||
function get_continent_code($ip = null) {
|
||
if (!isset($ip))
|
||
$ip = _IP;
|
||
|
||
global $ipService;
|
||
|
||
$locationRecord = $ipService->getCountryRecord($ip);
|
||
|
||
if (isset($locationRecord) && is_object($locationRecord)) {
|
||
$continentCode = $locationRecord->continent->code ?? '??';
|
||
} else {
|
||
$continentCode = '??';
|
||
}
|
||
|
||
return strtolower($continentCode);
|
||
}
|
||
|
||
/**
|
||
* returns the server id for its code. codes are for example "eu", "eu2", "na", "na2", "na3"
|
||
* @param $code
|
||
* @return int the server id that matches its code, -1 if servercode was invalid
|
||
*/
|
||
function get_server_id_by_code($code) {
|
||
$code = strtolower($code);
|
||
|
||
foreach (IMAGE_SERVER_INFO AS $server_id => $server_info) {
|
||
if ($server_info['server_code'] === $code) {
|
||
return $server_id;
|
||
}
|
||
}
|
||
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* returns the closest image server id by the users location with a random fallback. keeps the selected server id sticky
|
||
* by hashing its with the ip.
|
||
* @param null $continentCode
|
||
* @param null $countryCode
|
||
* @param null $serverContinentCode
|
||
* @param null $selectedServerId
|
||
* @return int always returns a valid server, even if region wasnt detected
|
||
*/
|
||
|
||
|
||
function get_server_id_by_geography($ip = null, &$continentCode = null, &$countryCode = null, &$serverContinentCode = null, &$selectedServerId = null) {
|
||
|
||
if (!isset($ip))
|
||
$ip = _IP;
|
||
|
||
global $ipService;
|
||
|
||
$locationRecord = $ipService->getCountryRecord($ip);
|
||
if (isset($locationRecord) && is_object($locationRecord)) {
|
||
$continentCode = $locationRecord->continent->code ?? '??';
|
||
$countryCode = ($locationRecord->country ?? $locationRecord->registeredCountry ?? $locationRecord->representedCountry)->isoCode ?? '??';
|
||
} else {
|
||
$continentCode = '??';
|
||
$countryCode = '??';
|
||
}
|
||
|
||
$serverContinentCode = IMAGE_SERVER_CONTINENT_MAPPING[strtolower($continentCode)] ?? '??';
|
||
|
||
$possible_server_ids = [];
|
||
|
||
// Collect all image servers that belong to this continent
|
||
foreach (IMAGE_SERVER_INFO AS $server_id => $server_info) {
|
||
if ($server_info['continent_code'] === strtolower($serverContinentCode))
|
||
$possible_server_ids[] = $server_id;
|
||
}
|
||
|
||
// Collect the numeric last part of the ip xxx.xxx.xxx.123, so 123 is our hash for the sticky random server selection
|
||
// if its ipv6, take the last bit and convert it from hex to int
|
||
if (strpos(_IP, ':') !== false) {
|
||
$tmp = explode(':', $ip);
|
||
$ip_hash = (int)hexdec(end($tmp));
|
||
} else {
|
||
$tmp = explode('.', $ip);
|
||
$ip_hash = (int)end($tmp);
|
||
}
|
||
|
||
if (empty($possible_server_ids)) {
|
||
// Not sure when this happens, but select one at random or we get into a zero division error below
|
||
$allServerIds = \array_keys(IMAGE_SERVER_INFO);
|
||
return $allServerIds[\array_rand($allServerIds)];
|
||
}
|
||
|
||
$index = $ip_hash % count($possible_server_ids); // This returns a random sticky index for available server ids
|
||
$selectedServerId = $possible_server_ids[$index] ?? 0;
|
||
|
||
return $selectedServerId;
|
||
}
|
||
|
||
class Notify_Callback {
|
||
private $post_id;
|
||
|
||
function __construct($post_id) {
|
||
$this->post_id = (int)$post_id;
|
||
}
|
||
|
||
public function notify($matches) {
|
||
global $sql, $user, $timestamp, $memcached;
|
||
|
||
$username = substr($matches[0], 1);
|
||
$user_id = $sql->prep($matches[0], "SELECT user_id FROM mangadex_users WHERE username = ?", [$username], 'fetchColumn', '');
|
||
|
||
if ($user_id) {
|
||
// Check if the user $user_id has the current user on his blocklist.
|
||
$mention_user = new User($user_id, 'user_id');
|
||
$blockList = $mention_user->get_blocked_user_ids();
|
||
|
||
// Add the notification only if this user doesnt have the post author on his blocklist
|
||
if (!isset($blockList[$user->user_id])) {
|
||
$sql->modify('add_notification', " INSERT IGNORE INTO mangadex_notifications (notification_id, post_id, mentioner_user_id, mentionee_user_id, timestamp, is_read)
|
||
VALUES (NULL, ?, ?, ?, ?, 0) ", [$this->post_id, $user->user_id, $user_id, $timestamp]);
|
||
|
||
$memcached->delete("user_{$user_id}_unread_notifications");
|
||
$memcached->delete("notifications_$user_id");
|
||
}
|
||
|
||
return "@[url=" . URL . "user/$user_id]{$username}[/url]";
|
||
}
|
||
else
|
||
return $matches[0];
|
||
}
|
||
}
|
||
|
||
function parse_template($templateName, $templateVar = [], $templateDir = 'bootstrap4')
|
||
{
|
||
$absPath = ABSPATH . '/templates/' . $templateDir . '/' . str_replace(['../', './', '`', '´'], '', $templateName) . '.tpl.php';
|
||
if (!file_exists($absPath))
|
||
throw new Exception("Template $templateName not found!");
|
||
|
||
ob_start();
|
||
include ($absPath);
|
||
$content = ob_get_clean();
|
||
return $content;
|
||
}
|
||
|
||
function get_results_as_object($results, $id_name) {
|
||
$obj = new \stdClass();
|
||
foreach ($results as $i => $row) {
|
||
$obj->{$i} = new \stdClass();
|
||
foreach ($row as $key => $value) {
|
||
$obj->{$i}->$key = $value;
|
||
}
|
||
$obj->{$i}->$id_name = $i;
|
||
}
|
||
|
||
return $obj;
|
||
}
|
||
|
||
function thread_label($name) {
|
||
return str_replace(array_keys(THREAD_LABELS), THREAD_LABELS, $name);
|
||
}
|
||
|
||
function make_links_clickable($text) {
|
||
$res = preg_replace("!(^|\s)((?:(?:f|ht)tp(?:s)?:\/\/)[-a-zA-Zа-яА-Я()0-9@:%_+.~#?&;\/\/=]+)($|\s)!ui", "$1<a href='$2' target='_blank' rel='nofollow'>$2</a>$3", $text);
|
||
return $res;
|
||
}
|
||
|
||
function hash_array($array) {
|
||
return hash('crc32b', serialize($array));
|
||
}
|
||
|
||
function validate_level($user, $type) {
|
||
$levels = [
|
||
'guest' => 1,
|
||
'validating' => 2,
|
||
'member' => 3,
|
||
'contributor' => 4,
|
||
'gl' => 5,
|
||
'pu' => 6,
|
||
'pr' => 10,
|
||
'mod' => 11,
|
||
'gmod' => 12,
|
||
'admin' => 15
|
||
];
|
||
return isset($levels[$type]) && $user->level_id >= $levels[$type];
|
||
}
|
||
|
||
function get_ip_bans()
|
||
{
|
||
global $sql;
|
||
|
||
$banlist = $sql->prep('ip_banlist', "SELECT * FROM mangadex_ip_bans WHERE expires > UNIX_TIMESTAMP() ORDER BY expires ASC", [], 'fetchAll', PDO::FETCH_ASSOC, 3600);
|
||
$ips = [];
|
||
foreach ($banlist AS $row) {
|
||
if ($row['expires'] > time())
|
||
$ips[] = $row['ip'];
|
||
}
|
||
return $ips;
|
||
}
|
||
|
||
function sanitizePostText($text) {
|
||
// Strip excessive amount of space/tabs/newline
|
||
$text = preg_replace('#\s{5,}#', "\n", $text);
|
||
// break up long words
|
||
$match = [];
|
||
if (preg_match_all("#[^\s]{64,}#", $text, $match, PREG_SET_ORDER)) {
|
||
foreach ($match as $m) {
|
||
$text = str_replace($m[0], implode(' ', str_split($m[0], 64)), $text);
|
||
}
|
||
}
|
||
|
||
return $text;
|
||
}
|
||
|
||
function pagination($num_rows, $current_page, $limit, $sort = 0) {
|
||
$array['num_rows'] = $num_rows;
|
||
$array['current_page'] = $current_page;
|
||
$array['limit'] = $limit;
|
||
$array['sort'] = $sort;
|
||
$array['offset'] = $limit * $current_page - $limit;
|
||
$array['last_page'] = ceil($num_rows / $limit);
|
||
|
||
if ($current_page == 1) {
|
||
$array['previous_page'] = "-";
|
||
$array['previous_class'] = "disabled";
|
||
}
|
||
else {
|
||
$array['previous_page'] = $current_page - 1;
|
||
$array['previous_class'] = "paging";
|
||
}
|
||
if ($current_page == $array['last_page']) {
|
||
$array['next_page'] = "-";
|
||
$array['next_class'] = "disabled";
|
||
}
|
||
else {
|
||
$array['next_page'] = $current_page + 1;
|
||
$array['next_class'] = "paging";
|
||
}
|
||
|
||
return $array;
|
||
}
|
||
|
||
function slugify($str) {
|
||
$slugified = trim(preg_replace('/\W+/', '-', strtolower(html_entity_decode($str))), "-");
|
||
if (empty($slugified)) {
|
||
$slugified = '-';
|
||
}
|
||
return $slugified;
|
||
}
|
||
|
||
function prepare_in($array) {
|
||
return count($array) > 0 ? str_repeat("?,", count($array) - 1) . "?" : "";
|
||
}
|
||
|
||
function prepare_int($number) {
|
||
if (is_int($number))
|
||
return $number;
|
||
else
|
||
die("Error: Possible SQL injection.");
|
||
}
|
||
|
||
function prepare_numeric($number) {
|
||
if (is_numeric($number))
|
||
return $number;
|
||
else
|
||
die("Error: Possible SQL injection.");
|
||
}
|
||
|
||
function prepare_identifier($ident) {
|
||
return "`" . str_replace("`", "``", $ident) . "`";
|
||
}
|
||
|
||
function prepare_orderby($order, $allowed_orders) {
|
||
$key = array_search($order, $allowed_orders); // see if we have such a name
|
||
return $allowed_orders[$key]; //if not, first one will be set automatically. smart enuf :)
|
||
}
|
||
|
||
function read_dir($dir) {
|
||
if ($dir[0] !== '/') {
|
||
// make absolute if dir is relative
|
||
$dir = rtrim(ABSPATH, '/') . '/' . $dir;
|
||
}
|
||
return array_diff(@scandir($dir, SCANDIR_SORT_ASCENDING), array('..', '.'));
|
||
}
|
||
|
||
function remove_padding($str) {
|
||
if (ltrim($str, '0') == '' || substr(ltrim($str, '0'), 0, 1) == '.') {
|
||
return $str;
|
||
} else {
|
||
return ltrim($str, '0');
|
||
}
|
||
}
|
||
|
||
function strpos_recursive($haystack, $needle, $offset = 0, &$results = []) {
|
||
$offset = strpos($haystack, $needle, $offset);
|
||
if($offset === false) {
|
||
return $results;
|
||
} else {
|
||
$results[] = $offset;
|
||
return strpos_recursive($haystack, $needle, ($offset + 1), $results);
|
||
}
|
||
}
|
||
|
||
function validate_image($file, $name = 'file', $max_filesize = MAX_IMAGE_FILESIZE) {
|
||
$arr = explode(".", $file["name"]);
|
||
$ext = strtolower(end($arr));
|
||
$validate_extention = in_array($ext, ALLOWED_IMG_EXT);
|
||
$validate_file_size = ($file["size"] <= $max_filesize); //check file size
|
||
$validate_mime = in_array(mime_content_type($file["tmp_name"]), ALLOWED_MIME_TYPES);
|
||
$get_image_size = getimagesize($file["tmp_name"]);
|
||
|
||
if ($_FILES[$name]["error"])
|
||
return display_alert("danger", "Failed", "Error Code ({$file['error']}).");
|
||
elseif (!$validate_file_size)
|
||
return display_alert("danger", "Failed", "File size exceeds 1 MB.");
|
||
elseif (!$validate_extention)
|
||
return display_alert("danger", "Failed", "A .$ext file, not an image.");
|
||
elseif (!$validate_mime)
|
||
return display_alert("danger", "Failed", "Image failed validation.");
|
||
elseif (!$get_image_size)
|
||
return display_alert("danger", "Failed", "Image cannot be processed.");
|
||
else
|
||
return "";
|
||
}
|
||
|
||
function get_ext($filename, $type) {
|
||
$value = explode(".", $filename);
|
||
if ($type)
|
||
return strtolower(end($value));
|
||
else
|
||
return current($value);
|
||
}
|
||
|
||
function isJson($string) {
|
||
json_decode($string);
|
||
return (json_last_error() == JSON_ERROR_NONE);
|
||
}
|
||
|
||
/* TODO: Remove this
|
||
function mysql_escape_mimic($inp) {
|
||
if(is_array($inp))
|
||
return array_map(__METHOD__, $inp);
|
||
|
||
if(!empty($inp) && is_string($inp)) {
|
||
return str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $inp);
|
||
}
|
||
return $inp;
|
||
}
|
||
*/
|
||
|
||
function sanitise_id($id) {
|
||
if (preg_match("/^-?\d+$/", $id))
|
||
return $id;
|
||
else
|
||
die("Error: Possible SQL injection.");
|
||
}
|
||
|
||
function send_email($to, $subject, $body, $site = 2) {
|
||
$url = "https://mail.anidex.moe/";
|
||
$data = [
|
||
'site' => $site,
|
||
'to' => $to,
|
||
'subject' => $subject,
|
||
'body' => $body
|
||
];
|
||
$headers = [];
|
||
|
||
httpPost($url, $data, $headers);
|
||
}
|
||
/*
|
||
function send_email($to, $subject, $body) {
|
||
require_once (ABSPATH . "/scripts/phpmailer/src/PHPMailer.php");
|
||
require_once (ABSPATH . "/scripts/phpmailer/src/SMTP.php");
|
||
require_once (ABSPATH . "/scripts/phpmailer/src/Exception.php");
|
||
|
||
$mail = new PHPMailer\PHPMailer\PHPMailer;
|
||
$mail->SMTPDebug = false; //Enable SMTP debugging.
|
||
$mail->isSMTP(); //Set PHPMailer to use SMTP.
|
||
$mail->Host = SMTP_HOST; //Set SMTP host name
|
||
$mail->SMTPAuth = true; //Set this to true if SMTP host requires authentication to send email
|
||
$mail->Username = SMTP_USER; //Provide username and password
|
||
$mail->Password = SMTP_PASSWORD;
|
||
$mail->SMTPSecure = "tls"; //If SMTP requires TLS encryption then set it
|
||
$mail->Port = SMTP_PORT; //Set TCP port to connect to
|
||
$mail->From = SMTP_USER;
|
||
$mail->FromName = TITLE; //From: sdbx.moe
|
||
$mail->addBCC(SMTP_BCC); //bcc: holo@doki.co
|
||
$mail->addReplyTo(SMTP_USER); //reply-to: mangadexstaff@gmail.com
|
||
|
||
$mail->addAddress($to);
|
||
$mail->Subject = $subject;
|
||
$mail->Body = $body;
|
||
|
||
$mail->send();
|
||
}
|
||
*/
|
||
function rand_string($length) {
|
||
$chars = "abcdefghkmnpqrstuvwxyzABCDEFGHKMNPQRSTUVWXYZ23456789";
|
||
return substr(str_shuffle($chars), 0, $length);
|
||
}
|
||
|
||
function rand_letter($length) {
|
||
$chars = "abcdefghkmnqrstuvwxyzABCDEFGHKMNQRSTUVWXYZ";
|
||
return substr(str_shuffle($chars), 0, $length);
|
||
}
|
||
|
||
function get_time_ago($ptime, $display_ago = TRUE, $maxAgeForNow = 1) {
|
||
$etime = abs(time() - $ptime);
|
||
|
||
if (!$ptime)
|
||
return "Never";
|
||
elseif ($etime < $maxAgeForNow)
|
||
return "Now";
|
||
|
||
$ago = ($ptime < time() && $display_ago) ? " <span class='d-none d-xl-inline'>ago</span>" : "";
|
||
$in = ($ptime > time()) ? "in " : "";
|
||
|
||
$a = array( 365 * 24 * 60 * 60 => 'year',
|
||
30 * 24 * 60 * 60 => 'mo',
|
||
24 * 60 * 60 => 'day',
|
||
60 * 60 => 'hr',
|
||
60 => 'min',
|
||
1 => 'sec'
|
||
);
|
||
$a_plural = array( 'year' => 'years',
|
||
'mo' => 'mo',
|
||
'day' => 'days',
|
||
'hr' => 'hrs',
|
||
'min' => 'mins',
|
||
'sec' => 'secs'
|
||
);
|
||
|
||
foreach ($a as $secs => $str) {
|
||
$d = $etime / $secs;
|
||
if ($d >= 1) {
|
||
$r = round($d);
|
||
return $in . $r . ' ' . ($r > 1 ? $a_plural[$str] : $str) . $ago;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
function number_format_mod($number) {
|
||
if ($number >= 100)
|
||
return number_format($number, 0);
|
||
else
|
||
return number_format($number, 1);
|
||
}
|
||
|
||
function format_filesize($bytes) {
|
||
if ($bytes >= 1099511627776000)
|
||
return number_format_mod($bytes / 1024 / 1024 / 1024 / 1024 / 1024) . " PB";
|
||
elseif ($bytes >= 1073741824000)
|
||
return number_format_mod($bytes / 1024 / 1024 / 1024 / 1024) . " TB";
|
||
elseif ($bytes >= 1048576000)
|
||
return number_format_mod($bytes / 1024 / 1024 / 1024) . " GB";
|
||
elseif ($bytes >= 1024000)
|
||
return number_format_mod($bytes / 1024 / 1024) . " MB";
|
||
elseif ($bytes >= 1000)
|
||
return number_format_mod($bytes / 1024) . " KB";
|
||
elseif ($bytes >= 1)
|
||
return $bytes . " B";
|
||
else
|
||
return "0 B";
|
||
}
|
||
|
||
function reArrayFiles(&$file_post) {
|
||
$file_ary = [];
|
||
$file_count = count($file_post['name']);
|
||
$file_keys = array_keys($file_post);
|
||
|
||
for ($i = 0; $i < $file_count; $i++) {
|
||
foreach ($file_keys as $key) {
|
||
$file_ary[$i][$key] = $file_post[$key][$i];
|
||
}
|
||
}
|
||
|
||
return $file_ary;
|
||
}
|
||
|
||
function strpos_arr($haystack, $needle) {
|
||
if (!is_array($needle))
|
||
$needle = array($needle);
|
||
foreach($needle as $what) {
|
||
if (($pos = strpos($haystack, $what)) !== false)
|
||
return $pos;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/* TODO: remove
|
||
function get_data($url) {
|
||
$ch = curl_init();
|
||
$timeout = 5;
|
||
curl_setopt($ch, CURLOPT_URL, $url);
|
||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
|
||
$data = curl_exec($ch);
|
||
curl_close($ch);
|
||
return $data;
|
||
}
|
||
*/
|
||
|
||
/*
|
||
function download_file($url, $filepath) {
|
||
set_time_limit(0);
|
||
|
||
$file = fopen("$filepath", "w+");
|
||
|
||
$curl = curl_init($url);
|
||
|
||
// Update as of PHP 5.4 [] can be written []
|
||
curl_setopt_array($curl, [
|
||
CURLOPT_URL => $url,
|
||
CURLOPT_RETURNTRANSFER => 1,
|
||
CURLOPT_FILE => $file,
|
||
CURLOPT_TIMEOUT => 50,
|
||
CURLOPT_USERAGENT => 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)'
|
||
]);
|
||
|
||
curl_exec($curl);
|
||
curl_close($curl);
|
||
}
|
||
*/
|
||
|
||
function httpPost($url, $data, $headers) {
|
||
$curl = curl_init($url);
|
||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||
curl_setopt($curl, CURLOPT_POST, true);
|
||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||
$r = curl_exec($curl);
|
||
curl_close($curl);
|
||
return $r;
|
||
}
|
||
|
||
function httpGet($url, $str) {
|
||
$curl = curl_init($url);
|
||
curl_setopt($curl, CURLOPT_URL, $url . $str);
|
||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||
curl_setopt($curl, CURLOPT_TIMEOUT, 3);
|
||
$r = curl_exec($curl);
|
||
curl_close($curl);
|
||
return $r;
|
||
}
|
||
|
||
function rrmdir($dir) { //recursive delete folder
|
||
if (is_dir($dir)) {
|
||
$objects = scandir($dir);
|
||
foreach ($objects as $object) {
|
||
if ($object != "." && $object != "..") {
|
||
if (is_dir($dir."/".$object))
|
||
rrmdir($dir."/".$object);
|
||
else
|
||
@unlink($dir."/".$object);
|
||
}
|
||
}
|
||
rmdir($dir);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*************************************
|
||
* MangaDex functions
|
||
*************************************/
|
||
|
||
function remove_blocked_groups($chapters_array, $blocked_group_ids) {
|
||
foreach ($chapters_array as $key => $chapter) {
|
||
if (in_array($chapter['group_id'], array_keys($blocked_group_ids)))
|
||
unset($chapters_array[$key]);
|
||
}
|
||
return $chapters_array;
|
||
}
|
||
|
||
function get_og_tags($page, $id) {
|
||
global $sql, $parser;
|
||
|
||
$id = (int)$id;
|
||
|
||
$array['keywords'] = 'MangaDex, Manga Dex, Manga, Read Manga, Manga Online, Read Manga Free, Manga Scans, Free Manga, Read Manga Online';
|
||
$array['image'] = URL . "images/misc/default_brand.png?1";
|
||
$array['description'] = DESCRIPTION;
|
||
$array['title'] = TITLE;
|
||
$array['canonical'] = '';
|
||
|
||
switch ($page) {
|
||
case "main":
|
||
$array['title'] = "Latest updates - " . TITLE;
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "' />";
|
||
break;
|
||
|
||
case "search":
|
||
$array['title'] = "Search - " . TITLE;
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "search' />";
|
||
break;
|
||
|
||
case "chapter":
|
||
$chapter = $sql->prep("og_chapter_$id", '
|
||
SELECT mangas.manga_name, mangas.manga_id, mangas.manga_image, mangas.manga_description, chapters.volume, chapters.chapter, chapters.title
|
||
FROM mangadex_chapters AS chapters
|
||
LEFT JOIN mangadex_mangas AS mangas
|
||
ON chapters.manga_id = mangas.manga_id
|
||
WHERE chapters.chapter_id = ?
|
||
LIMIT 1', [$id], 'fetch', PDO::FETCH_OBJ, 3600);
|
||
|
||
if ($chapter) {
|
||
$parser->parse($chapter->manga_description);
|
||
$array['keywords'] = "$chapter->manga_name Chapter $chapter->chapter, $chapter->manga_name Volume $chapter->volume, $chapter->manga_name, $chapter->manga_name Manga, Read $chapter->manga_name online, $chapter->manga_name online For Free, Read $chapter->manga_name chapters for free, $chapter->manga_name chapters, $chapter->manga_name scans, $chapter->manga_name mangadex";
|
||
|
||
$array['title'] = (($chapter->volume) ? "Vol. $chapter->volume " : "" ).(($chapter->chapter) ? "Ch. $chapter->chapter " : "").((!$chapter->volume && !$chapter->chapter) ? "$chapter->title " : "" )."($chapter->manga_name) - " . TITLE;
|
||
$array['image'] = URL . "images/manga/$chapter->manga_id.thumb.jpg";
|
||
$array['description'] = $parser->getAsText();
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "chapter/$id' />";
|
||
}
|
||
break;
|
||
|
||
case "genre":
|
||
$genre = $sql->prep("og_genre_$id", ' SELECT * FROM mangadex_genres WHERE genre_id = ? LIMIT 1 ', [$id], 'fetch', PDO::FETCH_OBJ, 3600);
|
||
|
||
if (isset($genre->genre_id)) {
|
||
$array['title'] = "$genre->genre_name (Genre) - " . TITLE;
|
||
$array['description'] = $genre->genre_description;
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "genre/$genre->genre_id/" . slugify($genre->genre_name) . "' />";
|
||
}
|
||
break;
|
||
|
||
case "manga":
|
||
case "title":
|
||
$manga = $sql->prep("og_manga_$id", ' SELECT manga_name, manga_id, manga_description FROM mangadex_mangas WHERE manga_id = ? LIMIT 1 ', [$id], 'fetch', PDO::FETCH_OBJ, 3600);
|
||
|
||
if (isset($manga->manga_id)) {
|
||
$parser->parse($manga->manga_description);
|
||
$array['keywords'] = "$manga->manga_name, $manga->manga_name Manga, Read $manga->manga_name online, $manga->manga_name online, $manga->manga_name online For Free, Read $manga->manga_name chapters for free, $manga->manga_name series, $manga->manga_name chapters, $manga->manga_name scans, $manga->manga_name mangadex";
|
||
|
||
$array['title'] = "$manga->manga_name (Title) - " . TITLE;
|
||
$array['image'] = URL . "images/manga/$manga->manga_id.thumb.jpg";
|
||
$array['description'] = $parser->getAsText();
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "title/$manga->manga_id/" . slugify($manga->manga_name) . "' />";
|
||
}
|
||
break;
|
||
|
||
case "user":
|
||
$user = $sql->prep("og_user_$id", ' SELECT user_id, username, avatar FROM mangadex_users WHERE user_id = ? LIMIT 1 ', [$id], 'fetch', PDO::FETCH_OBJ, 3600);
|
||
|
||
if (isset($user->user_id)) {
|
||
$array['title'] = "$user->username (User) - " . TITLE;
|
||
$array['image'] = ($user->avatar) ? URL . "images/avatars/$user->user_id.$user->avatar" : URL . 'images/avatars/xmas' . (($id % 2) + 1) . '.png';
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "user/$user->user_id/" . slugify($user->username) . "' />";
|
||
}
|
||
break;
|
||
|
||
case "list":
|
||
$user = $sql->prep("og_list_user_$id", ' SELECT user_id, username, avatar FROM mangadex_users WHERE user_id = ? LIMIT 1 ', [$id], 'fetch', PDO::FETCH_OBJ, 3600);
|
||
$array['title'] = "$user->username's MDList - " . TITLE;
|
||
$array['image'] = ($user->avatar) ? URL . "images/avatars/$user->user_id.$user->avatar" : URL . 'images/avatars/' . rand(1,3) . '.jpg';
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "list/$user->user_id/' />";
|
||
break;
|
||
|
||
case "group":
|
||
$group = $sql->prep("og_group_$id", ' SELECT group_id, group_name FROM mangadex_groups WHERE group_id = ? LIMIT 1 ', [$id], 'fetch', PDO::FETCH_OBJ, 3600);
|
||
|
||
if (isset($group->group_id)) {
|
||
$array['title'] = "$group->group_name (Group) - " . TITLE;
|
||
$array['canonical'] = "<link rel='canonical' href='" . URL . "group/$group->group_id/" . slugify($group->group_name) . "' />";
|
||
} else {
|
||
$array['title'] = 'Group not found';
|
||
}
|
||
break;
|
||
|
||
case "forum":
|
||
$forum_name = $sql->prep("og_forum_$id", ' SELECT forum_name FROM mangadex_forums WHERE forum_id = ? LIMIT 1 ', [$id], 'fetchColumn', '', 3600);
|
||
$array['title'] = "$forum_name (Forum) - " . TITLE;
|
||
break;
|
||
|
||
case "thread":
|
||
$thread_name = $sql->prep("og_thread_$id", ' SELECT thread_name FROM mangadex_threads WHERE thread_id = ? LIMIT 1 ', [$id], 'fetchColumn', '', 3600);
|
||
$array['title'] = "$thread_name (Thread) - " . TITLE;
|
||
break;
|
||
|
||
case "titles":
|
||
$array['title'] = "Manga titles - " . TITLE;
|
||
break;
|
||
|
||
default:
|
||
$array['title'] = ($page) ? ucfirst(str_replace("_", " ", $page)) . " - " . TITLE : TITLE;
|
||
break;
|
||
}
|
||
|
||
return $array;
|
||
}
|
||
|
||
function generate_thumbnail($file, $large) {
|
||
|
||
if (file_exists ($file)) {
|
||
$thumbFile = preg_replace('/\\.[^.\\s]{3,4}$/', '', $file);
|
||
//$thumbFile = pathinfo($file, PATHINFO_FILENAME);
|
||
|
||
$thumbFile .= '.thumb.jpg';
|
||
|
||
// Setting the resize parameters
|
||
list($width, $height) = getimagesize($file);
|
||
|
||
// Some broken images may return an invalid height/width. return, so we dont run into a division-by-zero error
|
||
if ($width < 1 || $height < 1 || $width + $height > 10000)
|
||
return;
|
||
|
||
$modwidth = 100;
|
||
$modheight = $modwidth / $width * $height;
|
||
|
||
// Creating the Canvas
|
||
$tn= imagecreatetruecolor($modwidth, $modheight);
|
||
|
||
$type = exif_imagetype($file);
|
||
switch ($type) {
|
||
case IMAGETYPE_JPEG:
|
||
$image = ImageCreateFromJPEG($file);
|
||
break;
|
||
|
||
case IMAGETYPE_PNG:
|
||
$image = ImageCreateFromPNG($file);
|
||
break;
|
||
|
||
case IMAGETYPE_GIF:
|
||
$image = ImageCreateFromGIF($file);
|
||
break;
|
||
|
||
default:
|
||
exit;
|
||
break;
|
||
}
|
||
|
||
if ($image) {
|
||
// Resizing our image to fit the canvas
|
||
@imagecopyresampled($tn, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height);
|
||
|
||
// Save to file
|
||
@imagejpeg($tn, $thumbFile, 85);
|
||
|
||
//Free memory
|
||
@imagedestroy($tn);
|
||
}
|
||
|
||
if ($large) {
|
||
$thumbFile = preg_replace('/\\.[^.\\s]{3,4}$/', '', $file);
|
||
|
||
if ($large == 1)
|
||
$thumbFile .= '.large.jpg';
|
||
else
|
||
$thumbFile .= ".$large.jpg";
|
||
|
||
// Setting the resize parameters
|
||
list($width, $height) = getimagesize($file);
|
||
|
||
if ($large == 1)
|
||
$modwidth = 150;
|
||
else
|
||
$modwidth = $large;
|
||
|
||
$modheight = $modwidth / $width * $height;
|
||
|
||
// Creating the Canvas
|
||
$tn= imagecreatetruecolor($modwidth, $modheight);
|
||
|
||
$type = exif_imagetype($file);
|
||
switch ($type) {
|
||
case IMAGETYPE_JPEG:
|
||
$image = ImageCreateFromJPEG($file);
|
||
break;
|
||
|
||
case IMAGETYPE_PNG:
|
||
$image = ImageCreateFromPNG($file);
|
||
break;
|
||
|
||
case IMAGETYPE_GIF:
|
||
$image = ImageCreateFromGIF($file);
|
||
break;
|
||
|
||
default:
|
||
exit;
|
||
break;
|
||
}
|
||
|
||
if ($image) {
|
||
// Resizing our image to fit the canvas
|
||
@imagecopyresampled($tn, $image, 0, 0, 0, 0, $modwidth, $modheight, $width, $height);
|
||
|
||
// Save to file
|
||
@imagejpeg($tn, $thumbFile, 85);
|
||
|
||
//Free memory
|
||
@imagedestroy($tn);
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
function redirect_url($target, $httpcode=303)
|
||
{
|
||
if ($target{0} !== '/' && !stripos($target, DOMAIN)) {
|
||
die('Possible XSS Attack: Invalid redirection URL! Follow at your own risk: '.$target);
|
||
}
|
||
http_response_code($httpcode);
|
||
header('location: '.$target);
|
||
die();
|
||
}
|
||
|
||
/*************************************
|
||
* Update database
|
||
*************************************/
|
||
|
||
function update_cron_logs($type, $result) {
|
||
global $sql;
|
||
$sql->modify('update_cron_logs', " INSERT INTO mangadex_logs_cron (id, timestamp, type, result) VALUES (NULL, UNIX_TIMESTAMP(), ?, ?) ", [$type, $result]);
|
||
}
|
||
|
||
function visit_log_cumulative($ip, $table = "visit") {
|
||
global $sql;
|
||
$field = prepare_identifier("log_$table");
|
||
$sql->modify('visit_log_cumulative', " INSERT INTO mangadex_logs (log_ip, log_visit, log_dl, log_rss, log_timestamp) VALUES (?, 0, 0, 0, UNIX_TIMESTAMP())
|
||
ON DUPLICATE KEY UPDATE $field = $field + 1 ", [$ip]);
|
||
}
|
||
|
||
function condenseUA($ua_str) {
|
||
$user_agents = ['AhrefsBot', 'bingbot', 'Googlebot', 'YandexBot', 'Android', 'iPad', 'iPhone', 'Macintosh', 'Windows', 'RSS', 'Linux', 'CrOS'];
|
||
foreach ($user_agents as $ua) {
|
||
if (strpos($ua_str, $ua) !== false)
|
||
$string = $ua;
|
||
}
|
||
$string = $string ?? $ua_str;
|
||
return $string;
|
||
}
|
||
|
||
function visit_log($server, $ip, $user_id, $hentai_toggle = 0, $table = "visits") {
|
||
global $sql;
|
||
$timestamp = time();
|
||
$query_string = (isset($server['QUERY_STRING'])) ? substr(str_replace(['page=', '&id=', '&p=', '&mode=', '&type='], ['/', '/', '/', '/', '/'], $server['QUERY_STRING']), 0, 255) : "";
|
||
$referer = (isset($server['HTTP_REFERER'])) ? substr(str_replace(['https://mangadex.org', 'https://www.mangadex.org'], ['', ''], $server['HTTP_REFERER']), 0, 255) : "";
|
||
$user_agent = (isset($server['HTTP_USER_AGENT'])) ? substr($server['HTTP_USER_AGENT'], 0, 255) : "";
|
||
|
||
$user_agent_string = condenseUA($user_agent);
|
||
|
||
$sql->modify('visit_log', " INSERT INTO mangadex_logs_$table (visit_id, visit_ip, visit_user_id, visit_user_agent, visit_referrer, visit_timestamp, visit_page, visit_h_toggle)
|
||
VALUES (NULL, ?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?) ", [$ip, $user_id, $user_agent_string, $referer, $query_string, $hentai_toggle]);
|
||
|
||
global $memcached;
|
||
$cache = $memcached->get($ip);
|
||
|
||
if ($cache === FALSE || $timestamp - $cache[1] > 600) {
|
||
$memcached->set($ip, [1, $timestamp]);
|
||
}
|
||
else {
|
||
$memcached->set($ip, [$cache[0] + 1, $cache[1]]);
|
||
}
|
||
}
|
||
|
||
function visit_log_api($server, $ip, $user_id, $hentai_toggle = 0) {
|
||
global $sql;
|
||
$query_string = (isset($server['QUERY_STRING'])) ? substr(str_replace(['page=', '&id=', '&p=', '&mode=', '&type='], ['/', '/', '/', '/', '/'], $server['QUERY_STRING']), 0, 255) : "";
|
||
$referer = (isset($server['HTTP_REFERER'])) ? substr(str_replace(['https://mangadex.org', 'https://mangadex.com'], ['', ''], $server['HTTP_REFERER']), 0, 255) : "";
|
||
$user_agent = (isset($server['HTTP_USER_AGENT'])) ? substr($server['HTTP_USER_AGENT'], 0, 255) : "";
|
||
|
||
$user_agent_string = condenseUA($user_agent);
|
||
|
||
$sql->modify('visit_log_api', " INSERT INTO mangadex_logs_api (visit_id, visit_ip, visit_user_id, visit_user_agent, visit_referrer, visit_timestamp, visit_page, visit_h_toggle)
|
||
VALUES (NULL, ?, ?, ?, ?, UNIX_TIMESTAMP(), ?, ?) ", [$ip, $user_id, $user_agent_string, $referer, $query_string, $hentai_toggle]);
|
||
}
|
||
|
||
function update_views_v2($type, $id, $ip, $user_id = 0) {
|
||
global $memcached, $sql;
|
||
|
||
$name = "{$type}_{$id}_$ip";
|
||
|
||
$cache = $memcached->get($name);
|
||
|
||
if ($cache === FALSE) {
|
||
$memcached->set($name, TRUE, 3600);
|
||
|
||
$table = prepare_identifier("mangadex_{$type}s");
|
||
$field = prepare_identifier("{$type}_views");
|
||
$field_id = prepare_identifier("{$type}_id");
|
||
$sql->modify('update_views_v2', " UPDATE $table SET $field = $field + 1 WHERE $field_id = ? LIMIT 1 ", [$id]);
|
||
if ($type == "chapter") {
|
||
$sql->modify('update_views_v2', " INSERT INTO mangadex_chapter_live_views (timestamp, chapter_id, ip) VALUES (UNIX_TIMESTAMP(), ?, ?) ", [$id, $ip]);
|
||
|
||
if ($user_id)
|
||
$sql->modify('update_views_v2', " UPDATE mangadex_user_stats SET chapters_read = chapters_read + 1 WHERE user_id = ? ", [$user_id]);
|
||
}
|
||
}
|
||
}
|
||
|
||
function process_user_limit($limit = 600, $prefix = '', $reset_seconds = 600, $expire_seconds = 86400)
|
||
{
|
||
global $memcached;
|
||
|
||
if (isset($_SERVER['HTTP_USER_AGENT']) && strpos($_SERVER['HTTP_USER_AGENT'], 'Googlebot') !== FALSE) {
|
||
// Perform a dns lookup
|
||
try {
|
||
$hostname = gethostbyaddr(_IP);
|
||
if (stripos($hostname, '.googlebot.com') === false && stripos($hostname, '.google.com') === false) {
|
||
throw new \RuntimeException(sprintf('Possible googlebot useragent faking. Please check if IP "%s" and host "%s" are legit for the useragent "%s"', _IP, $hostname, $_SERVER['HTTP_USER_AGENT']), E_USER_ERROR);
|
||
}
|
||
} catch (\RuntimeException $e) {
|
||
die();
|
||
} catch (\Throwable $e) {
|
||
trigger_error(sprintf('Exception thrown during googlebot reverse dns lookup: %s', $e->getMessage()), E_USER_WARNING);
|
||
}
|
||
} else {
|
||
// limit everyone else
|
||
$ip = _IP;
|
||
$visit_count = $memcached->get($prefix.$ip);
|
||
|
||
if (!(defined('DISABLE_HITCOUNTER') && DISABLE_HITCOUNTER) && $visit_count !== FALSE && $visit_count[0] > $limit) {
|
||
return false;
|
||
}
|
||
|
||
// Update limits
|
||
if ($visit_count === false || time() - $visit_count[1] > $reset_seconds) {
|
||
$memcached->set($prefix.$ip, [1, time()], $expire_seconds);
|
||
} else {
|
||
$memcached->set($prefix.$ip, [$visit_count[0] + 1, $visit_count[1]], $expire_seconds);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
function get_zip_originalsize($filename) {
|
||
$size = 0;
|
||
$resource = zip_open($filename);
|
||
while ($dir_resource = zip_read($resource)) {
|
||
$size += zip_entry_filesize($dir_resource);
|
||
}
|
||
zip_close($resource);
|
||
|
||
return $size;
|
||
}
|
||
|
||
/*************************************
|
||
* Discord webhook
|
||
*************************************/
|
||
function post_on_discord($webhookUrl, $hookObject) {
|
||
if ($webhookUrl) {
|
||
// Convert to json
|
||
$hookObject = json_encode($hookObject, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
|
||
|
||
// Prepare
|
||
$ch = curl_init();
|
||
curl_setopt_array($ch, [
|
||
CURLOPT_URL => $webhookUrl,
|
||
CURLOPT_POST => true,
|
||
CURLOPT_POSTFIELDS => $hookObject,
|
||
CURLOPT_HTTPHEADER => [
|
||
'Content-Type: application/json'
|
||
],
|
||
CURLOPT_RETURNTRANSFER => true,
|
||
CURLOPT_FAILONERROR => true
|
||
]);
|
||
|
||
// Post
|
||
try {
|
||
curl_exec($ch);
|
||
if (curl_errno($ch)) {
|
||
trigger_error(curl_error($ch), E_USER_WARNING);
|
||
}
|
||
curl_close($ch);
|
||
} catch (\Throwable $e) {
|
||
// just consume the error
|
||
}
|
||
}
|
||
}
|