This commit is contained in:
2023-01-02 19:56:44 +08:00
commit e187878b7a
3244 changed files with 260239 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
<?php
namespace app\controller;
use Webman\Captcha\CaptchaBuilder;
use Respect\Validation\Validator as v;
use support\Request;
use yzh52521\EasyHttp\Response;
use yzh52521\EasyHttp\RequestException;
use yzh52521\EasyHttp\Http;
use support\Redis;
use support\View;
class File
{
public function check(Request $request)
{
$id=$request->cookie('id', 'blank');
$key=$request->cookie('key', 'blank');
$path=$request->input('path','blank');
if($key=='blank' || $id=='blank'){
return json(['code'=>509,'msg'=>'未登录或参数错误']);
}
$name=base64_encode($path);
$redis = Redis::connection('default');
if($redis->exists('BookCache_'.$name)){
if($redis->hget('BookCache_'.$name,'Status')=='OK'){
return json(['code'=>200, 'msg'=>'找到文件', 'size'=>$redis->hget('BookCache_'.$name,'Size'),'name'=>$redis->hget('BookCache_'.$name,'Name')]);
}else{
return json(['code'=>202,'msg'=>'文件下载中']);
}
}else {
return json(['code'=>201, 'msg'=>'未找到文件']);
}
}
public function download(Request $request)
{
$id=$request->cookie('id', 'blank');
$key=$request->cookie('key', 'blank');
$path=$request->input('path','blank');
if($key=='blank' || $id=='blank'){
return json(['code'=>509,'msg'=>'未登录或参数错误']);
}
$auth=array('remix_userid'=>"$id",'remix_userkey'=>"$key",'siteLanguageV2'=>'zh','selectedSiteMode'=>'books');
$url='http://'.getenv('Zlibrary')."$path";
$get=Http::withProxy('socks5h://'.getenv('proxy'))->withCookies($auth,getenv('Zlibrary'));
$head=$get->head($url);
$ContentLength=(int)$head->header('Content-Length');
$size=round(($ContentLength/1048576),2);
if($size>=30){
return json(['code'=>500,'msg'=>'文件太大了!']);
}
if($head->header('Content-Type')=='text/html; charset=UTF-8'){
return json(['code'=>404,'msg'=>'链接错误']);
}
$redis = Redis::connection('default');
$name=base64_encode($path);
$redis->hset('BookCache_'.$name,'Time',time());
$redis->hset('BookCache_'.$name,'Date',date("Y/m/d H:i:s"));
$redis->hset('BookCache_'.$name,'Status','Downloading');
if(!is_dir(base_path().'/books/'.date("Y/m/"))){
mkdir(base_path().'/books/'.date("Y/m/"),0777,true);
}
$filepath=base_path().'/books/'.date("Y/m/").$name.'.bin';
$return=$get->get($url)->body();
$file = fopen("$filepath","w");
fwrite($file,$return);
fclose($file);
$filerealname=explode('"',explode(";",$head->header('Content-Disposition'))[1])[1];
$redis->hset('BookCache_'.$name,'Path',$filepath);
$redis->hset('BookCache_'.$name,'Size',$size);
$redis->hset('BookCache_'.$name,'Name',$filerealname);
$redis->hset('BookCache_'.$name,'Status','OK');
return json(['code'=>200,'name'=>"$filerealname",'size'=>"$size"]);
}
public function get(Request $request)
{
$id=$request->cookie('id', 'blank');
$key=$request->cookie('key', 'blank');
$path=$request->input('path','blank');
if($key=='blank' || $id=='blank'){
return json(['code'=>509,'msg'=>'未登录或参数错误']);
}
$redis = Redis::connection('default');
$name=base64_encode($path);
if($redis->exists('BookCache_'.$name)){
if($redis->hget('BookCache_'.$name,'Status')=='OK'){
$redis->hset('BookCache_'.$name,'LastDown',time());
return response()->download($redis->hget('BookCache_'.$name,'Path'),$redis->hget('BookCache_'.$name,'Name'));
}else{
return json(['code'=>202,'msg'=>'文件仍在下载中']);
}
}else {
return json(['code'=>201, 'msg'=>'未找到文件']);
}
}
}
+173
View File
@@ -0,0 +1,173 @@
<?php
namespace app\controller;
use Webman\Captcha\CaptchaBuilder;
use Respect\Validation\Validator as v;
use support\Request;
use yzh52521\EasyHttp\Response;
use yzh52521\EasyHttp\RequestException;
use yzh52521\EasyHttp\Http;
use support\Redis;
use support\View;
class IndexController
{
public function index(Request $request)
{
$redis = Redis::connection('default');
$kf='ProxyCache_';
$response = response();
$id=$request->cookie('id', 'blank');
$key=$request->cookie('key', 'blank');
if($key=='blank' || $id=='blank'){
return redirect('/login');
}
$path=$request->uri();
if($path==''||$path=='/'){
$path='/?signAll=1&ts=1657';
}
$rpath=$kf.urlencode("$path");
if($redis->get($rpath)){
$response->withHeaders(json_decode($redis->hget($rpath,'CT')));
$response->withBody($redis->hget($rpath,'body'));
return $response;
}
$url='http://'.getenv('Zlibrary').$path;
$auth=array('remix_userid'=>"$id",'remix_userkey'=>"$key",'siteLanguageV2'=>'zh','selectedSiteMode'=>'books');
$return = Http::withProxy('socks5h://'.getenv('proxy'))->withCookies($auth,getenv('Zlibrary'))->get($url);
$response->withHeaders($return->headers());
$back=$return->body();
if($return->header('Content-Type')=='text/html; charset=UTF-8'){
$ver=getenv('version');
$front= <<<EOF
<html><body>
<center>
<div style="background-color: bisque;color: black;position:fixed!important;font-size:1.8rem;line-height:1.618;z-index:9999!important;text-align:-webkit-center;">
Zlibrary Proxy(v$ver) UserID:$id <a style="color: coral;" href="/login/logout">[退出账号]</a><a style="color: black;" href="//www.pmnet.gq" target="_blank_pmnet"> [PublicMirrorsNetwork]</a>
</div>
</center></body></html>
EOF;
$back=$front.$back;
}
/**Make Cache */
if($path=='/resources/build/global.js?0.495' || $path=='/resources/build/global.css?0.495' || $path=='/resources/ext/freewall.js' || preg_match("/^image*/",$return->header('Content-Type')) ){
$redis->hset($rpath,'CT',json_encode($return->headers()));
$redis->hset($rpath,'body',$back);
$redis->expire($rpath,43200);
}
$response->withBody($back);
return $response;
}
public function login(Request $request)
{
return view('login');
}
public function check(Request $request)
{
$username=$request->post('name','blank');
$password=$request->post('password','blank');
$code=$request->post('code','blank');
if($username=='blank' || $password=='blank' || $code=='blank'){
return json(['code'=>500, 'msg'=>'缺少参数']);
}
try {
$V=v::Email()->setName('用户名')->check($username);
} catch (ValidationException $exception) {
return json(['code'=>500, 'msg'=>$exception->getMessage()]);
}
try {
$V=v::stringType()->setName('密码')->noWhitespace()->check($password);
} catch (ValidationException $exception) {
return json(['code'=>500, 'msg'=>$exception->getMessage()]);
}
try {
$V=v::stringType()->length(5, 5)->setName('验证码')->noWhitespace()->check($code);
} catch (ValidationException $exception) {
return json(['code'=>500, 'msg'=>$exception->getMessage()]);
}
if (strtolower($code) !== $request->session()->get('captcha')) {
return json(['code' => 400, 'msg' => '输入的验证码不正确']);
}
$url='http://'.getenv('ZlibraryLogin').'/rpc.php';
$response = Http::withProxy('socks5h://'.getenv('proxy'))->post("$url", ['isModal' => true,'email'=>"$username",'password'=>"$password",'site_mode'=>'books','action'=>'login','redirectUrl'=>'','isSinglelogin'=>'1','isTorVersion'=>'1','gg_json_mode'=>'1']);
if(!$response->successful()){
return json(['code' => 501, 'msg' => '登陆失败,服务端错误']);
}
$return=$response->body();
$return=json_decode($return);
if(isset($return->response->validationError)){
return json(['code' => 502, 'msg' => 'Zlib登陆失败:'.$return->response->message]);
}
$url=parse_url($return->response->params)['query'];
$queryParts = explode('&', $url);
$params = array();
foreach ($queryParts as $param) {
$item = explode('=', $param);
$params[$item[0]] = $item[1];
}
return json(['code'=>200,'msg'=>'登陆成功','userid'=>$params['remix_userid']])->cookie('id', $params['remix_userid'],43200,'/')->cookie('key', $params['remix_userkey'],43200,'/');
}
public function code(Request $request)
{
// 初始化验证码类
$builder = new CaptchaBuilder;
// 生成验证码
$builder->build();
// 将验证码的值存储到session中
$request->session()->set('captcha', strtolower($builder->getPhrase()));
// 获得验证码图片二进制数据
$img_content = $builder->get();
// 输出验证码二进制数据
return response($img_content, 200, ['Content-Type' => 'image/jpeg']);
}
public function logout(Request $request)
{
$response = response();
$response->cookie('id','', -1,'/');
$response->cookie('key','', -1,'/');
$response->header('Location', '/login');
$response->withStatus(302);
return $response;
}
public function download(Request $request)
{
$id=$request->cookie('id', 'blank');
$key=$request->cookie('key', 'blank');
if($key=='blank' || $id=='blank'){
return redirect('/login');
}
$path=$request->uri();
View::assign([
'id' => $id,
'key'=> $key,
'path'=> $path,
]);
return view('index');
}
public function file(Request $request)
{
return response()->file(base_path() . '/app/controller/IndexController.php');
}
}
+4
View File
@@ -0,0 +1,4 @@
<?php
/**
* Here is your custom functions.
*/
+42
View File
@@ -0,0 +1,42 @@
<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
/**
* Class StaticFile
* @package app\middleware
*/
class StaticFile implements MiddlewareInterface
{
public function process(Request $request, callable $next): Response
{
// Access to files beginning with. Is prohibited
if (strpos($request->path(), '/.') !== false) {
return response('<h1>403 forbidden</h1>', 403);
}
/** @var Response $response */
$response = $next($request);
// Add cross domain HTTP header
/*$response->withHeaders([
'Access-Control-Allow-Origin' => '*',
'Access-Control-Allow-Credentials' => 'true',
]);*/
return $response;
}
}
+26
View File
@@ -0,0 +1,26 @@
<?php
/**
* 节流设置
* @copyright The PHP-Tools
*/
namespace app\middleware;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
/**
* Class StaticFile
* @package app\middleware
*/
class Throttle implements MiddlewareInterface
{
public function process(Request $request, callable $next):Response
{
if ( $route = $request->route ) {
$params = $route->param();
}
return (new \yzh52521\middleware\Throttle())->handle($request, $next, $params??[]);
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
namespace app\model;
use support\Model;
class Test extends Model
{
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'test';
/**
* The primary key associated with the table.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
}
+164
View File
@@ -0,0 +1,164 @@
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<base href="/" />
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href='zlibproxy/normalize.css' rel='stylesheet' type='text/css'>
<link href="https://fonts.laysense.com/css/5000/zh-cn/douyufont/douyufont.css" rel="preload" as="style" onload="this.rel='stylesheet'">
<link href="https://fonts.laysense.com/css/5000/zh-cn/harmonyossans/harmonyossans.css" rel="preload" as="style" onload="this.rel='stylesheet'">
<link id="theme_css" rel="stylesheet" href="zlibproxy/sakura.css">
<style>
.pmnet { font-family: DOUYUFont;}
html {font-family: HarmonyOSSans;}
.animbox {
margin: 50px auto;
width: 200px;
text-align: center;
}
/*设置各竖条的共有样式*/
.animbox > div {
background-color: #279fcf;
width: 4px;
height: 35px;
border-radius: 2px;
margin: 2px;
animation-fill-mode: both;
display: inline-block;
animation: anim 0.9s 0s infinite cubic-bezier(.11, .49, .38, .78);
}
/*设置动画延迟*/
.animbox > :nth-child(2), .animbox > :nth-child(4) {
animation-delay: 0.25s !important;
}
.animbox > :nth-child(1), .animbox > :nth-child(5) {
animation-delay: 0.5s !important;
}
/*定义动画*/
@keyframes anim {
0% { transform: scaley(1); }
80% { transform: scaley(0.3); }
90% { transform: scaley(1); }
}
</style>
<title>(ProxyDownload)Z-Library</title>
</head>
<body>
<script>
//切换深色模式
if(window.matchMedia('(prefers-color-scheme: dark)').matches){
document.getElementById('theme_css').href = 'zlibproxy/sakura-dark.css';
}
</script>
<main>
<center>
<div style="background-color: bisque;color: black;">
Zlibrary Proxy(v<?php echo(getenv('version'));?>) UserID:<?php echo($id);?> <a style="color: coral;" href="/login/logout">[退出账号]</a>
</div>
</center>
<div id="container">
<a href="/" target="_blank_home">[返回ZlibraryProxy]</a>
<h1>下载图书</h1>
<div id="load" class="animbox" style="display: none;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<br />
</div>
<p id="notice"></p>
<hr />
<div id="down" style="display: none;">
<a id="downloadurl" target="_blank_downbook">
<h3 style="margin-top:15%;margin-bottom:15%">📥点此下载图书</h3><br /><p id="bookname"></p><br /><p id="booksize"></p>
</a>
<hr />
<button onclick="download()">下载内容打不开?点此重新生成文件</button>(重新生成将消耗Zlib每日次数)
</div>
<div id="start" style="display: none;">
<button onclick="download()">点此开始下载图书</button>
</div>
</div>
</main>
<script src="zlibproxy/jquery-3.6.3.min.js"></script>
<script>
var path='<?php echo($path) ?>';
$.ajax({
type: "POST",
url: '/zlibproxy/check',
data: {'path':path},
async: true,
dataType: 'json',
cache: false,
beforeSend: function () {
$('#notice').html('正在查询缓存,请稍等……');
$('#load').show();
},
success: function (data) {
if (data.code == 200) {
$('#notice').html('图书已被缓存,本次下载无需消耗Zlib每日次数');
$("#downloadurl").attr("href","/zlibproxy/get?path="+path);
$('#bookname').html(data.name);
$('#booksize').html(data.size+'MB');
$('#down').show();
}
if (data.code == 202) {
$('#notice').html('图书仍在下载中,请稍等 (5秒后刷新)');
setTimeout(function(){location.reload();},5000);
}
if (data.code == 201) {
$('#notice').html('图书暂未被缓存,本次下载需要消耗Zlib次数(请确保小于30Mb否则会浪费一次次数)');
$('#start').show();
}
if (data.code == 509) {
$('#notice').html('缺少参数或未登录');
setTimeout(function(){$(location).attr('href','/login')},1500);
}
$('#load').hide();
},
});
function download(){
$.ajax({
type: "POST",
url: '/zlibproxy/download',
data: {'path':path},
async: true,
dataType: 'json',
cache: false,
beforeSend: function () {
$('#notice').html('服务器正在通过Tor从Zlib下载图书……请耐心等待');
$('#load').show();
$('#start').hide();
},
success: function (data) {
if (data.code == 200) {
$('#notice').html('图书已获取成功,请点击下方链接下载图书');
$("#downloadurl").attr("href","/zlibproxy/get?path="+path);
$('#bookname').html(data.name);
$('#booksize').html(data.size+'MB');
$('#down').show();
$('#start').hide();
}
if (data.code == 500) {
$('#notice').html('文件过大(大于30Mb),暂时无法通过ZlibProxy下载');
$('#start').hide();
}
if (data.code == 400) {
$('#notice').html('图书不存在……请尝试别的图书');
$('#start').hide();
}
if (data.code == 509) {
$('#notice').html('缺少参数或未登录');
setTimeout(function(){$(location).attr('href','/login')},1500);
}
$('#load').hide();
},
});
}
</script>
</body>
</html>
+161
View File
@@ -0,0 +1,161 @@
<!--
Copyright (C) 2023 admin@pmnet.gq
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href='zlibproxy/normalize.css' rel='stylesheet' type='text/css'>
<link href="https://fonts.laysense.com/css/5000/zh-cn/douyufont/douyufont.css" rel="preload" as="style" onload="this.rel='stylesheet'">
<link href="https://fonts.laysense.com/css/5000/zh-cn/harmonyossans/harmonyossans.css" rel="preload" as="style" onload="this.rel='stylesheet'">
<link id="theme_css" rel="stylesheet" href="zlibproxy/sakura.css">
<style>
.pmnet { font-family: DOUYUFont;}
html {font-family: HarmonyOSSans;}
.animbox {
margin: 50px auto;
width: 200px;
text-align: center;
}
/*设置各竖条的共有样式*/
.animbox > div {
background-color: #279fcf;
width: 4px;
height: 35px;
border-radius: 2px;
margin: 2px;
animation-fill-mode: both;
display: inline-block;
animation: anim 0.9s 0s infinite cubic-bezier(.11, .49, .38, .78);
}
/*设置动画延迟*/
.animbox > :nth-child(2), .animbox > :nth-child(4) {
animation-delay: 0.25s !important;
}
.animbox > :nth-child(1), .animbox > :nth-child(5) {
animation-delay: 0.5s !important;
}
/*定义动画*/
@keyframes anim {
0% { transform: scaley(1); }
80% { transform: scaley(0.3); }
90% { transform: scaley(1); }
}
</style>
<title>镜像站增加申请-Mirrors.pw</title>
</head>
<body>
<script>
//切换深色模式
if(window.matchMedia('(prefers-color-scheme: dark)').matches){
document.getElementById('theme_css').href = 'zlibproxy/sakura-dark.css';
}
</script>
<main>
<h1>Z-library Proxy</h1><hr />
<p>这是一个Zlibrary的代理镜像</p>
<a href="https://www.pmnet.gq/" target="_blank_pmnet">由[<span class="pmnet">PublicMirrorsNetwork</span>]维护</a>
<blockquote>
本代理利用广大的Tor代理和中继节点,基于<a href="" target="_blank_tor">TOR</a>技术提供服务
<br />
本代理使用Laysense提供的强大内部SD-WAN技术
<br />
使用前请确保您的行为符合当地法律
<br />
由于Zlibrary的邮件服务器已经宕机,任何新注册和更改密码请求均无效,均无法使用,如果您的账号还未通过邮箱激活将无法使用本服务
<br />
<span style="color: coral;">本代理不会保存您的密码(仅在浏览器cookies保存您的ID)</span>
</blockquote>
<section>
<h4>登录到Z-Library</h4>
<hr />
<form action="new_apply.php" method="POST">
<p>
<label for="name">*Zlibrary账号(email)</label>
<input required="required" name="name" id="name" placeholder="Your Zlib Username" type="email" style="width:50%">
</p>
<p>
<label for="password">*Zlibrary密码</label>
<input required="required" name="password" id="password" placeholder="Your Zilb Password" type="password" style="width:50%">
</p>
<p>
<label for="password">*验证码 <img style="margin-bottom:0px" src="login/code" /></label>
<input required="required" name="code" id="code" placeholder="CaptchaCode" type="text" style="width:35%">
</p>
<div id="load" class="animbox" style="display: none;">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<p style="color: blueviolet;" id="notice"></p>
</form>
<p>
<button onclick="login()" value="登录" style="width:30%">登录</button>
</p>
</section>
</main>
<footer>
<hr/>
©PMNET.GQ 2023 Made with <a href="https://oxal.org/projects/sakura">sakura.css</a>
</footer>
<script src="zlibproxy/jquery-3.6.3.min.js"></script>
<script>
function login(){
var name = $("#name").val();
var password = $("#password").val();
var ccode = $("#code").val();
$.ajax({
type: "POST",
url: '/login/check',
data: {'name':name,'password':password,'code':ccode},
async: true,
dataType: 'json',
cache: false,
beforeSend: function () {
$('#notice').html('正在登录……(最多可能需要30秒以上,请耐心等待)');
$('#load').show();
},
success: function (data) {
if (data.code == 200) {
$('#notice').html('欢迎您'+data.userid+',正在前往Zlibrary镜像站,享受阅读的乐趣吧~');
setTimeout(function(){$(location).attr('href','/')},1500);
} else {
$('#notice').html(data.msg);
}
$('#load').hide();
},
clearForm: true,
resetForm: false
});
}
</script>
</body>
</html>