diff --git a/.gitignore b/.gitignore index 70f0875..140fada 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1 @@ -assets/* -!assets/.gitignore -protected/runtime/* -!protected/runtime/.gitignore -protected/data/*.db -themes/classic/views/ +vendor/* diff --git a/README.md b/README.md index d922aeb..cb7d098 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,73 @@ # 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` 启动项目。 + +接下来,浏览器打开网址,输入要加速下载的链接,查看加速效果。 + +使用中遇到问题欢迎反馈。 \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..ca08353 --- /dev/null +++ b/composer.json @@ -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" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..e1f0ebe --- /dev/null +++ b/composer.lock @@ -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" +} diff --git a/ghproxy.conf b/ghproxy.conf new file mode 100644 index 0000000..09ca966 --- /dev/null +++ b/ghproxy.conf @@ -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; + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..117c638 --- /dev/null +++ b/index.html @@ -0,0 +1,188 @@ + + + + + + + + + GitHub 文件加速 + + + Fork me on GitHub +

+ GitHub 文件加速 +

+
+ + +
+

+ GitHub文件链接带不带协议头都可以,支持release、archive以及文件,右键复制出来的链接都是符合标准的,更多用法、clone加速请参考这篇文章。 +

+

release、archive使用cf加速,文件会跳转至JsDelivr

+

注意,不支持项目文件夹

+
+
+

分支源码:https://github.com/hunshcn/project/archive/master.zip

+

+ release源码:https://github.com/hunshcn/project/archive/v0.1.0.tar.gz +

+

+ release文件:https://github.com/hunshcn/project/releases/download/v0.1.0/example.zip +

+

分支文件:https://github.com/hunshcn/project/blob/master/filename

+
+
+

+ 本项目为 gh-proxy 的PHP版本,基于 ReactPHP 开发,开源于GitHub + tlanyan/ghproxy +

+ + diff --git a/index.php b/index.php new file mode 100644 index 0000000..1b135c0 --- /dev/null +++ b/index.php @@ -0,0 +1,178 @@ +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( + ), + "

unable to deal with request: $url

" + ); +} + +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( + ), + "

File Not Found!

" + ); +} + + +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'; +} \ No newline at end of file