├── WebSocket ├── Workerman │ ├── .gitignore │ ├── Lib │ │ ├── Constants.php │ │ └── Timer.php │ ├── MIT-LICENSE.txt │ ├── composer.json │ ├── Protocols │ │ ├── Frame.php │ │ ├── ProtocolInterface.php │ │ ├── Text.php │ │ └── Http │ │ │ └── mime.types │ ├── Autoloader.php │ ├── Events │ │ ├── EventInterface.php │ │ ├── React │ │ │ ├── ExtEventLoop.php │ │ │ ├── LibEventLoop.php │ │ │ └── StreamSelectLoop.php │ │ ├── Ev.php │ │ ├── Event.php │ │ └── Libevent.php │ └── Connection │ │ ├── ConnectionInterface.php │ │ └── UdpConnection.php ├── PPOI │ ├── config.php │ └── function.php └── GlobalData │ ├── Server.php │ └── Client.php ├── WebUI ├── Cache │ ├── emailverifytoken.cache │ └── passwordToken.cache ├── View │ └── Tpl │ │ ├── media │ │ ├── l.png │ │ ├── icon.png │ │ ├── Material.woff2 │ │ ├── icons │ │ │ ├── link.png │ │ │ ├── block.png │ │ │ ├── diamond.png │ │ │ └── no-comm.png │ │ ├── Material.css │ │ ├── syntax-highlight.js │ │ └── miner-ui.js │ │ ├── 404.html │ │ ├── message.html │ │ ├── footer.html │ │ ├── settings.html │ │ ├── infotos.html │ │ ├── resetpasswd.html │ │ ├── infofaq.html │ │ ├── sitesnew.html │ │ ├── revokekey.html │ │ ├── documentation.html │ │ ├── requestresetpasswd.html │ │ ├── searchuser.html │ │ ├── infocaptcha.html │ │ ├── settingsaccount.html │ │ ├── signup.html │ │ ├── infoprivacy.html │ │ ├── login.html │ │ ├── settingspayment.html │ │ ├── settingsites.html │ │ ├── header.html │ │ ├── documentationcaptcha.html │ │ ├── documentationsimpleui.html │ │ └── dashboard.html ├── lib │ ├── cryptonight.wasm │ ├── cryptonight-asmjs.min.js.mem │ ├── miner.min.js │ └── captcha.min.js ├── Configs │ ├── Mysql.Config.php │ ├── Router.Config.php │ ├── Framework.Config.php │ └── Site.Config.php ├── .htaccess ├── Framework │ ├── Init.php │ ├── Library │ │ ├── Framework.php │ │ ├── Framework.Captcha.php │ │ ├── Framework.XT.php │ │ ├── Framework.Security.php │ │ └── Framework.Error.php │ └── Common │ │ └── Function.php ├── Modules │ ├── Index.Module.php │ ├── Info.Module.php │ ├── Documentation.Module.php │ ├── Init.Module.php │ └── User.Module.php ├── index.php └── captcha │ ├── index.html │ ├── captcha-ui.min.js │ └── captcha.css ├── ORIJS ├── cryptonight.wasm ├── cryptonight-asmjs.min.js.mem ├── Pools.txt └── xmrjs.html ├── WebAPI ├── Configs │ ├── Mysql.Config.php │ ├── Router.Config.php │ ├── Framework.Config.php │ └── Site.Config.php ├── Modules │ ├── Index.Module.php │ ├── Stat.Module.php │ ├── Token.Module.php │ ├── Init.Module.php │ └── User.Module.php ├── Framework │ ├── Init.php │ ├── Library │ │ ├── Framework.php │ │ ├── Framework.Captcha.php │ │ ├── Framework.XT.php │ │ ├── Framework.Security.php │ │ └── Framework.Error.php │ └── Common │ │ └── Function.php └── index.php ├── CronJob ├── config.php ├── function.php └── cronjob.php └── README.md /WebSocket/Workerman/.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | .buildpath 3 | .project 4 | .settings 5 | .idea -------------------------------------------------------------------------------- /WebUI/Cache/emailverifytoken.cache: -------------------------------------------------------------------------------- 1 | be7cWTVACsrQzJYqKISDVaIUU1jHOwUe6XTRSEgSBEWiSjG1RrDFFkCChDXq 2 | -------------------------------------------------------------------------------- /ORIJS/cryptonight.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/ORIJS/cryptonight.wasm -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/View/Tpl/media/l.png -------------------------------------------------------------------------------- /WebUI/lib/cryptonight.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/lib/cryptonight.wasm -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/View/Tpl/media/icon.png -------------------------------------------------------------------------------- /WebUI/Cache/passwordToken.cache: -------------------------------------------------------------------------------- 1 | 8b90tvGmaek1QNy0eouADaTXsHrydFU9[c]pB4p7AB2JVqN0gXa1[c]dm74cEGMOdHarLnnaA6TPWplb[c]dt3sQ 2 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/404.html: -------------------------------------------------------------------------------- 1 | 2 |

404

3 |

Not Found

4 | 5 | -------------------------------------------------------------------------------- /ORIJS/cryptonight-asmjs.min.js.mem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/ORIJS/cryptonight-asmjs.min.js.mem -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/Material.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/View/Tpl/media/Material.woff2 -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/icons/link.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/View/Tpl/media/icons/link.png -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/icons/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/View/Tpl/media/icons/block.png -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/icons/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/View/Tpl/media/icons/diamond.png -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/icons/no-comm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/View/Tpl/media/icons/no-comm.png -------------------------------------------------------------------------------- /WebUI/lib/cryptonight-asmjs.min.js.mem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kagurazakasanae/ProjectPoi/HEAD/WebUI/lib/cryptonight-asmjs.min.js.mem -------------------------------------------------------------------------------- /ORIJS/Pools.txt: -------------------------------------------------------------------------------- 1 | https://www.minercircle.com 2 | https://xmrpool.net 3 | https://pool.xmr.pt 4 | https://monero.lindon-pool.win 5 | https://xmr.geilidao.com -------------------------------------------------------------------------------- /WebAPI/Configs/Mysql.Config.php: -------------------------------------------------------------------------------- 1 | "127.0.0.1", 5 | "Username" => "root", 6 | "Password" => "root", 7 | "Database" => "projectpoi" 8 | ); -------------------------------------------------------------------------------- /WebUI/Configs/Mysql.Config.php: -------------------------------------------------------------------------------- 1 | "127.0.0.1", 5 | "Username" => "root", 6 | "Password" => "root", 7 | "Database" => "projectpoi" 8 | ); -------------------------------------------------------------------------------- /WebAPI/Modules/Index.Module.php: -------------------------------------------------------------------------------- 1 | "Token,Loader", 6 | "user" => "User,Loader", 7 | "stats" => "Stat,Loader" 8 | ); -------------------------------------------------------------------------------- /WebUI/View/Tpl/message.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

{$messagetitle}

4 |
5 | 6 |

7 | {$messagecontent} 8 |

9 | -------------------------------------------------------------------------------- /WebUI/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteBase / 4 | RewriteRule ^index\.php$ - [L] 5 | RewriteCond %{REQUEST_FILENAME} !-f 6 | RewriteCond %{REQUEST_FILENAME} !-d 7 | RewriteRule . /index.php [L] 8 | -------------------------------------------------------------------------------- /CronJob/config.php: -------------------------------------------------------------------------------- 1 | '127.0.0.1', 4 | 'REDIS_PORT'=>6379, 5 | 'REDIS_PASSWD'=>'Kh9STlXx', 6 | 'MYSQL_SERVER'=>'127.0.0.1', 7 | 'MYSQL_DB'=>'projectpoi', 8 | 'MYSQL_USER'=>'projectpoi', 9 | 'MYSQL_PASS'=>'cA+gPri6' 10 | ); -------------------------------------------------------------------------------- /CronJob/function.php: -------------------------------------------------------------------------------- 1 | '67.198.246.90', 4 | 'REDIS_PORT'=>6379, 5 | 'REDIS_PASSWD'=>'Kh9STlXx', 6 | 'MYSQL_SERVER'=>'127.0.0.1', 7 | 'MYSQL_DB'=>'projectpoi', 8 | 'MYSQL_USER'=>'projectpoi', 9 | 'MYSQL_PASS'=>'cA+gPri6' 10 | ); -------------------------------------------------------------------------------- /WebSocket/PPOI/function.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/footer.html: -------------------------------------------------------------------------------- 1 |
2 | © 2017 PPoi.org 3 | – 4 | FAQ – 5 | ToS – 6 | 隐私政策 8 |
9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /WebUI/Configs/Router.Config.php: -------------------------------------------------------------------------------- 1 | "Account,Loader", 6 | "dashboard" => "Dashboard,Loader", 7 | "settings" => "Settings,Loader", 8 | "documentation" => "Documentation,Loader", 9 | "contact" => "Info,Contact", 10 | "info" => "Info,Loader" 11 | ); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ProjectPoi 2 | ProjectPoi (原ppoi.org) 源码 3 | 4 | ## 安装说明 5 | 没有,看得懂的自己研究下吧(其实就是懒) 6 | 7 | ## 已知问题 8 | - 高负载下多服务器同步问题 9 | - 用户挖矿数据同步问题 10 | - 自动payout问题(这个可能只是钱包设置不对) 11 | - 内含大量梦游代码警告 12 | 13 | ## 版权 14 | - JavaScript Miner部分由CoinHive的10个月之前的版本Ctrl+S而来 15 | - PHP部分代码是本人梦游代码,随便使用无需保留任何说明 16 | - 前端by [@Archeb](https://github.com/Archeb) 17 | -------------------------------------------------------------------------------- /WebUI/Modules/Index.Module.php: -------------------------------------------------------------------------------- 1 | XT -> setdata('thistitle', '首页'); 10 | $this -> XT -> parse('index'); 11 | H('normal'); 12 | $this -> XT -> out(); 13 | return true; 14 | } 15 | } -------------------------------------------------------------------------------- /WebAPI/Configs/Framework.Config.php: -------------------------------------------------------------------------------- 1 | false, //指定是否默认开启session 9 | "DEBUG_MODE" => false, //指定是否开启debug模式 10 | "LOG_ERROR" => false, //是否记录错误 11 | "DEFAULT_MODULE" => 'Index', //指定默认加载的模块 12 | "DEFAULT_ACTION" => 'ShowIndex' //指定默认执行的action 13 | ); 14 | -------------------------------------------------------------------------------- /WebUI/Configs/Framework.Config.php: -------------------------------------------------------------------------------- 1 | false, //指定是否默认开启session 9 | "DEBUG_MODE" => true, //指定是否开启debug模式 10 | "LOG_ERROR" => false, //是否记录错误 11 | "DEFAULT_MODULE" => 'Index', //指定默认加载的模块 12 | "DEFAULT_ACTION" => 'ShowIndex' //指定默认执行的action 13 | ); 14 | -------------------------------------------------------------------------------- /WebAPI/Configs/Site.Config.php: -------------------------------------------------------------------------------- 1 | 'ProjectPoi', 10 | "SITE_URL" => 'http://127.0.0.1', 11 | "SITE_TITLE" => 'ProjectPoi', 12 | "SITE_DES" => 'ProjectPoi is a JavaScript based XMR miner.', 13 | "SITE_KEY" => 'jJFul4QGBpL9rPyK', 14 | "REDIS_SERVER" => '37.59.115.211', 15 | "REDIS_PORT" => '6379', 16 | "REDIS_PASSWD" => 'Kh9STlXx' 17 | ); -------------------------------------------------------------------------------- /CronJob/cronjob.php: -------------------------------------------------------------------------------- 1 | syncData(); 10 | 11 | if(date('i') == 0){ 12 | $cb -> hour_avrg(); 13 | } 14 | if(date('h') == 0 && date('i') <= 1){ 15 | $cb -> updateDiff(); 16 | } 17 | if(date('h') % 2 == 0 && date('i') <= 1){ 18 | $cb -> payXMR(); 19 | } 20 | /* 21 | if(date('i') % 30 == 0){ 22 | $cb -> cleanToken(); 23 | }*/ -------------------------------------------------------------------------------- /WebAPI/index.php: -------------------------------------------------------------------------------- 1 | SystemERROR(); 23 | } 24 | -------------------------------------------------------------------------------- /WebUI/index.php: -------------------------------------------------------------------------------- 1 | SystemERROR(); 23 | } 24 | -------------------------------------------------------------------------------- /WebUI/Configs/Site.Config.php: -------------------------------------------------------------------------------- 1 | 'ProjectPoi', 10 | "SITE_URL" => 'http://127.0.0.1', 11 | "SITE_TITLE" => 'ProjectPoi', 12 | "SITE_DES" => 'ProjectPoi 是一个基于JavaScript的门罗币挖矿程序', 13 | "SITE_KEY" => 'jJFul4QGBpL9rPyK', 14 | "SMTP_SERVER" => 'smtp.privateemail.com', 15 | "SMTP_PORT" => '465', 16 | "SMTP_MAILADDR" => 'projectpoi@yukikaze.me', 17 | "SMTP_USER" => 'projectpoi@yukikaze.me', 18 | "SMTP_PASS" => '2bvziyzIQndMRUkI' 19 | ); -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/Material.css: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: url(/View/Tpl/media/Material.woff2) format('woff2'); 7 | } 8 | 9 | .material-icons { 10 | font-family: 'Material Icons'; 11 | font-weight: normal; 12 | font-style: normal; 13 | font-size: 24px; 14 | line-height: 1; 15 | letter-spacing: normal; 16 | text-transform: none; 17 | display: inline-block; 18 | white-space: nowrap; 19 | word-wrap: normal; 20 | direction: ltr; 21 | -webkit-font-feature-settings: 'liga'; 22 | -webkit-font-smoothing: antialiased; 23 | } -------------------------------------------------------------------------------- /WebUI/View/Tpl/settings.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

设置

4 |
5 | 6 |
7 |
8 |

站点 & API 密钥

9 |

10 | 创建新的站点或者更换您的API密钥 11 |

12 |
13 | 14 |
15 |

支付

16 |

17 | 设置您的钱包地址以及最低支付金额 18 |

19 |
20 |
21 | 22 |
23 |
24 |

账户

25 |

26 | 更改您的密码或邮箱 27 |

28 |
29 |
30 | 31 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/infotos.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

服务协议(ToS)

4 | 5 |
6 |

7 | 当您使用了ProjectPoi的服务时,将默认您同意以下条款。 8 |

9 |
    10 |
  1. 11 | 仅在合法的情况下使用。 12 |
  2. 13 |
  3. 14 | 尝试对本站的爆破,攻击等将可能导致账户被封禁。 15 |
  4. 16 |
  5. 17 | 我们保留因为任何原因封禁您的账号的权力。 18 |
  6. 19 |
  7. 20 | 对于您和您的用户的硬件损害我们不负责任。 21 |
  8. 22 |
  9. 23 | 我们保留未来修改本协议的权力。 24 |
  10. 25 |
26 |
27 | 28 |
29 |

安全与Bug回报

30 |

31 | 如果您发现了任何安全隐患或者Bug,您可以通过 32 | 来回报给我们。 取决于问题的严重性我们将会考虑支付您报酬。 33 |

34 |

35 | 注意:我们不将DDos攻击等视作安全隐患。 36 |

37 |
38 | 39 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/resetpasswd.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

重设密码

4 |
5 | 6 |

账户: {$email}

7 | 8 |
9 | 10 | 11 |
12 |
13 | 14 | 17 |

最少8位字符

18 |
19 |
20 |
21 | 22 |
23 | 24 |
25 |
26 | 27 |

28 | « 返回登录 29 |

30 | 31 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/infofaq.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

FAQ

5 |
6 | 7 |

在移动设备上能用么?

8 |

9 | 能,不过很费电而且还会让设备变暖手宝。 10 |

11 | 12 |

能商量下更高的报酬么?

13 |

14 | 再高都要倒贴了。 15 |

16 | 17 |

我大约能获得多少XMR的报酬?

18 |

19 | 我们目前为每100W个hash支付 0.0002061 XMR。 20 | 如果您每月有100W个访问, 假设他们的平均速度为30Hash/s (中端笔记本),平均停留5分钟,您将获得: 21 |

22 |

23 | 24 | (1000000 人 * 30 hashes/s * 5 分钟 * 60 秒)/1000000 * 25 | 0.0002061 xmr = 1.8549 xmr / 月. 26 | 27 |

28 | 29 |

咋提现啊?

30 |

31 | 每隔两小时系统自动处理一次,单笔最低为0.3XMR。 32 |

33 | 34 |

我怎么才能把其嵌入到我的站点?

35 |

36 | 参阅 文档 37 |

38 | 39 |

40 | 更详细的信息请参阅 文档 41 |

42 | 43 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/sitesnew.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | 设置 » 5 | 站点 & API 密钥 » 添加站点 6 |

7 |
8 | 9 |

10 | 注意:每个用户最多可以创建5个站点,目前我们暂时不提供扩充服务。 11 |

12 | 13 |
14 | 15 | 16 |
17 |
18 | 19 | 23 |
24 |
25 | 26 | 29 |
30 |
31 |
32 | 33 | 34 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/revokekey.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | 设置 » 5 | 站点 & API 密钥 » 更换密钥 6 |

7 |
8 |

9 | 如果您认为您的API密钥已经泄露,您可以在此更换密钥,系统将自动生成新的密钥, 10 |

11 |

12 | 所有使用旧密钥的API请求将会出错! 13 |

14 | 15 |

{$notice}

16 | 17 |
18 | 19 | 20 |
21 |
22 | 23 | 26 |

27 | 请输入您 当前的 密码来更换密钥。 28 |

29 |
30 |
31 | 32 | 35 |
36 |
37 |
38 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/documentation.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

文档

4 |
5 | 6 |
7 |

访问API

8 |

9 | 要想使用任何ProjectPoi的API,你必须先注册账号,然后可以获得一个Site Key和API Key。 10 |

11 |

12 | Site Key必须放在网页上给组件作为验证(比如简易挖矿UI和验证码),而API Key则用于与服务器通过HTTP API通信。 13 |

14 |
15 | 16 |
17 |
18 |

简易挖矿UI

19 |

20 | 最简单的集成方法,而且方便用户控制 21 |

22 |
23 |
24 |

验证码

25 |

26 | 使用ProjectPoi验证码组件 27 |

28 |
29 |
30 | 31 |
32 |
33 |

JS挖矿

34 |

35 | 内置在网页中的JS挖矿组件 36 |

37 |
38 |
39 |

HTTP API

40 |

41 | 强大的自定义HTTP API 42 |

43 |
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Lib/Constants.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | 15 | // Date.timezone 16 | if (!ini_get('date.timezone')) { 17 | date_default_timezone_set('Asia/Shanghai'); 18 | } 19 | // Display errors. 20 | ini_set('display_errors', 'on'); 21 | // Reporting all. 22 | error_reporting(E_ALL); 23 | 24 | // Reset opcache. 25 | if (function_exists('opcache_reset')) { 26 | opcache_reset(); 27 | } 28 | 29 | // For onError callback. 30 | define('WORKERMAN_CONNECT_FAIL', 1); 31 | // For onError callback. 32 | define('WORKERMAN_SEND_FAIL', 2); 33 | 34 | // Compatible with php7 35 | if(!class_exists('Error')) 36 | { 37 | class Error extends Exception 38 | { 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/requestresetpasswd.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

找回密码

4 |
5 | 6 |

7 | 如果您忘记了密码,您可以在此请求重设您的密码。 8 |

9 | 10 |
11 |
12 |
13 | 14 |
15 |
16 |
17 |
18 | 19 | 22 |
加载验证码...
如果无法加载,请禁用adblock!
28 |
29 |
30 |
31 | 32 | 33 |
34 |
35 |
36 | 37 |

38 | « 返回登录 39 |

40 | 41 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/searchuser.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | 控制台 5 | » 用户 » {$searchword}* 6 |

7 |
8 | 9 |
10 |
11 |
12 |

 

13 |
14 |
15 | 16 |
17 |
18 | 19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 37 | 38 | 39 |
日期站点用户名Hashes
{$s['lastsubmit']}{$s['sitename']}{$s['username']} 36 | {$s['hashes']}
40 |
41 | 42 | 43 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/infocaptcha.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

FAQ

5 |
6 |

PoW验证码

7 | 8 |

发生了什么?为什么我的风扇狂转?

9 |

10 | 当您单击“验证我”选项时,程序将在浏览器中运行了一段JavaScript代码。这个代码解决了一个数学难题,对CPU需求较大。 11 |

12 |

13 | 当您的浏览器计算出了结果时,将会发送到我们的服务器进行验证,一旦您的浏览器计算到了足够多的解,您将可以继续提交表单。 14 |

15 |

16 | 虽然这个不像Google的 reCaptcha 一样 “证明你是人”, 这个验证码是靠让您的浏览器完成特定计算完成的。 17 |

18 | 19 |

为什么这么慢?

20 |

21 | 根据您的计算机配置,解决这些数学难题可能需要相当长的一段时间。计算机的速度越快,验证速度就越快。 22 |

23 |

24 | 智能手机或平板电脑在这方面特别慢。如果您希望运行速度更快,请使用笔记本电脑或台式电脑。 25 |

26 |

27 | 更新您的浏览器也可以有帮助。使用支持WebAssembly的浏览器 Chrome 或 28 | Firefox. 29 |

30 | 31 |

到底在算什么东西?

32 |

33 | 门罗币区块链。 34 | 门罗币是跟比特币类似的数字货币。我们使用门罗币是因为它所用的Cryptonight在CPU上也可以很好的运行。 35 |

36 |

37 | 实际上,您在挖掘此货币,每个您解决的问题都将交给网站所有者以便他们获得报酬。在此过程中我们只收集了计算结果,不会收集任何您的个人信息。 38 |

39 | 40 |

41 | 您也可以将此验证码嵌入您自己的网站,并让您的用户使用。详见ppoi.org 42 |

43 | 44 | -------------------------------------------------------------------------------- /WebSocket/Workerman/MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2009-2015 walkor and contributors (see https://github.com/walkor/workerman/contributors) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /WebSocket/Workerman/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "workerman/workerman", 3 | "type": "library", 4 | "keywords": [ 5 | "event-loop", 6 | "asynchronous" 7 | ], 8 | "homepage": "http://www.workerman.net", 9 | "license": "MIT", 10 | "description": "An asynchronous event driven PHP framework for easily building fast, scalable network applications.", 11 | "authors": [ 12 | { 13 | "name": "walkor", 14 | "email": "walkor@workerman.net", 15 | "homepage": "http://www.workerman.net", 16 | "role": "Developer" 17 | } 18 | ], 19 | "support": { 20 | "email": "walkor@workerman.net", 21 | "issues": "https://github.com/walkor/workerman/issues", 22 | "forum": "http://wenda.workerman.net/", 23 | "wiki": "http://doc3.workerman.net/index.html", 24 | "source": "https://github.com/walkor/workerman" 25 | }, 26 | "require": { 27 | "php": ">=5.3", 28 | "ext-pcntl": "*", 29 | "ext-posix": "*" 30 | }, 31 | "suggest": { 32 | "ext-event": "For better performance. " 33 | }, 34 | "autoload": { 35 | "psr-4": { 36 | "Workerman\\": "./" 37 | } 38 | }, 39 | "minimum-stability": "dev" 40 | } 41 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/settingsaccount.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | 设置 » 5 | 账户 6 |

7 |
8 | 9 | 10 |

{$notice}

11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 | 22 | 23 |

24 | 如果您更改了您的邮箱地址,您将需要重新验证新的地址。 25 |

26 |
27 | 28 |
29 | 30 | 33 |

34 | 不更改密码请留空,最少8位字符。 35 |

36 |
37 |
38 | 39 | 42 |

43 | 请输入您 当前的 密码来保存更改。 44 |

45 |
46 |
47 | 48 | 49 |
50 |
51 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/signup.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

注册

4 |
5 | 6 |

{$notice}

7 | 8 |
9 |
10 |
11 | 12 | 16 |

17 | 将会向此地址发送一封确认邮件。 18 |

19 |
20 |
21 |
22 |
23 | 24 | 27 |

最少8位字符

28 |
29 |
30 |
31 | 32 | 35 |
加载验证码...
如果无法加载,请禁用adblock!
41 |
42 |
43 |
44 | 45 | 46 |
47 |
48 |
49 | 50 | -------------------------------------------------------------------------------- /WebUI/Modules/Info.Module.php: -------------------------------------------------------------------------------- 1 | ''),32)['1']; 10 | H('normal'); 11 | switch($uri){ 12 | case "faq": 13 | $this -> showFAQ(); 14 | break; 15 | case "terms-of-service": 16 | $this -> showTOS(); 17 | break; 18 | case "privacy": 19 | $this -> showPrivacy(); 20 | break; 21 | case "captcha-help": 22 | $this -> showCaptchaHelp(); 23 | break; 24 | default: 25 | parent::outNotFound(); 26 | return true; 27 | break; 28 | } 29 | } 30 | 31 | 32 | private function showFAQ(){ 33 | $this -> XT -> setdata('thistitle', 'FAQ'); 34 | $this -> XT -> parse('infofaq'); 35 | $this -> XT -> out(); 36 | return true; 37 | } 38 | 39 | private function showTOS(){ 40 | $this -> XT -> setdata('thistitle', 'ToS'); 41 | $this -> XT -> parse('infotos'); 42 | $this -> XT -> out(); 43 | return true; 44 | } 45 | 46 | private function showPrivacy(){ 47 | $this -> XT -> setdata('thistitle', '隐私政策'); 48 | $this -> XT -> parse('infoprivacy'); 49 | $this -> XT -> out(); 50 | return true; 51 | } 52 | 53 | private function showCaptchaHelp(){ 54 | $this -> XT -> setdata('thistitle', 'PoW验证码'); 55 | $this -> XT -> parse('infocaptcha'); 56 | $this -> XT -> out(); 57 | return true; 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /WebUI/View/Tpl/infoprivacy.html: -------------------------------------------------------------------------------- 1 | 2 |

隐私政策

3 | 4 |

5 | 我们尊重用户的隐私,我们将尽量不获得任何信息。 6 |

7 | 8 |

JavaScript挖矿程序和验证码

9 | 30 | 31 |

本站 (ppoi.org)

32 | 53 | -------------------------------------------------------------------------------- /WebAPI/Modules/Stat.Module.php: -------------------------------------------------------------------------------- 1 | ''),32)['1']; 10 | switch($uri){ 11 | case "payout": 12 | $this -> showPayout(); 13 | return; 14 | break; 15 | case "site": 16 | $this -> getSites(); 17 | return; 18 | break; 19 | default: 20 | parent::genError('4'); 21 | return; 22 | break; 23 | } 24 | } 25 | 26 | private function showPayout(){ 27 | $info = json_decode($this -> Mysql -> select('system', array('key'=>'xmr_info'))[0]['value'], true); 28 | $info['success'] = true; 29 | $info['error'] = ''; 30 | H('json'); 31 | echo json_encode($info); 32 | return; 33 | } 34 | 35 | private function getSites(){ 36 | $para = D('POST', array('[String]secret'=>''), 64); 37 | if(trim($para['secret']) == ''){ 38 | parent::genError('6'); 39 | return; 40 | } 41 | $sitedata = array(); 42 | if($uinfo = $this -> Mysql -> select('users', array('api_key'=>$para['secret']))[0]){ 43 | $sites = $this -> Mysql -> select('sites', array('uid'=>$uinfo['uid'])); 44 | foreach($sites as $s){ 45 | $sitedata[] = array('hashes'=>$s['hashes'],'speed'=>$s['speed']); 46 | } 47 | H('json'); 48 | echo json_encode(array('success'=>true, 'sitedata'=>$sitedata, 'error'=>'')); 49 | return; 50 | }else{ 51 | parent::genError('2'); 52 | return; 53 | } 54 | } 55 | 56 | } -------------------------------------------------------------------------------- /WebUI/View/Tpl/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

登录

5 |
6 | 7 |

{$notice}

8 | 9 |
10 | 11 |
12 |
13 | 14 | 18 |
19 |
20 |
21 |
22 | 23 | 26 |

27 | 忘记密码? 28 |

29 |
30 |
31 |
32 | 33 | 36 |
加载验证码...
如果无法加载,请禁用adblock!
42 |
43 |
44 |
45 | 46 | 47 |
48 |
49 |
50 |
51 |

52 | 还没有账户? 立即注册! 53 |

54 |
55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/settingspayment.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | 设置 » 5 | 支付设置 6 |

7 |
8 | 9 | 10 |

{$notice}

11 | 12 | 13 |
14 | 15 | 16 |
17 | 18 | 22 |

23 | 请注意我们目前只能向钱包地址发送,我们暂时无法向交易所直接发送门罗币。如果您需要门罗币钱包,您可以在 24 | mymonero.com 25 | 上注册一个。 26 |

27 |
28 |
29 | 30 | 34 | XMR 35 |

36 | 当金额大于此额度时将发送付款,最少额度为0.3XMR。 37 |

38 |
39 | 40 |
41 | 42 | 45 |

46 | 请输入您 当前的 密码来保存更改。 47 |

48 |
49 | 50 |
51 |
52 | 53 | 54 |
55 |
56 |
57 | 58 | -------------------------------------------------------------------------------- /WebUI/Framework/Library/Framework.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\TcpConnection; 17 | 18 | /** 19 | * Frame Protocol. 20 | */ 21 | class Frame 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * 26 | * @param string $buffer 27 | * @param TcpConnection $connection 28 | * @return int 29 | */ 30 | public static function input($buffer, TcpConnection $connection) 31 | { 32 | if (strlen($buffer) < 4) { 33 | return 0; 34 | } 35 | $unpack_data = unpack('Ntotal_length', $buffer); 36 | return $unpack_data['total_length']; 37 | } 38 | 39 | /** 40 | * Decode. 41 | * 42 | * @param string $buffer 43 | * @return string 44 | */ 45 | public static function decode($buffer) 46 | { 47 | return substr($buffer, 4); 48 | } 49 | 50 | /** 51 | * Encode. 52 | * 53 | * @param string $buffer 54 | * @return string 55 | */ 56 | public static function encode($buffer) 57 | { 58 | $total_length = 4 + strlen($buffer); 59 | return pack('N', $total_length) . $buffer; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /WebAPI/Modules/Token.Module.php: -------------------------------------------------------------------------------- 1 | ''),32)['1']; 10 | switch($uri){ 11 | case "verify": 12 | $this -> verifyToken(); 13 | return; 14 | break; 15 | default: 16 | parent::genError('4'); 17 | return; 18 | break; 19 | } 20 | } 21 | 22 | public function verifyToken(){ 23 | $para = D('POST', array('[String]secret'=>'', '[String]token'=>'', '[String]hashes'=>''), 64); 24 | foreach($para as $p){ 25 | if(trim($p) == ''){ 26 | parent::genError('6'); 27 | return; 28 | } 29 | } 30 | if(!is_numeric($para['hashes'])){ 31 | parent::genError('1'); 32 | return; 33 | } 34 | $token = $this -> redis -> get('tokens-'.$para['token']); 35 | if($token){ 36 | $token = json_decode($token, true); 37 | }else{ 38 | parent::genError('7'); 39 | return; 40 | } 41 | if($uinfo = $this -> Mysql -> select('users', array('api_key'=>$para['secret']))[0]){ 42 | if($this -> Mysql -> confirm('sites', array('site_key'=>$token[0], 'uid'=>$uinfo['uid']))){ 43 | if($token[2] >= $para['hashes']){ 44 | $this -> redis -> del('tokens-'.$para['token']); 45 | H('json'); 46 | echo json_encode(array('success'=>true, 'hashes'=>intval($token[2]), 'created'=>$token[3], 'error'=>'')); 47 | return; 48 | }else{ 49 | parent::genError('7'); 50 | return; 51 | } 52 | }else{ 53 | parent::genError('7'); 54 | return; 55 | } 56 | }else{ 57 | parent::genError('2'); 58 | return; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /WebUI/Modules/Documentation.Module.php: -------------------------------------------------------------------------------- 1 | ''),32)['1']; 10 | H('normal'); 11 | switch($uri){ 12 | case "": 13 | $this -> showIndex(); 14 | break; 15 | case "simple-ui": 16 | $this -> showSimpleUi(); 17 | break; 18 | case "captcha": 19 | $this -> showCaptcha(); 20 | break; 21 | case "miner": 22 | $this -> showMiner(); 23 | break; 24 | case "http-api": 25 | $this -> showHTTPApi(); 26 | break; 27 | default: 28 | parent::outNotFound(); 29 | return true; 30 | break; 31 | } 32 | } 33 | 34 | private function showIndex(){ 35 | $this -> XT -> setdata('thistitle', '文档'); 36 | $this -> XT -> parse('documentation'); 37 | $this -> XT -> out(); 38 | return true; 39 | } 40 | 41 | private function showSimpleUi(){ 42 | $this -> XT -> setdata('thistitle', '文档'); 43 | $this -> XT -> parse('documentationsimpleui'); 44 | $this -> XT -> out(); 45 | return true; 46 | } 47 | 48 | private function showCaptcha(){ 49 | $this -> XT -> setdata('thistitle', '验证码'); 50 | $this -> XT -> parse('documentationcaptcha'); 51 | $this -> XT -> out(); 52 | return true; 53 | } 54 | 55 | private function showMiner(){ 56 | $this -> XT -> setdata('thistitle', 'JavaScript挖矿'); 57 | $this -> XT -> parse('documentationminer'); 58 | $this -> XT -> out(); 59 | return true; 60 | } 61 | 62 | private function showHTTPApi(){ 63 | $this -> XT -> setdata('thistitle', 'HTTP API'); 64 | $this -> XT -> parse('documentationhttpapi'); 65 | $this -> XT -> out(); 66 | return true; 67 | } 68 | } -------------------------------------------------------------------------------- /WebAPI/Modules/Init.Module.php: -------------------------------------------------------------------------------- 1 | Mysql = M("Mysql"); 12 | $this -> Configs = C("Site"); 13 | $this -> redis = new Redis; 14 | $this -> redis -> connect($this -> Configs['REDIS_SERVER'], $this -> Configs['REDIS_PORT']); 15 | $this -> redis -> auth($this -> Configs['REDIS_PASSWD']); 16 | } 17 | 18 | public static function genError($code){ 19 | H('json'); 20 | if($code == '1' ){ 21 | echo '{"success":false,"error":"bad_request"}'; 22 | return true; 23 | }elseif($code == '2'){ 24 | echo '{"success":false,"error":"invalid_secret"}'; 25 | return true; 26 | }elseif($code == '3'){ 27 | echo '{"success":false,"error":"wrong_method"}'; 28 | return true; 29 | }elseif($code == '4'){ 30 | echo '{"success":false,"error":"not_found"}'; 31 | return true; 32 | }elseif($code == '5'){ 33 | echo '{"success":false,"error":"internal_error"}'; 34 | return true; 35 | }elseif($code == '6'){ 36 | echo '{"success":false,"error":"missing_input"}'; 37 | return true; 38 | }elseif($code == '7'){ 39 | echo '{"success":false,"error":"invalid_token"}'; 40 | return true; 41 | }elseif($code == '8'){ 42 | echo '{"success":false,"error":"unknown_user"}'; 43 | return true; 44 | }elseif($code == '9'){ 45 | echo '{"success":false,"error":"insufficent_funds"}'; 46 | return true; 47 | } 48 | } 49 | //根据sitekey获取siteid 50 | public function getSidBySitekey($key){ 51 | if($res = $this -> redis -> get('site-'.$key)){ 52 | return json_decode($res, true)[2]; 53 | }else{ 54 | return false; 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/syntax-highlight.js: -------------------------------------------------------------------------------- 1 | var SH = function(element) { 2 | SH.p = []; 3 | var code = element.innerHTML; 4 | for (var i = 0; i < SH.REGEXP.length; i+=2) { 5 | code = code.replace(SH.REGEXP[i], SH.REGEXP[i+1]); 6 | } 7 | element.innerHTML = code; 8 | }; 9 | SH.span = function(c, r) { return '' + (r || '$1') + ''; }; 10 | SH.push = function(m) { return ''; }; 11 | SH.pushBlock = function(m, comment, regexp, string){ 12 | var s = ''; 13 | if (comment) { s = SH.span('comments', m); } 14 | else if (regexp) { s = SH.span('regexp', m); } 15 | else if (string) { s = SH.span('strings', m); } 16 | return SH.push(s); 17 | }; 18 | SH.pop = function( m, i ) { return SH.p[i-1].replace(SH.REGEXP[12], SH.REGEXP[13]); }; 19 | SH.REGEXP = [ 20 | /\\.|\$\w+/g, SH.push, 21 | /([\[({=:+,](\s|(\/\*[\s|\S]*?\*\/|\/\/.*))*)\/(?![\/\*])/g, '$1/', 22 | /(\/\*[\s|\S]*?\*\/|<!--[\s|\S]*?-->|\/\/.*|#.*)|(\/.+?\/\w*)|(".*?"|'.*?')/g, SH.pushBlock, 23 | /((&\w+;|[-\/+*=?:.,;()\[\]{}|%^!])+)/g, SH.span('punct'), 24 | /\b(input|div|form|script|break|case|catch|continue|default|delete|do|else|false|finally|for|function|if|in|instanceof|string|number|boolean|new|null|return|switch|this|throw|true|try|typeof|var|void|while|with)\b/gi, SH.span('keywords'), 25 | /\b(0x[\da-f]+|\d+)\b/g, SH.span('numbers'), 26 | //g, SH.pop, 27 | //g, '' 28 | ]; 29 | SH.Highlight = function() { 30 | var elements = document.querySelectorAll('.sh'); 31 | for (var i = 0; i < elements.length; i++) { 32 | new SH(elements[i]); 33 | } 34 | }; 35 | if (document.readyState === 'complete' || document.readyState === 'interactive') { 36 | SH.Highlight(); 37 | } 38 | else { 39 | document.addEventListener('readystatechange', function(){ 40 | if (document.readyState === "interactive") { 41 | SH.Highlight(); 42 | } 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Protocols/ProtocolInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\ConnectionInterface; 17 | 18 | /** 19 | * Protocol interface 20 | */ 21 | interface ProtocolInterface 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * Please return the length of package. 26 | * If length is unknow please return 0 that mean wating more data. 27 | * If the package has something wrong please return false the connection will be closed. 28 | * 29 | * @param ConnectionInterface $connection 30 | * @param string $recv_buffer 31 | * @return int|false 32 | */ 33 | public static function input($recv_buffer, ConnectionInterface $connection); 34 | 35 | /** 36 | * Decode package and emit onMessage($message) callback, $message is the result that decode returned. 37 | * 38 | * @param ConnectionInterface $connection 39 | * @param string $recv_buffer 40 | * @return mixed 41 | */ 42 | public static function decode($recv_buffer, ConnectionInterface $connection); 43 | 44 | /** 45 | * Encode package brefore sending to client. 46 | * 47 | * @param ConnectionInterface $connection 48 | * @param mixed $data 49 | * @return string 50 | */ 51 | public static function encode($data, ConnectionInterface $connection); 52 | } 53 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Protocols/Text.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Protocols; 15 | 16 | use Workerman\Connection\TcpConnection; 17 | 18 | /** 19 | * Text Protocol. 20 | */ 21 | class Text 22 | { 23 | /** 24 | * Check the integrity of the package. 25 | * 26 | * @param string $buffer 27 | * @param TcpConnection $connection 28 | * @return int 29 | */ 30 | public static function input($buffer, TcpConnection $connection) 31 | { 32 | // Judge whether the package length exceeds the limit. 33 | if (strlen($buffer) >= TcpConnection::$maxPackageSize) { 34 | $connection->close(); 35 | return 0; 36 | } 37 | // Find the position of "\n". 38 | $pos = strpos($buffer, "\n"); 39 | // No "\n", packet length is unknown, continue to wait for the data so return 0. 40 | if ($pos === false) { 41 | return 0; 42 | } 43 | // Return the current package length. 44 | return $pos + 1; 45 | } 46 | 47 | /** 48 | * Encode. 49 | * 50 | * @param string $buffer 51 | * @return string 52 | */ 53 | public static function encode($buffer) 54 | { 55 | // Add "\n" 56 | return $buffer . "\n"; 57 | } 58 | 59 | /** 60 | * Decode. 61 | * 62 | * @param string $buffer 63 | * @return string 64 | */ 65 | public static function decode($buffer) 66 | { 67 | // Remove "\n" 68 | return trim($buffer); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/settingsites.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

4 | 设置 » 5 | 站点 & API 密钥 6 |

7 |
8 | 9 |

{$notice}

10 | 11 | 12 |

13 | 如果您希望将您的不同站点区分统计的话,您可以在本页面添加新的站点。 14 |

15 | 16 |

17 | 站点标识码 将用于您的JavaScript中并暴露给所有网站的访客。API密钥 则可以用来获取用户/Token所获得的hash,查询您的账户信息等。所以它应当被妥善保管而不是暴露给网站的访客。 18 |

19 | 20 |

21 | 如果您认为您的API密钥已经泄露,您可以选择更换密钥,旧密钥将自动失效。 22 |

23 |
24 |
25 | 26 |
27 |
28 |

29 | {$apikey} 30 | 31 | (更换密钥) 32 | 33 |

34 |
35 |
36 | 37 |
38 | 39 | 40 | 41 |
42 |
43 |
44 | 45 |
46 |
47 | 52 |
53 |
54 |
55 |
56 | 57 |
58 |
59 |

{$s['site_key']}

60 |
61 |
62 | 63 |
64 | 65 |
66 | 67 |
68 |
69 | 70 | 71 |

添加新站点

72 | 73 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Autoloader.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman; 15 | 16 | /** 17 | * Autoload. 18 | */ 19 | class Autoloader 20 | { 21 | /** 22 | * Autoload root path. 23 | * 24 | * @var string 25 | */ 26 | protected static $_autoloadRootPath = ''; 27 | 28 | /** 29 | * Set autoload root path. 30 | * 31 | * @param string $root_path 32 | * @return void 33 | */ 34 | public static function setRootPath($root_path) 35 | { 36 | self::$_autoloadRootPath = $root_path; 37 | } 38 | 39 | /** 40 | * Load files by namespace. 41 | * 42 | * @param string $name 43 | * @return boolean 44 | */ 45 | public static function loadByNamespace($name) 46 | { 47 | $class_path = str_replace('\\', DIRECTORY_SEPARATOR, $name); 48 | if (strpos($name, 'Workerman\\') === 0) { 49 | $class_file = __DIR__ . substr($class_path, strlen('Workerman')) . '.php'; 50 | } else { 51 | if (self::$_autoloadRootPath) { 52 | $class_file = self::$_autoloadRootPath . DIRECTORY_SEPARATOR . $class_path . '.php'; 53 | } 54 | if (empty($class_file) || !is_file($class_file)) { 55 | $class_file = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . "$class_path.php"; 56 | } 57 | } 58 | 59 | if (is_file($class_file)) { 60 | require_once($class_file); 61 | if (class_exists($name, false)) { 62 | return true; 63 | } 64 | } 65 | return false; 66 | } 67 | } 68 | 69 | spl_autoload_register('\Workerman\Autoloader::loadByNamespace'); -------------------------------------------------------------------------------- /WebUI/lib/miner.min.js: -------------------------------------------------------------------------------- 1 | self.ProjectPoi = self.ProjectPoi || {}; 2 | self.ProjectPoi.CONFIG = { 3 | LIB_URL: "https://ppoi.org/lib/", 4 | WEBSOCKET_SHARDS: [ 5 | ["wss://ws01.ppoi.org/proxy"] 6 | ], 7 | CAPTCHA_URL: "https://ppoi.org/captcha/", 8 | MINER_URL: "https://ppoi.org/media/miner.html" 9 | }; 10 | (function(window) { 11 | "use strict"; 12 | var Miner = function(div) { 13 | this.div = div; 14 | var params = div.dataset; 15 | var url = ProjectPoi.CONFIG.MINER_URL + "?key=" + params.key + "&user=" + encodeURIComponent(params.user || "") + "&whitelabel=" + (params.whitelabel === "true" ? "1" : "0") + "&autostart=" + (params.autostart === "true" ? "1" : "0") + "&throttle=" + (params.throttle || "") + "&threads=" + (params.threads || "") + "&background=" + (params.background || "").replace(/#/g, "") + "&text=" + (params.text || "").replace(/#/g, "") + "&action=" + (params.action || "").replace(/#/g, "") + "&graph=" + (params.graph || "").replace(/#/g, ""); 16 | if (params.start !== undefined) { 17 | url += "&start=" + encodeURIComponent(params.start) 18 | } 19 | this.div.innerHTML = ""; 20 | this.iframe = document.createElement("iframe"); 21 | this.iframe.style.width = "100%"; 22 | this.iframe.style.height = "100%"; 23 | this.iframe.style.border = "none"; 24 | this.iframe.src = url; 25 | this.div.appendChild(this.iframe) 26 | }; 27 | Miner.CreateElements = function() { 28 | var elements = document.querySelectorAll(".projectpoi-miner"); 29 | for (var i = 0; i < elements.length; i++) { 30 | new Miner(elements[i]) 31 | } 32 | }; 33 | if (document.readyState === "complete" || document.readyState === "interactive") { 34 | Miner.CreateElements() 35 | } else { 36 | document.addEventListener("readystatechange", function() { 37 | if (document.readyState === "interactive") { 38 | Miner.CreateElements() 39 | } 40 | }) 41 | } 42 | window.ProjectPoi = window.ProjectPoi || {}; 43 | window.ProjectPoi.Miner = Miner 44 | })(window); -------------------------------------------------------------------------------- /WebUI/View/Tpl/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {$thistitle} – 8 | {$name} – {$description} 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 42 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /WebUI/Modules/Init.Module.php: -------------------------------------------------------------------------------- 1 | Mysql = M("Mysql"); 14 | $this -> XT = M("XT"); 15 | $this -> Configs = C("Site"); 16 | $this -> User = new User($this -> Configs); 17 | $this -> XT -> setdata("site",$this -> Configs['SITE_URL']); 18 | $this -> XT -> setdata("name",$this -> Configs['SITE_TITLE']); 19 | $this -> XT -> setdata("description",$this -> Configs['SITE_DES']); 20 | $islogin = $this -> User -> isLogin($this -> Configs['SITE_KEY']); 21 | $this -> XT -> setdata('logined', $islogin); 22 | if($islogin){ 23 | $this -> XT -> setdata('nonce', substr(json_decode($_COOKIE['session'], true)['id'],0,16)); 24 | } 25 | $module = D('REWRITE',array('[String]0'=>'','[String]1'=>'')); 26 | $module = $module[0] != 'account' ? $module[0] : $module[1]; 27 | $this -> XT -> setdata('thismodule', $module); 28 | } 29 | 30 | public function outNotfound(){ 31 | H('404'); 32 | $this -> XT -> setdata('thistitle', '页面未找到'); 33 | $this -> XT -> parse('404'); 34 | $this -> XT -> out(); 35 | return true; 36 | } 37 | 38 | public function outError($title, $reason){ 39 | $this -> XT -> setdata('thistitle', '错误'); 40 | $this -> XT -> setdata('messagetitle', $title); 41 | $this -> XT -> setdata('messagecontent', $reason); 42 | $this -> XT -> parse('message'); 43 | H('403'); 44 | $this -> XT -> out(); 45 | return true; 46 | } 47 | 48 | public function verifyToken($token, $hashes){ 49 | $data = http_build_query(array('secret'=>'H9ZDTr2vHO1VKW4mBIVTWEaF', 'token'=>$token, 'hashes'=>$hashes)); 50 | $ch = curl_init(); 51 | curl_setopt($ch, CURLOPT_URL, 'https://api.ppoi.org/token/verify'); 52 | curl_setopt($ch, CURLOPT_TIMEOUT, 5); 53 | curl_setopt($ch, CURLOPT_SSLVERSION, 4); 54 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 55 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 56 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 57 | curl_setopt($ch, CURLOPT_POST, true); 58 | curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 59 | $ret = curl_exec($ch); 60 | curl_close($ch); 61 | return json_decode($ret, true); 62 | } 63 | } -------------------------------------------------------------------------------- /WebSocket/Workerman/Events/EventInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | interface EventInterface 17 | { 18 | /** 19 | * Read event. 20 | * 21 | * @var int 22 | */ 23 | const EV_READ = 1; 24 | 25 | /** 26 | * Write event. 27 | * 28 | * @var int 29 | */ 30 | const EV_WRITE = 2; 31 | 32 | /** 33 | * Except event 34 | * 35 | * @var int 36 | */ 37 | const EV_EXCEPT = 3; 38 | 39 | /** 40 | * Signal event. 41 | * 42 | * @var int 43 | */ 44 | const EV_SIGNAL = 4; 45 | 46 | /** 47 | * Timer event. 48 | * 49 | * @var int 50 | */ 51 | const EV_TIMER = 8; 52 | 53 | /** 54 | * Timer once event. 55 | * 56 | * @var int 57 | */ 58 | const EV_TIMER_ONCE = 16; 59 | 60 | /** 61 | * Add event listener to event loop. 62 | * 63 | * @param mixed $fd 64 | * @param int $flag 65 | * @param callable $func 66 | * @param mixed $args 67 | * @return bool 68 | */ 69 | public function add($fd, $flag, $func, $args = null); 70 | 71 | /** 72 | * Remove event listener from event loop. 73 | * 74 | * @param mixed $fd 75 | * @param int $flag 76 | * @return bool 77 | */ 78 | public function del($fd, $flag); 79 | 80 | /** 81 | * Remove all timers. 82 | * 83 | * @return void 84 | */ 85 | public function clearAllTimer(); 86 | 87 | /** 88 | * Main loop. 89 | * 90 | * @return void 91 | */ 92 | public function loop(); 93 | 94 | /** 95 | * Destroy loop. 96 | * 97 | * @return mixed 98 | */ 99 | public function destroy(); 100 | 101 | /** 102 | * Get Timer count. 103 | * 104 | * @return mixed 105 | */ 106 | public function getTimerCount(); 107 | } 108 | -------------------------------------------------------------------------------- /WebAPI/Framework/Library/Framework.Captcha.php: -------------------------------------------------------------------------------- 1 | font = ROOT_PATH.'/View/Tpl/static/fonts/Elephant.ttf'; 26 | } 27 | //生成随机码 28 | private function createCode() 29 | { 30 | $_len = strlen($this->charset) - 1; 31 | for ($i = 0; $i < $this->codelen; $i++) { 32 | $this->code .= $this->charset[mt_rand(0, $_len)]; 33 | } 34 | } 35 | //生成背景 36 | private function createBg() 37 | { 38 | $this->img = imagecreatetruecolor($this->width, $this->height); 39 | $color = imagecolorallocate($this->img, mt_rand(157, 255), mt_rand(157, 255), mt_rand(157, 255)); 40 | imagefilledrectangle($this->img, 0, $this->height, $this->width, 0, $color); 41 | } 42 | //生成文字 43 | private function createFont() 44 | { 45 | $_x = $this->width / $this->codelen; 46 | for ($i = 0; $i < $this->codelen; $i++) { 47 | $this->fontcolor = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156)); 48 | imagettftext($this->img, $this->fontsize, mt_rand(-30, 30), $_x * $i + mt_rand(1, 5), $this->height / 1.4, $this->fontcolor, $this->font, $this->code[$i]); 49 | } 50 | } 51 | //生成线条、雪花 52 | private function createLine() 53 | { 54 | //线条 55 | for ($i = 0; $i < 6; $i++) { 56 | $color = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156)); 57 | imageline($this->img, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $color); 58 | } 59 | //雪花 60 | for ($i = 0; $i < 100; $i++) { 61 | $color = imagecolorallocate($this->img, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255)); 62 | imagestring($this->img, mt_rand(1, 5), mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0,9), $color); 63 | } 64 | } 65 | //输出 66 | private function outPut() 67 | { 68 | header('Content-type:image/png'); 69 | imagepng($this->img); 70 | imagedestroy($this->img); 71 | } 72 | //对外生成 73 | public function doimg() 74 | { 75 | $this->createBg(); 76 | $this->createCode(); 77 | $this->createLine(); 78 | $this->createFont(); 79 | $this->outPut(); 80 | } 81 | //获取验证码 82 | public function getCode() 83 | { 84 | return strtolower($this->code); 85 | } 86 | } -------------------------------------------------------------------------------- /WebUI/Framework/Library/Framework.Captcha.php: -------------------------------------------------------------------------------- 1 | font = ROOT_PATH.'/View/Tpl/static/fonts/Elephant.ttf'; 26 | } 27 | //生成随机码 28 | private function createCode() 29 | { 30 | $_len = strlen($this->charset) - 1; 31 | for ($i = 0; $i < $this->codelen; $i++) { 32 | $this->code .= $this->charset[mt_rand(0, $_len)]; 33 | } 34 | } 35 | //生成背景 36 | private function createBg() 37 | { 38 | $this->img = imagecreatetruecolor($this->width, $this->height); 39 | $color = imagecolorallocate($this->img, mt_rand(157, 255), mt_rand(157, 255), mt_rand(157, 255)); 40 | imagefilledrectangle($this->img, 0, $this->height, $this->width, 0, $color); 41 | } 42 | //生成文字 43 | private function createFont() 44 | { 45 | $_x = $this->width / $this->codelen; 46 | for ($i = 0; $i < $this->codelen; $i++) { 47 | $this->fontcolor = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156)); 48 | imagettftext($this->img, $this->fontsize, mt_rand(-30, 30), $_x * $i + mt_rand(1, 5), $this->height / 1.4, $this->fontcolor, $this->font, $this->code[$i]); 49 | } 50 | } 51 | //生成线条、雪花 52 | private function createLine() 53 | { 54 | //线条 55 | for ($i = 0; $i < 6; $i++) { 56 | $color = imagecolorallocate($this->img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156)); 57 | imageline($this->img, mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0, $this->width), mt_rand(0, $this->height), $color); 58 | } 59 | //雪花 60 | for ($i = 0; $i < 100; $i++) { 61 | $color = imagecolorallocate($this->img, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255)); 62 | imagestring($this->img, mt_rand(1, 5), mt_rand(0, $this->width), mt_rand(0, $this->height), mt_rand(0,9), $color); 63 | } 64 | } 65 | //输出 66 | private function outPut() 67 | { 68 | header('Content-type:image/png'); 69 | imagepng($this->img); 70 | imagedestroy($this->img); 71 | } 72 | //对外生成 73 | public function doimg() 74 | { 75 | $this->createBg(); 76 | $this->createCode(); 77 | $this->createLine(); 78 | $this->createFont(); 79 | $this->outPut(); 80 | } 81 | //获取验证码 82 | public function getCode() 83 | { 84 | return strtolower($this->code); 85 | } 86 | } -------------------------------------------------------------------------------- /WebAPI/Framework/Library/Framework.XT.php: -------------------------------------------------------------------------------- 1 | t_cache)){ 14 | if(!mkdir($this->t_cache)){ 15 | throw new Exception("Failed to create cache directory:".$this->t_cache); 16 | } 17 | } 18 | } 19 | function setdata($k,$v){ 20 | $this->data[$k]=$v; 21 | } 22 | function subtemplate($filename){ 23 | if(is_array($filename)){ 24 | foreach($filename as $v){ 25 | $this->parse($v); 26 | } 27 | }else{ 28 | $this->parse($filename); 29 | } 30 | } 31 | function __parsedata($content){ 32 | //模板包含 33 | $this->subtp=array(); 34 | preg_match_all("//iu",$content,$rt); 35 | if(!empty($rt[1][0])){ 36 | foreach($rt[1] as $v){ 37 | if(!empty($v)){ 38 | $this->subtp[$v]=$v; 39 | } 40 | } 41 | if(!empty($this->subtp)){ 42 | $this->subtemplate($this->subtp,true); 43 | } 44 | } 45 | $content = preg_replace("//iu", "t_cache/\\1.php');?>", $content); 46 | //变量 47 | $content = preg_replace("/\{(\\\$[a-zA-Z0-9\[\]'_]+)\}/s", "", $content); 48 | //逻辑 49 | $content = preg_replace("//iu", "", $content); 50 | $content = preg_replace("//iu", "", $content); //<--新增 51 | $content = preg_replace("//iu", "", $content); 52 | //循环 53 | $content = preg_replace("//iu", "", $content); 54 | $content = preg_replace("//iu", "", $content); 55 | $content = preg_replace("//iu", "", $content); //<--新增 56 | $content = preg_replace("//iu", "", $content); //<--新增 57 | //PHP CODE 58 | $content = preg_replace("//iu", "", $content); //<--新增 59 | return $content; 60 | } 61 | function parse($filename=null,$sub=false){ 62 | $filename=(empty($filename)?basename($_SERVER["PHP_SELF"],".php"):$filename); 63 | $content_path=$this->t_cache."/".$filename.".php"; 64 | if(!file_exists($content_path)||$this->compile){ 65 | $content=implode("",file($this->folder.'/'.$filename.$this->t_type)); 66 | $content=$this->__parsedata($content); 67 | file_put_contents($content_path,$content); 68 | } 69 | !$sub?$this->content_path=$content_path:''; 70 | } 71 | function out(){ 72 | extract($this->data); 73 | include_once($this->content_path); 74 | } 75 | } 76 | ?> -------------------------------------------------------------------------------- /WebUI/Framework/Library/Framework.XT.php: -------------------------------------------------------------------------------- 1 | t_cache)){ 14 | if(!mkdir($this->t_cache)){ 15 | throw new Exception("Failed to create cache directory:".$this->t_cache); 16 | } 17 | } 18 | } 19 | function setdata($k,$v){ 20 | $this->data[$k]=$v; 21 | } 22 | function subtemplate($filename){ 23 | if(is_array($filename)){ 24 | foreach($filename as $v){ 25 | $this->parse($v); 26 | } 27 | }else{ 28 | $this->parse($filename); 29 | } 30 | } 31 | function __parsedata($content){ 32 | //模板包含 33 | $this->subtp=array(); 34 | preg_match_all("//iu",$content,$rt); 35 | if(!empty($rt[1][0])){ 36 | foreach($rt[1] as $v){ 37 | if(!empty($v)){ 38 | $this->subtp[$v]=$v; 39 | } 40 | } 41 | if(!empty($this->subtp)){ 42 | $this->subtemplate($this->subtp,true); 43 | } 44 | } 45 | $content = preg_replace("//iu", "t_cache/\\1.php');?>", $content); 46 | //变量 47 | $content = preg_replace("/\{(\\\$[a-zA-Z0-9\[\]'_]+)\}/s", "", $content); 48 | //逻辑 49 | $content = preg_replace("//iu", "", $content); 50 | $content = preg_replace("//iu", "", $content); //<--新增 51 | $content = preg_replace("//iu", "", $content); 52 | //循环 53 | $content = preg_replace("//iu", "", $content); 54 | $content = preg_replace("//iu", "", $content); 55 | $content = preg_replace("//iu", "", $content); //<--新增 56 | $content = preg_replace("//iu", "", $content); //<--新增 57 | //PHP CODE 58 | $content = preg_replace("//iu", "", $content); //<--新增 59 | return $content; 60 | } 61 | function parse($filename=null,$sub=false){ 62 | $filename=(empty($filename)?basename($_SERVER["PHP_SELF"],".php"):$filename); 63 | $content_path=$this->t_cache."/".$filename.".php"; 64 | if(!file_exists($content_path)||$this->compile){ 65 | $content=implode("",file($this->folder.'/'.$filename.$this->t_type)); 66 | $content=$this->__parsedata($content); 67 | file_put_contents($content_path,$content); 68 | } 69 | !$sub?$this->content_path=$content_path:''; 70 | } 71 | function out(){ 72 | extract($this->data); 73 | include_once($this->content_path); 74 | } 75 | } 76 | ?> -------------------------------------------------------------------------------- /WebSocket/Workerman/Connection/ConnectionInterface.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Connection; 15 | 16 | /** 17 | * ConnectionInterface. 18 | */ 19 | abstract class ConnectionInterface 20 | { 21 | /** 22 | * Statistics for status command. 23 | * 24 | * @var array 25 | */ 26 | public static $statistics = array( 27 | 'connection_count' => 0, 28 | 'total_request' => 0, 29 | 'throw_exception' => 0, 30 | 'send_fail' => 0, 31 | ); 32 | 33 | /** 34 | * Emitted when data is received. 35 | * 36 | * @var callback 37 | */ 38 | public $onMessage = null; 39 | 40 | /** 41 | * Emitted when the other end of the socket sends a FIN packet. 42 | * 43 | * @var callback 44 | */ 45 | public $onClose = null; 46 | 47 | /** 48 | * Emitted when an error occurs with connection. 49 | * 50 | * @var callback 51 | */ 52 | public $onError = null; 53 | 54 | /** 55 | * Sends data on the connection. 56 | * 57 | * @param string $send_buffer 58 | * @return void|boolean 59 | */ 60 | abstract public function send($send_buffer); 61 | 62 | /** 63 | * Get remote IP. 64 | * 65 | * @return string 66 | */ 67 | abstract public function getRemoteIp(); 68 | 69 | /** 70 | * Get remote port. 71 | * 72 | * @return int 73 | */ 74 | abstract public function getRemotePort(); 75 | 76 | /** 77 | * Get remote address. 78 | * 79 | * @return string 80 | */ 81 | abstract public function getRemoteAddress(); 82 | 83 | /** 84 | * Get remote IP. 85 | * 86 | * @return string 87 | */ 88 | abstract public function getLocalIp(); 89 | 90 | /** 91 | * Get remote port. 92 | * 93 | * @return int 94 | */ 95 | abstract public function getLocalPort(); 96 | 97 | /** 98 | * Get remote address. 99 | * 100 | * @return string 101 | */ 102 | abstract public function getLocalAddress(); 103 | 104 | /** 105 | * Is ipv4. 106 | * 107 | * @return bool 108 | */ 109 | abstract public function isIPv4(); 110 | 111 | /** 112 | * Is ipv6. 113 | * 114 | * @return bool 115 | */ 116 | abstract public function isIPv6(); 117 | 118 | /** 119 | * Close connection. 120 | * 121 | * @param $data 122 | * @return void 123 | */ 124 | abstract public function close($data = null); 125 | } 126 | -------------------------------------------------------------------------------- /WebAPI/Modules/User.Module.php: -------------------------------------------------------------------------------- 1 | ''),32)['1']; 10 | switch($uri){ 11 | case "balance": 12 | $this -> getBalance(); 13 | return; 14 | break; 15 | case "withdraw": 16 | $this -> withdrawUser(); 17 | return; 18 | break; 19 | default: 20 | parent::genError('4'); 21 | return; 22 | break; 23 | } 24 | } 25 | 26 | private function getBalance(){ 27 | $para = D('POST', array('[String]secret'=>'', '[String]name'=>'', '[String]sitekey'=>''), 64); 28 | foreach($para as $p){ 29 | if(trim($p) == ''){ 30 | parent::genError('6'); 31 | return; 32 | } 33 | } 34 | $sid = parent::getSidBySitekey($para['sitekey']); 35 | if($uinfo = $this -> redis -> get('siteuser-'.$sid.'-'.$para['name'])){ 36 | if($keyuserinfo = $this -> Mysql -> select('users', array('api_key'=>$para['secret']))[0]){ 37 | if($this -> Mysql -> confirm('sites', array('uid'=>$keyuserinfo['uid'], 'sid'=>$sid))){ 38 | H('json'); 39 | $uinfo=json_decode($uinfo, true); 40 | echo json_encode(array('success'=>true, 'name'=>$para['name'], 'total'=>$uinfo[0], 'lastsubmit'=>$uinfo[1], 'error'=>'')); 41 | return; 42 | }else{ 43 | parent::genError('7'); 44 | return; 45 | } 46 | }else{ 47 | parent::genError('2'); 48 | return; 49 | } 50 | }else{ 51 | parent::genError('8'); 52 | return; 53 | } 54 | } 55 | 56 | private function withdrawUser(){ 57 | $para = D('POST', array('[String]secret'=>'', '[String]name'=>'', '[String]sitekey'=>'', '[String]amount'=>''), 64); 58 | foreach($para as $p){ 59 | if(trim($p) == ''){ 60 | parent::genError('6'); 61 | return; 62 | } 63 | } 64 | if(!is_numeric($para['amount']) || $para['amount'] <= 0){ 65 | parent::genError('1'); 66 | return; 67 | } 68 | $sid = parent::getSidBySitekey($para['sitekey']); 69 | if($uinfo = $this -> redis -> get('siteuser-'.$sid.'-'.$para['name'])){ 70 | $uinfo=json_decode($uinfo, true); 71 | if($uinfo[0] < $para['amount']){ 72 | parent::genError('9'); 73 | return; 74 | } 75 | if($keyuserinfo = $this -> Mysql -> select('users', array('api_key'=>$para['secret']))){ 76 | if($this -> Mysql -> confirm('sites', array('uid'=>$keyuserinfo['uid'], 'sid'=>$sid))){ 77 | $uinfo[0] -= $para['amount']; 78 | $this -> redis -> set('siteuser-'.$sid.'-'.$para['name'], json_encode($uinfo)); 79 | H('json'); 80 | echo json_encode(array('success'=>true, 'name'=>$para['name'], 'amount'=>$para['amount'], 'error'=>'')); 81 | return; 82 | }else{ 83 | parent::genError('7'); 84 | return; 85 | } 86 | }else{ 87 | parent::genError('2'); 88 | return; 89 | } 90 | }else{ 91 | parent::genError('8'); 92 | return; 93 | } 94 | } 95 | 96 | private function getTopUser(){ 97 | 98 | } 99 | } -------------------------------------------------------------------------------- /WebUI/lib/captcha.min.js: -------------------------------------------------------------------------------- 1 | self.ProjectPoi = self.ProjectPoi || {}; 2 | self.ProjectPoi.CONFIG = { 3 | LIB_URL: "https://ppoi.org/lib/", 4 | WEBSOCKET_SHARDS: [ 5 | ["wss://ws01.ppoi.org/proxy"] 6 | ], 7 | CAPTCHA_URL: "https://ppoi.org/captcha/", 8 | MINER_URL: "https://ppoi.org/View/Tpl/miner.html" 9 | }; 10 | (function(window) { 11 | "use strict"; 12 | var Captcha = function(div) { 13 | this.div = div; 14 | this.goal = parseInt(this.div.dataset.hashes, 10) || 1024; 15 | this.key = this.div.dataset.key; 16 | this.callback = this.div.dataset.callback; 17 | this.disableSelector = this.div.dataset.disableElements; 18 | this.autostart = div.dataset.autostart === "true"; 19 | this.whitelabel = div.dataset.whitelabel === "true"; 20 | this.div.innerHTML = ""; 21 | this.iframe = document.createElement("iframe"); 22 | this.iframe.style.width = "304px"; 23 | this.iframe.style.height = "76px"; 24 | this.iframe.style.border = "none"; 25 | this.iframe.src = ProjectPoi.CONFIG.CAPTCHA_URL + "?goal=" + this.goal + "&key=" + this.key + "&autostart=" + (this.autostart ? "1" : "0") + "&whitelabel=" + (this.whitelabel ? "1" : "0"); 26 | this.div.appendChild(this.iframe); 27 | this.input = document.createElement("input"); 28 | this.input.type = "hidden"; 29 | this.input.name = "projectpoi-captcha-token"; 30 | this.div.appendChild(this.input); 31 | window.addEventListener("message", this.onMessage.bind(this)); 32 | if (this.disableSelector) { 33 | var elements = document.querySelectorAll(this.disableSelector); 34 | for (var i = 0; i < elements.length; i++) { 35 | elements[i].disabled = true 36 | } 37 | } 38 | }; 39 | Captcha.prototype.onMessage = function(ev) { 40 | if (ev.source !== this.iframe.contentWindow) { 41 | return 42 | } 43 | if (ev.data.type === "projectpoi-goal-reached" && ev.data.params) { 44 | this.input.value = ev.data.params.token; 45 | if (this.callback) { 46 | var callback = window[this.callback]; 47 | if (typeof callback === "function") { 48 | callback(ev.data.params.token) 49 | } 50 | } 51 | if (this.disableSelector) { 52 | var elements = document.querySelectorAll(this.disableSelector); 53 | for (var i = 0; i < elements.length; i++) { 54 | elements[i].disabled = false 55 | } 56 | } 57 | } 58 | }; 59 | Captcha.CreateElements = function() { 60 | var elements = document.querySelectorAll(".projectpoi-captcha"); 61 | for (var i = 0; i < elements.length; i++) { 62 | new Captcha(elements[i]) 63 | } 64 | }; 65 | if (document.readyState === "complete" || document.readyState === "interactive") { 66 | Captcha.CreateElements() 67 | } else { 68 | document.addEventListener("readystatechange", function() { 69 | if (document.readyState === "interactive") { 70 | Captcha.CreateElements() 71 | } 72 | }) 73 | } 74 | window.ProjectPoi = window.ProjectPoi || {}; 75 | window.ProjectPoi.Captcha = Captcha 76 | })(window); -------------------------------------------------------------------------------- /WebSocket/GlobalData/Server.php: -------------------------------------------------------------------------------- 1 | count = 1; 31 | $worker->name = 'globalDataServer'; 32 | $worker->onMessage = array($this, 'onMessage'); 33 | $worker->reloadable = false; 34 | $this->_worker = $worker; 35 | } 36 | 37 | /** 38 | * onMessage. 39 | * @param TcpConnection $connection 40 | * @param string $buffer 41 | */ 42 | public function onMessage($connection, $buffer) 43 | { 44 | if($buffer === 'ping') 45 | { 46 | return; 47 | } 48 | $data = unserialize($buffer); 49 | if(!$buffer || !isset($data['cmd']) || !isset($data['key'])) 50 | { 51 | return $connection->close(serialize('bad request')); 52 | } 53 | $cmd = $data['cmd']; 54 | $key = $data['key']; 55 | switch($cmd) 56 | { 57 | case 'get': 58 | if(!isset($this->_dataArray[$key])) 59 | { 60 | return $connection->send('N;'); 61 | } 62 | return $connection->send(serialize($this->_dataArray[$key])); 63 | break; 64 | case 'set': 65 | $this->_dataArray[$key] = $data['value']; 66 | $connection->send('b:1;'); 67 | break; 68 | case 'add': 69 | if(isset($this->_dataArray[$key])) 70 | { 71 | return $connection->send('b:0;'); 72 | } 73 | $this->_dataArray[$key] = $data['value']; 74 | return $connection->send('b:1;'); 75 | break; 76 | case 'increment': 77 | if(!isset($this->_dataArray[$key])) 78 | { 79 | return $connection->send('b:0;'); 80 | } 81 | if(!is_numeric($this->_dataArray[$key])) 82 | { 83 | $this->_dataArray[$key] = 0; 84 | } 85 | $this->_dataArray[$key] = $this->_dataArray[$key]+$data['step']; 86 | return $connection->send(serialize($this->_dataArray[$key])); 87 | break; 88 | case 'cas': 89 | if(isset($this->_dataArray[$key]) && md5(serialize($this->_dataArray[$key])) === $data['md5']) 90 | { 91 | $this->_dataArray[$key] = $data['value']; 92 | return $connection->send('b:1;'); 93 | } 94 | $connection->send('b:0;'); 95 | break; 96 | case 'delete': 97 | unset($this->_dataArray[$key]); 98 | $connection->send('b:1;'); 99 | break; 100 | default: 101 | $connection->close(serialize('bad cmd '. $cmd)); 102 | } 103 | } 104 | } 105 | 106 | 107 | -------------------------------------------------------------------------------- /WebUI/captcha/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ProjectPoi 验证码 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 19 |
点击验证
20 |
21 | 22 |
23 | 24 | 25 | 26 | 27 |
已验证
28 |
29 | 30 |
31 | 33 | 34 | 35 | 36 |
37 | 未知错误 38 | 刷新 39 |
40 |
41 | 42 |
43 |

44 | ProjectPoi

45 | 这是什么? 46 |
47 | 48 | 53 | 54 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Protocols/Http/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/x-javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/x-icon ico; 22 | image/x-jng jng; 23 | image/x-ms-bmp bmp; 24 | image/svg+xml svg svgz; 25 | image/webp webp; 26 | 27 | application/java-archive jar war ear; 28 | application/mac-binhex40 hqx; 29 | application/msword doc; 30 | application/pdf pdf; 31 | application/postscript ps eps ai; 32 | application/rtf rtf; 33 | application/vnd.ms-excel xls; 34 | application/vnd.ms-powerpoint ppt; 35 | application/vnd.wap.wmlc wmlc; 36 | application/vnd.google-earth.kml+xml kml; 37 | application/vnd.google-earth.kmz kmz; 38 | application/x-7z-compressed 7z; 39 | application/x-cocoa cco; 40 | application/x-java-archive-diff jardiff; 41 | application/x-java-jnlp-file jnlp; 42 | application/x-makeself run; 43 | application/x-perl pl pm; 44 | application/x-pilot prc pdb; 45 | application/x-rar-compressed rar; 46 | application/x-redhat-package-manager rpm; 47 | application/x-sea sea; 48 | application/x-shockwave-flash swf; 49 | application/x-stuffit sit; 50 | application/x-tcl tcl tk; 51 | application/x-x509-ca-cert der pem crt; 52 | application/x-xpinstall xpi; 53 | application/xhtml+xml xhtml; 54 | application/zip zip; 55 | 56 | application/octet-stream bin exe dll; 57 | application/octet-stream deb; 58 | application/octet-stream dmg; 59 | application/octet-stream eot; 60 | application/octet-stream iso img; 61 | application/octet-stream msi msp msm; 62 | 63 | audio/midi mid midi kar; 64 | audio/mpeg mp3; 65 | audio/ogg ogg; 66 | audio/x-m4a m4a; 67 | audio/x-realaudio ra; 68 | 69 | video/3gpp 3gpp 3gp; 70 | video/mp4 mp4; 71 | video/mpeg mpeg mpg; 72 | video/quicktime mov; 73 | video/webm webm; 74 | video/x-flv flv; 75 | video/x-m4v m4v; 76 | video/x-mng mng; 77 | video/x-ms-asf asx asf; 78 | video/x-ms-wmv wmv; 79 | video/x-msvideo avi; 80 | } 81 | -------------------------------------------------------------------------------- /WebAPI/Framework/Library/Framework.Security.php: -------------------------------------------------------------------------------- 1 | 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) { 93 | return substr($result, 26); 94 | } else { 95 | return ''; 96 | } 97 | } else { 98 | $ustr = $keyc . str_replace('=', '', base64_encode($result)); 99 | $ustr = str_replace('+', '[a]', $ustr); 100 | $ustr = str_replace('&', '[b]', $ustr); 101 | $ustr = str_replace('/', '[c]', $ustr); 102 | return $ustr; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /WebUI/Framework/Library/Framework.Security.php: -------------------------------------------------------------------------------- 1 | 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) { 93 | return substr($result, 26); 94 | } else { 95 | return ''; 96 | } 97 | } else { 98 | $ustr = $keyc . str_replace('=', '', base64_encode($result)); 99 | $ustr = str_replace('+', '[a]', $ustr); 100 | $ustr = str_replace('&', '[b]', $ustr); 101 | $ustr = str_replace('/', '[c]', $ustr); 102 | return $ustr; 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /WebUI/View/Tpl/media/miner-ui.js: -------------------------------------------------------------------------------- 1 | var MinerUI = function(miner, elements) { 2 | this.miner = miner; 3 | this.elements = elements; 4 | 5 | this.intervalUpdateStats = 0; 6 | this.intervalDrawGraph = 0; 7 | 8 | this.ctx = this.elements.canvas.getContext('2d'); 9 | 10 | this.elements.startButton.addEventListener('click', this.start.bind(this)); 11 | this.elements.stopButton.addEventListener('click', this.stop.bind(this)); 12 | 13 | this.elements.threadsAdd.addEventListener('click', this.addThread.bind(this)); 14 | this.elements.threadsRemove.addEventListener('click', this.removeThread.bind(this)); 15 | 16 | this.stats = []; 17 | for (var i = 0, x = 0; x < 300; i++, x += 5) { 18 | this.stats.push({hashes: 0, accepted: 0}); 19 | } 20 | 21 | this.didAcceptHash = false; 22 | if (this.miner) { 23 | this.miner.on('accepted', function(){ 24 | this.didAcceptHash = true; 25 | }.bind(this)); 26 | } 27 | }; 28 | 29 | MinerUI.prototype.start = function(ev) { 30 | ev.preventDefault(); 31 | 32 | if (!this.miner) { 33 | this.elements.blkWarn.style.display = 'block'; 34 | this.elements.startButton.style.display = 'none'; 35 | return false; 36 | } 37 | 38 | this.miner.start(ProjectPoi.FORCE_MULTI_TAB); 39 | this.elements.container.classList.add('running'); 40 | this.elements.container.classList.remove('stopped'); 41 | 42 | this.intervalUpdateStats = setInterval(this.updateStats.bind(this), 50); 43 | this.intervalDrawGraph = setInterval(this.drawGraph.bind(this), 500); 44 | 45 | this.elements.threads.textContent = this.miner.getNumThreads(); 46 | 47 | return false; 48 | }; 49 | 50 | MinerUI.prototype.stop = function(ev) { 51 | this.miner.stop(); 52 | this.elements.hashesPerSecond.textContent = 0; 53 | this.elements.container.classList.remove('running'); 54 | this.elements.container.classList.add('stopped'); 55 | 56 | clearInterval(this.intervalUpdateStats); 57 | clearInterval(this.intervalDrawGraph); 58 | 59 | ev.preventDefault(); 60 | return false; 61 | }; 62 | 63 | MinerUI.prototype.addThread = function(ev) { 64 | this.miner.setNumThreads(this.miner.getNumThreads() + 1); 65 | this.elements.threads.textContent = this.miner.getNumThreads(); 66 | 67 | ev.preventDefault(); 68 | return false; 69 | }; 70 | 71 | MinerUI.prototype.removeThread = function(ev) { 72 | this.miner.setNumThreads(Math.max(0, this.miner.getNumThreads() - 1)); 73 | this.elements.threads.textContent = this.miner.getNumThreads(); 74 | 75 | ev.preventDefault(); 76 | return false; 77 | }; 78 | 79 | MinerUI.prototype.updateStats = function() { 80 | this.elements.hashesPerSecond.textContent = this.miner.getHashesPerSecond().toFixed(1); 81 | this.elements.hashesTotal.textContent = this.miner.getTotalHashes(true); 82 | }; 83 | 84 | MinerUI.prototype.drawGraph = function() { 85 | 86 | // Resize canvas if necessary 87 | if (this.elements.canvas.offsetWidth !== this.elements.canvas.width) { 88 | this.elements.canvas.width = this.elements.canvas.offsetWidth; 89 | this.elements.canvas.height = this.elements.canvas.offsetHeight; 90 | } 91 | var w = this.elements.canvas.width; 92 | var h = this.elements.canvas.height; 93 | 94 | 95 | var current = this.stats.shift(); 96 | var last = this.stats[this.stats.length-1]; 97 | current.hashes = this.miner.getHashesPerSecond(); 98 | current.accepted = this.didAcceptHash; 99 | this.didAcceptHash = false; 100 | this.stats.push(current); 101 | 102 | // Find max value 103 | var vmax = 0; 104 | for (var i = 0; i < this.stats.length; i++) { 105 | var v = this.stats[i].hashes; 106 | if (v > vmax) { vmax = v; } 107 | } 108 | 109 | // Draw all bars 110 | this.ctx.clearRect(0, 0, w, h); 111 | for (var i = this.stats.length, j = 1; i--; j++) { 112 | var s = this.stats[i]; 113 | 114 | var vh = ((s.hashes/vmax) * (h - 16))|0; 115 | if (s.accepted) { 116 | this.ctx.fillStyle = '#aaa'; 117 | this.ctx.fillRect(w - j*10, h - vh, 9, vh); 118 | } 119 | else { 120 | this.ctx.fillStyle = '#ccc'; 121 | this.ctx.fillRect(w - j*10, h - vh, 9, vh); 122 | } 123 | } 124 | }; 125 | -------------------------------------------------------------------------------- /WebAPI/Framework/Library/Framework.Error.php: -------------------------------------------------------------------------------- 1 | Error = $error; 17 | $this -> Trace = $error -> getTrace(); 18 | $this -> ErrorMessage = htmlspecialchars($error -> getMessage()); 19 | $this -> Configs = C("Framework"); 20 | } 21 | public function SystemERROR(){ 22 | $html = << 25 | 26 | 27 | System Error 28 | 29 | 30 | 75 | 76 | 77 |
78 |

System Error

79 |
  • 80 | HTML; 81 | $html .= $this -> ErrorMessage; 82 | $html .= <<
  • 84 | 85 |

    PHP Debug

      86 | AHTML; 87 | if($this -> Configs['DEBUG_MODE'] === true){ 88 | for($i=0;$i Trace);$i++){ 89 | if(isset($this -> Trace[$i]['file'])){ 90 | $this -> Trace[$i]['file'] = str_replace('\\','/',$this -> Trace[$i]['file']); 91 | $this -> Trace[$i]['file'] = str_replace(ROOT_PATH.'/','',$this -> Trace[$i]['file']); 92 | } 93 | if(isset($this -> Trace[$i]['line'])){ 94 | $html .= '
    • [Line: '.$this -> Trace[$i]['line'].']'; 95 | }else{ 96 | $html .= '
    • [Line: 0]Unkown file'; 97 | } 98 | if(isset($this -> Trace[$i]['file'])){ 99 | $html .= $this -> Trace[$i]['file']; 100 | } 101 | if(isset($this -> Trace[$i]['class'])){ 102 | $html .= '('.$this -> Trace[$i]['class'].$this -> Trace[$i]['type'].$this -> Trace[$i]['function'].')
    • '; 103 | }else{ 104 | $html .= '('.$this -> Trace[$i]['function'].')'; 105 | } 106 | } 107 | }else{ 108 | $html .= '
    • DEBUG_MODE has been disabled
    • '; 109 | } 110 | $html .= <<
    我们已经将此出错信息详细记录, 由此给您带来的访问不便我们深感歉意.
    112 |
    113 | 114 | 115 | BHTML; 116 | echo $html; 117 | if($this -> Configs['LOG_ERROR']){ 118 | $this -> LogError(); 119 | } 120 | } 121 | private function LogError(){ 122 | file_put_contents(ROOT_PATH.'/Framework/Logs/'.time().mt_rand(100,999).'.txt',var_export($this -> Trace,true),FILE_APPEND); 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /WebUI/Framework/Library/Framework.Error.php: -------------------------------------------------------------------------------- 1 | Error = $error; 17 | $this -> Trace = $error -> getTrace(); 18 | $this -> ErrorMessage = htmlspecialchars($error -> getMessage()); 19 | $this -> Configs = C("Framework"); 20 | } 21 | public function SystemERROR(){ 22 | $html = << 25 | 26 | 27 | System Error 28 | 29 | 30 | 75 | 76 | 77 |
    78 |

    System Error

    79 |
  • 80 | HTML; 81 | $html .= $this -> ErrorMessage; 82 | $html .= <<
  • 84 | 85 |

    PHP Debug

      86 | AHTML; 87 | if($this -> Configs['DEBUG_MODE'] === true){ 88 | for($i=0;$i Trace);$i++){ 89 | if(isset($this -> Trace[$i]['file'])){ 90 | $this -> Trace[$i]['file'] = str_replace('\\','/',$this -> Trace[$i]['file']); 91 | $this -> Trace[$i]['file'] = str_replace(ROOT_PATH.'/','',$this -> Trace[$i]['file']); 92 | } 93 | if(isset($this -> Trace[$i]['line'])){ 94 | $html .= '
    • [Line: '.$this -> Trace[$i]['line'].']'; 95 | }else{ 96 | $html .= '
    • [Line: 0]Unkown file'; 97 | } 98 | if(isset($this -> Trace[$i]['file'])){ 99 | $html .= $this -> Trace[$i]['file']; 100 | } 101 | if(isset($this -> Trace[$i]['class'])){ 102 | $html .= '('.$this -> Trace[$i]['class'].$this -> Trace[$i]['type'].$this -> Trace[$i]['function'].')
    • '; 103 | }else{ 104 | $html .= '('.$this -> Trace[$i]['function'].')'; 105 | } 106 | } 107 | }else{ 108 | $html .= '
    • DEBUG_MODE has been disabled
    • '; 109 | } 110 | $html .= <<
    我们已经将此出错信息详细记录, 由此给您带来的访问不便我们深感歉意.
    112 |
    113 | 114 | 115 | BHTML; 116 | echo $html; 117 | if($this -> Configs['LOG_ERROR']){ 118 | $this -> LogError(); 119 | } 120 | } 121 | private function LogError(){ 122 | file_put_contents(ROOT_PATH.'/Framework/Logs/'.time().mt_rand(100,999).'.txt',var_export($this -> Trace,true),FILE_APPEND); 123 | } 124 | 125 | } -------------------------------------------------------------------------------- /WebUI/captcha/captcha-ui.min.js: -------------------------------------------------------------------------------- 1 | (function(window) { 2 | "use strict"; 3 | var CaptchaUI = function(siteKey, goal, elements) { 4 | this.siteKey = siteKey; 5 | this.goal = goal; 6 | this.startBound = this.start.bind(this); 7 | this.progress = 0; 8 | this.elements = {}; 9 | for (var name in elements) { 10 | this.elements[name] = document.getElementById(elements[name]) 11 | } 12 | this.elements.start.addEventListener("click", this.startBound) 13 | }; 14 | CaptchaUI.prototype.start = function() { 15 | if (this.miner) { 16 | return 17 | } 18 | if (!window.ProjectPoi.Token) { 19 | this.onError({ 20 | error: "请禁用Adblock!" 21 | }); 22 | return 23 | } 24 | this.elements.start.removeEventListener("click", this.startBound); 25 | this.elements.container.classList.add("in-progress"); 26 | this.updateInterval = setInterval(this.update.bind(this), 250); 27 | this.miner = new ProjectPoi.Token(this.siteKey, this.goal); 28 | this.miner.on("accepted", this.onHashAccepted.bind(this)); 29 | this.miner.on("authed", this.onAuthed.bind(this)); 30 | this.miner.on("error", this.onError.bind(this)); 31 | this.miner.start(ProjectPoi.FORCE_MULTI_TAB); 32 | if (!this.miner.hasWASMSupport()) { 33 | this.elements.slowWarning.style.display = "block" 34 | } 35 | }; 36 | CaptchaUI.prototype.setProgress = function(progress) { 37 | this.progress = Math.min(1, Math.max(this.progress, progress)); 38 | this.elements.progress.style.width = Math.ceil(this.progress * 100) + "%" 39 | }; 40 | CaptchaUI.prototype.onHashAccepted = function(params) { 41 | if (params.hashes >= this.goal) { 42 | this.setProgress(1); 43 | this.onGoalReached() 44 | } 45 | }; 46 | CaptchaUI.prototype.onAuthed = function(params) { 47 | this.elements.progress.style.display = "block"; 48 | setTimeout(function() { 49 | this.setProgress(.03) 50 | }.bind(this), 100); 51 | this.elements.errorContainer.style.display = "none" 52 | }; 53 | CaptchaUI.prototype.onGoalReached = function() { 54 | clearInterval(this.updateInterval); 55 | setTimeout(function() { 56 | this.elements.container.classList.add("done") 57 | }.bind(this), 500); 58 | setTimeout(function() { 59 | this.elements.verifiedContainer.style.display = "block" 60 | }.bind(this), 750); 61 | if (window.parent) { 62 | window.parent.postMessage({ 63 | type: "projectpoi-goal-reached", 64 | params: { 65 | hashes: this.miner.getAcceptedHashes(), 66 | token: this.miner.getToken() 67 | } 68 | }, "*") 69 | } 70 | }; 71 | CaptchaUI.prototype.onError = function(params) { 72 | this.elements.errorContainer.style.display = "block"; 73 | this.elements.errorText.textContent = params.error 74 | }; 75 | CaptchaUI.prototype.update = function() { 76 | var hashes = this.miner.getTotalHashes(true); 77 | var p = hashes / this.goal; 78 | this.setProgress(p * p / (p * p + .2) + .01) 79 | }; 80 | CaptchaUI.queryParam = function(name) { 81 | var results = new RegExp("[?&]" + name.replace(/[\[\]]/g, "\\$&") + "(=([^&#]*)|&|#|$)").exec(window.location.href); 82 | if (!results) { 83 | return null 84 | } 85 | if (!results[2]) { 86 | return "" 87 | } 88 | return decodeURIComponent(results[2].replace(/\+/g, " ")) 89 | }; 90 | window.ProjectPoi = window.ProjectPoi || {}; 91 | window.ProjectPoi.CaptchaUI = CaptchaUI 92 | })(window); 93 | self.ProjectPoi = self.ProjectPoi || {}; 94 | self.ProjectPoi.CONFIG = { 95 | LIB_URL: "https://ppoi.org/lib/", 96 | WEBSOCKET_SHARDS: [ 97 | ["wss://ws01.ppoi.org/proxy"] 98 | ], 99 | CAPTCHA_URL: "https://ppoi.org/captcha/", 100 | MINER_URL: "https://ppoi.org/media/miner.html" 101 | }; -------------------------------------------------------------------------------- /WebUI/captcha/captcha.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-sizing: border-box; 3 | -moz-box-sizing: border-box; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | background: #f9f9f9; 9 | font-family: sans-serif; 10 | line-height: 1.3; 11 | color: #555; 12 | font-size: 14px; 13 | padding: 0; 14 | margin: 0 auto; 15 | width: 304px; 16 | height: 76px; 17 | position: relative; 18 | border: 1px solid #ccc; 19 | } 20 | 21 | .column { 22 | top: 0; 23 | position: absolute; 24 | height: 74px; 25 | } 26 | 27 | .column-main { 28 | left: 25px; 29 | width: 175px; 30 | } 31 | 32 | .verify-me-progress { 33 | position: relative; 34 | display: inline-block; 35 | width: 26px; 36 | height: 26px; 37 | background-color: #fff; 38 | border: 2px solid #555; 39 | border-radius: 3px; 40 | margin: 25px 8px -8px 0; 41 | } 42 | 43 | .verify-me-progress:hover { 44 | box-shadow: inset 0px 1px 2px #ccc; 45 | border: 2px solid #333; 46 | } 47 | 48 | .verify-me-container.in-progress .verify-me-progress { 49 | border: 0; 50 | background-color: #ccc; 51 | animation: anim-effect-verify 0.5s ease-out forwards; 52 | } 53 | 54 | @keyframes anim-effect-verify { 55 | 0% { 56 | box-shadow: inset 0 0 0 16px #fff; 57 | } 58 | 50% { 59 | box-shadow: inset 0 0 0 0px #fff; 60 | } 61 | 75% { 62 | width: 26px; 63 | } 64 | 100% { 65 | width: 100%; 66 | } 67 | } 68 | 69 | .verify-me-container.done .verify-me-progress { 70 | animation: anim-effect-done 0.25s ease-out forwards; 71 | } 72 | 73 | @keyframes anim-effect-done { 74 | 0% { 75 | width: 170px; 76 | margin-left: 0px; 77 | } 78 | 100% { 79 | width: 0; 80 | margin-left: 170px; 81 | } 82 | } 83 | 84 | .progress { 85 | display: none; 86 | width: 0; 87 | height: 26px; 88 | border-radius: 3px; 89 | background: #21b0f9; 90 | transition: width 0.25s; 91 | } 92 | 93 | .verify-me-text { 94 | display: inline-block; 95 | font-size: 16px; 96 | color: #000; 97 | } 98 | 99 | .verify-me-container.in-progress .verify-me-text { 100 | transition: opacity 0.25s; 101 | opacity: 0; 102 | } 103 | 104 | 105 | .verified-container { 106 | display: none; 107 | } 108 | 109 | .verified-text { 110 | display: inline-block; 111 | font-size: 16px; 112 | color: #000; 113 | } 114 | 115 | .checkmark-circle { 116 | stroke-dasharray: 166; 117 | stroke-dashoffset: 166; 118 | stroke-width: 2; 119 | stroke-miterlimit: 10; 120 | stroke: #21b0f9; 121 | fill: none; 122 | animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards; 123 | } 124 | 125 | .checkmark { 126 | width: 32px; 127 | height: 32px; 128 | border-radius: 50%; 129 | display: inline-block; 130 | stroke-width: 5; 131 | stroke: #fff; 132 | stroke-miterlimit: 10; 133 | box-shadow: inset 0px 0px 0px #21b0f9; 134 | animation: fill .4s ease-in-out .4s forwards, scale .3s ease-in-out .9s both; 135 | margin: 22px 8px -10px -4px; 136 | } 137 | 138 | .checkmark-check { 139 | transform-origin: 50% 50%; 140 | stroke-dasharray: 48; 141 | stroke-dashoffset: 48; 142 | animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards; 143 | } 144 | 145 | @keyframes stroke { 146 | 100% { 147 | stroke-dashoffset: 0; 148 | } 149 | } 150 | @keyframes scale { 151 | 0%, 100% { 152 | transform: none; 153 | } 154 | 50% { 155 | transform: scale3d(1.1, 1.1, 1); 156 | } 157 | } 158 | @keyframes fill { 159 | 100% { 160 | box-shadow: inset 0px 0px 0px 30px #21b0f9; 161 | } 162 | } 163 | 164 | .error-container { 165 | background-color: #f9f9f9; 166 | display: none; 167 | } 168 | 169 | .exclamation { 170 | width: 32px; 171 | height: 74px; 172 | margin: 0px 8px 0px -2px; 173 | display: inline-block; 174 | float: left; 175 | } 176 | 177 | .error-text { 178 | display: block; 179 | display: flex; 180 | flex-direction: column; 181 | justify-content: center; 182 | font-size: 16px; 183 | color: #500; 184 | height: 74px; 185 | } 186 | 187 | #error-text { 188 | vertical-align: middle; 189 | line-height: normal; 190 | } 191 | 192 | .slow-warning { 193 | display: none; 194 | position: absolute; 195 | font-size: 12px; 196 | left: 24px; 197 | top: 56px; 198 | } 199 | 200 | a.help.warn { 201 | color: #ff9600; 202 | } 203 | 204 | .column-aside { 205 | left: 220px; 206 | width: 80px; 207 | } 208 | 209 | h1 { 210 | font-size: 14px; 211 | line-height: 1.2; 212 | font-weight: normal; 213 | text-transform: lowercase; 214 | color: #21b0f9; 215 | margin: 10px 0 4px 0; 216 | } 217 | 218 | img.icon { 219 | width: 16px; 220 | height: 16px; 221 | vertical-align: middle; 222 | margin: 0 4px 0 -2px; 223 | } 224 | 225 | h2 { 226 | font-size: 11px; 227 | margin: 0; 228 | } 229 | 230 | a.help { 231 | font-size: 12px; 232 | color: #aaa; 233 | text-decoration: underline; 234 | } 235 | 236 | a.help:hover { 237 | color: #000; 238 | } 239 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/documentationcaptcha.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |

    4 | 文档 » 5 | 验证码 6 |

    7 |
    8 | 9 |
    10 |

    概览

    11 |

    12 | 13 | 本文档将教您在您的网站上显示并自定义ProjectPoi组件。从站长的角度来看,ProjectPoi和传统的验证码类似(如谷歌的reCaptcha)。 14 | 15 |

    16 |

    17 | ProjectPoi组件运行在用户的浏览器上,会生成一个Token并和其他表单信息一起提交,你可以在服务器后端通过HTTP API验证这个Token。 18 |

    19 |

    20 | 与其他验证码不同,用户不需要证明他们是人类,而是通过进行大量的计算来验证,因为需要占用计算资源,所以可以有效地防止垃圾信息骚扰 21 |

    22 |
    23 | 24 |
    25 |

    集成

    26 |

    27 | 如果想要把ProjectPoi验证码集成到你的网站上,你要首先加载 captcha.min.js 到你的页面上,然后放置<div class="projectpoi-captcha"> </div>来显示验证码 28 |

    29 |

    30 | 如果成功加载JS,div元素内容将会被替换成验证码 31 |

    32 | 33 |
     34 | <form action="?" method="post">
     35 | 	<!-- other form fields -->
     36 | 
     37 | 	<script src="https://ppoi.org/lib/captcha.min.js" async></script>
     38 | 	<div class="projectpoi-captcha" data-hashes="1024" data-key="SITE_KEY">
     39 | 		<em>Loading Captcha...<br>
     40 | 		If it doesn't load, please disable Adblock!</em>
     41 | 	</div>
     42 | 
     43 | 	<input type="submit" value="Submit"/>
     44 | </form>
     45 | 
    46 |

    47 | 当验证完毕之后,会自动生成一个token,并以projectpoi-captcha-token参数和其他内容一起被发送到服务器 48 |

    49 |

    50 | 在服务器端,你可以通过使用HTTP API 51 | /token/verify 来验证token是否正确 52 |

    53 |
     54 | curl -X POST \
     55 | 	-d "token=<projectpoi-captcha-token>" \
     56 | 	-d "hashes=1024" \
     57 | 	-d "secret=<secret-key>" \
     58 | 	"https://api.ppoi.org/token/verify"
     59 | 
     60 | # {"success": true, "created": 1504205981, "hashes": 1024}
     61 | 
    62 | 63 |

    64 | Hash数量会分别在服务端和客户端被验证一次,以防止用户作弊或绕过 65 |

    66 |
    67 | 68 |
    69 |

    参数

    70 |

    71 | 你可以通过修改或添加data-属性来指定以下参数,标了*号的是可选参数 72 |

    73 | 74 | 75 | 76 | 77 | 81 | 82 | 83 | 84 | 87 | 88 | 89 | 90 | 94 | 95 | 96 | 97 | 100 | 101 | 102 | 103 | 106 | 107 | 108 | 109 | 112 | 113 |
    data-key 78 | 你的Site Key,参考 79 | 设置 - 站点. 80 |
    data-hashes 85 | 需要计算的Hash数量,因为我们的矿池难度为128,所以数量必须是128的倍数 86 |
    *data-autostart 91 | (可选)是否自动开始计算,可选值为 92 | true|false 默认为 false(不开启) 93 |
    *data-whitelabel 98 | (可选)是否隐藏ProjectPoi Logo和“这是什么”链接 99 |
    *data-callback 104 | (可选)当验证完成时的JS回调函数名 105 |
    *data-disable-elements 110 | (可选)验证完毕前需要禁用的元素,比如“提交”按钮。支持CSS选择器。 111 |
    114 |

    完整例子

    115 |
    116 | <form action="?" method="post">
    117 | 	<!-- other form fields -->
    118 | 
    119 | 	<script src="https://ppoi.org/lib/captcha.min.js" async></script>
    120 | 	<script>
    121 | 		function myCaptchaCallback(token) {
    122 | 			alert('Hash已达设定值. Token 为: ' + token);
    123 | 		}
    124 | 	</script>
    125 | 	<div class="projectpoi-captcha" 
    126 | 		data-hashes="1024" 
    127 | 		data-key="SITE_KEY"
    128 | 		data-autostart="false"
    129 | 		data-whitelabel="false"
    130 | 		data-disable-elements="input[type=submit]"
    131 | 		data-callback="myCaptchaCallback"
    132 | 	>
    133 | 		<em>加载验证码...<br>
    134 | 		If it doesn't load, please disable Adblock!</em>
    135 | 	</div>
    136 | 
    137 | 	<!-- submit button will be automatically disabled and later enabled
    138 | 		again when the captcha is solved -->
    139 | 	<input type="submit" value="Submit"/>
    140 | </form>
    141 | 
    142 | 143 |
    144 | 145 |
    146 |

    PHP后端验证例子

    147 |
    148 | $post_data = [
    149 | 	'secret' => "SECRET-KEY", // <- Your secret key
    150 | 	'token' => $_POST['projectpoi-captcha-token'],
    151 | 	'hashes' => 1024
    152 | ];
    153 | 
    154 | $post_context = stream_context_create([
    155 | 	'http' => [
    156 | 		'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
    157 | 		'method'  => 'POST',
    158 | 		'content' => http_build_query($post_data)
    159 | 	]
    160 | ]);
    161 | 
    162 | $url = 'https://api.ppoi.org/token/verify';
    163 | $response = json_decode(file_get_contents($url, false, $post_context));
    164 | 
    165 | if ($response && $response->success) {
    166 | 	// All good. Token verified!
    167 | }
    168 | 
    169 | 170 |

    171 | 更多信息(如错误代码等)请参考 172 | HTTP API文档. 173 |

    174 | 175 | 176 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Connection/UdpConnection.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Connection; 15 | 16 | /** 17 | * UdpConnection. 18 | */ 19 | class UdpConnection extends ConnectionInterface 20 | { 21 | /** 22 | * Application layer protocol. 23 | * The format is like this Workerman\\Protocols\\Http. 24 | * 25 | * @var \Workerman\Protocols\ProtocolInterface 26 | */ 27 | public $protocol = null; 28 | 29 | /** 30 | * Udp socket. 31 | * 32 | * @var resource 33 | */ 34 | protected $_socket = null; 35 | 36 | /** 37 | * Remote address. 38 | * 39 | * @var string 40 | */ 41 | protected $_remoteAddress = ''; 42 | 43 | /** 44 | * Construct. 45 | * 46 | * @param resource $socket 47 | * @param string $remote_address 48 | */ 49 | public function __construct($socket, $remote_address) 50 | { 51 | $this->_socket = $socket; 52 | $this->_remoteAddress = $remote_address; 53 | } 54 | 55 | /** 56 | * Sends data on the connection. 57 | * 58 | * @param string $send_buffer 59 | * @param bool $raw 60 | * @return void|boolean 61 | */ 62 | public function send($send_buffer, $raw = false) 63 | { 64 | if (false === $raw && $this->protocol) { 65 | $parser = $this->protocol; 66 | $send_buffer = $parser::encode($send_buffer, $this); 67 | if ($send_buffer === '') { 68 | return null; 69 | } 70 | } 71 | return strlen($send_buffer) === stream_socket_sendto($this->_socket, $send_buffer, 0, $this->_remoteAddress); 72 | } 73 | 74 | /** 75 | * Get remote IP. 76 | * 77 | * @return string 78 | */ 79 | public function getRemoteIp() 80 | { 81 | $pos = strrpos($this->_remoteAddress, ':'); 82 | if ($pos) { 83 | return trim(substr($this->_remoteAddress, 0, $pos), '[]'); 84 | } 85 | return ''; 86 | } 87 | 88 | /** 89 | * Get remote port. 90 | * 91 | * @return int 92 | */ 93 | public function getRemotePort() 94 | { 95 | if ($this->_remoteAddress) { 96 | return (int)substr(strrchr($this->_remoteAddress, ':'), 1); 97 | } 98 | return 0; 99 | } 100 | 101 | /** 102 | * Get remote address. 103 | * 104 | * @return string 105 | */ 106 | public function getRemoteAddress() 107 | { 108 | return $this->_remoteAddress; 109 | } 110 | 111 | /** 112 | * Get local IP. 113 | * 114 | * @return string 115 | */ 116 | public function getLocalIp() 117 | { 118 | $address = $this->getLocalAddress(); 119 | $pos = strrpos($address, ':'); 120 | if (!$pos) { 121 | return ''; 122 | } 123 | return substr($address, 0, $pos); 124 | } 125 | 126 | /** 127 | * Get local port. 128 | * 129 | * @return int 130 | */ 131 | public function getLocalPort() 132 | { 133 | $address = $this->getLocalAddress(); 134 | $pos = strrpos($address, ':'); 135 | if (!$pos) { 136 | return 0; 137 | } 138 | return (int)substr(strrchr($address, ':'), 1); 139 | } 140 | 141 | /** 142 | * Get local address. 143 | * 144 | * @return string 145 | */ 146 | public function getLocalAddress() 147 | { 148 | return (string)@stream_socket_get_name($this->_socket, false); 149 | } 150 | 151 | /** 152 | * Is ipv4. 153 | * 154 | * return bool. 155 | */ 156 | public function isIpV4() 157 | { 158 | if ($this->transport === 'unix') { 159 | return false; 160 | } 161 | return strpos($this->getRemoteIp(), ':') === false; 162 | } 163 | 164 | /** 165 | * Is ipv6. 166 | * 167 | * return bool. 168 | */ 169 | public function isIpV6() 170 | { 171 | if ($this->transport === 'unix') { 172 | return false; 173 | } 174 | return strpos($this->getRemoteIp(), ':') !== false; 175 | } 176 | 177 | /** 178 | * Close connection. 179 | * 180 | * @param mixed $data 181 | * @param bool $raw 182 | * @return bool 183 | */ 184 | public function close($data = null, $raw = false) 185 | { 186 | if ($data !== null) { 187 | $this->send($data, $raw); 188 | } 189 | return true; 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Lib/Timer.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Lib; 15 | 16 | use Workerman\Events\EventInterface; 17 | use Exception; 18 | 19 | /** 20 | * Timer. 21 | * 22 | * example: 23 | * Workerman\Lib\Timer::add($time_interval, callback, array($arg1, $arg2..)); 24 | */ 25 | class Timer 26 | { 27 | /** 28 | * Tasks that based on ALARM signal. 29 | * [ 30 | * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], 31 | * run_time => [[$func, $args, $persistent, time_interval],[$func, $args, $persistent, time_interval],..]], 32 | * .. 33 | * ] 34 | * 35 | * @var array 36 | */ 37 | protected static $_tasks = array(); 38 | 39 | /** 40 | * event 41 | * 42 | * @var \Workerman\Events\EventInterface 43 | */ 44 | protected static $_event = null; 45 | 46 | /** 47 | * Init. 48 | * 49 | * @param \Workerman\Events\EventInterface $event 50 | * @return void 51 | */ 52 | public static function init($event = null) 53 | { 54 | if ($event) { 55 | self::$_event = $event; 56 | } else { 57 | pcntl_signal(SIGALRM, array('\Workerman\Lib\Timer', 'signalHandle'), false); 58 | } 59 | } 60 | 61 | /** 62 | * ALARM signal handler. 63 | * 64 | * @return void 65 | */ 66 | public static function signalHandle() 67 | { 68 | if (!self::$_event) { 69 | pcntl_alarm(1); 70 | self::tick(); 71 | } 72 | } 73 | 74 | /** 75 | * Add a timer. 76 | * 77 | * @param int $time_interval 78 | * @param callback $func 79 | * @param mixed $args 80 | * @param bool $persistent 81 | * @return int/false 82 | */ 83 | public static function add($time_interval, $func, $args = array(), $persistent = true) 84 | { 85 | if ($time_interval <= 0) { 86 | echo new Exception("bad time_interval"); 87 | return false; 88 | } 89 | 90 | if (self::$_event) { 91 | return self::$_event->add($time_interval, 92 | $persistent ? EventInterface::EV_TIMER : EventInterface::EV_TIMER_ONCE, $func, $args); 93 | } 94 | 95 | if (!is_callable($func)) { 96 | echo new Exception("not callable"); 97 | return false; 98 | } 99 | 100 | if (empty(self::$_tasks)) { 101 | pcntl_alarm(1); 102 | } 103 | 104 | $time_now = time(); 105 | $run_time = $time_now + $time_interval; 106 | if (!isset(self::$_tasks[$run_time])) { 107 | self::$_tasks[$run_time] = array(); 108 | } 109 | self::$_tasks[$run_time][] = array($func, (array)$args, $persistent, $time_interval); 110 | return 1; 111 | } 112 | 113 | 114 | /** 115 | * Tick. 116 | * 117 | * @return void 118 | */ 119 | public static function tick() 120 | { 121 | if (empty(self::$_tasks)) { 122 | pcntl_alarm(0); 123 | return; 124 | } 125 | 126 | $time_now = time(); 127 | foreach (self::$_tasks as $run_time => $task_data) { 128 | if ($time_now >= $run_time) { 129 | foreach ($task_data as $index => $one_task) { 130 | $task_func = $one_task[0]; 131 | $task_args = $one_task[1]; 132 | $persistent = $one_task[2]; 133 | $time_interval = $one_task[3]; 134 | try { 135 | call_user_func_array($task_func, $task_args); 136 | } catch (\Exception $e) { 137 | echo $e; 138 | } 139 | if ($persistent) { 140 | self::add($time_interval, $task_func, $task_args); 141 | } 142 | } 143 | unset(self::$_tasks[$run_time]); 144 | } 145 | } 146 | } 147 | 148 | /** 149 | * Remove a timer. 150 | * 151 | * @param mixed $timer_id 152 | * @return bool 153 | */ 154 | public static function del($timer_id) 155 | { 156 | if (self::$_event) { 157 | return self::$_event->del($timer_id, EventInterface::EV_TIMER); 158 | } 159 | 160 | return false; 161 | } 162 | 163 | /** 164 | * Remove all timers. 165 | * 166 | * @return void 167 | */ 168 | public static function delAll() 169 | { 170 | self::$_tasks = array(); 171 | pcntl_alarm(0); 172 | if (self::$_event) { 173 | self::$_event->clearAllTimer(); 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/documentationsimpleui.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |

    4 | 文档 » 5 | Simple Miner UI 6 |

    7 |
    8 | 9 |
    10 |

    概览

    11 |

    12 | 本片文档指导您如何在页面上显示一个ProjectPoi 挖矿UI。 13 |

    14 |

    15 | 本简易UI由Iframe加载到一个 <div> 16 | 元素,您可以调整它的大小和颜色等。 17 |

    18 |
    19 | 20 |
    请禁用 Adblock!
    30 |
    31 | 简易挖矿UI作为横幅的一个演示,使用了自定义配色。 32 |
    33 |
    34 |
    35 | 36 |
    37 |

    嵌入

    38 |

    39 | 要嵌入ProjectPoi 挖矿UI, 您必须在页面中引用 40 | miner.min.js 并在您想显示UI的地方创建一个带有 projectpoi-miner 的 41 | <div> 42 |

    43 |

    44 | 记住替换 YOUR_SITE_KEY 成您自己的站点标识码。您可以在 45 | 设置 中找到您的。 46 |

    47 |

    48 | 在 <div> 中的文本(请禁用Adblock!) 49 | 可以被替换。 50 |

    51 | 52 |
     53 | <script src="https://ppoi.org/lib/miner.min.js" async></script>
     54 | <div class="projectpoi-miner" 
     55 | 	style="width: 256px; height: 310px"
     56 | 	data-key="YOUR_SITE_KEY">
     57 | 	<em>请禁用Adblock!</em>
     58 | </div>
     59 | 
    60 |
    61 | 62 |
    63 |

    自定义

    64 |
    65 |
    66 |

    67 | 通过使用 68 | style 属性您可以自定义本UI的样式。 本UI在各种大小的设备上均能良好展示。 69 |

    70 |

    71 | 比如您可以把本UI当做您的光顾横幅。UI支持的常用横幅格式有:300×250,160×600,336×280,728×90等。 72 |

    73 |

    74 | 如果您想进一步自定义其样式, data- 属性和各种div元素的选项都是可以使用的。 除了 data-key 属性以外其他都是可选属性。 75 |

    76 |
    77 |
    78 |
    Please disable Adblock!
    88 |
    89 |
    90 | 91 | 92 | 93 | 94 | 98 | 99 | 100 | 101 | 104 | 105 | 106 | 107 | 111 | 112 | 113 | 114 | 118 | 119 | 120 | 121 | 127 | 128 | 129 | 130 | 136 | 137 | 138 | 139 | 145 | 146 | 147 | 148 | 154 | 155 | 156 | 157 | 160 | 161 | 162 | 163 | 168 | 169 | 170 | 171 | 174 | 175 |
    data-key 95 | 您的站点标识码。参见 96 | 设置 » 站点与API. 97 |
    data-user 102 | 可选。Hash将加入到哪个用户。如果您不知道是什么可留空。 103 |
    data-autostart 108 | 可选。 是否自动启动挖矿 109 | (true|false)。 默认为 false. 110 |
    data-whitelabel 115 | 可选。 是否隐藏 Powered by ProjectPoi 文本 116 | (true|false)。默认为 false. 117 |
    data-background 122 | 可选。 16进制表示的背景颜色。 例如.: #000000 黑色, 123 | #ff0000 红色。 通过 124 | htmlcolorcodes.com 125 | 可以找到具体的颜色。 126 |
    data-text 131 | 可选。 16进制表示的文本颜色。 例如.: #000000 黑色, 132 | #ff0000 红色。 通过 133 | htmlcolorcodes.com 134 | 可以找到具体的颜色。 135 |
    data-action 140 | 可选。 16进制表示的动作颜色。 例如.: #000000 黑色, 141 | #ff0000 红色。 通过 142 | htmlcolorcodes.com 143 | 可以找到具体的颜色。 144 |
    data-graph 149 | 可选。 16进制表示的图标颜色。 例如.: #000000 黑色, 150 | #ff0000 红色。 通过 151 | htmlcolorcodes.com 152 | 可以找到具体的颜色。 153 |
    data-threads 158 | 可选。 默认开始的线程数。 159 |
    data-throttle 164 | 可选。 默认保留的资源数,具体参见 165 | miner.setThrottle() 166 | 167 |
    data-start 172 | 可选。 开始按钮的文本,默认为 "Start Mining". 173 |
    176 |

    绿色配色示例

    177 |
    178 | <script src="https://ppoi.org/lib/miner.min.js" async></script>
    179 | <div class="projectpoi-miner" 
    180 | 	style="width: 256px; height: 310px"
    181 | 	data-key="YOUR_SITE_KEY"
    182 | 	data-autostart="false"
    183 | 	data-whitelabel="false"
    184 | 	data-background="#000000"
    185 | 	data-text="#eeeeee"
    186 | 	data-action="#00ff00"
    187 | 	data-graph="#555555"
    188 | 	data-threads="4"
    189 | 	data-throttle="0.1"
    190 | 	data-start="Start Now!">
    191 | 	<em>Please disable Adblock!</em>
    192 | </div>
    193 | 
    194 | 195 | 196 | -------------------------------------------------------------------------------- /WebUI/View/Tpl/dashboard.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
    4 | 5 | 新推出: 6 | 简易挖矿UI 7 | 8 |
    9 |

    控制台

    10 | 11 |

    {$notice}

    12 | 13 |
    14 |
    15 |

    Hashes/s

    16 |

    {$speed}

    17 |
    18 |
    19 |

    总计Hash

    20 |

    {$totalhash}

    21 |
    22 |
    23 |

    总计支付

    24 |

    25 | {$totalpaid} 26 | XMR 27 |

    28 |
    29 |
    30 |

    等待支付

    31 |

    32 | {$pandingpay} XMR 33 |

    34 |
    35 |
    36 | 37 |

    38 | 当前报酬 39 | {$mhashxmr} XMR per 1M hashes
    40 | (挖矿难度: 41 | {$diff}G, 42 | 区块奖励: 43 | {$blockreward} XMR, 44 | 报酬 : {$payout}%, 45 | 信息更新于: {$payoutupdatetime}) 46 |

    47 |
    48 | 49 |
    50 |

    站点列表

    51 |
    52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 68 | 69 | 70 | 71 |
    名称Hashes/s总计Hash总计XMR
    {$s['site_name']}{$s['speed']} {$s['hashes']} 66 | XMR 67 |
    72 |
    73 |
    74 | 75 | 76 | 77 |
    78 |

    最近7天每小时平均Hashes/s

    79 |
    80 | 129 |
    130 |
    131 |

    支付记录

    132 |
    133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 |
    日期编号XMR
    {$p['$p['time']}{$p['tran_id']} {$p['xmr']}
    150 |
    151 | 152 |

    暂时还没有支付记录

    153 | 154 |
    155 | 156 |
    157 |
    158 |
    159 |

    新用户

    160 |
    161 |
    162 | 163 |
    164 |
    165 | 166 |
    167 |
    168 | 169 |
    170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 185 | 186 | 187 | 188 |
    最后提交站点名称Hashes
    {$u['lastsubmit']}{$u['sitename']}{$u['username']} 184 | {$u['hashes']}
    189 |
    190 |

    只显示最后提交最近的20个用户

    191 |
    192 | 193 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Events/React/ExtEventLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | use Workerman\Events\EventInterface; 16 | 17 | /** 18 | * Class ExtEventLoop 19 | * @package Workerman\Events\React 20 | */ 21 | class ExtEventLoop extends \React\EventLoop\ExtEventLoop 22 | { 23 | /** 24 | * Event base. 25 | * 26 | * @var EventBase 27 | */ 28 | protected $_eventBase = null; 29 | 30 | /** 31 | * All signal Event instances. 32 | * 33 | * @var array 34 | */ 35 | protected $_signalEvents = array(); 36 | 37 | /** 38 | * @var array 39 | */ 40 | protected $_timerIdMap = array(); 41 | 42 | /** 43 | * @var int 44 | */ 45 | protected $_timerIdIndex = 0; 46 | 47 | /** 48 | * Add event listener to event loop. 49 | * 50 | * @param $fd 51 | * @param $flag 52 | * @param $func 53 | * @param array $args 54 | * @return bool 55 | */ 56 | public function add($fd, $flag, $func, $args = array()) 57 | { 58 | $args = (array)$args; 59 | switch ($flag) { 60 | case EventInterface::EV_READ: 61 | return $this->addReadStream($fd, $func); 62 | case EventInterface::EV_WRITE: 63 | return $this->addWriteStream($fd, $func); 64 | case EventInterface::EV_SIGNAL: 65 | return $this->addSignal($fd, $func); 66 | case EventInterface::EV_TIMER: 67 | $timer_id = ++$this->_timerIdIndex; 68 | $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { 69 | call_user_func_array($func, $args); 70 | }); 71 | $this->_timerIdMap[$timer_id] = $timer_obj; 72 | return $timer_id; 73 | case EventInterface::EV_TIMER_ONCE: 74 | $timer_id = ++$this->_timerIdIndex; 75 | $timer_obj = $this->addTimer($fd, function() use ($func, $args, $timer_id) { 76 | unset($this->_timerIdMap[$timer_id]); 77 | call_user_func_array($func, $args); 78 | }); 79 | $this->_timerIdMap[$timer_id] = $timer_obj; 80 | return $timer_id; 81 | } 82 | return false; 83 | } 84 | 85 | /** 86 | * Remove event listener from event loop. 87 | * 88 | * @param mixed $fd 89 | * @param int $flag 90 | * @return bool 91 | */ 92 | public function del($fd, $flag) 93 | { 94 | switch ($flag) { 95 | case EventInterface::EV_READ: 96 | return $this->removeReadStream($fd); 97 | case EventInterface::EV_WRITE: 98 | return $this->removeWriteStream($fd); 99 | case EventInterface::EV_SIGNAL: 100 | return $this->removeSignal($fd); 101 | case EventInterface::EV_TIMER: 102 | case EventInterface::EV_TIMER_ONCE; 103 | if (isset($this->_timerIdMap[$fd])){ 104 | $timer_obj = $this->_timerIdMap[$fd]; 105 | unset($this->_timerIdMap[$fd]); 106 | $this->cancelTimer($timer_obj); 107 | return true; 108 | } 109 | } 110 | return false; 111 | } 112 | 113 | 114 | /** 115 | * Main loop. 116 | * 117 | * @return void 118 | */ 119 | public function loop() 120 | { 121 | $this->run(); 122 | } 123 | 124 | /** 125 | * Construct 126 | */ 127 | public function __construct() 128 | { 129 | parent::__construct(); 130 | $class = new \ReflectionClass('\React\EventLoop\ExtEventLoop'); 131 | $property = $class->getProperty('eventBase'); 132 | $property->setAccessible(true); 133 | $this->_eventBase = $property->getValue($this); 134 | } 135 | 136 | /** 137 | * Add signal handler. 138 | * 139 | * @param $signal 140 | * @param $callback 141 | * @return bool 142 | */ 143 | public function addSignal($signal, $callback) 144 | { 145 | $event = \Event::signal($this->_eventBase, $signal, $callback); 146 | if (!$event||!$event->add()) { 147 | return false; 148 | } 149 | $this->_signalEvents[$signal] = $event; 150 | } 151 | 152 | /** 153 | * Remove signal handler. 154 | * 155 | * @param $signal 156 | */ 157 | public function removeSignal($signal) 158 | { 159 | if (isset($this->_signalEvents[$signal])) { 160 | $this->_signalEvents[$signal]->del(); 161 | unset($this->_signalEvents[$signal]); 162 | } 163 | } 164 | 165 | /** 166 | * Destroy loop. 167 | * 168 | * @return void 169 | */ 170 | public function destroy() 171 | { 172 | foreach ($this->_signalEvents as $event) { 173 | $event->del(); 174 | } 175 | } 176 | 177 | /** 178 | * Get timer count. 179 | * 180 | * @return integer 181 | */ 182 | public function getTimerCount() 183 | { 184 | return count($this->_timerIdMap); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Events/React/LibEventLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | use Workerman\Events\EventInterface; 16 | 17 | /** 18 | * Class LibEventLoop 19 | * @package Workerman\Events\React 20 | */ 21 | class LibEventLoop extends \React\EventLoop\LibEventLoop 22 | { 23 | /** 24 | * Event base. 25 | * 26 | * @var event_base resource 27 | */ 28 | protected $_eventBase = null; 29 | 30 | /** 31 | * All signal Event instances. 32 | * 33 | * @var array 34 | */ 35 | protected $_signalEvents = array(); 36 | 37 | /** 38 | * @var array 39 | */ 40 | protected $_timerIdMap = array(); 41 | 42 | /** 43 | * @var int 44 | */ 45 | protected $_timerIdIndex = 0; 46 | 47 | /** 48 | * Add event listener to event loop. 49 | * 50 | * @param $fd 51 | * @param $flag 52 | * @param $func 53 | * @param array $args 54 | * @return bool 55 | */ 56 | public function add($fd, $flag, $func, $args = array()) 57 | { 58 | $args = (array)$args; 59 | switch ($flag) { 60 | case EventInterface::EV_READ: 61 | return $this->addReadStream($fd, $func); 62 | case EventInterface::EV_WRITE: 63 | return $this->addWriteStream($fd, $func); 64 | case EventInterface::EV_SIGNAL: 65 | return $this->addSignal($fd, $func); 66 | case EventInterface::EV_TIMER: 67 | $timer_id = ++$this->_timerIdIndex; 68 | $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { 69 | call_user_func_array($func, $args); 70 | }); 71 | $this->_timerIdMap[$timer_id] = $timer_obj; 72 | return $timer_id; 73 | case EventInterface::EV_TIMER_ONCE: 74 | $timer_id = ++$this->_timerIdIndex; 75 | $timer_obj = $this->addTimer($fd, function() use ($func, $args, $timer_id) { 76 | unset($this->_timerIdMap[$timer_id]); 77 | call_user_func_array($func, $args); 78 | }); 79 | $this->_timerIdMap[$timer_id] = $timer_obj; 80 | return $timer_id; 81 | } 82 | return false; 83 | } 84 | 85 | /** 86 | * Remove event listener from event loop. 87 | * 88 | * @param mixed $fd 89 | * @param int $flag 90 | * @return bool 91 | */ 92 | public function del($fd, $flag) 93 | { 94 | switch ($flag) { 95 | case EventInterface::EV_READ: 96 | return $this->removeReadStream($fd); 97 | case EventInterface::EV_WRITE: 98 | return $this->removeWriteStream($fd); 99 | case EventInterface::EV_SIGNAL: 100 | return $this->removeSignal($fd); 101 | case EventInterface::EV_TIMER: 102 | case EventInterface::EV_TIMER_ONCE; 103 | if (isset($this->_timerIdMap[$fd])){ 104 | $timer_obj = $this->_timerIdMap[$fd]; 105 | unset($this->_timerIdMap[$fd]); 106 | $this->cancelTimer($timer_obj); 107 | return true; 108 | } 109 | } 110 | return false; 111 | } 112 | 113 | 114 | /** 115 | * Main loop. 116 | * 117 | * @return void 118 | */ 119 | public function loop() 120 | { 121 | $this->run(); 122 | } 123 | 124 | /** 125 | * Construct. 126 | */ 127 | public function __construct() 128 | { 129 | parent::__construct(); 130 | $class = new \ReflectionClass('\React\EventLoop\LibEventLoop'); 131 | $property = $class->getProperty('eventBase'); 132 | $property->setAccessible(true); 133 | $this->_eventBase = $property->getValue($this); 134 | } 135 | 136 | /** 137 | * Add signal handler. 138 | * 139 | * @param $signal 140 | * @param $callback 141 | * @return bool 142 | */ 143 | public function addSignal($signal, $callback) 144 | { 145 | $event = event_new(); 146 | $this->_signalEvents[$signal] = $event; 147 | event_set($event, $signal, EV_SIGNAL | EV_PERSIST, $callback); 148 | event_base_set($event, $this->_eventBase); 149 | event_add($event); 150 | } 151 | 152 | /** 153 | * Remove signal handler. 154 | * 155 | * @param $signal 156 | */ 157 | public function removeSignal($signal) 158 | { 159 | if (isset($this->_signalEvents[$signal])) { 160 | $event = $this->_signalEvents[$signal]; 161 | event_del($event); 162 | unset($this->_signalEvents[$signal]); 163 | } 164 | } 165 | 166 | /** 167 | * Destroy loop. 168 | * 169 | * @return void 170 | */ 171 | public function destroy() 172 | { 173 | foreach ($this->_signalEvents as $event) { 174 | event_del($event); 175 | } 176 | } 177 | 178 | /** 179 | * Get timer count. 180 | * 181 | * @return integer 182 | */ 183 | public function getTimerCount() 184 | { 185 | return count($this->_timerIdMap); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Events/Ev.php: -------------------------------------------------------------------------------- 1 | 10 | * @link http://www.workerman.net/ 11 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 12 | */ 13 | namespace Workerman\Events; 14 | 15 | use Workerman\Worker; 16 | 17 | /** 18 | * ev eventloop 19 | */ 20 | class Ev implements EventInterface 21 | { 22 | /** 23 | * All listeners for read/write event. 24 | * 25 | * @var array 26 | */ 27 | protected $_allEvents = array(); 28 | 29 | /** 30 | * Event listeners of signal. 31 | * 32 | * @var array 33 | */ 34 | protected $_eventSignal = array(); 35 | 36 | /** 37 | * All timer event listeners. 38 | * [func, args, event, flag, time_interval] 39 | * 40 | * @var array 41 | */ 42 | protected $_eventTimer = array(); 43 | 44 | /** 45 | * Timer id. 46 | * 47 | * @var int 48 | */ 49 | protected static $_timerId = 1; 50 | 51 | /** 52 | * Add a timer. 53 | * {@inheritdoc} 54 | */ 55 | public function add($fd, $flag, $func, $args = null) 56 | { 57 | $callback = function ($event, $socket) use ($fd, $func) { 58 | try { 59 | call_user_func($func, $fd); 60 | } catch (\Exception $e) { 61 | Worker::log($e); 62 | exit(250); 63 | } catch (\Error $e) { 64 | Worker::log($e); 65 | exit(250); 66 | } 67 | }; 68 | switch ($flag) { 69 | case self::EV_SIGNAL: 70 | $event = new \EvSignal($fd, $callback); 71 | $this->_eventSignal[$fd] = $event; 72 | return true; 73 | case self::EV_TIMER: 74 | case self::EV_TIMER_ONCE: 75 | $repeat = $flag == self::EV_TIMER_ONCE ? 0 : $fd; 76 | $param = array($func, (array)$args, $flag, $fd, self::$_timerId); 77 | $event = new \EvTimer($fd, $repeat, array($this, 'timerCallback'), $param); 78 | $this->_eventTimer[self::$_timerId] = $event; 79 | return self::$_timerId++; 80 | default : 81 | $fd_key = (int)$fd; 82 | $real_flag = $flag === self::EV_READ ? \Ev::READ : \Ev::WRITE; 83 | $event = new \EvIo($fd, $real_flag, $callback); 84 | $this->_allEvents[$fd_key][$flag] = $event; 85 | return true; 86 | } 87 | 88 | } 89 | 90 | /** 91 | * Remove a timer. 92 | * {@inheritdoc} 93 | */ 94 | public function del($fd, $flag) 95 | { 96 | switch ($flag) { 97 | case self::EV_READ: 98 | case self::EV_WRITE: 99 | $fd_key = (int)$fd; 100 | if (isset($this->_allEvents[$fd_key][$flag])) { 101 | $this->_allEvents[$fd_key][$flag]->stop(); 102 | unset($this->_allEvents[$fd_key][$flag]); 103 | } 104 | if (empty($this->_allEvents[$fd_key])) { 105 | unset($this->_allEvents[$fd_key]); 106 | } 107 | break; 108 | case self::EV_SIGNAL: 109 | $fd_key = (int)$fd; 110 | if (isset($this->_eventSignal[$fd_key])) { 111 | $this->_eventSignal[$fd_key]->stop(); 112 | unset($this->_eventSignal[$fd_key]); 113 | } 114 | break; 115 | case self::EV_TIMER: 116 | case self::EV_TIMER_ONCE: 117 | if (isset($this->_eventTimer[$fd])) { 118 | $this->_eventTimer[$fd]->stop(); 119 | unset($this->_eventTimer[$fd]); 120 | } 121 | break; 122 | } 123 | return true; 124 | } 125 | 126 | /** 127 | * Timer callback. 128 | * 129 | * @param \EvWatcher $event 130 | */ 131 | public function timerCallback($event) 132 | { 133 | $param = $event->data; 134 | $timer_id = $param[4]; 135 | if ($param[2] === self::EV_TIMER_ONCE) { 136 | $this->_eventTimer[$timer_id]->stop(); 137 | unset($this->_eventTimer[$timer_id]); 138 | } 139 | try { 140 | call_user_func_array($param[0], $param[1]); 141 | } catch (\Exception $e) { 142 | Worker::log($e); 143 | exit(250); 144 | } catch (\Error $e) { 145 | Worker::log($e); 146 | exit(250); 147 | } 148 | } 149 | 150 | /** 151 | * Remove all timers. 152 | * 153 | * @return void 154 | */ 155 | public function clearAllTimer() 156 | { 157 | foreach ($this->_eventTimer as $event) { 158 | $event->stop(); 159 | } 160 | $this->_eventTimer = array(); 161 | } 162 | 163 | /** 164 | * Main loop. 165 | * 166 | * @see EventInterface::loop() 167 | */ 168 | public function loop() 169 | { 170 | \Ev::run(); 171 | } 172 | 173 | /** 174 | * Destroy loop. 175 | * 176 | * @return void 177 | */ 178 | public function destroy() 179 | { 180 | foreach ($this->_allEvents as $event) { 181 | $event->stop(); 182 | } 183 | } 184 | 185 | /** 186 | * Get timer count. 187 | * 188 | * @return integer 189 | */ 190 | public function getTimerCount() 191 | { 192 | return count($this->_eventTimer); 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Events/React/StreamSelectLoop.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events\React; 15 | use Workerman\Events\EventInterface; 16 | 17 | /** 18 | * Class StreamSelectLoop 19 | * @package Workerman\Events\React 20 | */ 21 | class StreamSelectLoop extends \React\EventLoop\StreamSelectLoop 22 | { 23 | /** 24 | * @var array 25 | */ 26 | protected $_timerIdMap = array(); 27 | 28 | /** 29 | * @var int 30 | */ 31 | protected $_timerIdIndex = 0; 32 | 33 | /** 34 | * Add event listener to event loop. 35 | * 36 | * @param $fd 37 | * @param $flag 38 | * @param $func 39 | * @param array $args 40 | * @return bool 41 | */ 42 | public function add($fd, $flag, $func, $args = array()) 43 | { 44 | $args = (array)$args; 45 | switch ($flag) { 46 | case EventInterface::EV_READ: 47 | return $this->addReadStream($fd, $func); 48 | case EventInterface::EV_WRITE: 49 | return $this->addWriteStream($fd, $func); 50 | case EventInterface::EV_SIGNAL: 51 | return $this->addSignal($fd, $func); 52 | case EventInterface::EV_TIMER: 53 | $timer_obj = $this->addPeriodicTimer($fd, function() use ($func, $args) { 54 | call_user_func_array($func, $args); 55 | }); 56 | $this->_timerIdMap[++$this->_timerIdIndex] = $timer_obj; 57 | return $this->_timerIdIndex; 58 | case EventInterface::EV_TIMER_ONCE: 59 | $index = ++$this->_timerIdIndex; 60 | $timer_obj = $this->addTimer($fd, function() use ($func, $args, $index) { 61 | $this->del($index,EventInterface::EV_TIMER_ONCE); 62 | call_user_func_array($func, $args); 63 | }); 64 | $this->_timerIdMap[$index] = $timer_obj; 65 | return $this->_timerIdIndex; 66 | } 67 | return false; 68 | } 69 | 70 | /** 71 | * Remove event listener from event loop. 72 | * 73 | * @param mixed $fd 74 | * @param int $flag 75 | * @return bool 76 | */ 77 | public function del($fd, $flag) 78 | { 79 | switch ($flag) { 80 | case EventInterface::EV_READ: 81 | return $this->removeReadStream($fd); 82 | case EventInterface::EV_WRITE: 83 | return $this->removeWriteStream($fd); 84 | case EventInterface::EV_SIGNAL: 85 | return $this->removeSignal($fd); 86 | case EventInterface::EV_TIMER: 87 | case EventInterface::EV_TIMER_ONCE; 88 | if (isset($this->_timerIdMap[$fd])){ 89 | $timer_obj = $this->_timerIdMap[$fd]; 90 | unset($this->_timerIdMap[$fd]); 91 | $this->cancelTimer($timer_obj); 92 | return true; 93 | } 94 | } 95 | return false; 96 | } 97 | 98 | 99 | /** 100 | * Main loop. 101 | * 102 | * @return void 103 | */ 104 | public function loop() 105 | { 106 | $this->run(); 107 | } 108 | 109 | /** 110 | * Add signal handler. 111 | * 112 | * @param $signal 113 | * @param $callback 114 | * @return bool 115 | */ 116 | public function addSignal($signal, $callback) 117 | { 118 | if(DIRECTORY_SEPARATOR === '/') { 119 | pcntl_signal($signal, $callback); 120 | } 121 | } 122 | 123 | /** 124 | * Remove signal handler. 125 | * 126 | * @param $signal 127 | */ 128 | public function removeSignal($signal) 129 | { 130 | if(DIRECTORY_SEPARATOR === '/') { 131 | pcntl_signal($signal, SIG_IGN); 132 | } 133 | } 134 | 135 | /** 136 | * Emulate a stream_select() implementation that does not break when passed 137 | * empty stream arrays. 138 | * 139 | * @param array &$read An array of read streams to select upon. 140 | * @param array &$write An array of write streams to select upon. 141 | * @param integer|null $timeout Activity timeout in microseconds, or null to wait forever. 142 | * 143 | * @return integer|false The total number of streams that are ready for read/write. 144 | * Can return false if stream_select() is interrupted by a signal. 145 | */ 146 | protected function streamSelect(array &$read, array &$write, $timeout) 147 | { 148 | if ($read || $write) { 149 | $except = null; 150 | // Calls signal handlers for pending signals 151 | if(DIRECTORY_SEPARATOR === '/') { 152 | pcntl_signal_dispatch(); 153 | } 154 | // suppress warnings that occur, when stream_select is interrupted by a signal 155 | return @stream_select($read, $write, $except, $timeout === null ? null : 0, $timeout); 156 | } 157 | 158 | // Calls signal handlers for pending signals 159 | if(DIRECTORY_SEPARATOR === '/') { 160 | pcntl_signal_dispatch(); 161 | } 162 | $timeout && usleep($timeout); 163 | 164 | return 0; 165 | } 166 | 167 | /** 168 | * Destroy loop. 169 | * 170 | * @return void 171 | */ 172 | public function destroy() 173 | { 174 | 175 | } 176 | 177 | /** 178 | * Get timer count. 179 | * 180 | * @return integer 181 | */ 182 | public function getTimerCount() 183 | { 184 | return count($this->_timerIdMap); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /WebSocket/Workerman/Events/Event.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright 有个鬼<42765633@qq.com> 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | use Workerman\Worker; 17 | 18 | /** 19 | * libevent eventloop 20 | */ 21 | class Event implements EventInterface 22 | { 23 | /** 24 | * Event base. 25 | * @var object 26 | */ 27 | protected $_eventBase = null; 28 | 29 | /** 30 | * All listeners for read/write event. 31 | * @var array 32 | */ 33 | protected $_allEvents = array(); 34 | 35 | /** 36 | * Event listeners of signal. 37 | * @var array 38 | */ 39 | protected $_eventSignal = array(); 40 | 41 | /** 42 | * All timer event listeners. 43 | * [func, args, event, flag, time_interval] 44 | * @var array 45 | */ 46 | protected $_eventTimer = array(); 47 | 48 | /** 49 | * Timer id. 50 | * @var int 51 | */ 52 | protected static $_timerId = 1; 53 | 54 | /** 55 | * construct 56 | * @return void 57 | */ 58 | public function __construct() 59 | { 60 | $this->_eventBase = new \EventBase(); 61 | } 62 | 63 | /** 64 | * @see EventInterface::add() 65 | */ 66 | public function add($fd, $flag, $func, $args=array()) 67 | { 68 | switch ($flag) { 69 | case self::EV_SIGNAL: 70 | 71 | $fd_key = (int)$fd; 72 | $event = \Event::signal($this->_eventBase, $fd, $func); 73 | if (!$event||!$event->add()) { 74 | return false; 75 | } 76 | $this->_eventSignal[$fd_key] = $event; 77 | return true; 78 | 79 | case self::EV_TIMER: 80 | case self::EV_TIMER_ONCE: 81 | 82 | $param = array($func, (array)$args, $flag, $fd, self::$_timerId); 83 | $event = new \Event($this->_eventBase, -1, \Event::TIMEOUT|\Event::PERSIST, array($this, "timerCallback"), $param); 84 | if (!$event||!$event->addTimer($fd)) { 85 | return false; 86 | } 87 | $this->_eventTimer[self::$_timerId] = $event; 88 | return self::$_timerId++; 89 | 90 | default : 91 | $fd_key = (int)$fd; 92 | $real_flag = $flag === self::EV_READ ? \Event::READ | \Event::PERSIST : \Event::WRITE | \Event::PERSIST; 93 | $event = new \Event($this->_eventBase, $fd, $real_flag, $func, $fd); 94 | if (!$event||!$event->add()) { 95 | return false; 96 | } 97 | $this->_allEvents[$fd_key][$flag] = $event; 98 | return true; 99 | } 100 | } 101 | 102 | /** 103 | * @see Events\EventInterface::del() 104 | */ 105 | public function del($fd, $flag) 106 | { 107 | switch ($flag) { 108 | 109 | case self::EV_READ: 110 | case self::EV_WRITE: 111 | 112 | $fd_key = (int)$fd; 113 | if (isset($this->_allEvents[$fd_key][$flag])) { 114 | $this->_allEvents[$fd_key][$flag]->del(); 115 | unset($this->_allEvents[$fd_key][$flag]); 116 | } 117 | if (empty($this->_allEvents[$fd_key])) { 118 | unset($this->_allEvents[$fd_key]); 119 | } 120 | break; 121 | 122 | case self::EV_SIGNAL: 123 | $fd_key = (int)$fd; 124 | if (isset($this->_eventSignal[$fd_key])) { 125 | $this->_eventSignal[$fd_key]->del(); 126 | unset($this->_eventSignal[$fd_key]); 127 | } 128 | break; 129 | 130 | case self::EV_TIMER: 131 | case self::EV_TIMER_ONCE: 132 | if (isset($this->_eventTimer[$fd])) { 133 | $this->_eventTimer[$fd]->del(); 134 | unset($this->_eventTimer[$fd]); 135 | } 136 | break; 137 | } 138 | return true; 139 | } 140 | 141 | /** 142 | * Timer callback. 143 | * @param null $fd 144 | * @param int $what 145 | * @param int $timer_id 146 | */ 147 | public function timerCallback($fd, $what, $param) 148 | { 149 | $timer_id = $param[4]; 150 | 151 | if ($param[2] === self::EV_TIMER_ONCE) { 152 | $this->_eventTimer[$timer_id]->del(); 153 | unset($this->_eventTimer[$timer_id]); 154 | } 155 | 156 | try { 157 | call_user_func_array($param[0], $param[1]); 158 | } catch (\Exception $e) { 159 | Worker::log($e); 160 | exit(250); 161 | } catch (\Error $e) { 162 | Worker::log($e); 163 | exit(250); 164 | } 165 | } 166 | 167 | /** 168 | * @see Events\EventInterface::clearAllTimer() 169 | * @return void 170 | */ 171 | public function clearAllTimer() 172 | { 173 | foreach ($this->_eventTimer as $event) { 174 | $event->del(); 175 | } 176 | $this->_eventTimer = array(); 177 | } 178 | 179 | 180 | /** 181 | * @see EventInterface::loop() 182 | */ 183 | public function loop() 184 | { 185 | $this->_eventBase->loop(); 186 | } 187 | 188 | /** 189 | * Destroy loop. 190 | * 191 | * @return void 192 | */ 193 | public function destroy() 194 | { 195 | foreach ($this->_eventSignal as $event) { 196 | $event->del(); 197 | } 198 | } 199 | 200 | /** 201 | * Get timer count. 202 | * 203 | * @return integer 204 | */ 205 | public function getTimerCount() 206 | { 207 | return count($this->_eventTimer); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /WebUI/Modules/User.Module.php: -------------------------------------------------------------------------------- 1 | Configs = $configs; 11 | $this -> m = M("Mysql"); 12 | } 13 | 14 | public static function isLogin($sitekey){ 15 | if(isset($_COOKIE['session'])){ 16 | if($sess = json_decode($_COOKIE['session'], true)){ 17 | $ip = Security::GetIP(); 18 | if(!$ip){ 19 | throw new Exception('Can not get your IP'); 20 | } 21 | if(!is_array($sess['n']) && !is_array($sess['pp']) && $sess['id'] === md5($sess['n'].$sess['pp'].$sitekey) && sprintf('%u', ip2long($ip)) === $sess['pp']){ 22 | return $sess['n']; 23 | } 24 | } 25 | return false; 26 | } 27 | } 28 | 29 | public function loginInUser($email, $password){ 30 | $m = $this -> m; 31 | $ip = Security::GetIP(); 32 | if(!$ip){ 33 | throw new Exception('Can not get your IP'); 34 | } 35 | if($data = $m -> select('users', array('email'=>$email, 'password' => md5(md5($password).$this -> Configs['SITE_KEY'])))){ 36 | if($data[0]['ban'] == ''){ 37 | setcookie('session',json_encode(array('n'=>$email, 'id'=>md5($email.sprintf('%u', ip2long(Security::GetIP())).$this -> Configs['SITE_KEY']), 'pp'=>sprintf('%u', ip2long($ip)))), time() + (86400 * 7), '/'); 38 | return true; 39 | }else{ 40 | return $data[0]['ban']; 41 | } 42 | }else{ 43 | return false; 44 | } 45 | } 46 | 47 | public function getUserinfo($email){ 48 | $m = $this -> m; 49 | return $m -> select('users', array('email' => $email))[0]; 50 | } 51 | 52 | public function regUser($email, $password){ 53 | $m = $this -> m; 54 | if($m -> confirm('users', array('email'=>$email))){ 55 | return false; 56 | }else{ 57 | $ip = Security::GetIP(); 58 | if(!$ip){ 59 | throw new Exception('Can not get your IP'); 60 | } 61 | $m -> add('users', array('email'=>$email, 'password' => md5(md5($password).$this -> Configs['SITE_KEY']), 'api_key' => RandChar(24), 'is_validated' => '0', 'reg_date' => time(), 'reg_ip' => sprintf('%u', ip2long($ip)), 'payment_config' => '', 'paid_xmr' => '0', 'paid_hashes' => '0', 'total_hashes' => '0', 'last_total' => '0', 'hour_avrg' => '')); 62 | $uid = $m -> select('users', array('email'=>$email))[0]['uid']; 63 | $m -> add('sites', array('uid'=>$uid, 'site_name'=>'你的站点', 'site_key'=>RandChar(24), 'hashes'=>'0', 'last_hashes'=>'0', 'speed'=>'0')); 64 | $activelink = $this -> Configs['SITE_URL'].'/account/verify?token='.Security::authcode($email, 'ENCODE', $this -> Configs['SITE_KEY'], 86400); 65 | $mailcontent = '您好,感谢您注册ProjectPoi。
    您的验证链接为: '.$activelink.'注意:该链接有效期只有1天。'; 66 | Import('PHPMailer'); 67 | Import('SMTP'); 68 | $mail = new PHPMailer(false); 69 | $mail -> isSMTP(); 70 | $mail -> Host = $this -> Configs['SMTP_SERVER']; 71 | $mail -> SMTPAuth = true; 72 | $mail -> Username = $this -> Configs['SMTP_USER']; 73 | $mail -> Password = $this -> Configs['SMTP_PASS']; 74 | $mail -> SMTPSecure = 'tls'; 75 | $mail -> Port = 587; 76 | $mail -> setFrom($this -> Configs['SMTP_USER'], 'ProjectPoi'); 77 | $mail -> addAddress($email); 78 | $mail -> isHTML(true); 79 | $mail -> Subject = 'ProjectPoi 邮箱地址验证'; 80 | $mail -> Body = $mailcontent; 81 | $mail -> send(); 82 | return true; 83 | } 84 | } 85 | 86 | public function sendResetLink($email){ 87 | $resetlink = $this -> Configs['SITE_URL'].'/account/reset-password?token='.Security::authcode('ResetPassword***'.$email, 'ENCODE', $this -> Configs['SITE_KEY'], 7200); 88 | $mailcontent = '您好,
    要重设您的密码,请点击以下链接: '.$resetlink.'
    注意:该链接有效期只有2小时。
    如果您没有请求重设密码,那么可能是有人在尝试进入您的账户,请注意您的账户安全。
    请求IP: '.Security::GetIP(); 89 | Import('PHPMailer'); 90 | Import('SMTP'); 91 | $mail = new PHPMailer(false); 92 | // $mail -> SMTPDebug = 2; 93 | $mail -> isSMTP(); 94 | $mail -> Host = $this -> Configs['SMTP_SERVER']; 95 | $mail -> SMTPAuth = true; 96 | $mail -> Username = $this -> Configs['SMTP_USER']; 97 | $mail -> Password = $this -> Configs['SMTP_PASS']; 98 | $mail -> SMTPSecure = 'tls'; 99 | $mail -> Port = 587; 100 | $mail -> setFrom($this -> Configs['SMTP_USER'], 'ProjectPoi'); 101 | $mail -> addAddress($email); 102 | $mail -> isHTML(true); 103 | $mail -> Subject = 'ProjectPoi 重设密码'; 104 | $mail -> Body = $mailcontent; 105 | $mail -> send(); 106 | return true; 107 | } 108 | 109 | public function verifyUser($email){ 110 | $m = $this -> m; 111 | $m -> update('users', array('is_validated' => '1'), array('email' => $email)); 112 | return true; 113 | } 114 | 115 | public function updatePassword($email, $password){ 116 | $m = $this -> m; 117 | $m -> update('users', array('password' => md5(md5($password).$this -> Configs['SITE_KEY'])), array('email' => $email)); 118 | return true; 119 | } 120 | 121 | public function updatePayment($email, $payment){ 122 | $m = $this -> m; 123 | $m -> update('users', array('payment_config' => $payment), array('email' => $email)); 124 | return true; 125 | } 126 | 127 | public function updateEmail($email, $newemail){ 128 | $m = $this -> m; 129 | $m -> update('users', array('email' => $newemail, 'is_validated' => '0'), array('email' => $email)); 130 | $activelink = $this -> Configs['SITE_URL'].'/account/verify?token='.Security::authcode($email, 'ENCODE', $this -> Configs['SITE_KEY'], 86400); 131 | $mailcontent = '您好,您在ProjectPoi上更改了新的邮箱。
    您的验证链接为: '.$activelink.'
    注意:该链接有效期只有1天。'; 132 | Import('PHPMailer'); 133 | Import('SMTP'); 134 | $mail = new PHPMailer(false); 135 | $mail -> isSMTP(); 136 | $mail -> Host = $this -> Configs['SMTP_SERVER']; 137 | $mail -> SMTPAuth = true; 138 | $mail -> Username = $this -> Configs['SMTP_USER']; 139 | $mail -> Password = $this -> Configs['SMTP_PASS']; 140 | $mail -> SMTPSecure = 'tls'; 141 | $mail -> Port = 587; 142 | $mail -> setFrom($this -> Configs['SMTP_USER'], 'ProjectPoi'); 143 | $mail -> addAddress($email); 144 | $mail -> isHTML(true); 145 | $mail -> Subject = 'ProjectPoi 邮箱地址验证'; 146 | $mail -> Body = $mailcontent; 147 | $mail -> send(); 148 | } 149 | 150 | public function updateAPIKey($email){ 151 | $m = $this -> m; 152 | $m -> update('users', array('api_key' => RandChar(24)), array('email' => $email)); 153 | return true; 154 | } 155 | 156 | } -------------------------------------------------------------------------------- /WebAPI/Framework/Common/Function.php: -------------------------------------------------------------------------------- 1 | $v){ 57 | if(stristr($k,'[Int]')){ 58 | $k = str_replace('[Int]','',$k); 59 | if(isset($Q[$k])){ 60 | if(is_numeric($Q[$k])){ 61 | $Q[$k] = (int)$Q[$k]; 62 | }else{ 63 | throw new Exception("Parameter '$k' must be integer"); 64 | } 65 | }else{ 66 | $R[$k] = (int)''; 67 | continue; 68 | } 69 | }elseif(stristr($k,'[String]')){ 70 | $k = str_replace('[String]','',$k); 71 | if(isset($Q[$k])){ 72 | if(is_string($Q[$k])){ 73 | $Q[$k] = (string)$Q[$k]; 74 | }else{ 75 | throw new Exception("Parameter '$k' must be string"); 76 | } 77 | }else{ 78 | $R[$k] = (string)''; 79 | continue; 80 | } 81 | }elseif(stristr($k,'[Array]')){ 82 | $k = str_replace('[Array]','',$k); 83 | if(isset($Q[$k])){ 84 | if(is_array($Q[$k])){ 85 | $Q[$k] = (array)$Q[$k]; 86 | }else{ 87 | throw new Exception("Parameter '$k' must be array"); 88 | } 89 | }else{ 90 | $R[$k] = array(); 91 | continue; 92 | } 93 | } 94 | $filters = explode(',',$v); 95 | for($i=0;$i 0){ 149 | if(is_array($Q[$k])){ 150 | for($t=0;$t $length){ 152 | throw new Exception("The request is too long"); 153 | } 154 | } 155 | }else{ 156 | if(strlen($Q[$k]) > $length){ 157 | throw new Exception("The request is too long"); 158 | } 159 | } 160 | } 161 | if(isset($Q[$k])){ 162 | $R[$k] = $Q[$k]; 163 | }else{ 164 | $R[$k] = ''; 165 | } 166 | } 167 | return $R; 168 | } 169 | 170 | function RandChar($length){ 171 | $chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'; 172 | $return = ''; 173 | for($i=0;$i<$length;$i++){ 174 | $return .= substr($chars,mt_rand(1,strlen($chars)-1),1); 175 | } 176 | return $return; 177 | } 178 | 179 | function H($code){ 180 | switch($code){ 181 | case "normal": 182 | header("Content-type:text/html;charset=UTF-8"); 183 | break; 184 | case "json": 185 | header("Content-type:application/json"); 186 | break; 187 | case "404": 188 | header("HTTP/1.1 404 Not Found"); 189 | break; 190 | case "500": 191 | header('HTTP/1.1 500 Internal Server Error'); 192 | break; 193 | } 194 | } 195 | 196 | function T($message,$location){ 197 | $html = << 199 | 200 | 201 | 202 | 提示 203 | 208 | 209 | 210 |
    211 | 212 | '; 216 | $html .= <<
    213 | HTML; 214 | $html .= $message; 215 | $html .= '

    如果浏览器未跳转请点击此处

    218 |
    219 | 220 | 221 | AHTML; 222 | echo $html; 223 | } 224 | 225 | function isGet(){ 226 | return $_SERVER['REQUEST_METHOD'] == 'GET'; 227 | } 228 | 229 | function isPost(){ 230 | return $_SERVER['REQUEST_METHOD'] == 'POST'; 231 | } 232 | 233 | function fileCacheGet($name){ 234 | if(file_exists(ROOT_PATH.'/Cache/'.$name.'.cache')){ 235 | return file_get_contents(ROOT_PATH.'/Cache/'.$name.'.cache'); 236 | }else{ 237 | return false; 238 | } 239 | } 240 | 241 | function fileCachePut($name, $content){ 242 | file_put_contents(ROOT_PATH.'/Cache/'.$name.'.cache', $content."\n", FILE_APPEND); 243 | } -------------------------------------------------------------------------------- /WebUI/Framework/Common/Function.php: -------------------------------------------------------------------------------- 1 | $v){ 57 | if(stristr($k,'[Int]')){ 58 | $k = str_replace('[Int]','',$k); 59 | if(isset($Q[$k])){ 60 | if(is_numeric($Q[$k])){ 61 | $Q[$k] = (int)$Q[$k]; 62 | }else{ 63 | throw new Exception("Parameter '$k' must be integer"); 64 | } 65 | }else{ 66 | $R[$k] = (int)''; 67 | continue; 68 | } 69 | }elseif(stristr($k,'[String]')){ 70 | $k = str_replace('[String]','',$k); 71 | if(isset($Q[$k])){ 72 | if(is_string($Q[$k])){ 73 | $Q[$k] = (string)$Q[$k]; 74 | }else{ 75 | throw new Exception("Parameter '$k' must be string"); 76 | } 77 | }else{ 78 | $R[$k] = (string)''; 79 | continue; 80 | } 81 | }elseif(stristr($k,'[Array]')){ 82 | $k = str_replace('[Array]','',$k); 83 | if(isset($Q[$k])){ 84 | if(is_array($Q[$k])){ 85 | $Q[$k] = (array)$Q[$k]; 86 | }else{ 87 | throw new Exception("Parameter '$k' must be array"); 88 | } 89 | }else{ 90 | $R[$k] = array(); 91 | continue; 92 | } 93 | } 94 | $filters = explode(',',$v); 95 | for($i=0;$i 0){ 149 | if(is_array($Q[$k])){ 150 | for($t=0;$t $length){ 152 | throw new Exception("The request is too long"); 153 | } 154 | } 155 | }else{ 156 | if(strlen($Q[$k]) > $length){ 157 | throw new Exception("The request is too long"); 158 | } 159 | } 160 | } 161 | if(isset($Q[$k])){ 162 | $R[$k] = $Q[$k]; 163 | }else{ 164 | $R[$k] = ''; 165 | } 166 | } 167 | return $R; 168 | } 169 | 170 | function RandChar($length){ 171 | $chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890'; 172 | $return = ''; 173 | for($i=0;$i<$length;$i++){ 174 | $return .= substr($chars,mt_rand(1,strlen($chars)-1),1); 175 | } 176 | return $return; 177 | } 178 | 179 | function H($code){ 180 | switch($code){ 181 | case "normal": 182 | header("Content-type:text/html;charset=UTF-8"); 183 | break; 184 | case "json": 185 | header("Content-type:application/json"); 186 | break; 187 | case "404": 188 | header("HTTP/1.1 404 Not Found"); 189 | break; 190 | case "500": 191 | header('HTTP/1.1 500 Internal Server Error'); 192 | break; 193 | } 194 | } 195 | 196 | function T($message,$location){ 197 | $html = << 199 | 200 | 201 | 202 | 提示 203 | 208 | 209 | 210 |
    211 | 212 | '; 216 | $html .= <<
    213 | HTML; 214 | $html .= $message; 215 | $html .= '

    如果浏览器未跳转请点击此处

    218 |
    219 | 220 | 221 | AHTML; 222 | echo $html; 223 | } 224 | 225 | function isGet(){ 226 | return $_SERVER['REQUEST_METHOD'] == 'GET'; 227 | } 228 | 229 | function isPost(){ 230 | return $_SERVER['REQUEST_METHOD'] == 'POST'; 231 | } 232 | 233 | function fileCacheGet($name){ 234 | if(file_exists(ROOT_PATH.'/Cache/'.$name.'.cache')){ 235 | return file_get_contents(ROOT_PATH.'/Cache/'.$name.'.cache'); 236 | }else{ 237 | return false; 238 | } 239 | } 240 | 241 | function fileCachePut($name, $content){ 242 | file_put_contents(ROOT_PATH.'/Cache/'.$name.'.cache', $content."\n", FILE_APPEND); 243 | } -------------------------------------------------------------------------------- /WebSocket/Workerman/Events/Libevent.php: -------------------------------------------------------------------------------- 1 | 10 | * @copyright walkor 11 | * @link http://www.workerman.net/ 12 | * @license http://www.opensource.org/licenses/mit-license.php MIT License 13 | */ 14 | namespace Workerman\Events; 15 | 16 | use Workerman\Worker; 17 | 18 | /** 19 | * libevent eventloop 20 | */ 21 | class Libevent implements EventInterface 22 | { 23 | /** 24 | * Event base. 25 | * 26 | * @var resource 27 | */ 28 | protected $_eventBase = null; 29 | 30 | /** 31 | * All listeners for read/write event. 32 | * 33 | * @var array 34 | */ 35 | protected $_allEvents = array(); 36 | 37 | /** 38 | * Event listeners of signal. 39 | * 40 | * @var array 41 | */ 42 | protected $_eventSignal = array(); 43 | 44 | /** 45 | * All timer event listeners. 46 | * [func, args, event, flag, time_interval] 47 | * 48 | * @var array 49 | */ 50 | protected $_eventTimer = array(); 51 | 52 | /** 53 | * construct 54 | */ 55 | public function __construct() 56 | { 57 | $this->_eventBase = event_base_new(); 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | public function add($fd, $flag, $func, $args = array()) 64 | { 65 | switch ($flag) { 66 | case self::EV_SIGNAL: 67 | $fd_key = (int)$fd; 68 | $real_flag = EV_SIGNAL | EV_PERSIST; 69 | $this->_eventSignal[$fd_key] = event_new(); 70 | if (!event_set($this->_eventSignal[$fd_key], $fd, $real_flag, $func, null)) { 71 | return false; 72 | } 73 | if (!event_base_set($this->_eventSignal[$fd_key], $this->_eventBase)) { 74 | return false; 75 | } 76 | if (!event_add($this->_eventSignal[$fd_key])) { 77 | return false; 78 | } 79 | return true; 80 | case self::EV_TIMER: 81 | case self::EV_TIMER_ONCE: 82 | $event = event_new(); 83 | $timer_id = (int)$event; 84 | if (!event_set($event, 0, EV_TIMEOUT, array($this, 'timerCallback'), $timer_id)) { 85 | return false; 86 | } 87 | 88 | if (!event_base_set($event, $this->_eventBase)) { 89 | return false; 90 | } 91 | 92 | $time_interval = $fd * 1000000; 93 | if (!event_add($event, $time_interval)) { 94 | return false; 95 | } 96 | $this->_eventTimer[$timer_id] = array($func, (array)$args, $event, $flag, $time_interval); 97 | return $timer_id; 98 | 99 | default : 100 | $fd_key = (int)$fd; 101 | $real_flag = $flag === self::EV_READ ? EV_READ | EV_PERSIST : EV_WRITE | EV_PERSIST; 102 | 103 | $event = event_new(); 104 | 105 | if (!event_set($event, $fd, $real_flag, $func, null)) { 106 | return false; 107 | } 108 | 109 | if (!event_base_set($event, $this->_eventBase)) { 110 | return false; 111 | } 112 | 113 | if (!event_add($event)) { 114 | return false; 115 | } 116 | 117 | $this->_allEvents[$fd_key][$flag] = $event; 118 | 119 | return true; 120 | } 121 | 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function del($fd, $flag) 128 | { 129 | switch ($flag) { 130 | case self::EV_READ: 131 | case self::EV_WRITE: 132 | $fd_key = (int)$fd; 133 | if (isset($this->_allEvents[$fd_key][$flag])) { 134 | event_del($this->_allEvents[$fd_key][$flag]); 135 | unset($this->_allEvents[$fd_key][$flag]); 136 | } 137 | if (empty($this->_allEvents[$fd_key])) { 138 | unset($this->_allEvents[$fd_key]); 139 | } 140 | break; 141 | case self::EV_SIGNAL: 142 | $fd_key = (int)$fd; 143 | if (isset($this->_eventSignal[$fd_key])) { 144 | event_del($this->_eventSignal[$fd_key]); 145 | unset($this->_eventSignal[$fd_key]); 146 | } 147 | break; 148 | case self::EV_TIMER: 149 | case self::EV_TIMER_ONCE: 150 | // 这里 fd 为timerid 151 | if (isset($this->_eventTimer[$fd])) { 152 | event_del($this->_eventTimer[$fd][2]); 153 | unset($this->_eventTimer[$fd]); 154 | } 155 | break; 156 | } 157 | return true; 158 | } 159 | 160 | /** 161 | * Timer callback. 162 | * 163 | * @param mixed $_null1 164 | * @param int $_null2 165 | * @param mixed $timer_id 166 | */ 167 | protected function timerCallback($_null1, $_null2, $timer_id) 168 | { 169 | if ($this->_eventTimer[$timer_id][3] === self::EV_TIMER) { 170 | event_add($this->_eventTimer[$timer_id][2], $this->_eventTimer[$timer_id][4]); 171 | } 172 | try { 173 | call_user_func_array($this->_eventTimer[$timer_id][0], $this->_eventTimer[$timer_id][1]); 174 | } catch (\Exception $e) { 175 | Worker::log($e); 176 | exit(250); 177 | } catch (\Error $e) { 178 | Worker::log($e); 179 | exit(250); 180 | } 181 | if (isset($this->_eventTimer[$timer_id]) && $this->_eventTimer[$timer_id][3] === self::EV_TIMER_ONCE) { 182 | $this->del($timer_id, self::EV_TIMER_ONCE); 183 | } 184 | } 185 | 186 | /** 187 | * {@inheritdoc} 188 | */ 189 | public function clearAllTimer() 190 | { 191 | foreach ($this->_eventTimer as $task_data) { 192 | event_del($task_data[2]); 193 | } 194 | $this->_eventTimer = array(); 195 | } 196 | 197 | /** 198 | * {@inheritdoc} 199 | */ 200 | public function loop() 201 | { 202 | event_base_loop($this->_eventBase); 203 | } 204 | 205 | /** 206 | * Destroy loop. 207 | * 208 | * @return void 209 | */ 210 | public function destroy() 211 | { 212 | foreach ($this->_eventSignal as $event) { 213 | event_del($event); 214 | } 215 | } 216 | 217 | /** 218 | * Get timer count. 219 | * 220 | * @return integer 221 | */ 222 | public function getTimerCount() 223 | { 224 | return count($this->_eventTimer); 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- /WebSocket/GlobalData/Client.php: -------------------------------------------------------------------------------- 1 | _globalServers = array_values((array)$servers); 50 | } 51 | 52 | /** 53 | * Connect to global server. 54 | * @throws \Exception 55 | */ 56 | protected function getConnection($key) 57 | { 58 | $offset = crc32($key)%count($this->_globalServers); 59 | if($offset < 0) 60 | { 61 | $offset = -$offset; 62 | } 63 | 64 | if(!isset($this->_globalConnections[$offset]) || feof($this->_globalConnections[$offset])) 65 | { 66 | $connection = stream_socket_client("tcp://{$this->_globalServers[$offset]}", $code, $msg, $this->timeout); 67 | if(!$connection) 68 | { 69 | throw new \Exception($msg); 70 | } 71 | stream_set_timeout($connection, $this->timeout); 72 | if(class_exists('\Workerman\Lib\Timer') && php_sapi_name() === 'cli') 73 | { 74 | $timer_id = \Workerman\Lib\Timer::add($this->pingInterval, function($connection)use(&$timer_id) 75 | { 76 | $buffer = pack('N', 8)."ping"; 77 | if(strlen($buffer) !== @fwrite($connection, $buffer)) 78 | { 79 | @fclose($connection); 80 | \Workerman\Lib\Timer::del($timer_id); 81 | } 82 | }, array($connection)); 83 | } 84 | $this->_globalConnections[$offset] = $connection; 85 | } 86 | return $this->_globalConnections[$offset]; 87 | } 88 | 89 | 90 | /** 91 | * Magic methods __set. 92 | * @param string $key 93 | * @param mixed $value 94 | * @throws \Exception 95 | */ 96 | public function __set($key, $value) 97 | { 98 | $connection = $this->getConnection($key); 99 | $this->writeToRemote(array( 100 | 'cmd' => 'set', 101 | 'key' => $key, 102 | 'value' => $value, 103 | ), $connection); 104 | $this->readFromRemote($connection); 105 | } 106 | 107 | /** 108 | * Magic methods __isset. 109 | * @param string $key 110 | */ 111 | public function __isset($key) 112 | { 113 | return null !== $this->__get($key); 114 | } 115 | 116 | /** 117 | * Magic methods __unset. 118 | * @param string $key 119 | * @throws \Exception 120 | */ 121 | public function __unset($key) 122 | { 123 | $connection = $this->getConnection($key); 124 | $this->writeToRemote(array( 125 | 'cmd' => 'delete', 126 | 'key' => $key 127 | ), $connection); 128 | $this->readFromRemote($connection); 129 | } 130 | 131 | /** 132 | * Magic methods __get. 133 | * @param string $key 134 | * @throws \Exception 135 | */ 136 | public function __get($key) 137 | { 138 | $connection = $this->getConnection($key); 139 | $this->writeToRemote(array( 140 | 'cmd' => 'get', 141 | 'key' => $key, 142 | ), $connection); 143 | return $this->readFromRemote($connection); 144 | } 145 | 146 | /** 147 | * Cas. 148 | * @param string $key 149 | * @param mixed $value 150 | * @throws \Exception 151 | */ 152 | public function cas($key, $old_value, $new_value) 153 | { 154 | $connection = $this->getConnection($key); 155 | $this->writeToRemote(array( 156 | 'cmd' => 'cas', 157 | 'md5' => md5(serialize($old_value)), 158 | 'key' => $key, 159 | 'value' => $new_value, 160 | ),$connection); 161 | return $this->readFromRemote($connection); 162 | } 163 | 164 | /** 165 | * Add. 166 | * @param string $key 167 | * @throws \Exception 168 | */ 169 | public function add($key, $value) 170 | { 171 | $connection = $this->getConnection($key); 172 | $this->writeToRemote(array( 173 | 'cmd' => 'add', 174 | 'key' => $key, 175 | 'value' => $value, 176 | ), $connection); 177 | return $this->readFromRemote($connection); 178 | } 179 | 180 | /** 181 | * Increment. 182 | * @param string $key 183 | * @throws \Exception 184 | */ 185 | public function increment($key, $step = 1) 186 | { 187 | $connection = $this->getConnection($key); 188 | $this->writeToRemote(array( 189 | 'cmd' => 'increment', 190 | 'key' => $key, 191 | 'step' => $step, 192 | ), $connection); 193 | return $this->readFromRemote($connection); 194 | } 195 | 196 | /** 197 | * Write data to global server. 198 | * @param string $buffer 199 | */ 200 | protected function writeToRemote($data, $connection) 201 | { 202 | $buffer = serialize($data); 203 | $buffer = pack('N',4 + strlen($buffer)) . $buffer; 204 | $len = fwrite($connection, $buffer); 205 | if($len !== strlen($buffer)) 206 | { 207 | throw new \Exception('writeToRemote fail'); 208 | } 209 | } 210 | 211 | /** 212 | * Read data from global server. 213 | * @throws Exception 214 | */ 215 | protected function readFromRemote($connection) 216 | { 217 | $all_buffer = ''; 218 | $total_len = 4; 219 | $head_read = false; 220 | while(1) 221 | { 222 | $buffer = fread($connection, 8192); 223 | if($buffer === '' || $buffer === false) 224 | { 225 | throw new \Exception('readFromRemote fail'); 226 | } 227 | $all_buffer .= $buffer; 228 | $recv_len = strlen($all_buffer); 229 | if($recv_len >= $total_len) 230 | { 231 | if($head_read) 232 | { 233 | break; 234 | } 235 | $unpack_data = unpack('Ntotal_length', $all_buffer); 236 | $total_len = $unpack_data['total_length']; 237 | if($recv_len >= $total_len) 238 | { 239 | break; 240 | } 241 | $head_read = true; 242 | } 243 | } 244 | return unserialize(substr($all_buffer, 4)); 245 | } 246 | } 247 | --------------------------------------------------------------------------------