找回密码
 注册
搜索
免费空间 免费域名 免费AI 老牌主机商首月仅1美分!27美元/年!Namecheap优惠码Spaceship优惠码
楼主: 微醺

[建站交流] 站长搞个免费吧网址展示平台吧

[复制链接]
发表于 前天 23:51 | 显示全部楼层
efc88ff45580620 发表于 2025-12-25 23:42
http://64185.chez.com
欢迎测试,
今天小谷帮我写的导航提交系统。

好洋气
发表于 前天 23:57 | 显示全部楼层

只能说花里胡哨
只要不满意,我就让小谷重新写,后台添加了排序功能,编辑功能。
小谷重写了无数遍,没有任何怨言,
刚才我又让他添加了前台的搜索框。
发表于 昨天 12:20 | 显示全部楼层
efc88ff45580620 发表于 2025-12-25 23:42
http://64185.chez.com
欢迎测试,
今天小谷帮我写的导航提交系统。

提交申请报错:
Warning: Cannot modify header information - headers already sent by (output started at /mnt/127/doms/chez.com/f/3/64185/index.php:62) in /mnt/127/doms/chez.com/f/3/64185/index.php on line 65
发表于 昨天 15:21 | 显示全部楼层
shim 发表于 2025-12-26 12:20
提交申请报错:
Warning: Cannot modify header information - headers already sent by (output started ...

晚上我再让小谷修改,这家伙又糊弄我。
发表于 昨天 15:49 | 显示全部楼层
shim 发表于 2025-12-26 12:20
提交申请报错:
Warning: Cannot modify header information - headers already sent by (output started ...

问题分析与修正思路
PHP 5.2 兼容性问题:
json_encode/decode 在 PHP 5.2 中对中文处理有问题,需要手动处理 UTF-8
PHP 5.2 不支持短数组语法(但原代码已用array())
date() 函数时区问题(PHP 5.2 默认可能无时区设置)
trim() 等函数在空值下的兼容性
安全问题:
无 CSRF 防护
密码明文存储
输入验证不严格
URL 跳转无验证
功能健壮性:
文件写入无锁机制,并发写入会出错
无错误处理
数组操作无边界检查
Cookie 和 Session 处理不规范
发表于 昨天 16:45 | 显示全部楼层
efc88ff45580620 发表于 2025-12-26 15:21
晚上我再让小谷修改,这家伙又糊弄我。
  1. <?php
  2. /**
  3. * 炫彩导航 - 终极管理版 (全兼容修复版)
  4. * 功能:搜索、排序、编辑、审核、后台改密
  5. * 兼容:PHP 5.2+
  6. * 修复:解决 header 已发送错误
  7. */
  8. // ========== 所有业务逻辑必须放在最顶部(无任何输出之前) ==========
  9. // 兼容PHP 5.2时区问题
  10. if(function_exists('date_default_timezone_set')){
  11.     date_default_timezone_set('PRC');
  12. }

  13. // 开启输出缓冲(关键:解决header已发送问题)
  14. ob_start();

  15. // 字符编码设置(PHP 5.2兼容)
  16. header("Content-Type: text/html; charset=utf-8");
  17. @session_start(); // 兼容PHP 5.2的session启动方式

  18. // 配置常量(便于维护)
  19. define('DATA_FILE', 'nav_db.json');
  20. define('SITE_TITLE', '炫彩收录导航');
  21. define('DEFAULT_PASS', 'Tmd123');
  22. define('COOKIE_EXPIRE', 3600*24);

  23. // --- 安全函数(PHP 5.2兼容) ---
  24. /**
  25. * 安全过滤输入
  26. * @param string $str 输入字符串
  27. * @return string 过滤后的字符串
  28. */
  29. function safe_input($str) {
  30.     if(empty($str)) return '';
  31.     // PHP 5.2兼容的过滤
  32.     if(get_magic_quotes_gpc()){
  33.         $str = stripslashes($str);
  34.     }
  35.     return htmlspecialchars(trim($str), ENT_QUOTES, 'UTF-8');
  36. }

  37. /**
  38. * JSON编码(兼容PHP 5.2中文)
  39. * @param array $data 数据数组
  40. * @return string JSON字符串
  41. */
  42. function json_encode_52($data) {
  43.     if(function_exists('json_encode')){
  44.         // PHP 5.2 json_encode中文转义问题修复
  45.         return preg_replace("#\\\u([0-9a-f]{4})#ie", "iconv('UCS-2BE', 'UTF-8', pack('H4', '\\1'))", json_encode($data));
  46.     }
  47.     return '';
  48. }

  49. /**
  50. * 安全写入文件(加锁防止并发问题)
  51. * @param string $file 文件路径
  52. * @param string $content 内容
  53. * @return bool 是否成功
  54. */
  55. function safe_file_put_contents($file, $content) {
  56.     $dir = dirname($file);
  57.     // 检查目录是否存在
  58.     if(!is_dir($dir)){
  59.         @mkdir($dir, 0755, true);
  60.     }
  61.    
  62.     // 加锁写入(PHP 5.2兼容)
  63.     $fp = fopen($file, 'w');
  64.     if(!$fp) return false;
  65.    
  66.     flock($fp, LOCK_EX);
  67.     $result = fwrite($fp, $content);
  68.     flock($fp, LOCK_UN);
  69.     fclose($fp);
  70.    
  71.     return $result !== false;
  72. }

  73. // --- 数据读取与初始化 ---
  74. if (!file_exists(DATA_FILE)) {
  75.     $data = array(
  76.         "config" => array("password" => md5(DEFAULT_PASS)), // 密码加密存储
  77.         "active" => array(array("name"=>"百度","url"=>"https://www.baidu.com", "time"=>date("Y-m-d"))),
  78.         "pending" => array()
  79.     );
  80.     safe_file_put_contents(DATA_FILE, json_encode_52($data));
  81. } else {
  82.     // 读取文件(处理空文件情况)
  83.     $fileContent = @file_get_contents(DATA_FILE);
  84.     if($fileContent === false || $fileContent === ''){
  85.         $data = array(
  86.             "config" => array("password" => md5(DEFAULT_PASS)),
  87.             "active" => array(),
  88.             "pending" => array()
  89.         );
  90.     }else{
  91.         $data = json_decode($fileContent, true);
  92.         // 兼容旧数据结构
  93.         if (!is_array($data)) $data = array();
  94.         if (!isset($data['config']) || !is_array($data['config'])) {
  95.             $data['config'] = array("password" => md5(DEFAULT_PASS));
  96.         }
  97.         // 确保密码是加密的(升级旧数据)
  98.         if(isset($data['config']['password']) && strlen($data['config']['password']) != 32){
  99.             $data['config']['password'] = md5($data['config']['password']);
  100.         }
  101.         if (!isset($data['active']) || !is_array($data['active'])) $data['active'] = array();
  102.         if (!isset($data['pending']) || !is_array($data['pending'])) $data['pending'] = array();
  103.     }
  104. }

  105. $admin_pass = isset($data['config']['password']) ? $data['config']['password'] : md5(DEFAULT_PASS);

  106. // --- 登录/退出逻辑 ---
  107. $isAdmin = false;
  108. // 验证管理员身份(PHP 5.2兼容)
  109. if (isset($_SESSION['admin']) && $_SESSION['admin'] === "logined") {
  110.     $isAdmin = true;
  111. } elseif (isset($_COOKIE['admin_auth']) && $_COOKIE['admin_auth'] === $admin_pass) {
  112.     $_SESSION['admin'] = "logined"; // 同步session
  113.     $isAdmin = true;
  114. }

  115. // ========== 所有涉及header跳转的逻辑必须放在HTML输出前 ==========
  116. // 登录处理
  117. $login_error = '';
  118. if (isset($_POST['login_pass']) && !empty($_POST['login_pass'])) {
  119.     $login_pass = md5(trim($_POST['login_pass']));
  120.     if ($login_pass === $admin_pass) {
  121.         $_SESSION['admin'] = "logined";
  122.         setcookie("admin_auth", $admin_pass, time()+COOKIE_EXPIRE, '/'); // 指定路径,兼容多目录
  123.         header("Location: " . $_SERVER['PHP_SELF']);
  124.         exit; // 必须exit,防止后续代码执行
  125.     } else {
  126.         $login_error = "<script>alert('密码错误!');</script>";
  127.     }
  128. }

  129. // 退出处理
  130. if (isset($_GET['logout']) && $_GET['logout'] == 1) {
  131.     $_SESSION = array(); // 清空session
  132.     if (isset($_COOKIE[session_name()])) {
  133.         setcookie(session_name(), '', time()-COOKIE_EXPIRE, '/');
  134.     }
  135.     setcookie("admin_auth", "", time()-COOKIE_EXPIRE, '/');
  136.     session_destroy();
  137.     header("Location: " . $_SERVER['PHP_SELF']);
  138.     exit; // 必须exit
  139. }

  140. // 修改密码
  141. $pw_error = '';
  142. if ($isAdmin && isset($_POST['change_pw'])) {
  143.     $new_pw = trim($_POST['new_password']);
  144.     if (!empty($new_pw) && strlen($new_pw) >= 6) {
  145.         $data['config']['password'] = md5($new_pw);
  146.         safe_file_put_contents(DATA_FILE, json_encode_52($data));
  147.         header("Location: ?logout=1");
  148.         exit; // 必须exit
  149.     } else {
  150.         $pw_error = "<script>alert('新密码不能为空且至少6位!');</script>";
  151.     }
  152. }

  153. // 保存/提交链接
  154. $save_error = '';
  155. if (isset($_POST['save_node'])) {
  156.     $name = safe_input($_POST['app_name']);
  157.     $url = safe_input($_POST['app_url']);
  158.     $edit_id = isset($_POST['edit_id']) ? trim($_POST['edit_id']) : "";
  159.    
  160.     // 验证输入
  161.     if(empty($name) || empty($url)){
  162.         $save_error = "<script>alert('网站名称和网址不能为空!');</script>";
  163.     } elseif(!preg_match('/^https?:\/\/.+/i', $url)){
  164.         $save_error = "<script>alert('请输入有效的网址(以http/https开头)!');</script>";
  165.     } else {
  166.         if ($edit_id !== "" && $isAdmin) {
  167.             $edit_id_int = intval($edit_id);
  168.             if(isset($data['active'][$edit_id_int])){
  169.                 $data['active'][$edit_id_int] = array(
  170.                     "name"=>$name,
  171.                     "url"=>$url,
  172.                     "time"=>date("Y-m-d")
  173.                 );
  174.             }
  175.         } else {
  176.             $data['pending'][] = array(
  177.                 "name"=>$name,
  178.                 "url"=>$url,
  179.                 "time"=>date("Y-m-d")
  180.             );
  181.             $save_error = "<script>alert('申请已提交');</script>";
  182.         }
  183.         
  184.         safe_file_put_contents(DATA_FILE, json_encode_52($data));
  185.         header("Location: " . $_SERVER['PHP_SELF']);
  186.         exit; // 必须exit
  187.     }
  188. }

  189. // 管理员操作(审核/删除/排序)
  190. if ($isAdmin && isset($_GET['action']) && isset($_GET['id'])) {
  191.     $id = intval($_GET['id']);
  192.     $action = safe_input($_GET['action']);
  193.    
  194.     // 验证操作类型
  195.     $allowed_actions = array('approve', 'reject', 'del', 'up', 'down');
  196.     if(in_array($action, $allowed_actions)){
  197.         switch ($action) {
  198.             case 'approve':
  199.                 if(isset($data['pending'][$id])){
  200.                     $data['active'][] = $data['pending'][$id];
  201.                     unset($data['pending'][$id]);
  202.                 }
  203.                 break;
  204.             case 'reject':
  205.                 if(isset($data['pending'][$id])){
  206.                     unset($data['pending'][$id]);
  207.                 }
  208.                 break;
  209.             case 'del':
  210.                 if(isset($data['active'][$id])){
  211.                     unset($data['active'][$id]);
  212.                 }
  213.                 break;
  214.             case 'up':
  215.                 if($id > 0 && isset($data['active'][$id]) && isset($data['active'][$id-1])){
  216.                     $tmp = $data['active'][$id];
  217.                     $data['active'][$id] = $data['active'][$id-1];
  218.                     $data['active'][$id-1] = $tmp;
  219.                 }
  220.                 break;
  221.             case 'down':
  222.                 $active_count = count($data['active']);
  223.                 if($id < $active_count-1 && isset($data['active'][$id]) && isset($data['active'][$id+1])){
  224.                     $tmp = $data['active'][$id];
  225.                     $data['active'][$id] = $data['active'][$id+1];
  226.                     $data['active'][$id+1] = $tmp;
  227.                 }
  228.                 break;
  229.         }
  230.         
  231.         // 重新索引数组(PHP 5.2兼容)
  232.         $data['pending'] = isset($data['pending']) && is_array($data['pending']) ? array_values($data['pending']) : array();
  233.         $data['active'] = isset($data['active']) && is_array($data['active']) ? array_values($data['active']) : array();
  234.         
  235.         safe_file_put_contents(DATA_FILE, json_encode_52($data));
  236.     }
  237.     header("Location: " . $_SERVER['PHP_SELF']);
  238.     exit; // 必须exit
  239. }

  240. // 编辑链接数据准备
  241. $edit_node = array("name"=>"", "url"=>"", "id"=>"");
  242. if($isAdmin && isset($_GET['edit']) && is_numeric($_GET['edit'])){
  243.     $eid = intval($_GET['edit']);
  244.     if(isset($data['active'][$eid])){
  245.         $edit_node = $data['active'][$eid];
  246.         $edit_node['id'] = $eid;
  247.     }
  248. }

  249. // ========== HTML输出部分(所有跳转逻辑已处理完毕) ==========
  250. ?>
  251. <!DOCTYPE html>
  252. <html lang="zh-CN">
  253. <head>
  254.     <meta charset="UTF-8">
  255.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  256.     <title><?php echo htmlspecialchars(SITE_TITLE); ?></title>
  257.     <style>
  258.         @keyframes gradient { 0% {background-position: 0% 50%;} 50% {background-position: 100% 50%;} 100% {background-position: 0% 50%;} }
  259.         body { margin: 0; min-height: 100vh; background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab); background-size: 400% 400%; animation: gradient 15s ease infinite; font-family: sans-serif; color: #fff; }
  260.         .container { max-width: 900px; margin: 0 auto; padding: 20px; }
  261.         .glass { background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 15px; padding: 20px; margin-bottom: 20px; box-shadow: 0 4px 15px rgba(0,0,0,0.1); }
  262.         .search-area { text-align: center; margin-bottom: 30px; }
  263.         #search-input { width: 60%; max-width: 400px; background: rgba(255,255,255,0.2); border: 1px solid rgba(255,255,255,0.4); padding: 12px 20px; border-radius: 30px; color: #fff; font-size: 16px; outline: none; transition: 0.3s; }
  264.         #search-input:focus { width: 80%; background: #fff; color: #333; }
  265.         .engine-btns { margin-top: 12px; display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; }
  266.         .engine-btns button { background: rgba(255,255,255,0.2); border: 1px solid rgba(255,255,255,0.2); color: #fff; padding: 6px 15px; border-radius: 20px; cursor: pointer; font-size: 13px; }
  267.         .nav-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 15px; }
  268.         .card-wrap { position: relative; }
  269.         .nav-card { background: rgba(255, 255, 255, 0.2); padding: 20px; border-radius: 12px; text-decoration: none; color: #fff; text-align: center; font-weight: bold; display: block; border: 1px solid rgba(255,255,255,0.1); transition: 0.3s; overflow: hidden; text-overflow: ellipsis; }
  270.         .nav-card:hover { background: #fff; color: #e73c7e; transform: translateY(-3px); }
  271.         .sort-tools { position: absolute; bottom: -8px; left: 50%; transform: translateX(-50%); display: none; background: rgba(0,0,0,0.7); border-radius: 10px; padding: 2px 8px; gap: 8px; z-index: 5; }
  272.         .card-wrap:hover .sort-tools { display: flex; }
  273.         .sort-tools a { color: #fff; text-decoration: none; font-size: 11px; }
  274.         .del-tag { position: absolute; top: -8px; right: -5px; background: #ff4d4d; color: white; border-radius: 50%; width: 18px; height: 18px; text-decoration: none; font-size: 12px; line-height: 18px; text-align:center; }
  275.         .edit-tag { position: absolute; top: -8px; left: -5px; background: #23a6d5; color: white; border-radius: 50%; width: 18px; height: 18px; text-decoration: none; font-size: 11px; line-height: 18px; text-align:center; }
  276.         input { background: rgba(255,255,255,0.2); border: 1px solid rgba(255,255,255,0.3); padding: 10px; border-radius: 8px; color: #fff; outline: none; margin: 5px 0;}
  277.         .btn-main { background: #fff; color: #e73c7e; border: none; padding: 10px 20px; border-radius: 8px; font-weight: bold; cursor: pointer; }
  278.         footer { text-align: center; padding: 40px; background: rgba(0,0,0,0.2); margin-top: 40px; }
  279.     </style>
  280. </head>
  281. <body>
  282. <?php
  283. // 输出错误提示(放在HTML内,避免header冲突)
  284. echo $login_error . $pw_error . $save_error;
  285. ?>
  286. <div class="container">
  287.     <h1 style="text-align:center; text-shadow: 0 4px 10px rgba(0,0,0,0.2);">✨ <?php echo htmlspecialchars(SITE_TITLE); ?></h1>

  288.     <div class="search-area">
  289.         <input type="text" id="search-input" placeholder="输入关键词搜索..." onkeyup="filterLinks()">
  290.         <div class="engine-btns">
  291.             <button onclick="webSearch('https://www.baidu.com/s?wd=')">百度</button>
  292.             <button onclick="webSearch('https://www.google.com/search?q=')">Google</button>
  293.             <button onclick="webSearch('https://yandex.com/search/?text=')">Yandex</button>
  294.         </div>
  295.     </div>

  296.     <?php if($isAdmin): ?>
  297.     <div class="glass" style="border-left: 5px solid #00ff00;">
  298.         <div style="display:flex; justify-content:space-between; align-items:flex-start;">
  299.             <div>
  300.                 <h3 style="margin:0">🛠️ 管理中心 | <a href="?logout=1" style="color:yellow; text-decoration:none;">退出登录</a></h3>
  301.                 <div style="margin-top:10px;">
  302.                     <form method="POST" style="display:flex; gap:5px;">
  303.                         <input type="password" name="new_password" placeholder="设置新管理密码(至少6位)" style="padding:5px; font-size:12px;">
  304.                         <button type="submit" name="change_pw" class="btn-main" style="padding:5px 10px; font-size:12px;">修改密码</button>
  305.                     </form>
  306.                 </div>
  307.             </div>
  308.             <div style="text-align:right;">
  309.                 <?php if(!empty($data['pending'])): ?>
  310.                 <p style="margin:0; font-size:14px;">待审核 (<?php echo count($data['pending']); ?>)</p>
  311.                 <?php foreach($data['pending'] as $id => $item): ?>
  312.                     <div style="font-size:12px; margin-top:5px;">
  313.                         <?php echo htmlspecialchars($item['name']); ?>
  314.                         <a href="?action=approve&id=<?php echo $id; ?>" style="color:#0f0;">[准]</a>
  315.                         <a href="?action=reject&id=<?php echo $id; ?>" style="color:#f44;" onclick="return confirm('确定拒绝?')">[拒]</a>
  316.                     </div>
  317.                 <?php endforeach; ?>
  318.                 <?php endif; ?>
  319.             </div>
  320.         </div>
  321.     </div>
  322.     <?php endif; ?>

  323.     <div class="nav-grid" id="link-container">
  324.         <?php if(!empty($data['active'])): ?>
  325.             <?php foreach($data['active'] as $id => $nav): ?>
  326.                 <div class="card-wrap" data-name="<?php echo strtolower(htmlspecialchars($nav['name'])); ?>">
  327.                     <a href="<?php echo htmlspecialchars($nav['url']); ?>" target="_blank" class="nav-card"><?php echo htmlspecialchars($nav['name']); ?></a>
  328.                     <?php if($isAdmin): ?>
  329.                         <a href="?edit=<?php echo $id; ?>#form" class="edit-tag">✎</a>
  330.                         <a href="?action=del&id=<?php echo $id; ?>" class="del-tag" onclick="return confirm('确定删除?')">×</a>
  331.                         <div class="sort-tools">
  332.                             <a href="?action=up&id=<?php echo $id; ?>">◀ 前移</a> <a href="?action=down&id=<?php echo $id; ?>">后移 ▶</a>
  333.                         </div>
  334.                     <?php endif; ?>
  335.                 </div>
  336.             <?php endforeach; ?>
  337.         <?php endif; ?>
  338.     </div>

  339.     <div id="form" class="glass" style="margin-top:40px; text-align:center;">
  340.         <h3><?php echo ($edit_node['id']!=="") ? "📝 修改内容" : "📩 申请收录"; ?></h3>
  341.         <form method="POST">
  342.             <input type="hidden" name="edit_id" value="<?php echo htmlspecialchars($edit_node['id']); ?>">
  343.             <input type="text" name="app_name" placeholder="网站名称" required style="width:120px;" value="<?php echo htmlspecialchars($edit_node['name']); ?>">
  344.             <input type="url" name="app_url" placeholder="网址 https://..." required style="width:250px;" value="<?php echo htmlspecialchars($edit_node['url']); ?>">
  345.             <button type="submit" name="save_node" class="btn-main"><?php echo ($edit_node['id']!=="") ? "保存修改" : "提交申请"; ?></button>
  346.             <?php if($edit_node['id']!==""): ?><br><a href="<?php echo $_SERVER['PHP_SELF']; ?>" style="color:#fff; font-size:12px;">取消编辑</a><?php endif; ?>
  347.         </form>
  348.     </div>
  349. </div>

  350. <script>
  351. function filterLinks() {
  352.     var input = document.getElementById('search-input').value.toLowerCase();
  353.     var cards = document.getElementsByClassName('card-wrap');
  354.     for (var i = 0; i < cards.length; i++) {
  355.         var name = cards[i].getAttribute('data-name');
  356.         cards[i].style.display = name.indexOf(input) > -1 ? "block" : "none";
  357.     }
  358. }
  359. function webSearch(baseUrl) {
  360.     var query = document.getElementById('search-input').value;
  361.     if (query) {
  362.         window.open(baseUrl + encodeURIComponent(query), '_blank');
  363.     } else {
  364.         alert('请输入搜索关键词');
  365.     }
  366. }
  367. </script>

  368. <footer>
  369.     <?php if(!$isAdmin): ?>
  370.         <form method="POST">
  371.             <input type="password" name="login_pass" placeholder="管理密码" style="width:80px; font-size:12px;">
  372.             <button type="submit" class="btn-main" style="padding:5px 10px; font-size:12px;">登录</button>
  373.         </form>
  374.     <?php endif; ?>
  375.     <p style="font-size:10px; opacity:0.5; margin-top:15px;">&copy; 2025 <?php echo htmlspecialchars(SITE_TITLE); ?> | PHP 5.2兼容版</p>
  376. </footer>
  377. </body>
  378. </html>
  379. <?php
  380. // 结束输出缓冲并发送内容
  381. ob_end_flush();
  382. ?>
复制代码
发表于 昨天 16:52 | 显示全部楼层

这个版本修复了吗
发表于 昨天 18:52 | 显示全部楼层

应该是修复了,测试可用

phpidc.chez.com/link
发表于 昨天 19:07 | 显示全部楼层
yaner 发表于 2025-12-26 18:52
应该是修复了,测试可用

phpidc.chez.com/link

一会我去上传
发表于 昨天 20:59 | 显示全部楼层
yaner 发表于 2025-12-26 18:52
应该是修复了,测试可用

phpidc.chez.com/link

修我又添加了一个功能之前只能通过,现在有了不通过的功能,之前只能通过之后再删除,现在可以直接否决掉
附带增加了一个提示,提交之后会提示:提交成功,请等待管理员审核!


小谷已经开始不耐烦了,动不动就把搜索给我少几个
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|小黑屋|免费吧论坛

GMT+8, 2025-12-27 01:05 , Processed in 0.112131 second(s), 3 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表