diff --git a/src/php/abuse.php b/src/php/abuse.php index a208ee4..1d1cb7a 100644 --- a/src/php/abuse.php +++ b/src/php/abuse.php @@ -1,46 +1,46 @@ -hGet($key, $id); - if($views !== False) { - if($views >= Config::$Instance->download_captcha_check * 2) { - - } else if($views >= Config::$Instance->download_captcha_check) { - http_response_code(429); // Too many requests, tell the client to do captcha check - exit(); - } - } - - $redis->hIncrBy($key, $id, 1); - } - - public function VerifyCaptcha($token) : ?object { - if(isset(Config::$Instance->recaptcha_secret)) { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, 'https://www.google.com/recaptcha/api/siteverify'); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, array( - "secret" => Config::$Instance->recaptcha_secret, - "response" => $token, - "remoteip" => USER_IP - )); - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - $crsp = json_decode(curl_exec($ch)); - curl_close ($ch); - - return $crsp; - } - return null; - } - - public function ResetRateLimits($id) { - $redis = StaticRedis::WriteOp(); - $key = REDIS_PREFIX . "uvc:" . USER_IP; - $redis->hSet($key, $id, 0); - } - } +hGet($key, $id); + if($views !== False) { + if($views >= Config::$Instance->download_captcha_check * 2) { + + } else if($views >= Config::$Instance->download_captcha_check) { + http_response_code(429); // Too many requests, tell the client to do captcha check + exit(); + } + } + + $redis->hIncrBy($key, $id, 1); + } + + public function VerifyCaptcha($token) : ?object { + if(isset(Config::$Instance->recaptcha_secret)) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'https://www.google.com/recaptcha/api/siteverify'); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, array( + "secret" => Config::$Instance->recaptcha_secret, + "response" => $token, + "remoteip" => USER_IP + )); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $crsp = json_decode(curl_exec($ch)); + curl_close ($ch); + + return $crsp; + } + return null; + } + + public function ResetRateLimits($id) { + $redis = StaticRedis::WriteOp(); + $key = REDIS_PREFIX . "uvc:" . USER_IP; + $redis->hSet($key, $id, 0); + } + } ?> \ No newline at end of file diff --git a/src/php/admin.php b/src/php/admin.php index 94c0c51..9314793 100644 --- a/src/php/admin.php +++ b/src/php/admin.php @@ -1,9 +1,9 @@ - \ No newline at end of file diff --git a/src/php/api.php b/src/php/api.php index 42989fb..a00310b 100644 --- a/src/php/api.php +++ b/src/php/api.php @@ -1,88 +1,88 @@ -cmd = $cmd; - - $fs = new FileStore(Config::$Instance->upload_folder); - - switch($cmd->cmd){ - case "site_info": { - $rsp->ok = true; - $rsp->data = array( - "max_upload_size" => Config::$Instance->max_upload_size, - "basic_stats" => Stats::Get(), - "upload_host" => Upload::GetUploadHost(), - "geoip_info" => geoip_database_info(), - "host" => gethostname() - ); - break; - } - case "file_info": { - $rsp->ok = true; - $rsp->data = $fs->GetFileInfo($cmd->id); - //$rsp->data->DownloadHost = Upload::GetUploadHost(); //bypass CF proxy for downloads (slow..) - break; - } - case 'captcha_info': { - if(isset(Config::$Instance->recaptcha_site_key) && Config::$Instance->recaptcha_site_key !== False && isset(Config::$Instance->recaptcha_secret) && Config::$Instance->recaptcha_secret !== False) { - $rsp->ok = true; - $rsp->data = array( - "site_key" => Config::$Instance->recaptcha_site_key - ); - } - break; - } - case "verify_captcha_rate_limit": { - $abuse = new Abuse(); - $rsp->data = $abuse->VerifyCaptcha($cmd->token); - if($rsp->data !== null && $rsp->data->success) { - $abuse->ResetRateLimits($cmd->id); - $rsp->ok = true; - } - break; - } - case "7_day_tx_graph": { - $stats = Stats::GetTxStats(24 * 7); - $data = array(); - foreach($stats as $time => $bytes){ - $data[] = array( - "t" => date_timestamp_get(date_create_from_format("YmdH", $time)) * 1000, - "y" => $bytes - ); - } - - $rsp->data = array( - "datasets" => array( - array( - "label" => "bytes", - "data" => $data - ) - ) - ); - $rsp->ok = true; - break; - } - } - - header('Content-Type: application/json'); - echo json_encode($rsp); - } - } -?> \ No newline at end of file +cmd = $cmd; + + $fs = new FileStore(Config::$Instance->upload_folder); + + switch($cmd->cmd){ + case "site_info": { + $rsp->ok = true; + $rsp->data = array( + "max_upload_size" => Config::$Instance->max_upload_size, + "basic_stats" => Stats::Get(), + "upload_host" => Upload::GetUploadHost(), + "geoip_info" => geoip_database_info(), + "host" => gethostname() + ); + break; + } + case "file_info": { + $rsp->ok = true; + $rsp->data = $fs->GetFileInfo($cmd->id); + //$rsp->data->DownloadHost = Upload::GetUploadHost(); //bypass CF proxy for downloads (slow..) + break; + } + case 'captcha_info': { + if(isset(Config::$Instance->recaptcha_site_key) && Config::$Instance->recaptcha_site_key !== False && isset(Config::$Instance->recaptcha_secret) && Config::$Instance->recaptcha_secret !== False) { + $rsp->ok = true; + $rsp->data = array( + "site_key" => Config::$Instance->recaptcha_site_key + ); + } + break; + } + case "verify_captcha_rate_limit": { + $abuse = new Abuse(); + $rsp->data = $abuse->VerifyCaptcha($cmd->token); + if($rsp->data !== null && $rsp->data->success) { + $abuse->ResetRateLimits($cmd->id); + $rsp->ok = true; + } + break; + } + case "7_day_tx_graph": { + $stats = Stats::GetTxStats(24 * 7); + $data = array(); + foreach($stats as $time => $bytes){ + $data[] = array( + "t" => date_timestamp_get(date_create_from_format("YmdH", $time)) * 1000, + "y" => $bytes + ); + } + + $rsp->data = array( + "datasets" => array( + array( + "label" => "bytes", + "data" => $data + ) + ) + ); + $rsp->ok = true; + break; + } + } + + header('Content-Type: application/json'); + echo json_encode($rsp); + } + } +?> diff --git a/src/php/auth.php b/src/php/auth.php index d31a2e6..7ec0d35 100644 --- a/src/php/auth.php +++ b/src/php/auth.php @@ -1,38 +1,38 @@ -GetAuthorizationHeader(); - if (!empty($headers)) { - if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) { - return $matches[1]; - } - } - return null; - } - - function CheckApiToken($token) { - return StaticRedis::ReadOp()->sIsMember(REDIS_PREFIX . "api-keys", $token); - } - } +GetAuthorizationHeader(); + if (!empty($headers)) { + if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) { + return $matches[1]; + } + } + return null; + } + + function CheckApiToken($token) { + return StaticRedis::ReadOp()->sIsMember(REDIS_PREFIX . "api-keys", $token); + } + } ?> \ No newline at end of file diff --git a/src/php/blobfile.php b/src/php/blobfile.php index 1869319..5e5c087 100644 --- a/src/php/blobfile.php +++ b/src/php/blobfile.php @@ -1,40 +1,41 @@ -Version = 1; - $bf->Hash = $header_data["hash256"]; - $bf->Uploaded = $header_data["uploaded"]; - return $bf; - } elseif($version == 2) { - $header = fread($input, 11); //+7 magic bytes + 4 byte timestamp - $header_data = unpack("H14magic/Vuploaded", $header); - fclose($input); - - //error_log("Magic is: " . $header_data["magic"]); - if($header_data["magic"] == "4f4944f09f90b1") { //OID🐱 as hex (UTF-8) - $bf->Version = 2; - $bf->Uploaded = $header_data["uploaded"]; - return $bf; - } - } else { - fclose($input); - } - - return null; - } - } +Version = 1; + $bf->Hash = $header_data["hash256"]; + $bf->Uploaded = $header_data["uploaded"]; + return $bf; + } elseif($version == 2) { + $header = fread($input, 11); //+7 magic bytes + 4 byte timestamp + $header_data = unpack("H14magic/Vuploaded", $header); + fclose($input); + + //error_log("Magic is: " . $header_data["magic"]); + if($header_data["magic"] == "4f4944f09f90b1") { //OID🐱 as hex (UTF-8) + $bf->Version = 2; + $bf->Uploaded = $header_data["uploaded"]; + return $bf; + } + } else { + fclose($input); + } + } + return null; + } + } ?> \ No newline at end of file diff --git a/src/php/config.php b/src/php/config.php index e20b7ee..9b9328c 100644 --- a/src/php/config.php +++ b/src/php/config.php @@ -1,33 +1,33 @@ -hGet(REDIS_PREFIX . 'config', $config_name); - } - - public static function MGetConfig($config_name) { - $redis = StaticRedis::ReadOp(); - return (object)$redis->hMGet(REDIS_PREFIX . 'config', $config_name); - } - - public static function LoadConfig($config_name){ - self::$Instance = self::MGetConfig($config_name); - - //set defaults - if(!isset(self::$Instance->upload_folder) || self::$Instance->upload_folder == False) { - self::$Instance->upload_folder = "out"; - } - if(!isset(self::$Instance->public_hash_algo) || self::$Instance->public_hash_algo == False) { - self::$Instance->public_hash_algo = "ripemd160"; - } - if(!isset(self::$Instance->max_upload_size) || self::$Instance->max_upload_size == False) { - self::$Instance->max_upload_size = 104857600; //100MiB is the default upload size - } - if(!isset(self::$Instance->download_captcha_check) || self::$Instance->download_captcha_check == False) { - self::$Instance->download_captcha_check = 10; - } - } - } +hGet(REDIS_PREFIX . 'config', $config_name); + } + + public static function MGetConfig($config_name) { + $redis = StaticRedis::ReadOp(); + return (object)$redis->hMGet(REDIS_PREFIX . 'config', $config_name); + } + + public static function LoadConfig($config_name){ + self::$Instance = self::MGetConfig($config_name); + + //set defaults + if(!isset(self::$Instance->upload_folder) || self::$Instance->upload_folder == False) { + self::$Instance->upload_folder = "out"; + } + if(!isset(self::$Instance->public_hash_algo) || self::$Instance->public_hash_algo == False) { + self::$Instance->public_hash_algo = "ripemd160"; + } + if(!isset(self::$Instance->max_upload_size) || self::$Instance->max_upload_size == False) { + self::$Instance->max_upload_size = 104857600; //100MiB is the default upload size + } + if(!isset(self::$Instance->download_captcha_check) || self::$Instance->download_captcha_check == False) { + self::$Instance->download_captcha_check = 10; + } + } + } ?> \ No newline at end of file diff --git a/src/php/cron.php b/src/php/cron.php index e8e4c76..52185bb 100644 --- a/src/php/cron.php +++ b/src/php/cron.php @@ -1,62 +1,62 @@ -upload_folder, $_SERVER["cron_root"]); - - //delete expired files - $pmsg = "`" . gethostname() . ":\n"; - $redis = StaticRedis::ReadOp(); - $deleted = false; - foreach($fs->ListFiles() as $file) { - $id = basename($file); - $file_key = REDIS_PREFIX . $id; - $lv = $redis->hGet($file_key, "lastview"); - $expire = time() - (30 * 24 * 60 * 60); - - //use the file upload timestamp if there is no view data recorded - //if the file upload time is greater than the current timestamp, mark as old (!!abuse!!) - //this will also force legacy file uploads with no views to be deleted (header will always fail to load) - if($lv === false) { - $file_header = BlobFile::LoadHeader($file); - if($file_header !== null && $file_header->Uploaded <= time()){ - $lv = $file_header->Uploaded; - } else { - //cant read file header or upload timestamp is invalid, mark as old - $lv = 0; - } - } - - if($lv !== false && intval($lv) < $expire) { - $nmsg = "Deleting expired file: " . $id . " (lastview=" . date("Y-m-d h:i:s", intval($lv)) . ")\n"; - if(strlen($pmsg) + strlen($nmsg) >= 2000){ - //send to discord public hook - $pmsg = $pmsg . "`"; - Discord::SendPublic(array( - "content" => $pmsg - )); - $pmsg = "`"; - } - $pmsg = $pmsg . $nmsg; - unlink($file); - $deleted = true; - } - } - - //send last message if any - if(strlen($pmsg) > 0 && $deleted) { - $pmsg = $pmsg . "`"; - Discord::SendPublic(array( - "content" => $pmsg - )); - } - - if(StaticRedis::$IsConnectedToSlave == False) { - echo "Runing master node tasks..\n"; - Stats::Collect($fs); - } - } +upload_folder, $_SERVER["cron_root"]); + + //delete expired files + $pmsg = "`" . gethostname() . ":\n"; + $redis = StaticRedis::ReadOp(); + $deleted = false; + foreach($fs->ListFiles() as $file) { + $id = basename($file); + $file_key = REDIS_PREFIX . $id; + $lv = $redis->hGet($file_key, "lastview"); + $expire = time() - (30 * 24 * 60 * 60); + + //use the file upload timestamp if there is no view data recorded + //if the file upload time is greater than the current timestamp, mark as old (!!abuse!!) + //this will also force legacy file uploads with no views to be deleted (header will always fail to load) + if($lv === false) { + $file_header = BlobFile::LoadHeader($file); + if($file_header !== null && $file_header->Uploaded <= time()){ + $lv = $file_header->Uploaded; + } else { + //cant read file header or upload timestamp is invalid, mark as old + $lv = $file_header !== null ? $file_header->Uploaded : 0; + } + } + + if($lv !== false && (intval($lv) < $expire) || intval($lv) > time()) { + $nmsg = "Deleting expired file: " . $id . " (lastview=" . date("Y-m-d h:i:s", intval($lv)) . ")\n"; + if(strlen($pmsg) + strlen($nmsg) >= 2000){ + //send to discord public hook + $pmsg = $pmsg . "`"; + Discord::SendPublic(array( + "content" => $pmsg + )); + $pmsg = "`"; + } + $pmsg = $pmsg . $nmsg; + unlink($file); + $deleted = true; + } + } + + //send last message if any + if(strlen($pmsg) > 0 && $deleted) { + $pmsg = $pmsg . "`"; + Discord::SendPublic(array( + "content" => $pmsg + )); + } + + if(StaticRedis::$IsConnectedToSlave == False) { + echo "Runing master node tasks..\n"; + Stats::Collect($fs); + } + } ?> \ No newline at end of file diff --git a/src/php/discord.php b/src/php/discord.php index d0b6574..e520f18 100644 --- a/src/php/discord.php +++ b/src/php/discord.php @@ -1,26 +1,26 @@ -discord_webhook_pub, $msg); - } - - private static function CallWebhook($url, $data) : void { - self::CurlPost($url, json_encode($data)); - } - - private static function CurlPost($url, $data) : ?string { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $data); - curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); - - $result = curl_exec($ch); - curl_close($ch); - return $result; - } - } - +discord_webhook_pub, $msg); + } + + private static function CallWebhook($url, $data) : void { + self::CurlPost($url, json_encode($data)); + } + + private static function CurlPost($url, $data) : ?string { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $data); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); + + $result = curl_exec($ch); + curl_close($ch); + return $result; + } + } + ?> \ No newline at end of file diff --git a/src/php/download.php b/src/php/download.php index 4077ba7..9fcf993 100644 --- a/src/php/download.php +++ b/src/php/download.php @@ -1,56 +1,56 @@ -Fs = new FileStore(Config::$Instance->upload_folder); - if($this->Fs->FileExists($id)) { - $this->StartDownload($id, $this->Fs->GetFileInfo($id)); - } else { - http_response_code(404); - } - } else { - http_response_code(404); - } - } - - function StartDownload($id, $info) : void { - $abuse = new Abuse(); - $tracking = new Tracking(); - - header("Cache-Control: private"); - if(isset($_SERVER["HTTP_ORIGIN"])) { - header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]); - header("Access-Control-Allow-Method: GET"); - } - - $abuse->CheckDownload($id); - $tracking->TrackDownload($this->Fs, $id); - - if($_SERVER["REQUEST_METHOD"] === "GET") { - $this->InternalNginxRedirect($this->Fs->GetRelativeFilePath($id), 604800, $info); - } - } - - function InternalNginxRedirect($location, $expire, $info) : void { - header("X-Accel-Redirect: /" . $location); - if($info->IsLegacyUpload) { - header("Content-Type: $info->LegacyMime"); - header("Content-Disposition: inline; filename=\"$info->LegacyFilename\""); - } else { - header("Content-Type: application/octet-stream"); - } - } - } +Fs = new FileStore(Config::$Instance->upload_folder); + if($this->Fs->FileExists($id)) { + $this->StartDownload($id, $this->Fs->GetFileInfo($id)); + } else { + http_response_code(404); + } + } else { + http_response_code(404); + } + } + + function StartDownload($id, $info) : void { + $abuse = new Abuse(); + $tracking = new Tracking(); + + header("Cache-Control: private"); + if(isset($_SERVER["HTTP_ORIGIN"])) { + header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]); + header("Access-Control-Allow-Method: GET"); + } + + $abuse->CheckDownload($id); + $tracking->TrackDownload($this->Fs, $id); + + if($_SERVER["REQUEST_METHOD"] === "GET") { + $this->InternalNginxRedirect($this->Fs->GetRelativeFilePath($id), 604800, $info); + } + } + + function InternalNginxRedirect($location, $expire, $info) : void { + header("X-Accel-Redirect: /" . $location); + if($info->IsLegacyUpload) { + header("Content-Type: $info->LegacyMime"); + header("Content-Disposition: inline; filename=\"$info->LegacyFilename\""); + } else { + header("Content-Type: application/octet-stream"); + } + } + } ?> \ No newline at end of file diff --git a/src/php/fileinfo.php b/src/php/fileinfo.php index 4fa6a32..0b2ba00 100644 --- a/src/php/fileinfo.php +++ b/src/php/fileinfo.php @@ -1,15 +1,15 @@ - \ No newline at end of file diff --git a/src/php/filestore.php b/src/php/filestore.php index 02d2b8a..b53c98e 100644 --- a/src/php/filestore.php +++ b/src/php/filestore.php @@ -1,135 +1,135 @@ -UploadFolder = $dir; - $this->DocumentRoot = $root === null ? $_SERVER["DOCUMENT_ROOT"] : $root; - } - - public function SetFileStats($info) : void { - $redis = StaticRedis::WriteOp(); - $file_key = REDIS_PREFIX . $info->FileId; - - $redis->hMSet($file_key, array( - 'views' => $info->Views, - 'lastview' => $info->LastView - )); - } - - public function GetFileStats($id) : object { - $redis = StaticRedis::ReadOp(); - $file_key = REDIS_PREFIX . $id; - - $public_file_info = $redis->hMGet($file_key, array('views', 'lastview', 'islegacy', 'filename', 'mime')); - return (object)array( - "views" => ($public_file_info["views"] !== False ? $public_file_info["views"] : 0), - "lastview" => ($public_file_info["lastview"] !== False ? $public_file_info["lastview"] : 0), - "islegacy" => ($public_file_info["islegacy"] !== False ? $public_file_info["islegacy"] === "1" : false), - "filename" => ($public_file_info["filename"] !== False ? $public_file_info["filename"] : ""), - "mime" => ($public_file_info["mime"] !== False ? $public_file_info["mime"] : ""), - ); - } - - public function SetAsLegacyFile($info) : void { - $redis = StaticRedis::WriteOp(); - $file_key = REDIS_PREFIX . $info->FileId; - $redis->hMSet($file_key, array( - 'islegacy' => true, - 'filename' => $info->LegacyFilename, - 'mime' => $info->LegacyMime - )); - } - - public function GetUploadDirAbsolute() : string { - return "$this->DocumentRoot/$this->UploadFolder"; - } - - public function GetRelativeFilePath($id) : string { - return "$this->UploadFolder/$id"; - } - - public function GetAbsoluteFilePath($id) : string { - return $this->GetUploadDirAbsolute() . "/" . $id; - } - - public function GetFileInfo($id) : ?FileInfo { - $file_path = $this->GetAbsoluteFilePath($id); - if($this->FileExists($id)) { - $stats = $this->GetFileStats($id); - $file_stat = stat($file_path); - - $file = new FileInfo(); - $file->FileId = $id; - $file->Views = intval($stats->views); - $file->LastView = intval($stats->lastview); - $file->Size = $file_stat["size"]; - $file->Uploaded = $file_stat["ctime"]; - - $file->IsLegacyUpload = $stats->islegacy; - $file->LegacyFilename = $stats->filename; - $file->LegacyMime = $stats->mime; - - return $file; - } - return NULL; - } - - public function FileExists($id) : bool { - $file_path = $this->GetAbsoluteFilePath($id); - return file_exists($file_path); - } - - public function StoreFile($file, $id) : bool { - $file_path = $this->GetAbsoluteFilePath($id); - - if(!file_exists($file_path)) { - $fout = fopen($file_path, 'wb+'); - stream_copy_to_stream($file, $fout); - fclose($fout); - return true; - } - return false; - } - - public function StoreV1File($bf, $file) : ?string { - $id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $bf->Hash)), 62); - - $input = fopen($file, "rb"); - $res = $this->StoreFile($input, $id); - fclose($input); - - return $res ? $id : null; - } - - public function StoreV2File($bf, $file) : ?string { - //we need to seek to the end before finding the id, do that first - $input = fopen($file, "rb"); - $temp_name = tempnam($this->GetUploadDirAbsolute(), "VTMP_"); - $input_temp = fopen($temp_name, "wb+"); - stream_copy_to_stream($input, $input_temp); - fclose($input); - - fseek($input_temp, -32, SEEK_END); - $hash = unpack("H64hash256", fread($input_temp, 32)); - fclose($input_temp); - - $id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $hash["hash256"])), 62); - $file_path = $this->GetAbsoluteFilePath($id); - if(!file_exists($file_path)){ - rename($temp_name, $file_path); - return $id; - } - return null; - } - - public function GetFileSize($id) : int { - return filesize($this->GetAbsoluteFilePath($id)); - } - - public function ListFiles() : array { - return glob($this->GetUploadDirAbsolute() . "/*"); - } - } +UploadFolder = $dir; + $this->DocumentRoot = $root === null ? $_SERVER["DOCUMENT_ROOT"] : $root; + } + + public function SetFileStats($info) : void { + $redis = StaticRedis::WriteOp(); + $file_key = REDIS_PREFIX . $info->FileId; + + $redis->hMSet($file_key, array( + 'views' => $info->Views, + 'lastview' => $info->LastView + )); + } + + public function GetFileStats($id) : object { + $redis = StaticRedis::ReadOp(); + $file_key = REDIS_PREFIX . $id; + + $public_file_info = $redis->hMGet($file_key, array('views', 'lastview', 'islegacy', 'filename', 'mime')); + return (object)array( + "views" => ($public_file_info["views"] !== False ? $public_file_info["views"] : 0), + "lastview" => ($public_file_info["lastview"] !== False ? $public_file_info["lastview"] : 0), + "islegacy" => ($public_file_info["islegacy"] !== False ? $public_file_info["islegacy"] === "1" : false), + "filename" => ($public_file_info["filename"] !== False ? $public_file_info["filename"] : ""), + "mime" => ($public_file_info["mime"] !== False ? $public_file_info["mime"] : ""), + ); + } + + public function SetAsLegacyFile($info) : void { + $redis = StaticRedis::WriteOp(); + $file_key = REDIS_PREFIX . $info->FileId; + $redis->hMSet($file_key, array( + 'islegacy' => true, + 'filename' => $info->LegacyFilename, + 'mime' => $info->LegacyMime + )); + } + + public function GetUploadDirAbsolute() : string { + return "$this->DocumentRoot/$this->UploadFolder"; + } + + public function GetRelativeFilePath($id) : string { + return "$this->UploadFolder/$id"; + } + + public function GetAbsoluteFilePath($id) : string { + return $this->GetUploadDirAbsolute() . "/" . $id; + } + + public function GetFileInfo($id) : ?FileInfo { + $file_path = $this->GetAbsoluteFilePath($id); + if($this->FileExists($id)) { + $stats = $this->GetFileStats($id); + $file_stat = stat($file_path); + + $file = new FileInfo(); + $file->FileId = $id; + $file->Views = intval($stats->views); + $file->LastView = intval($stats->lastview); + $file->Size = $file_stat["size"]; + $file->Uploaded = $file_stat["ctime"]; + + $file->IsLegacyUpload = $stats->islegacy; + $file->LegacyFilename = $stats->filename; + $file->LegacyMime = $stats->mime; + + return $file; + } + return NULL; + } + + public function FileExists($id) : bool { + $file_path = $this->GetAbsoluteFilePath($id); + return file_exists($file_path); + } + + public function StoreFile($file, $id) : bool { + $file_path = $this->GetAbsoluteFilePath($id); + + if(!file_exists($file_path)) { + $fout = fopen($file_path, 'wb+'); + stream_copy_to_stream($file, $fout); + fclose($fout); + return true; + } + return false; + } + + public function StoreV1File($bf, $file) : ?string { + $id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $bf->Hash)), 62); + + $input = fopen($file, "rb"); + $res = $this->StoreFile($input, $id); + fclose($input); + + return $res ? $id : null; + } + + public function StoreV2File($bf, $file) : ?string { + //we need to seek to the end before finding the id, do that first + $input = fopen($file, "rb"); + $temp_name = tempnam($this->GetUploadDirAbsolute(), "VTMP_"); + $input_temp = fopen($temp_name, "wb+"); + stream_copy_to_stream($input, $input_temp); + fclose($input); + + fseek($input_temp, -32, SEEK_END); + $hash = unpack("H64hash256", fread($input_temp, 32)); + fclose($input_temp); + + $id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $hash["hash256"])), 62); + $file_path = $this->GetAbsoluteFilePath($id); + if(!file_exists($file_path)){ + rename($temp_name, $file_path); + return $id; + } + return null; + } + + public function GetFileSize($id) : int { + return filesize($this->GetAbsoluteFilePath($id)); + } + + public function ListFiles() : array { + return glob($this->GetUploadDirAbsolute() . "/*"); + } + } ?> \ No newline at end of file diff --git a/src/php/handler.php b/src/php/handler.php index 8b64520..b803e91 100644 --- a/src/php/handler.php +++ b/src/php/handler.php @@ -1,25 +1,25 @@ -HandleRequest(); - exit(); - } - } - } - //var_dump($_REQUEST); - http_response_code(400); - exit(); - } else { - http_response_code(500); - exit(); - } +HandleRequest(); + exit(); + } + } + } + //var_dump($_REQUEST); + http_response_code(400); + exit(); + } else { + http_response_code(500); + exit(); + } ?> \ No newline at end of file diff --git a/src/php/info.php b/src/php/info.php index 472679a..6e869b6 100644 --- a/src/php/info.php +++ b/src/php/info.php @@ -1,7 +1,7 @@ - \ No newline at end of file diff --git a/src/php/init.php b/src/php/init.php index f02280c..93f432e 100644 --- a/src/php/init.php +++ b/src/php/init.php @@ -1,13 +1,13 @@ - \ No newline at end of file diff --git a/src/php/requesthandler.php b/src/php/requesthandler.php index 23fc844..77e5c0e 100644 --- a/src/php/requesthandler.php +++ b/src/php/requesthandler.php @@ -1,5 +1,5 @@ - \ No newline at end of file diff --git a/src/php/staticredis.php b/src/php/staticredis.php index 937533f..a6ae986 100644 --- a/src/php/staticredis.php +++ b/src/php/staticredis.php @@ -1,35 +1,35 @@ -pconnect(REDIS_CONFIG); - if($con){ - $rep = self::$Instance->info(); - if($rep["role"] == "slave"){ - self::$IsConnectedToSlave = true; - self::$MasterInstance = new Redis(); - $mcon = self::$MasterInstance->pconnect($rep["master_host"], $rep["master_port"]); - return $con && $mcon; - } - } - return $con; - } - } +pconnect(REDIS_CONFIG); + if($con){ + $rep = self::$Instance->info(); + if($rep["role"] == "slave"){ + self::$IsConnectedToSlave = true; + self::$MasterInstance = new Redis(); + $mcon = self::$MasterInstance->pconnect($rep["master_host"], $rep["master_port"]); + return $con && $mcon; + } + } + return $con; + } + } ?> \ No newline at end of file diff --git a/src/php/stats.php b/src/php/stats.php index 0f94c42..c2af005 100644 --- a/src/php/stats.php +++ b/src/php/stats.php @@ -1,79 +1,79 @@ -get(self::$AllTransferStatsKey . $stat_key); - if($val != False){ - $ret[$stat_key] = intval($val); - } else { - $ret[$stat_key] = 0; - } - } - - return $ret; - } - - public static function Get() : Stats { - $redis = StaticRedis::ReadOp(); - - //calculate 24hr transfer stats - $tx_24h = 0; - foreach(self::GetTxStats(24) as $time => $bytes) { - $tx_24h += $bytes; - } - - //get general stats - $general = (object)$redis->hMGet(self::$GeneralStatsKey, array("files", "size")); - - $ret = new Stats(); - $ret->Transfer_24h = $tx_24h; - $ret->Files = intval($general->files !== False ? $general->files : 0); - $ret->Size = intval($general->size !== False ? $general->size : 0); - - return $ret; - } - - public static function TrackTransfer($id, $size) : void { - self::AddAllTransfer($size); - } - - public static function AddAllTransfer($size) : void { - $redis = StaticRedis::WriteOp(); - $stat_member = date("YmdH"); - $redis->incrBy(self::$AllTransferStatsKey . $stat_member, $size); - $redis->setTimeout(self::$AllTransferStatsKey . $stat_member, 2592000); //store 30 days only - } - - public static function Collect($fs) : void { - $redis = StaticRedis::WriteOp(); - - $files = $fs->ListFiles(); - $total_size = 0; - foreach($files as $file) { - $total_size += filesize($file); - } - - $redis->hMSet(self::$GeneralStatsKey, array( - "files" => count($files), - "size" => $total_size - )); - - //tick from cron job to create keys for every hour - //if no downloads are happening we will be missing keys - //this will prevent inaccurate reporting - self::AddAllTransfer(0); - } - } +get(self::$AllTransferStatsKey . $stat_key); + if($val != False){ + $ret[$stat_key] = intval($val); + } else { + $ret[$stat_key] = 0; + } + } + + return $ret; + } + + public static function Get() : Stats { + $redis = StaticRedis::ReadOp(); + + //calculate 24hr transfer stats + $tx_24h = 0; + foreach(self::GetTxStats(24) as $time => $bytes) { + $tx_24h += $bytes; + } + + //get general stats + $general = (object)$redis->hMGet(self::$GeneralStatsKey, array("files", "size")); + + $ret = new Stats(); + $ret->Transfer_24h = $tx_24h; + $ret->Files = intval($general->files !== False ? $general->files : 0); + $ret->Size = intval($general->size !== False ? $general->size : 0); + + return $ret; + } + + public static function TrackTransfer($id, $size) : void { + self::AddAllTransfer($size); + } + + public static function AddAllTransfer($size) : void { + $redis = StaticRedis::WriteOp(); + $stat_member = date("YmdH"); + $redis->incrBy(self::$AllTransferStatsKey . $stat_member, $size); + $redis->setTimeout(self::$AllTransferStatsKey . $stat_member, 2592000); //store 30 days only + } + + public static function Collect($fs) : void { + $redis = StaticRedis::WriteOp(); + + $files = $fs->ListFiles(); + $total_size = 0; + foreach($files as $file) { + $total_size += filesize($file); + } + + $redis->hMSet(self::$GeneralStatsKey, array( + "files" => count($files), + "size" => $total_size + )); + + //tick from cron job to create keys for every hour + //if no downloads are happening we will be missing keys + //this will prevent inaccurate reporting + self::AddAllTransfer(0); + } + } ?> \ No newline at end of file diff --git a/src/php/sync.php b/src/php/sync.php index 61c5809..521ac3c 100644 --- a/src/php/sync.php +++ b/src/php/sync.php @@ -1,59 +1,59 @@ -max_upload_size); - ini_set('upload_max_filesize', Config::$Instance->max_upload_size); - ini_set('memory_limit', Config::$Instance->max_upload_size); - ini_set('enable_post_data_reading', 0); - } - - public function HandleRequest() : void { - if(isset($_SERVER["HTTP_X_FILE_ID"])) { - $id = $_SERVER["HTTP_X_FILE_ID"]; - $fs = new FileStore(Config::$Instance->upload_folder); - if(!$fs->FileExists($id)) { - //resolve the hostnames to ips - $redis = StaticRedis::ReadOp(); - $sync_hosts = $redis->sMembers(REDIS_PREFIX . 'sync-hosts'); - - $sync_hosts_ips = array(); - foreach($sync_hosts as $host) { - $sync_hosts_ips[] = gethostbyname($host); - } - - //check the ip of the host submitting the file for sync - if(in_array(USER_IP, $sync_hosts_ips)) { - $fs->StoreFile("php://input", $id); - http_response_code(201); - } else { - http_response_code(401); - } - } else { - http_response_code(200); - } - } else { - http_response_code(400); - } - } - - public static function SyncFile($id, $filename, $host) : int { - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, "https://$host/sync"); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($filename)); - curl_setopt($ch, CURLOPT_HTTPHEADER, array( - "Content-Type: application/octet-stream", - "X-File-Id: " . $id - )); - curl_exec($ch); - $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); - curl_close ($ch); - - return intval($status); - } - } - -?> \ No newline at end of file +max_upload_size); + ini_set('upload_max_filesize', Config::$Instance->max_upload_size); + ini_set('memory_limit', Config::$Instance->max_upload_size); + ini_set('enable_post_data_reading', 0); + } + + public function HandleRequest() : void { + if(isset($_SERVER["HTTP_X_FILE_ID"])) { + $id = $_SERVER["HTTP_X_FILE_ID"]; + $fs = new FileStore(Config::$Instance->upload_folder); + if(!$fs->FileExists($id)) { + //resolve the hostnames to ips + $redis = StaticRedis::ReadOp(); + $sync_hosts = $redis->sMembers(REDIS_PREFIX . 'sync-hosts'); + + $sync_hosts_ips = array(); + foreach($sync_hosts as $host) { + $sync_hosts_ips[] = gethostbyname($host); + } + + //check the ip of the host submitting the file for sync + if(in_array(USER_IP, $sync_hosts_ips)) { + $fs->StoreFile(fopen("php://input", "rb"), $id); + http_response_code(201); + } else { + http_response_code(401); + } + } else { + http_response_code(200); + } + } else { + http_response_code(400); + } + } + + public static function SyncFile($id, $filename, $host) : int { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, "https://$host/sync"); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, file_get_contents($filename)); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + "Content-Type: application/octet-stream", + "X-File-Id: " . $id + )); + curl_exec($ch); + $status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE); + curl_close ($ch); + + return intval($status); + } + } + +?> diff --git a/src/php/syncthread.php b/src/php/syncthread.php index 8818459..14e6322 100644 --- a/src/php/syncthread.php +++ b/src/php/syncthread.php @@ -1,18 +1,18 @@ -Id = $id; - $this->FilePath = $filepath; - $this->Destination = $host; - } - - public function run() { - Sync::SyncFile($this->Id, $this->FilePath, $this->Destination); - } - } - +Id = $id; + $this->FilePath = $filepath; + $this->Destination = $host; + } + + public function run() { + Sync::SyncFile($this->Id, $this->FilePath, $this->Destination); + } + } + ?> \ No newline at end of file diff --git a/src/php/tracking.php b/src/php/tracking.php index 4b340d8..a2ee6ed 100644 --- a/src/php/tracking.php +++ b/src/php/tracking.php @@ -1,62 +1,64 @@ -GetFileSize($id); - - if(!$this->IsRangeRequest()) { - $redis->hIncrBy($file_key, 'views', 1); - $redis->hSet($file_key, 'lastview', time()); - - Stats::TrackTransfer($id, $file_size); - } else { - $range = $this->GetRequestRange($file_size); - Stats::TrackTransfer($id, $range->end - $range->start); - } - } - - function GetRequestRange($len) : ?object { - if(isset($_SERVER['HTTP_RANGE'])) { - $rby = explode('=', $_SERVER['HTTP_RANGE']); - $rbv = explode('-', $rby[1]); - return (object)array( - "start" => intval($rbv[0]), - "end" => intval($rbv[1] == "" ? $len : $rbv[1]) - ); - } - - return null; - } - - function IsRangeRequest() : bool { - $range = $this->GetRequestRange(0); - if($range !== null){ - if($range->start != 0){ - return true; - } - } - return false; - } - - public static function SendMatomoEvent() : void { - $msg = "?" . http_build_query(array( - "idsite" => 3, - "rec" => 1, - "apiv" => 1, - "_id" => isset($_COOKIE["VC:UID"]) ? $_COOKIE["VC:UID"] : uniqid(), - "url" => (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]", - "cip" => USER_IP, - "ua" => isset($_SERVER["HTTP_USER_AGENT"]) ? $_SERVER["HTTP_USER_AGENT"] : "", - "urlref" => isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "", - "h" => date("H"), - "m" => date("i"), - "s" => date("s") - )); - - //this should be sent to the slave node if we are connected on a slave - StaticRedis::ReadOp()->publish(StaticRedis::$IsConnectedToSlave ? 'v3-matomo' : 'v3-matomo-master', $msg); - } - } +GetFileSize($id); + + if(!$this->IsRangeRequest()) { + $this->TrackView($id); + Stats::TrackTransfer($id, $file_size); + } else { + $range = $this->GetRequestRange($file_size); + Stats::TrackTransfer($id, $range->end - $range->start); + } + } + + public function TrackView($id) : void { + $redis = StaticRedis::WriteOp(); + $file_key = REDIS_PREFIX . $id; + $redis->hIncrBy($file_key, 'views', 1); + $redis->hSet($file_key, 'lastview', time()); + } + + function GetRequestRange($len) : ?object { + if(isset($_SERVER['HTTP_RANGE'])) { + $rby = explode('=', $_SERVER['HTTP_RANGE']); + $rbv = explode('-', $rby[1]); + return (object)array( + "start" => intval($rbv[0]), + "end" => intval($rbv[1] == "" ? $len : $rbv[1]) + ); + } + + return null; + } + + function IsRangeRequest() : bool { + $range = $this->GetRequestRange(0); + if($range !== null){ + if($range->start != 0){ + return true; + } + } + return false; + } + + public static function SendMatomoEvent() : void { + $msg = "?" . http_build_query(array( + "idsite" => 3, + "rec" => 1, + "apiv" => 1, + "_id" => isset($_COOKIE["VC:UID"]) ? $_COOKIE["VC:UID"] : uniqid(), + "url" => (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]", + "cip" => USER_IP, + "ua" => isset($_SERVER["HTTP_USER_AGENT"]) ? $_SERVER["HTTP_USER_AGENT"] : "", + "urlref" => isset($_SERVER["HTTP_REFERER"]) ? $_SERVER["HTTP_REFERER"] : "", + "h" => date("H"), + "m" => date("i"), + "s" => date("s") + )); + + //this should be sent to the slave node if we are connected on a slave + StaticRedis::ReadOp()->publish(StaticRedis::$IsConnectedToSlave ? 'v3-matomo' : 'v3-matomo-master', $msg); + } + } ?> \ No newline at end of file diff --git a/src/php/upload.php b/src/php/upload.php index ecad26d..9c54c97 100644 --- a/src/php/upload.php +++ b/src/php/upload.php @@ -1,151 +1,158 @@ -max_upload_size); - ini_set('upload_max_filesize', Config::$Instance->max_upload_size); - ini_set('memory_limit', Config::$Instance->max_upload_size); - ini_set('enable_post_data_reading', 0); - - //check upload dir exists - if(!file_exists("$_SERVER[DOCUMENT_ROOT]/" . Config::$Instance->upload_folder)){ - mkdir("$_SERVER[DOCUMENT_ROOT]/" . Config::$Instance->upload_folder); - } - } - - public function HandleRequest() : void { - if(isset($_SERVER["HTTP_ORIGIN"])) { - header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]); - header("Access-Control-Allow-Method: POST,OPTIONS"); - header("Access-Control-Allow-Headers: Content-Type"); - } - - $rsp = new UploadResponse(); - $file_size = $_SERVER["CONTENT_LENGTH"]; - - if($file_size > Config::$Instance->max_upload_size){ - $rsp->status = 1; - $rsp->msg = "File is too large"; - } else { - $auth = new Auth(); - $token = $auth->GetBearerToken(); - - if($token !== null) { - if($auth->CheckApiToken($token)) { - $id = $this->SaveLegacyUpload(); - - //sync to other servers - if($id !== null) { - $rsp->sync = $this->SyncFileUpload($id); - $rsp->status = 200; - $rsp->id = $id; - } else { - $rsp->status = 3; - $rsp->msg = "Legacy upload error"; - } - } else { - http_response_code(403); - exit(); - } - } else { - $read_from = "php://input"; - $bf = BlobFile::LoadHeader($read_from); - - if($bf != null){ - //save upload - $id = $this->SaveUpload($bf, $read_from); - - //sync to other servers - if($id == null) { - $rsp->status = 4; - $rsp->msg = "Invalid VBF or file already exists"; - } else { - $rsp->sync = $this->SyncFileUpload($id); - $rsp->status = 200; - $rsp->id = $id; - } - } else { - $rsp->status = 2; - $rsp->msg = "Invalid file header"; - } - } - } - header('Content-Type: application/json'); - echo json_encode($rsp); - } - - function SyncFileUpload($id) : array { - $redis = StaticRedis::ReadOp(); - $sync_hosts = $redis->sMembers(REDIS_PREFIX . 'sync-hosts'); - if($sync_hosts !== False) { - $fs = new FileStore(Config::$Instance->upload_folder); - - $status_codes = []; - foreach($sync_hosts as $host) { - $status_codes[] = Sync::SyncFile($id, $fs->GetAbsoluteFilePath($id), $host); - } - - return $status_codes; - } - - return array(); - } - - function SaveUpload($bf, $rf) : ?string { - $fs = new FileStore(Config::$Instance->upload_folder); - switch($bf->Version) { - case 1: - return $fs->StoreV1File($bf, $rf); - case 2: - return $fs->StoreV2File($bf, $rf); - } - return null; - } - - function SaveLegacyUpload() : ?string { - if(isset($_SERVER["HTTP_X_LEGACY_FILENAME"])){ - $hash = hash_file("sha256", "php://input"); - $id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $hash)), 62); - - $fs = new FileStore(Config::$Instance->upload_folder); - $fs->StoreFile(fopen("php://input", "rb"), $id); - - $info = new FileInfo(); - $info->FileId = $id; - $info->LegacyFilename = $_SERVER["HTTP_X_LEGACY_FILENAME"]; - $info->LegacyMime = isset($_SERVER["CONTENT_TYPE"]) ? $_SERVER["CONTENT_TYPE"] : "application/octet-stream"; - - $fs->SetAsLegacyFile($info); - return $id; - } - return null; - } - - public static function GetUploadHost() : string { - $cont = geoip_continent_code_by_name(USER_IP); - if($cont === False){ - $cont = "EU"; - } - - $redis = StaticRedis::ReadOp(); - $map = $redis->hGetAll(REDIS_PREFIX . "upload-region-mapping"); - if($map !== False && isset($map[$cont])) { - return $map[$cont]; - } else { - return $_SERVER["HTTP_HOST"]; - } - } - } +max_upload_size); + ini_set('upload_max_filesize', Config::$Instance->max_upload_size); + ini_set('memory_limit', Config::$Instance->max_upload_size); + ini_set('enable_post_data_reading', 0); + + //check upload dir exists + if(!file_exists("$_SERVER[DOCUMENT_ROOT]/" . Config::$Instance->upload_folder)){ + mkdir("$_SERVER[DOCUMENT_ROOT]/" . Config::$Instance->upload_folder); + } + } + + public function HandleRequest() : void { + if(isset($_SERVER["HTTP_ORIGIN"])) { + header("Access-Control-Allow-Origin: " . $_SERVER["HTTP_ORIGIN"]); + header("Access-Control-Allow-Method: POST,OPTIONS"); + header("Access-Control-Allow-Headers: Content-Type"); + } + + $rsp = new UploadResponse(); + $file_size = $_SERVER["CONTENT_LENGTH"]; + + if($file_size > Config::$Instance->max_upload_size){ + $rsp->status = 1; + $rsp->msg = "File is too large"; + } else { + $auth = new Auth(); + $tracking = new Tracking(); + $token = $auth->GetBearerToken(); + + if($token !== null) { + if($auth->CheckApiToken($token)) { + $id = $this->SaveLegacyUpload(); + + //sync to other servers + if($id !== null) { + $rsp->sync = $this->SyncFileUpload($id); + $rsp->status = 200; + $rsp->id = $id; + + //finally set the last view to now + $tracking->TrackView($id); + } else { + $rsp->status = 3; + $rsp->msg = "Legacy upload error"; + } + } else { + http_response_code(403); + exit(); + } + } else { + $read_from = "php://input"; + $bf = BlobFile::LoadHeader($read_from); + + if($bf != null){ + //save upload + $id = $this->SaveUpload($bf, $read_from); + + //sync to other servers + if($id == null) { + $rsp->status = 4; + $rsp->msg = "Invalid VBF or file already exists"; + } else { + $rsp->sync = $this->SyncFileUpload($id); + $rsp->status = 200; + $rsp->id = $id; + + //finally set the last view to now + $tracking->TrackView($id); + } + } else { + $rsp->status = 2; + $rsp->msg = "Invalid file header"; + } + } + } + header('Content-Type: application/json'); + echo json_encode($rsp); + } + + function SyncFileUpload($id) : array { + $redis = StaticRedis::ReadOp(); + $sync_hosts = $redis->sMembers(REDIS_PREFIX . 'sync-hosts'); + if($sync_hosts !== False) { + $fs = new FileStore(Config::$Instance->upload_folder); + + $status_codes = []; + foreach($sync_hosts as $host) { + $status_codes[] = Sync::SyncFile($id, $fs->GetAbsoluteFilePath($id), $host); + } + + return $status_codes; + } + + return array(); + } + + function SaveUpload($bf, $rf) : ?string { + $fs = new FileStore(Config::$Instance->upload_folder); + switch($bf->Version) { + case 1: + return $fs->StoreV1File($bf, $rf); + case 2: + return $fs->StoreV2File($bf, $rf); + } + return null; + } + + function SaveLegacyUpload() : ?string { + if(isset($_SERVER["HTTP_X_LEGACY_FILENAME"])){ + $hash = hash_file("sha256", "php://input"); + $id = gmp_strval(gmp_init("0x" . hash(Config::$Instance->public_hash_algo, $hash)), 62); + + $fs = new FileStore(Config::$Instance->upload_folder); + $fs->StoreFile(fopen("php://input", "rb"), $id); + + $info = new FileInfo(); + $info->FileId = $id; + $info->LegacyFilename = $_SERVER["HTTP_X_LEGACY_FILENAME"]; + $info->LegacyMime = isset($_SERVER["CONTENT_TYPE"]) ? $_SERVER["CONTENT_TYPE"] : "application/octet-stream"; + + $fs->SetAsLegacyFile($info); + return $id; + } + return null; + } + + public static function GetUploadHost() : string { + $cont = geoip_continent_code_by_name(USER_IP); + if($cont === False){ + $cont = "EU"; + } + + $redis = StaticRedis::ReadOp(); + $map = $redis->hGetAll(REDIS_PREFIX . "upload-region-mapping"); + if($map !== False && isset($map[$cont])) { + return $map[$cont]; + } else { + return $_SERVER["HTTP_HOST"]; + } + } + } ?> \ No newline at end of file