feat: add project files

This commit is contained in:
tlanyan 2021-01-03 23:25:48 +08:00
parent 835f47b437
commit 9d0d1e3eb7
7 changed files with 1261 additions and 7 deletions

7
.gitignore vendored
View File

@ -1,6 +1 @@
assets/* vendor/*
!assets/.gitignore
protected/runtime/*
!protected/runtime/.gitignore
protected/data/*.db
themes/classic/views/

View File

@ -1,2 +1,73 @@
# ghproxy # ghproxy
Github proxy for China mainland users
Github文件下载加速PHP版基于异步PHP框架 [ReactPHP](https://github.com/reactphp)开发。
本项目主要参考 [gh-proxy](https://github.com/hunshcn/gh-proxy)其js版可运行在CloudFflare Worker上并提供了可运行在docker中的Python版。
## 使用教程
### 1. 安装PHP和composer
如系统已经安装PHP和composer可略过。
CentOS系统安装最新版PHP可参考[使用Remi源安装最新版PHP 7和PHP 8](https://tlanyan.me/install-newest-php7-and-php8-with-remi-repo/)Debian/Ubuntu系统可使用下面命令安装PHP
````bash
apt update
apt php-cli php-fpm php-bcmath php-gd php-mbstring \
php-mysql php-opcache php-xml php-zip php-json php-imagick
````
接着安装composer
````bash
wget https://getcomposer.org/installer
php installer --install-dir=/usr/local/bin --filename=composer
rm -rf installer
````
### 2. 安装composer依赖
下载/克隆本项目代码,进入文件夹内执行安装命令:
````bash
composer install
# 可选,基本没必要
composer dump-autoload -o
````
打开 `index.php` 文件,视自己情况可修改如下几个配置(一般保持默认即可)
- `ADDR`程序监听的IP默认是本机。如果前端不需要web服务器请改成 `0.0.0.0`
- `PORT`: 程序监听的端口
- `JSDELIVR`是否使用jsdelivr加速
- `CNPMJS`是否使用cnpmjs.org加速
- `SIZE_LIMIT`最大可下载文件大小默认2GB
最后将项目文件夹放置到web目录例如将文件夹移动到 `/var/www` 目录内。
### 3. 安装Nginx可选
可以选择使用Nginx/Apache httpd/Caddy等中间件在前端接受web请求也可以让程序直接监听端口处理请求。如果采用https访问建议使用Nginx的web服务器。
安装Nginx:
````bash
# CentOS
yum install -y nginx
systemctl enable nginx
## Debian/Ubuntu
apt install -y nginx
````
接着按照实际情况修改项目中的 `ghproxy.conf` 文件修改完毕后复制到Nginx的配置目录内。
### 4. 启动程序
进入项目文件夹,执行 `nohup php index.php &`,也可以在 tmux/screen 等终端窗口内执行 `php index.php` 启动项目。
接下来,浏览器打开网址,输入要加速下载的链接,查看加速效果。
使用中遇到问题欢迎反馈。

17
composer.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "tlanyan/ghproxy",
"description": "Github.com proxy for China mainland users",
"type": "project",
"license": "MIT",
"authors": [
{
"name": "tlanyan",
"email": "tlanyan@hotmail.com"
}
],
"minimum-stability": "stable",
"require": {
"react/event-loop": "^1.1",
"react/http": "^1.2"
}
}

777
composer.lock generated Normal file
View File

@ -0,0 +1,777 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "f164857cf38dd1192079d0fcf6e28b77",
"packages": [
{
"name": "evenement/evenement",
"version": "v3.0.1",
"source": {
"type": "git",
"url": "https://github.com/igorw/evenement.git",
"reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/igorw/evenement/zipball/531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
"reference": "531bfb9d15f8aa57454f5f0285b18bec903b8fb7",
"shasum": ""
},
"require": {
"php": ">=7.0"
},
"require-dev": {
"phpunit/phpunit": "^6.0"
},
"type": "library",
"autoload": {
"psr-0": {
"Evenement": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Igor Wiedler",
"email": "igor@wiedler.ch"
}
],
"description": "Événement is a very simple event dispatching library for PHP",
"keywords": [
"event-dispatcher",
"event-emitter"
],
"support": {
"issues": "https://github.com/igorw/evenement/issues",
"source": "https://github.com/igorw/evenement/tree/master"
},
"time": "2017-07-23T21:35:13+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"homepage": "https://github.com/php-fig/http-message",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
},
"time": "2016-08-06T14:39:51+00:00"
},
{
"name": "react/cache",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/cache.git",
"reference": "44a568925556b0bd8cacc7b49fb0f1cf0d706a0c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/cache/zipball/44a568925556b0bd8cacc7b49fb0f1cf0d706a0c",
"reference": "44a568925556b0bd8cacc7b49fb0f1cf0d706a0c",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"react/promise": "^3.0 || ^2.0 || ^1.1"
},
"require-dev": {
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Cache\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christian Lück",
"email": "christian@clue.engineering",
"homepage": "https://clue.engineering/"
},
{
"name": "Cees-Jan Kiewiet",
"email": "reactphp@ceesjankiewiet.nl",
"homepage": "https://wyrihaximus.net/"
},
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com",
"homepage": "https://sorgalla.com/"
},
{
"name": "Chris Boden",
"email": "cboden@gmail.com",
"homepage": "https://cboden.dev/"
}
],
"description": "Async, Promise-based cache interface for ReactPHP",
"keywords": [
"cache",
"caching",
"promise",
"reactphp"
],
"support": {
"issues": "https://github.com/reactphp/cache/issues",
"source": "https://github.com/reactphp/cache/tree/v1.1.0"
},
"funding": [
{
"url": "https://github.com/WyriHaximus",
"type": "github"
},
{
"url": "https://github.com/clue",
"type": "github"
}
],
"time": "2020-09-18T12:12:35+00:00"
},
{
"name": "react/dns",
"version": "v1.4.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/dns.git",
"reference": "665260757171e2ab17485b44e7ffffa7acb6ca1f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/dns/zipball/665260757171e2ab17485b44e7ffffa7acb6ca1f",
"reference": "665260757171e2ab17485b44e7ffffa7acb6ca1f",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"react/cache": "^1.0 || ^0.6 || ^0.5",
"react/event-loop": "^1.0 || ^0.5",
"react/promise": "^3.0 || ^2.7 || ^1.2.1",
"react/promise-timer": "^1.2"
},
"require-dev": {
"clue/block-react": "^1.2",
"phpunit/phpunit": "^9.3 || ^4.8.35"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Dns\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christian Lück",
"email": "christian@clue.engineering",
"homepage": "https://clue.engineering/"
},
{
"name": "Cees-Jan Kiewiet",
"email": "reactphp@ceesjankiewiet.nl",
"homepage": "https://wyrihaximus.net/"
},
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com",
"homepage": "https://sorgalla.com/"
},
{
"name": "Chris Boden",
"email": "cboden@gmail.com",
"homepage": "https://cboden.dev/"
}
],
"description": "Async DNS resolver for ReactPHP",
"keywords": [
"async",
"dns",
"dns-resolver",
"reactphp"
],
"support": {
"issues": "https://github.com/reactphp/dns/issues",
"source": "https://github.com/reactphp/dns/tree/v1.4.0"
},
"funding": [
{
"url": "https://github.com/WyriHaximus",
"type": "github"
},
{
"url": "https://github.com/clue",
"type": "github"
}
],
"time": "2020-09-18T12:12:55+00:00"
},
{
"name": "react/event-loop",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/reactphp/event-loop.git",
"reference": "6d24de090cd59cfc830263cfba965be77b563c13"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/event-loop/zipball/6d24de090cd59cfc830263cfba965be77b563c13",
"reference": "6d24de090cd59cfc830263cfba965be77b563c13",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35"
},
"suggest": {
"ext-event": "~1.0 for ExtEventLoop",
"ext-pcntl": "For signal handling support when using the StreamSelectLoop",
"ext-uv": "* for ExtUvLoop"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\EventLoop\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.",
"keywords": [
"asynchronous",
"event-loop"
],
"support": {
"issues": "https://github.com/reactphp/event-loop/issues",
"source": "https://github.com/reactphp/event-loop/tree/v1.1.1"
},
"time": "2020-01-01T18:39:52+00:00"
},
{
"name": "react/http",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/http.git",
"reference": "badb0a87890e14b9cdfa3aec3ba1aafd900401ac"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/http/zipball/badb0a87890e14b9cdfa3aec3ba1aafd900401ac",
"reference": "badb0a87890e14b9cdfa3aec3ba1aafd900401ac",
"shasum": ""
},
"require": {
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
"php": ">=5.3.0",
"psr/http-message": "^1.0",
"react/event-loop": "^1.0 || ^0.5",
"react/promise": "^2.3 || ^1.2.1",
"react/promise-stream": "^1.1",
"react/socket": "^1.6",
"react/stream": "^1.1",
"ringcentral/psr7": "^1.2"
},
"require-dev": {
"clue/block-react": "^1.1",
"clue/http-proxy-react": "^1.3",
"clue/reactphp-ssh-proxy": "^1.0",
"clue/socks-react": "^1.0",
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Http\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christian Lück",
"email": "christian@clue.engineering",
"homepage": "https://clue.engineering/"
},
{
"name": "Cees-Jan Kiewiet",
"email": "reactphp@ceesjankiewiet.nl",
"homepage": "https://wyrihaximus.net/"
},
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com",
"homepage": "https://sorgalla.com/"
},
{
"name": "Chris Boden",
"email": "cboden@gmail.com",
"homepage": "https://cboden.dev/"
}
],
"description": "Event-driven, streaming HTTP client and server implementation for ReactPHP",
"keywords": [
"async",
"client",
"event-driven",
"http",
"http client",
"http server",
"https",
"psr-7",
"reactphp",
"server",
"streaming"
],
"support": {
"issues": "https://github.com/reactphp/http/issues",
"source": "https://github.com/reactphp/http/tree/v1.2.0"
},
"funding": [
{
"url": "https://github.com/WyriHaximus",
"type": "github"
},
{
"url": "https://github.com/clue",
"type": "github"
}
],
"time": "2020-12-04T12:57:33+00:00"
},
{
"name": "react/promise",
"version": "v2.8.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/promise.git",
"reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/promise/zipball/f3cff96a19736714524ca0dd1d4130de73dbbbc4",
"reference": "f3cff96a19736714524ca0dd1d4130de73dbbbc4",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"require-dev": {
"phpunit/phpunit": "^7.0 || ^6.5 || ^5.7 || ^4.8.36"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Promise\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com"
}
],
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
"keywords": [
"promise",
"promises"
],
"support": {
"issues": "https://github.com/reactphp/promise/issues",
"source": "https://github.com/reactphp/promise/tree/v2.8.0"
},
"time": "2020-05-12T15:16:56+00:00"
},
{
"name": "react/promise-stream",
"version": "v1.2.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/promise-stream.git",
"reference": "6384d8b76cf7dcc44b0bf3343fb2b2928412d1fe"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/promise-stream/zipball/6384d8b76cf7dcc44b0bf3343fb2b2928412d1fe",
"reference": "6384d8b76cf7dcc44b0bf3343fb2b2928412d1fe",
"shasum": ""
},
"require": {
"php": ">=5.3",
"react/promise": "^2.1 || ^1.2",
"react/stream": "^1.0 || ^0.7 || ^0.6 || ^0.5 || ^0.4.6"
},
"require-dev": {
"clue/block-react": "^1.0",
"phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35",
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3",
"react/promise-timer": "^1.0"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Promise\\Stream\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christian Lück",
"email": "christian@lueck.tv"
}
],
"description": "The missing link between Promise-land and Stream-land for ReactPHP",
"homepage": "https://github.com/reactphp/promise-stream",
"keywords": [
"Buffer",
"async",
"promise",
"reactphp",
"stream",
"unwrap"
],
"support": {
"issues": "https://github.com/reactphp/promise-stream/issues",
"source": "https://github.com/reactphp/promise-stream/tree/v1.2.0"
},
"time": "2019-07-03T12:29:10+00:00"
},
{
"name": "react/promise-timer",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/promise-timer.git",
"reference": "daee9baf6ef30c43ea4c86399f828bb5f558f6e6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/promise-timer/zipball/daee9baf6ef30c43ea4c86399f828bb5f558f6e6",
"reference": "daee9baf6ef30c43ea4c86399f828bb5f558f6e6",
"shasum": ""
},
"require": {
"php": ">=5.3",
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5",
"react/promise": "^3.0 || ^2.7.0 || ^1.2.1"
},
"require-dev": {
"phpunit/phpunit": "^9.0 || ^5.7 || ^4.8.35"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Promise\\Timer\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christian Lück",
"email": "christian@lueck.tv"
}
],
"description": "A trivial implementation of timeouts for Promises, built on top of ReactPHP.",
"homepage": "https://github.com/reactphp/promise-timer",
"keywords": [
"async",
"event-loop",
"promise",
"reactphp",
"timeout",
"timer"
],
"support": {
"issues": "https://github.com/reactphp/promise-timer/issues",
"source": "https://github.com/reactphp/promise-timer/tree/v1.6.0"
},
"time": "2020-07-10T12:18:06+00:00"
},
{
"name": "react/socket",
"version": "v1.6.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/socket.git",
"reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/socket/zipball/e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
"reference": "e2b96b23a13ca9b41ab343268dbce3f8ef4d524a",
"shasum": ""
},
"require": {
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
"php": ">=5.3.0",
"react/dns": "^1.1",
"react/event-loop": "^1.0 || ^0.5",
"react/promise": "^2.6.0 || ^1.2.1",
"react/promise-timer": "^1.4.0",
"react/stream": "^1.1"
},
"require-dev": {
"clue/block-react": "^1.2",
"phpunit/phpunit": "^9.3 || ^5.7 || ^4.8.35",
"react/promise-stream": "^1.2"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Socket\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Christian Lück",
"email": "christian@clue.engineering",
"homepage": "https://clue.engineering/"
},
{
"name": "Cees-Jan Kiewiet",
"email": "reactphp@ceesjankiewiet.nl",
"homepage": "https://wyrihaximus.net/"
},
{
"name": "Jan Sorgalla",
"email": "jsorgalla@gmail.com",
"homepage": "https://sorgalla.com/"
},
{
"name": "Chris Boden",
"email": "cboden@gmail.com",
"homepage": "https://cboden.dev/"
}
],
"description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP",
"keywords": [
"Connection",
"Socket",
"async",
"reactphp",
"stream"
],
"support": {
"issues": "https://github.com/reactphp/socket/issues",
"source": "https://github.com/reactphp/socket/tree/v1.6.0"
},
"funding": [
{
"url": "https://github.com/WyriHaximus",
"type": "github"
},
{
"url": "https://github.com/clue",
"type": "github"
}
],
"time": "2020-08-28T12:49:05+00:00"
},
{
"name": "react/stream",
"version": "v1.1.1",
"source": {
"type": "git",
"url": "https://github.com/reactphp/stream.git",
"reference": "7c02b510ee3f582c810aeccd3a197b9c2f52ff1a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/stream/zipball/7c02b510ee3f582c810aeccd3a197b9c2f52ff1a",
"reference": "7c02b510ee3f582c810aeccd3a197b9c2f52ff1a",
"shasum": ""
},
"require": {
"evenement/evenement": "^3.0 || ^2.0 || ^1.0",
"php": ">=5.3.8",
"react/event-loop": "^1.0 || ^0.5 || ^0.4 || ^0.3.5"
},
"require-dev": {
"clue/stream-filter": "~1.2",
"phpunit/phpunit": "^7.0 || ^6.4 || ^5.7 || ^4.8.35"
},
"type": "library",
"autoload": {
"psr-4": {
"React\\Stream\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP",
"keywords": [
"event-driven",
"io",
"non-blocking",
"pipe",
"reactphp",
"readable",
"stream",
"writable"
],
"support": {
"issues": "https://github.com/reactphp/stream/issues",
"source": "https://github.com/reactphp/stream/tree/v1.1.1"
},
"time": "2020-05-04T10:17:57+00:00"
},
{
"name": "ringcentral/psr7",
"version": "1.3.0",
"source": {
"type": "git",
"url": "https://github.com/ringcentral/psr7.git",
"reference": "360faaec4b563958b673fb52bbe94e37f14bc686"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/ringcentral/psr7/zipball/360faaec4b563958b673fb52bbe94e37f14bc686",
"reference": "360faaec4b563958b673fb52bbe94e37f14bc686",
"shasum": ""
},
"require": {
"php": ">=5.3",
"psr/http-message": "~1.0"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0-dev"
}
},
"autoload": {
"psr-4": {
"RingCentral\\Psr7\\": "src/"
},
"files": [
"src/functions_include.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Michael Dowling",
"email": "mtdowling@gmail.com",
"homepage": "https://github.com/mtdowling"
}
],
"description": "PSR-7 message implementation",
"keywords": [
"http",
"message",
"stream",
"uri"
],
"support": {
"source": "https://github.com/ringcentral/psr7/tree/master"
},
"time": "2018-05-29T20:21:04+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.0.0"
}

28
ghproxy.conf Normal file
View File

@ -0,0 +1,28 @@
server {
listen 80;
#server_name gh.2i.gs;
# return 301 https://gh.2i.gs$request_uri;
#}
#server {
listen 443 ssl http2;
server_name gh.2i.gs;
charset utf-8;
access_log /var/log/nginx/ghproxy.access.log main;
error_log /var/log/nginx/ghproxy.error.log;
# ssl_trusted_certificate /etc/nginx/conf.d/2i.gs.pem;
# ssl_certificate /etc/nginx/conf.d/2i.gs.pem;
# ssl_certificate_key /etc/nginx/conf.d/2i.gs.key;
root /var/www/ghproxy;
location / {
index index.html;
try_files $uri $uri/ =404;
}
location ^~ /http {
proxy_pass http://localhost:8080;
}
}

188
index.html Normal file
View File

@ -0,0 +1,188 @@
<!DOCTYPE html>
<html lang="zh-Hans">
<style>
html,
body {
width: 100%;
margin: 0;
}
html {
height: 100%;
}
body {
min-height: 100%;
padding: 20px;
box-sizing: border-box;
}
p {
word-break: break-all;
}
@media (max-width: 500px) {
h1 {
margin-top: 80px;
}
}
.flex {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.block {
display: block;
position: relative;
}
.url {
font-size: 18px;
padding: 10px 10px 10px 5px;
position: relative;
width: 300px;
border: none;
border-bottom: 1px solid #bfbfbf;
}
input:focus {
outline: none;
}
.bar {
content: "";
height: 2px;
width: 100%;
bottom: 0;
position: absolute;
background: #00bfb3;
transition: 0.2s ease transform;
-moz-transition: 0.2s ease transform;
-webkit-transition: 0.2s ease transform;
transform: scaleX(0);
}
.url:focus ~ .bar {
transform: scaleX(1);
}
.btn {
line-height: 38px;
background-color: #00bfb3;
color: #fff;
white-space: nowrap;
text-align: center;
font-size: 14px;
border: none;
border-radius: 2px;
cursor: pointer;
padding: 5px;
width: 160px;
margin: 30px 0;
}
.tips,
.example {
color: #7b7b7b;
position: relative;
align-self: flex-start;
margin-left: 7.5em;
}
.tips > p:first-child::before {
position: absolute;
left: -3em;
content: "PS";
color: #7b7b7b;
}
.example > p:first-child::before {
position: absolute;
left: -7.5em;
content: "合法输入示例:";
color: #7b7b7b;
}
</style>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<script>
function toSubmit(e) {
e.preventDefault();
window.open("/" + document.getElementsByName("q")[0].value);
return false;
}
</script>
<title>GitHub 文件加速</title>
</head>
<body class="flex">
<a
style="position: absolute; top: 0; right: 0"
href="https://github.com/tlanyan/ghproxy"
><img
width="149"
height="149"
referrerpolicy="no-referrer"
src="https://inews.gtimg.com/newsapp_ls/0/12025455907/0"
alt="Fork me on GitHub"
data-recalc-dims="1"
/></a>
<h1 style="margin-bottom: 50px">
<img
src="https://ae01.alicdn.com/kf/H2fc84859291347418b11091fe0e508b8v.png"
style="width: 1.5em; margin-right: 0.2em; vertical-align: bottom"
/>GitHub 文件加速
</h1>
<form
action="./"
method="get"
style="padding-bottom: 40px"
target="_blank"
class="flex"
onsubmit="toSubmit(event)"
>
<label class="block" style="width: fit-content">
<input
class="block url"
name="q"
type="text"
placeholder="键入Github文件链接"
pattern="^((https|http):\/\/)?(github\.com\/.+?\/.+?\/(?:releases|archive|blob)|(raw\.githubusercontent\.com))\/.+$"
required
/>
<div class="bar"></div>
</label>
<input class="block btn" type="submit" value="下载" />
<div class="tips">
<p>
GitHub文件链接带不带协议头都可以支持release、archive以及文件右键复制出来的链接都是符合标准的更多用法、clone加速请参考<a
href="https://hunsh.net/archives/23/"
>这篇文章</a
>。
</p>
<p>release、archive使用cf加速文件会跳转至JsDelivr</p>
<p><strong>注意,不支持项目文件夹</strong></p>
</div>
<div class="example">
<p>分支源码https://github.com/hunshcn/project/archive/master.zip</p>
<p>
release源码https://github.com/hunshcn/project/archive/v0.1.0.tar.gz
</p>
<p>
release文件https://github.com/hunshcn/project/releases/download/v0.1.0/example.zip
</p>
<p>分支文件https://github.com/hunshcn/project/blob/master/filename</p>
</div>
</form>
<p style="position: sticky; top: calc(100% - 2.5em)">
本项目为 <a href="https://github.com/hunshcn/gh-proxy" target="_blank">gh-proxy</a> 的PHP版本基于 <a href="https://github.com/reactphp" target="_blank">ReactPHP</a> 开发开源于GitHub
<a style="color: #3294ea" href="https://github.com/tlanyan/ghproxy"
>tlanyan/ghproxy</a
>
</p>
</body>
</html>

178
index.php Normal file
View File

@ -0,0 +1,178 @@
<?php
require(__DIR__ . '/vendor/autoload.php');
define('ROOT', __DIR__);
// listen address, change to 0.0.0.0 to handle public requests
define('ADDR', '127.0.0.1');
define("PORT", 8080);
// use jsdelivr/cnpmjs
define('JSDELIVR', true);
define('CNPMJS', true);
// download size limit, defaults to 2GB
define('SIZE_LIMIT', 2 * 1024 * 1024 * 1024);
$loop = React\EventLoop\Factory::create();
$server = new React\Http\Server($loop, function (Psr\Http\Message\ServerRequestInterface $request) {
return handler($request);
});
$socket = new React\Socket\Server(ADDR . ':' . PORT, $loop);
$server->listen($socket);
echo 'listen on ', ADDR , ':', PORT, PHP_EOL;
$loop->run();
function handler(Psr\Http\Message\ServerRequestInterface $req) {
$url = $req->getUri()->getPath();
// strip start /
$url = substr($url, 1);
echo "request url: ", $url, PHP_EOL;
if (substr($url, 0, 4) !== 'http') {
return serveStaticFiles($url);
}
$exp1 = '/^https?:\/\/?github\.com\/.+?\/.+?\/(?:releases|archive)\/.*$/i';
$exp2 = '/^https?:\/\/?github\.com\/.+?\/.+?\/(?:blob)\/.*$/i';
$exp3 = '/^https?:\/\/?github\.com\/.+?\/.+?\/(?:info|git-).*$/i';
$exp4 = '/^https?:\/\/?raw\.githubusercontent\.com\/.+?\/.+?\/.+?\/.+$/i';
$exp5 = '/^https?:\/\/?api\.github\.com\/.+?\/.+?\/.+?\/.+$/i';
if (preg_match($exp1, $url) || preg_match($exp5, $url) || !CNPMJS && (preg_match($exp3, $url) || preg_match($exp4, $url))) {
return proxy($req);
} else if (preg_match($exp2, $url)) {
if (JSDELIVR){
$url = str_replace('/blob/', '@', $url);
$url = preg_replace('/^https?:\/\/github\.com/', 'https://cdn.jsdelivr.net/gh', $url);
return new React\Http\Message\Response(
302,
array(
'Location' => $url
)
);
}else{
$url = str_replace('/blob/', '/raw/', $url);
return proxy($req);
}
} else if (preg_match($exp3, $url)) {
$url = preg_replace('/^https?:\/\/github\.com/', 'https://github.com.cnpmjs.org', $url);
return new React\Http\Message\Response(
302,
array(
'Location' => $url
)
);
} else if (preg_match($exp4, $url)) {
$url = preg_replace('/(com\/.+?\/.+?)\/(.+?\/)/', '$1@$2', $url);
$url = preg_replace('/^https?:\/\/raw\.githubusercontent\.com/', 'https://cdn.jsdelivr.net/gh', $url);
return new React\Http\Message\Response(
302,
array(
'Location' => $url
)
);
}
return new React\Http\Message\Response(
500,
array(
),
"<h1>unable to deal with request: $url</h1>"
);
}
function serveStaticFiles(string $url) {
$path = ROOT . "/$url";
$path = realpath($path);
if (strpos(ROOT, $path) === 0 && is_file($path)) {
header('Content-Type:' . mime_content_type($path));
readfile($path);
return;
}
return new React\Http\Message\Response(
404,
array(
),
"<h1>File Not Found!</h1>"
);
}
function proxy(Psr\Http\Message\ServerRequestInterface $req) {
$requestMethod = $req->getMethod();
if ($requestMethod === 'OPTIONS' &&
isset($req->header['access-control-request-headers'])) {
return new React\Http\Message\Response(
204,
array(
'access-control-allow-origin' => '*',
'access-control-allow-methods' => 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age' => '1728000',
)
);
}
return fetch($req);
}
function fetch(Psr\Http\Message\ServerRequestInterface $req) {
global $loop;
$url = $req->getUri()->getPath();
// strip start /
$url = substr($url, 1);
$client = new React\Http\Browser($loop);
// see https://github.com/reactphp/http#streaming-response
return $client->requestStreaming($req->getMethod(), $url)->then(function (Psr\Http\Message\ResponseInterface $response) {
$headers = $response->getHeaders();
$body = $response->getBody();
assert($body instanceof Psr\Http\Message\StreamInterface);
assert($body instanceof React\Stream\ReadableStreamInterface);
if (isset($headers['Content-Length']) && intval($headers['Content-Length'][0]) > SIZE_LIMIT) {
echo 'length: ', normalizeSize(intval($headers['Content-Length'][0])), "exceed limit", PHP_EOL;
return new React\Http\Message\Response(
503
);
}
$headers['access-control-expose-headers'] = '*';
$headers['access-control-allow-origin'] = '*';
unset($headers['content-security-policy']);
unset($headers['content-security-policy-report-only']);
unset($headers['clear-site-data']);
$res = new React\Http\Message\Response(
200,
$headers
);
return $res->withBody($body);
});
}
function normalizeSize(int $size) {
$BASE = 1024;
$units = [
'KB',
'MB',
'GB',
];
foreach ($units as $unit) {
$size /= $BASE;
if ($size < 1024) {
return round($size, 2) . $unit;
}
}
return round($size, 2) . 'GB';
}