combine.php 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. <?php
  2. namespace app\index;
  3. class combine extends BaseUser
  4. {
  5. function initialize()
  6. {
  7. parent::initialize();
  8. }
  9. function index()
  10. {ini_set('display_errors', 1);
  11. ini_set('display_startup_errors', 1);
  12. error_reporting(E_ALL);
  13. // 获取页码参数
  14. $page = SafeRequest("page", "get");
  15. if (empty($page)) {
  16. $page = 1;
  17. }
  18. // 使用分页查询
  19. $result = db("combine")->where("userid", $this->userid)->order("id desc")->paginate(["page" => $page, 'list_rows' => 5]);
  20. $count = $result->total();
  21. ?>
  22. <!DOCTYPE html>
  23. <html lang="zh-cn">
  24. <head>
  25. <meta charset="utf-8">
  26. <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0" />
  27. <meta name="keywords" content="<?php echo IN_KEYWORDS; ?>" />
  28. <meta name="description" content="<?php echo IN_DESCRIPTION; ?>" />
  29. <title>外部链接合并 - <?php echo IN_NAME; ?> - 免费应用内测托管平台|iOS应用Beta测试分发|Android应用内测分发</title>
  30. <?php $this->static_(); ?>
  31. </head>
  32. <body>
  33. <?php $this->header(); ?>
  34. <style>
  35. .details-top {
  36. padding: 39px 30px;
  37. }
  38. .details-top .p1{
  39. color: rgba(21, 21, 21, 1);
  40. font-family: Source Han Sans SC;
  41. font-weight: 500;
  42. font-size: 16px;
  43. line-height: 20px;
  44. }
  45. #hotApp_box {
  46. display: flex;
  47. justify-content: space-between;
  48. align-items: start;
  49. margin: 0;
  50. }
  51. .download-details {
  52. padding: 10px 30px 72px;
  53. }
  54. .flex-left {
  55. width: calc(100% - 303px);
  56. }
  57. .flex-right {
  58. width: 303px;
  59. }
  60. #qrcode_img {
  61. width: 235px;
  62. height: 235px;
  63. object-fit: cover;
  64. border: 1px solid rgba(232, 234, 236, 1);
  65. }
  66. #qrcode_img::placeholder {
  67. color: rgba(143, 149, 159, 1);
  68. font-size: 16px;
  69. line-height: 22px;
  70. }
  71. .qrcode_url_tips {
  72. font-size: 13px;
  73. line-height: 17px;
  74. margin: 10px 0;
  75. }
  76. .qrcode_url_input_box {
  77. margin-bottom: 30px;
  78. }
  79. .qrcode_url_input_box input {
  80. border: 1px solid rgba(232, 234, 236, 1);
  81. /* width: 711px; */
  82. height: 52px;
  83. line-height: 52px;
  84. border-width: 1px;
  85. padding: 0 20px;
  86. box-sizing: border-box;
  87. font-size: 14px;
  88. color: rgba(21, 21, 21, 1);
  89. }
  90. .qrcode_url_input_box input::placeholder {
  91. font-size: 14px;
  92. color: rgba(143, 149, 159, 1);
  93. }
  94. .generate_btn_box {
  95. margin-top: 50px;
  96. }
  97. .generate_qrcode_btn {
  98. background: rgba(33, 104, 251, 1);
  99. width: 120px;
  100. height: 34px;
  101. border-radius: 4px;
  102. padding-top: 7px;
  103. padding-right: 20px;
  104. padding-bottom: 7px;
  105. padding-left: 20px;
  106. color: rgba(255, 255, 255, 1);
  107. font-family: Source Han Sans SC;
  108. font-weight: 500;
  109. font-style: Medium;
  110. font-size: 16px;
  111. line-height: 20px;
  112. }
  113. #hotApp-qrcode-downBtn:active:focus,
  114. #hotApp-qrcode-downBtn:hover,
  115. .generate_qrcode_btn:active:focus,
  116. .generate_qrcode_btn:hover {
  117. background: rgba(33, 104, 251, 1);
  118. color: rgba(255, 255, 255, 1);
  119. border: unset;
  120. outline: none;
  121. }
  122. .qrcode_show_box {
  123. text-align: right;
  124. margin-bottom: 12px;
  125. margin-top: 10px;
  126. }
  127. .qrcode_url_box { margin-bottom: 20px; }
  128. .qrcode_url_tips { margin-bottom: 10px; }
  129. .os_name { font-weight: bold; color: #333; }
  130. .qrcode_url_input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
  131. /* .qrcode_function {
  132. text-align: center;
  133. }
  134. .down_btnbox {
  135. text-align: center;
  136. } */
  137. .qrcode_function {
  138. margin: 0 auto;
  139. }
  140. .down_btnbox {
  141. padding-left: 126px;
  142. }
  143. #hotApp-qrcode-downBtn {
  144. border: 1px solid rgba(33, 104, 251, 1);
  145. width: 120px;
  146. height: 34px;
  147. border-radius: 4px;
  148. padding: 0 20px;
  149. background: rgba(255, 255, 255, 1);
  150. color: rgba(33, 104, 251, 1);
  151. font-size: 16px;
  152. line-height: 34px;
  153. float: unset;
  154. margin: 0 auto;
  155. }
  156. .tab-content {
  157. display: none;
  158. }
  159. .tab-content.active {
  160. display: block;
  161. }
  162. /* 标签页样式 */
  163. .tabs {
  164. margin: 12px 0 0 0;
  165. padding: 10px 30px;
  166. }
  167. .tabs .nav-tabs {
  168. border-bottom: 0 solid #e5e5e5;
  169. /* 添加横向滚动支持 */
  170. overflow-x: auto;
  171. overflow-y: hidden;
  172. white-space: nowrap;
  173. display: flex;
  174. flex-wrap: nowrap;
  175. -webkit-overflow-scrolling: touch;
  176. /* iOS滚动优化 */
  177. scrollbar-width: none;
  178. /* Firefox隐藏滚动条 */
  179. -ms-overflow-style: none;
  180. /* IE隐藏滚动条 */
  181. }
  182. /* 隐藏Webkit浏览器的滚动条 */
  183. .tabs .nav-tabs::-webkit-scrollbar {
  184. display: none;
  185. }
  186. .tabs .nav-tabs>li>a {
  187. border: none;
  188. padding: 12px 2px;
  189. margin-right: 24px;
  190. border-radius: 0;
  191. color: rgba(143, 149, 159, 1);
  192. font-family: Source Han Sans SC;
  193. font-weight: 500;
  194. font-size: 15px;
  195. line-height: 20px;
  196. }
  197. .tabs .nav-tabs>li>a:hover {
  198. border: none;
  199. background-color: #ffffff;
  200. color: rgba(75, 132, 255, 1);
  201. }
  202. .tabs .nav-tabs>li.active>a,
  203. .tabs .nav-tabs>li.active>a:hover,
  204. .tabs .nav-tabs>li.active>a:focus {
  205. border: none;
  206. border-bottom: 2px solid rgba(75, 132, 255, 1);
  207. color: rgba(75, 132, 255, 1);
  208. font-weight: 700;
  209. }
  210. /* 记录 */
  211. .table-responsive {
  212. overflow-x: auto;
  213. }
  214. /* 通用表格设置 */
  215. .table {
  216. border: 1px solid #e5e5e5;
  217. margin-bottom: 0;
  218. }
  219. .table>tbody>tr>th {
  220. background: rgba(245, 246, 247, 1);
  221. height: 36px;
  222. color: rgba(143, 149, 159, 1);
  223. font-family: Source Han Sans SC;
  224. font-weight: 500;
  225. font-size: 14px;
  226. line-height: 18px;
  227. text-align: center;
  228. vertical-align: middle !important;
  229. }
  230. .table>tbody>tr>td {
  231. color: rgba(0, 0, 0, 1);
  232. box-sizing: border-box;
  233. padding: 0 15px !important;
  234. height: 50px;
  235. text-align: center;
  236. font-family: Source Han Sans SC;
  237. font-weight: 400;
  238. font-size: 14px;
  239. line-height: 13px;
  240. border-top: unset;
  241. border-bottom: 1px solid rgba(232, 234, 236, 1);
  242. vertical-align: middle !important;
  243. }
  244. .table>tfoot>tr>td {
  245. padding: 0 15px !important;
  246. vertical-align: middle !important;
  247. text-align: center;
  248. }
  249. .table>tbody>tr:hover>td {
  250. background-color: #ebf7ff;
  251. }
  252. .table>tbody>tr>td.angle-parent {
  253. color: rgba(75, 132, 255, 1);
  254. }
  255. .table>tbody>tr>td>a {
  256. color: rgba(33, 104, 251, 1);
  257. font-weight: 500;
  258. font-size: 14px;
  259. }
  260. .table>tbody>tr>td>a+a {
  261. margin-left: 14px;
  262. }
  263. /* 翻页 */
  264. .pagination-box {
  265. /* text-align: right; */
  266. }
  267. .pagination {
  268. margin: 10px auto 10px;
  269. }
  270. .pagination>li>a,
  271. .pagination>li>span {
  272. color: rgba(33, 104, 251, 1);
  273. }
  274. .pagination>.active>a,
  275. .pagination>.active>a:focus,
  276. .pagination>.active>a:hover,
  277. .pagination>.active>span,
  278. .pagination>.active>span:focus,
  279. .pagination>.active>span:hover {
  280. background-color: rgba(33, 104, 251, 1);
  281. border-color: rgba(33, 104, 251, 1);
  282. }
  283. .pagination>li:first-child {
  284. display: inline-block;
  285. padding: 7px 0 7px 12px;
  286. background-color: transparent !important;
  287. border: unset;
  288. color: rgba(33, 104, 251, 1);
  289. pointer-events: none;
  290. }
  291. </style>
  292. <div class="release-app-wrap">
  293. <div class="container">
  294. <div class="release-app2">
  295. <div class="crumbs">
  296. <a href="/index/apps">我的应用</a>
  297. <span>/</span>
  298. <a href="/index/apps">应用列表</a>
  299. <span>/</span>
  300. 外部链接合并
  301. </div>
  302. <div class="row clearfix">
  303. <div class="col-sm-2">
  304. <aside class="aside-left">
  305. <ul>
  306. <li title="上传应用" class="<?php echo ($this->module == 'publish' || $this->module == 'publish_update') ? 'active' : '' ?>">
  307. <a href="/index/publish/<?php echo $this->action ?>"> <span class="iconfont icon-upload1"></span>上传应用</a>
  308. </li>
  309. <li title="应用列表" class="<?php echo $this->module == 'apps' ? 'active' : '' ?>">
  310. <a href="/index/apps/<?php echo $this->action ?>"><span class="iconfont icon-41"></span>应用列表</a>
  311. </li>
  312. <li title="绑定域名" class="<?php echo $this->module == 'domain' ? 'active' : '' ?>">
  313. <a href="/index/domain/<?php echo $this->action ?>"><span class="iconfont icon-liulanqi"></span>绑定域名</a>
  314. </li>
  315. <li title="外部链接合并" class="<?php echo $this->module == 'combine' ? 'active' : '' ?>">
  316. <a href="/index/combine/<?php echo $this->action ?>"><span class="iconfont icon-erweima"></span>外部链接合并</a>
  317. </li>
  318. <!-- <li title="合并记录" class="<?php echo $this->module == 'jilu' ? 'active' : '' ?>">
  319. <a href="/index/jilu/<?php echo $this->action ?>"><span class="iconfont icon-jilu"></span>合并记录</a>
  320. </li> -->
  321. </ul>
  322. </aside>
  323. </div>
  324. <div class="col-sm-10">
  325. <div class="aside-right">
  326. <div class="app-details app-details2">
  327. <div class="details-top clearfix">
  328. <b class="p1">外部链接合并</b>
  329. <div class="p1">
  330. 设置提示:本功能可将外部的ios链接或安卓链接,来和本站的链接进行合并到一起使用,<br>
  331. 以便更好的管理不同平台链接的使用,可生成二维码和短链接。
  332. </div>
  333. </div>
  334. <div style="height: 10px; background: rgb(242, 242, 245)"></div>
  335. <div class="tabs">
  336. <ul class="nav nav-tabs" role="tablist">
  337. <li role="presentation" class="active">
  338. <a href="?tab=combine" aria-controls="tab-combine" role="tab">链接合并</a>
  339. </li>
  340. <li role="presentation" class="">
  341. <a href="?tab=record" aria-controls="tab-record" role="tab">合并记录</a>
  342. </li>
  343. </ul>
  344. </div>
  345. <div class="download-details">
  346. <!-- 链接合并表单 -->
  347. <div id="tab-combine" class="generate_qrcode_box tab-content <?php echo (SafeRequest("tab", "get") != 'record') ? 'active' : ''; ?>">
  348. <div class="row" id="hotApp_box">
  349. <div class="flex-left">
  350. <div class="qrcode_url_box">
  351. <div class="qrcode_url_tips">
  352. <b class="os_name">iOS系统</b>
  353. </div>
  354. <div class="qrcode_url_input_box">
  355. <input type="text" placeholder="请输入苹果应用下载地址" id="ios_url" class="form-control qrcode_url_input">
  356. </div>
  357. </div>
  358. <div class="qrcode_url_box">
  359. <div class="qrcode_url_tips">
  360. <b class="os_name">安卓系统</b>
  361. </div>
  362. <div class="qrcode_url_input_box">
  363. <input type="text" id="android_url" class="form-control qrcode_url_input" placeholder="请输入安卓系统应用下载地址">
  364. </div>
  365. </div>
  366. <div class="qrcode_url_box" id="shortUrlha" style="display:none">
  367. <div class="qrcode_url_tips">
  368. <b class="os_name">短连接地址</b>
  369. </div>
  370. <div class="qrcode_url_input_box">
  371. <input type="text" id="shortUrlh" class="form-control qrcode_url_input" placeholder="">
  372. </div>
  373. </div>
  374. <div class="alert alert-success" style="display: none;">
  375. <span class="txt"></span>
  376. </div>
  377. <div class="alert alert-danger" style="display: none;">
  378. <span class="txt"></span>
  379. </div>
  380. <div class="generate_btn_box">
  381. <a class="btn generate_qrcode_btn">
  382. 生成二维码
  383. </a>
  384. </div>
  385. </div>
  386. <div class="flex-right">
  387. <div class="qrcode_show_box">
  388. <img class="qrcode_img" src="/img/qrcode_no.png" id="qrcode_img">
  389. </div>
  390. <div class="qrcode_function clearfix row">
  391. <input type="hidden" name="" class="qrcode_key" value="">
  392. <input type="hidden" name="" class="shortUrl" value="">
  393. <input type="hidden" name="download_url" id="download_url" value="<?php echo $_SERVER['HTTP_HOST']; ?>/index/combine/download?qrcode_path=">
  394. <input type="hidden" name="more_down_url" id="more_down_url" value="<?php echo $_SERVER['HTTP_HOST']; ?>/index/combine/downloadQrCode?qrcode_path=">
  395. <input type="hidden" name="" class="qrcode_path" value="">
  396. <div class="down_btnbox">
  397. <div class="btn-group down_qrcode_box">
  398. <a href="javascript:qrcodeDown();" style="width:100%" class="btn btn-default down_qrcode_btn" id="hotApp-qrcode-downBtn" data-downurl="" >下载二维码</a>
  399. </div>
  400. </div>
  401. </div>
  402. </div>
  403. </div>
  404. </div>
  405. <!-- 合并记录表格 -->
  406. <div id="tab-record" class="tab-content <?php echo (SafeRequest("tab", "get") == 'record') ? 'active' : ''; ?>">
  407. <div class="table-responsive">
  408. <table class="table table-striped">
  409. <!-- <thead>
  410. <tr>
  411. <th>ID</th>
  412. <th>iOS链接</th>
  413. <th>Android链接</th>
  414. <th>短链接</th>
  415. <th>创建时间</th>
  416. <th>操作</th>
  417. </tr>
  418. </thead> -->
  419. <tbody>
  420. <tr>
  421. <th>ID</th>
  422. <th>iOS链接</th>
  423. <th>Android链接</th>
  424. <th>短链接</th>
  425. <th>创建时间</th>
  426. <th>操作</th>
  427. </tr>
  428. <?php if(!empty($result) && $count > 0): ?>
  429. <?php foreach($result as $item): ?>
  430. <tr>
  431. <td><?php echo $item['id']; ?></td>
  432. <td><?php echo htmlspecialchars($item['ios']); ?></td>
  433. <td><?php echo htmlspecialchars($item['android']); ?></td>
  434. <td><?php echo htmlspecialchars($item['link']); ?></td>
  435. <td><?php echo date('Y-m-d H:i:s', $item['ctime']); ?></td>
  436. <td>
  437. <a href="<?php echo $item['link']; ?>" target="_blank" class="btn btn-xs btn-primary">查看</a>
  438. </td>
  439. </tr>
  440. <?php endforeach; ?>
  441. <?php else: ?>
  442. <tr>
  443. <td colspan="6" class="text-center">暂无记录</td>
  444. </tr>
  445. <?php endif; ?>
  446. </tbody>
  447. </table>
  448. <?php
  449. if ($count == 0) {
  450. ?>
  451. <div class="text-center no-content">
  452. <img src="/static/index/image/invoice-1.png" alt="">
  453. <p class="color-333 mt10">
  454. 暂无任何数据
  455. </p>
  456. </div>
  457. <?php
  458. }
  459. ?>
  460. </div>
  461. <div class="pagination-box">
  462. <?php echo getRender($result, $page); ?>
  463. </div>
  464. </div>
  465. </div>
  466. </div>
  467. </div>
  468. </div>
  469. </div>
  470. </div>
  471. <div class="warn-prompt-wrap clearfix">
  472. <dl class="clearfix fr warn-prompt-1">
  473. <dt class="fl">提示:</dt>
  474. <dd>请您确认您合并的二维码,符合
  475. 《<a href="/index/about/specification" target="_blank" class="color-hover">审核规范</a>》,如违反规范,APP将做删除处理,屡次合并二维码将被封禁账号。
  476. <br>根据最新审核规范,不接受如下APP在平台进行合并二维码:色情类、直播类、金融类、区块链虚拟币等。如已合并,将做删除处理。
  477. </dd>
  478. </dl>
  479. </div>
  480. </div>
  481. </div>
  482. </div>
  483. <script>
  484. // 页面加载时清理不必要的cookie
  485. $(document).ready(function() {
  486. console.log('页面加载完成!');
  487. cleanUnnecessaryCookies();
  488. // 检查jQuery是否加载
  489. if (typeof $ !== 'undefined') {
  490. console.log('jQuery已加载');
  491. } else {
  492. console.log('jQuery未加载!');
  493. }
  494. // 检查按钮是否存在
  495. if ($('#hotApp_box .generate_qrcode_btn').length > 0) {
  496. console.log('生成二维码按钮已找到');
  497. } else {
  498. console.log('生成二维码按钮未找到!');
  499. }
  500. // Tab切换功能
  501. $('.nav-tabs a').on('click', function(e) {
  502. e.preventDefault();
  503. var target = $(this).attr('href').replace('?tab=', '');
  504. // 获取当前URL参数
  505. var currentUrl = new URL(window.location);
  506. var currentPage = currentUrl.searchParams.get('page');
  507. // 构建新的URL
  508. var newUrl = '/index/combine/index';
  509. if (target === 'record') {
  510. newUrl += '?tab=record';
  511. if (currentPage) {
  512. newUrl += '&page=' + currentPage;
  513. }
  514. } else {
  515. newUrl += '?tab=combine';
  516. }
  517. // 跳转到新URL
  518. window.location.href = newUrl;
  519. });
  520. // 根据URL参数设置初始tab状态
  521. var urlParams = new URLSearchParams(window.location.search);
  522. var tabParam = urlParams.get('tab');
  523. if (tabParam === 'record') {
  524. $('.nav-tabs li').removeClass('active');
  525. $('.nav-tabs a[href="?tab=record"]').parent().addClass('active');
  526. $('.tab-content').removeClass('active');
  527. $('#tab-record').addClass('active');
  528. } else {
  529. $('.nav-tabs li').removeClass('active');
  530. $('.nav-tabs a[href="?tab=combine"]').parent().addClass('active');
  531. $('.tab-content').removeClass('active');
  532. $('#tab-combine').addClass('active');
  533. }
  534. });
  535. function qrcodeDown() {
  536. var qrcode_path = $('.qrcode_path').val();
  537. if (qrcode_path == '') {
  538. alert("请先生成二维码!");
  539. return false;
  540. } else {
  541. window.open(qrcode_path);
  542. }
  543. }
  544. // 绑定生成二维码按钮事件
  545. $('#hotApp_box .generate_qrcode_btn').on('click', function() {
  546. console.log('按钮被点击了!');
  547. var $btn = $(this);
  548. var ios_url = $('#ios_url').val();
  549. var android_url = $('#android_url').val();
  550. console.log('iOS URL:', ios_url);
  551. console.log('Android URL:', android_url);
  552. $btn.button('loading');
  553. if(!ios_url){
  554. alert('请输入IOS地址');
  555. $btn.button('reset');
  556. return false;
  557. }
  558. if(!android_url){
  559. alert('请输入安卓地址');
  560. $btn.button('reset');
  561. return false;
  562. }
  563. // 清理不必要的cookie
  564. cleanUnnecessaryCookies();
  565. console.log('开始发送AJAX请求...');
  566. $.ajax({
  567. type: "POST",
  568. url: "/index/combine/down",
  569. data: "ios_url=" + encodeURIComponent(ios_url) + "&android_url=" + encodeURIComponent(android_url),
  570. contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  571. headers: {
  572. "X-Requested-With": "XMLHttpRequest",
  573. "Accept": "application/json, text/javascript, */*; q=0.01"
  574. },
  575. success: function(ret) {
  576. console.log('AJAX成功响应:', ret);
  577. $btn.button('reset');
  578. if (ret.status == 1) {
  579. $('#qrcode_img').attr("src", ret.qrcode_path);
  580. $('#shortUrlh').val(ret.shortUrl);
  581. $('#shortUrlha').show();
  582. $('.qrcode_path').val(ret.qrcode_path);
  583. $('.shortUrl').val(ret.shortUrl);
  584. } else {
  585. alert(ret.msg || '生成失败!');
  586. }
  587. },
  588. error: function(err) {
  589. console.log('AJAX错误:', err);
  590. $btn.button('reset');
  591. alert('请求失败,请重试!');
  592. }
  593. });
  594. });
  595. function cleanUnnecessaryCookies() {
  596. // 定义需要保留的cookie
  597. var keepCookies = ['PHPSESSID', 'in_userid', 'in_username', 'in_userpassword'];
  598. // 获取所有cookie
  599. var cookies = document.cookie.split(';');
  600. // 清理不必要的cookie
  601. for (var i = 0; i < cookies.length; i++) {
  602. var cookie = cookies[i].trim();
  603. var cookieName = cookie.split('=')[0];
  604. // 如果cookie不在保留列表中,则删除
  605. if (keepCookies.indexOf(cookieName) === -1) {
  606. document.cookie = cookieName + '=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
  607. console.log('已删除cookie: ' + cookieName);
  608. }
  609. }
  610. }
  611. </script>
  612. <?php $this->footer(); ?>
  613. </body>
  614. </html>
  615. <?php
  616. }
  617. function down()
  618. {
  619. // 生产环境应该关闭错误显示
  620. if (defined('ENVIRONMENT') && ENVIRONMENT === 'production') {
  621. ini_set('display_errors', 0);
  622. ini_set('display_startup_errors', 0);
  623. error_reporting(0);
  624. } else {
  625. ini_set('display_errors', 1);
  626. ini_set('display_startup_errors', 1);
  627. error_reporting(E_ALL);
  628. }
  629. error_log("=== down() 方法开始执行 ===");
  630. // 设置session配置
  631. if (!session_id()) {
  632. session_set_cookie_params(0, '/', '', false, true);
  633. session_start();
  634. }
  635. // 设置AJAX响应头
  636. header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
  637. header("Cache-Control: no-store, no-cache, must-revalidate");
  638. header("Pragma: no-cache");
  639. header("Content-type: application/json; charset=utf-8");
  640. error_log("响应头已设置");
  641. // 检查用户登录状态
  642. error_log("检查用户登录状态: " . ($this->userlogined ? "已登录" : "未登录"));
  643. if (!$this->userlogined) {
  644. error_log("用户未登录,返回错误");
  645. $response = [
  646. "qrcode_path" => "",
  647. "status" => 0,
  648. "msg" => "请先登录后再操作!",
  649. "shortUrl" => ""
  650. ];
  651. echo json_encode($response);
  652. exit;
  653. }
  654. $_var_3 = SafeRequest("ios_url");
  655. $_var_4 = SafeRequest("android_url");
  656. error_log("接收到的参数 - ios_url: " . $_var_3 . ", android_url: " . $_var_4);
  657. if (!$_var_3) {
  658. $response = [
  659. "qrcode_path" => "",
  660. "status" => 0,
  661. "msg" => "请输入iOS地址!",
  662. "shortUrl" => ""
  663. ];
  664. echo json_encode($response);
  665. exit;
  666. }
  667. if (!$_var_4) {
  668. $response = [
  669. "qrcode_path" => "",
  670. "status" => 0,
  671. "msg" => "请输入Android地址!",
  672. "shortUrl" => ""
  673. ];
  674. echo json_encode($response);
  675. exit;
  676. }
  677. // 验证URL格式和安全性
  678. if (!$this->isValidUrl($_var_3)) {
  679. $response = [
  680. "qrcode_path" => "",
  681. "status" => 0,
  682. "msg" => "iOS地址格式无效!",
  683. "shortUrl" => ""
  684. ];
  685. echo json_encode($response);
  686. exit;
  687. }
  688. if (!$this->isValidUrl($_var_4)) {
  689. $response = [
  690. "qrcode_path" => "",
  691. "status" => 0,
  692. "msg" => "Android地址格式无效!",
  693. "shortUrl" => ""
  694. ];
  695. echo json_encode($response);
  696. exit;
  697. }
  698. // 生成短链接
  699. $_var_5 = $this->generateShortUrl();
  700. error_log("生成的短链接: " . $_var_5);
  701. // 生成短链接URL
  702. $short_url = "http://" . $_SERVER['HTTP_HOST'] . "/" . $_var_5;
  703. error_log("生成的短链接URL: " . $short_url);
  704. // 生成二维码图片路径
  705. $qrcode_url = "http://" . $_SERVER['HTTP_HOST'] . "/qrcode?link=" . urlencode($short_url);
  706. error_log("生成的二维码URL: " . $qrcode_url);
  707. // 保存到数据库 - 按照指定格式
  708. $insert_data = [
  709. "userid" => $this->userid,
  710. "username" => $this->username,
  711. "android" => $_var_4, // android字段存储android_url
  712. "ios" => $_var_3, // ios字段存储ios_url
  713. "link" => $short_url, // link字段存储短链接URL
  714. "short" => $_var_5, // short字段存储短链接标识符
  715. "ctime" => time()
  716. ];
  717. error_log("插入数据: " . json_encode($insert_data));
  718. try {
  719. $_var_7 = db("combine")->insertGetId($insert_data);
  720. error_log("数据库插入结果: " . $_var_7);
  721. } catch (Exception $e) {
  722. error_log("数据库错误: " . $e->getMessage());
  723. $response = [
  724. "qrcode_path" => "",
  725. "status" => 0,
  726. "msg" => "数据库操作失败,请稍后重试!",
  727. "shortUrl" => ""
  728. ];
  729. echo json_encode($response);
  730. exit;
  731. }
  732. if ($_var_7) {
  733. // 使用新的返回格式
  734. $response = [
  735. "qrcode_path" => $qrcode_url,
  736. "status" => 1,
  737. "msg" => "success",
  738. "shortUrl" => $short_url // 返回完整的短链接URL
  739. ];
  740. error_log("成功响应: " . json_encode($response));
  741. echo json_encode($response);
  742. } else {
  743. $response = [
  744. "qrcode_path" => "",
  745. "status" => 0,
  746. "msg" => "生成失败!",
  747. "shortUrl" => ""
  748. ];
  749. error_log("失败响应: " . json_encode($response));
  750. echo json_encode($response);
  751. }
  752. error_log("=== down() 方法执行完成 ===");
  753. exit;
  754. }
  755. function download()
  756. {
  757. $_var_8 = SafeRequest("qrcode_path");
  758. if (!$_var_8) {
  759. reJSON("参数错误!", 404);
  760. }
  761. // 修复路径遍历漏洞
  762. $qrcode_path = $_var_8;
  763. // 验证路径格式,只允许字母数字和基本符号
  764. if (!preg_match('/^[a-zA-Z0-9\/\-_\.]+$/', $qrcode_path)) {
  765. reJSON("无效的文件路径!", 403);
  766. }
  767. // 确保路径在允许的目录内
  768. $allowed_dirs = ['/uploads/qrcode/', '/qrcode/'];
  769. $is_allowed = false;
  770. foreach ($allowed_dirs as $dir) {
  771. if (strpos($qrcode_path, $dir) === 0) {
  772. $is_allowed = true;
  773. break;
  774. }
  775. }
  776. if (!$is_allowed) {
  777. reJSON("访问被拒绝!", 403);
  778. }
  779. $file_path = $_SERVER['DOCUMENT_ROOT'] . $qrcode_path;
  780. // 防止目录遍历
  781. $real_path = realpath($file_path);
  782. $doc_root = realpath($_SERVER['DOCUMENT_ROOT']);
  783. if ($real_path === false || strpos($real_path, $doc_root) !== 0) {
  784. reJSON("文件不存在!", 404);
  785. }
  786. if (file_exists($file_path)) {
  787. // 验证文件类型
  788. $finfo = finfo_open(FILEINFO_MIME_TYPE);
  789. $mime_type = finfo_file($finfo, $file_path);
  790. finfo_close($finfo);
  791. if ($mime_type !== 'image/png' && $mime_type !== 'image/jpeg' && $mime_type !== 'image/gif') {
  792. reJSON("不支持的文件类型!", 403);
  793. }
  794. header('Content-Type: ' . $mime_type);
  795. header('Content-Disposition: attachment; filename="qrcode.png"');
  796. readfile($file_path);
  797. exit;
  798. } else {
  799. reJSON("文件不存在!", 404);
  800. }
  801. }
  802. private function generateShortUrl()
  803. {
  804. $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  805. $short_url = '';
  806. // 使用更安全的随机数生成方法
  807. if (function_exists('random_bytes')) {
  808. $random_bytes = random_bytes(6);
  809. for ($i = 0; $i < 6; $i++) {
  810. $short_url .= $chars[ord($random_bytes[$i]) % strlen($chars)];
  811. }
  812. } elseif (function_exists('openssl_random_pseudo_bytes')) {
  813. $random_bytes = openssl_random_pseudo_bytes(6);
  814. for ($i = 0; $i < 6; $i++) {
  815. $short_url .= $chars[ord($random_bytes[$i]) % strlen($chars)];
  816. }
  817. } else {
  818. // 降级到rand(),但增加熵
  819. for ($i = 0; $i < 6; $i++) {
  820. $short_url .= $chars[rand(0, strlen($chars) - 1)];
  821. }
  822. }
  823. return $short_url; // 只返回短链接标识符,不包含域名
  824. }
  825. private function generateQrcodeImage($url)
  826. {
  827. $qrcode_path = '/uploads/qrcode/' . md5($url) . '.png';
  828. return $qrcode_path;
  829. }
  830. private function isValidUrl($url)
  831. {
  832. // 基本URL格式验证
  833. if (!filter_var($url, FILTER_VALIDATE_URL)) {
  834. return false;
  835. }
  836. // 解析URL
  837. $parsed_url = parse_url($url);
  838. if (!$parsed_url || !isset($parsed_url['scheme']) || !isset($parsed_url['host'])) {
  839. return false;
  840. }
  841. // 只允许HTTP和HTTPS协议
  842. if (!in_array($parsed_url['scheme'], ['http', 'https'])) {
  843. return false;
  844. }
  845. // 检查是否为私有IP地址(防止SSRF)
  846. $host = $parsed_url['host'];
  847. $ip = gethostbyname($host);
  848. if ($ip && $ip !== $host) {
  849. // 检查是否为私有IP
  850. if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
  851. // 这是公网IP,允许
  852. } else {
  853. // 这是私有IP或保留IP,拒绝
  854. return false;
  855. }
  856. }
  857. // 检查URL长度限制
  858. if (strlen($url) > 2048) {
  859. return false;
  860. }
  861. return true;
  862. }
  863. }