index.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <?php
  2. set_time_limit(0);
  3. header('X-Accel-Buffering: no');
  4. $FF_TOKEN = $_GET['ff-token'] ?? '';
  5. $VERIFIED = $FF_TOKEN === getenv('FF_TOKEN');
  6. require_once __DIR__ . '/vendor/autoload.php';
  7. use SensioLabs\AnsiConverter\AnsiToHtmlConverter;
  8. $converter = new AnsiToHtmlConverter();
  9. ?>
  10. <!DOCTYPE html>
  11. <html lang="zh-cmn-Hans">
  12. <head>
  13. <meta charset="UTF-8">
  14. <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, shrink-to-fit=no"/>
  15. <meta name="renderer" content="webkit"/>
  16. <meta name="force-rendering" content="webkit"/>
  17. <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
  18. <title>Freenom 续期控制台 | 你只需部署,剩下的事情交给我们</title>
  19. <link rel="stylesheet" href="css/mdui.min.css"/>
  20. <style>
  21. .loading-icon {
  22. width: 17px;
  23. height: 17px;
  24. margin-right: 10px;
  25. margin-top: -6px;
  26. font-size: 18px;
  27. }
  28. .success-icon {
  29. margin-top: -6px;
  30. margin-right: 10px;
  31. }
  32. #copy-btn {
  33. border-radius: 16px;
  34. }
  35. #output-box {
  36. word-wrap: break-word;
  37. font-size: 14px;
  38. }
  39. .a-tag {
  40. color: #f44336;
  41. text-decoration: none;
  42. font-weight: bold;
  43. }
  44. @-webkit-keyframes shake {
  45. 0% {
  46. opacity: 1;
  47. }
  48. 50% {
  49. opacity: 0;
  50. }
  51. 100% {
  52. opacity: 1;
  53. }
  54. }
  55. @keyframes shake {
  56. 0% {
  57. opacity: 1;
  58. }
  59. 50% {
  60. opacity: 0;
  61. }
  62. 100% {
  63. opacity: 1;
  64. }
  65. }
  66. .shake {
  67. -webkit-animation: shake 2s infinite;
  68. animation: shake 2s infinite;
  69. }
  70. </style>
  71. </head>
  72. <body>
  73. <div class="mdui-container">
  74. <div class="mdui-ripple mdui-ripple-yellow"
  75. mdui-tooltip="{content: '前往项目 GitHub 仓库', position: 'auto', delay: 500}">
  76. <a href="https://github.com/luolongfei/freenom" target="_blank">
  77. <img class="mdui-img-rounded mdui-center mdui-valign mdui-img-fluid" src="images/logo_bear.png" alt="logo"/>
  78. </a>
  79. </div>
  80. <ul class="mdui-list mdui-m-t-4">
  81. <li class="mdui-list-item mdui-ripple mdui-shadow-1">
  82. <div class="mdui-list-item-avatar">
  83. <img src="https://q2.qlogo.cn/headimg_dl?dst_uin=593198779&spec=100" alt="作者头像"/>
  84. </div>
  85. <div class="mdui-list-item-content">
  86. Freenom 续期控制台
  87. </div>
  88. </li>
  89. </ul>
  90. <?php if ($VERIFIED) { ?>
  91. <div class="mdui-panel" mdui-panel>
  92. <div class="mdui-panel-item mdui-panel-item-open">
  93. <div class="mdui-panel-item-header">
  94. 注意事项
  95. </div>
  96. <div class="mdui-panel-item-body">
  97. <p>1、当你看到我的时候,说明你已成功手动触发脚本执行</p>
  98. <p>2、如果不想每次手动触发执行都输入 FF_TOKEN 的值,你也可以点击右边的按钮,以复制执行地址,下次访问执行地址即可触发脚本执行 <strong><span
  99. class="mdui-text-color-red" id="app-url"></span></strong>
  100. <button class="mdui-btn mdui-btn-raised mdui-btn-dense mdui-ripple mdui-color-pink-accent"
  101. id="copy-btn" data-clipboard-target="#app-url">
  102. 复制地址
  103. </button>
  104. </p>
  105. <p>3、不要频繁刷新本页面,因为每次刷新都会手动触发脚本执行</p>
  106. <p>4、手动触发脚本执行只是为了方便你快速测试部署是否成功,而容器内部的定时任务是会自动执行脚本的,所以,部署完成后,剩下的一切就交给程序吧</p>
  107. </div>
  108. </div>
  109. <?php } else { ?>
  110. <div class="mdui-panel" mdui-panel>
  111. <div class="mdui-panel-item mdui-panel-item-open">
  112. <div class="mdui-panel-item-header">
  113. 请先验证身份
  114. </div>
  115. <div class="mdui-panel-item-body">
  116. <div class="mdui-textfield mdui-textfield-floating-label">
  117. <i class="mdui-icon material-icons">lock</i>
  118. <label class="mdui-textfield-label" for="pwd">请输入你在 Koyeb 配置的 FF_TOKEN
  119. 的值,即令牌</label>
  120. <input class="mdui-textfield-input" type="text" id="pwd"/>
  121. <div class="mdui-textfield-helper">
  122. 点击上行文字即可输入内容,输入完成后,请点击下方送信按钮以验证身份
  123. </div>
  124. </div>
  125. <button class="mdui-btn mdui-btn-block mdui-color-red mdui-ripple" id="submit-btn">
  126. 送信
  127. </button>
  128. </div>
  129. </div>
  130. </div>
  131. <script>
  132. let submitBtn = document.getElementById('submit-btn');
  133. submitBtn.onclick = function () {
  134. let ffToken = document.getElementById('pwd').value;
  135. ffToken = ffToken.replace(/\s/g, '');
  136. if (ffToken.length < 1) {
  137. mdui.snackbar({message: '请输入令牌'});
  138. return;
  139. }
  140. submitBtn.disabled = true;
  141. submitBtn.innerText = '送信中...';
  142. window.location.href = '?ff-token=' + ffToken;
  143. }
  144. </script>
  145. <?php } ?>
  146. <div class="mdui-panel-item mdui-panel-item-open" id="shell-box">
  147. <div class="mdui-panel-item-header" id="shell-title">
  148. <div id="running-box">
  149. <i class="mdui-icon material-icons loading-icon mdui-text-color-red shake">fiber_manual_record</i>
  150. 正在执行
  151. </div>
  152. <div id="success-box" style="display: none;">
  153. <i class="mdui-icon material-icons mdui-text-color-green-500 success-icon">check_circle</i>完成
  154. </div>
  155. </div>
  156. <div class="mdui-panel-item-body mdui-color-black" id="output-box">
  157. <?php
  158. if ($VERIFIED) {
  159. echo '<p>Freenom 自动续期工具</p>';
  160. echo '<p>开始执行</p><br>';
  161. $cmd = 'php /app/run';
  162. while (@ob_end_flush()) ;
  163. $proc = popen($cmd, 'r');
  164. while (!feof($proc)) {
  165. echo '<p>' . $converter->convert(fread($proc, 4096)) . '</p>';
  166. @flush();
  167. }
  168. echo '<p>执行完了</p>';
  169. echo '<p>Made with <i class="mdui-icon material-icons mdui-text-color-pink-a200 shake">favorite</i> by <a class="mdui-text-color-white-text" href="https:\/\/github.com/luolongfei" target="_blank">luolongfei</a></p>';
  170. echo '<script type="text/javascript">',
  171. "document.getElementById('running-box').style.display = 'none';
  172. document.getElementById('success-box').style.display = 'block';",
  173. '</script>';
  174. } else {
  175. echo '<p>你没有权限触发执行</p>';
  176. echo '<script type="text/javascript">',
  177. 'document.getElementById("shell-title").innerHTML = "啊,出错啦";',
  178. '</script>';
  179. }
  180. ?>
  181. </div>
  182. </div>
  183. </div>
  184. <div class="mdui-dialog" id="donation-dialog">
  185. <div class="mdui-dialog-content">
  186. <ul class="mdui-list mdui-list-dense">
  187. <li class="mdui-list-item mdui-ripple">
  188. <div class="mdui-list-item-avatar">
  189. <img src="https://q2.qlogo.cn/headimg_dl?dst_uin=593198779&spec=100" alt="作者头像"/>
  190. </div>
  191. <div class="mdui-list-item-content">
  192. <div class="mdui-list-item-title">Freenom 续期工具</div>
  193. <div class="mdui-list-item-text mdui-list-item-two-line">
  194. <span class="mdui-text-color-theme-text">如果你觉得本项目对你有帮助,请考虑赞助本项目。</span>
  195. </div>
  196. </div>
  197. </li>
  198. </ul>
  199. <div class="mdui-card">
  200. <div class="mdui-card-media">
  201. <img class="mdui-img-rounded" src="https://images.llfapp.com/pay.png" alt="赞助二维码"/>
  202. </div>
  203. <div class="mdui-card-content">
  204. <div id="smart-button-container">
  205. <div style="text-align: center;">
  206. <div id="paypal-button-container"></div>
  207. </div>
  208. </div>
  209. <script type='text/javascript' src='https://storage.ko-fi.com/cdn/widget/Widget_2.js'></script>
  210. <script type='text/javascript'>kofiwidget2.init('Support Me on Ko-fi', '#F05D59', 'X7X8CA7S1');
  211. kofiwidget2.draw();</script>
  212. </div>
  213. </div>
  214. </div>
  215. <div class="mdui-dialog-actions">
  216. <button class="mdui-btn mdui-ripple" mdui-dialog-close>不了</button>
  217. <button class="mdui-btn mdui-ripple" mdui-dialog-close
  218. onclick="mdui.snackbar({message: '赞助在哪里,我没收到呢'});">已赞助
  219. </button>
  220. </div>
  221. </div>
  222. </div>
  223. <div class="mdui-container">
  224. <p>
  225. <a href="https://github.com/luolongfei/freenom" target="_blank"
  226. class="mdui-btn mdui-btn-raised mdui-ripple"><i class="mdui-icon material-icons">link</i>
  227. 访问仓库</a>
  228. <a href="https://github.com/luolongfei/freenom/wiki/Donation-List"
  229. class="mdui-btn mdui-btn-raised mdui-ripple mdui-color-theme-accent"
  230. target="_blank"><i class="mdui-icon material-icons">format_list_bulleted</i>
  231. 赞助名单
  232. </a>
  233. <button class="mdui-btn mdui-btn-raised mdui-ripple mdui-color-theme-accent mdui-text-color-red"
  234. mdui-dialog="{target: '#donation-dialog'}"><i class="mdui-icon material-icons">exposure_plus_1</i>
  235. <strong>赞助作者</strong>
  236. </button>
  237. </p>
  238. </div>
  239. <script src="js/mdui.min.js"></script>
  240. <script src="js/clipboard.min.js"></script>
  241. <script src="https://www.paypal.com/sdk/js?client-id=sb&enable-funding=venmo&currency=USD"
  242. data-sdk-integration-source="button-factory"></script>
  243. <?php
  244. if ($FF_TOKEN !== '' && !$VERIFIED) { // 验证失败
  245. echo '<script type="text/javascript">',
  246. "mdui.snackbar({message: '你输入的令牌有误,请重试'});",
  247. '</script>';
  248. }
  249. if ($VERIFIED) { // 验证成功
  250. ?>
  251. <script type="text/javascript">
  252. document.getElementById('app-url').innerHTML = `https://${document.domain}/?ff-token=<?php echo $FF_TOKEN; ?>`;
  253. let clipboard = new ClipboardJS('#copy-btn');
  254. clipboard.on('success', function (e) {
  255. console.info('Action:', e.action);
  256. console.info('Text:', e.text);
  257. console.info('Trigger:', e.trigger);
  258. mdui.snackbar({message: '复制成功'});
  259. e.clearSelection();
  260. });
  261. clipboard.on('error', function (e) {
  262. console.error('Action:', e.action);
  263. console.error('Trigger:', e.trigger);
  264. alert('复制失败,请手动复制');
  265. });
  266. setTimeout(function () {
  267. document.getElementById('shell-box').scrollIntoView({behavior: 'smooth', block: 'start', inline: 'start'});
  268. }, 1500);
  269. </script>
  270. <?php
  271. }
  272. ?>
  273. <script>
  274. function initPayPalButton() {
  275. paypal.Buttons({
  276. style: {
  277. shape: 'rect',
  278. color: 'gold',
  279. layout: 'horizontal',
  280. label: 'paypal',
  281. },
  282. createOrder: function (data, actions) {
  283. return actions.order.create({
  284. purchase_units: [{
  285. "description": "赞助 freenom 自动续期脚本的作者,以促进项目持续发展。",
  286. "amount": {"currency_code": "USD", "value": 5}
  287. }]
  288. });
  289. },
  290. onApprove: function (data, actions) {
  291. return actions.order.capture().then(function (orderData) {
  292. const element = document.getElementById('paypal-button-container');
  293. element.innerHTML = '';
  294. element.innerHTML = '<h3>Thank you for your payment!</h3>';
  295. });
  296. },
  297. onError: function (err) {
  298. console.log(err);
  299. }
  300. }).render('#paypal-button-container');
  301. }
  302. initPayPalButton();
  303. </script>
  304. </body>
  305. </html>