266 lines
7.6 KiB
PHP
266 lines
7.6 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* 工具类文件
|
||
|
* 包含URL抓取、重复检测、IP限制等功能
|
||
|
*/
|
||
|
|
||
|
class Utils {
|
||
|
private $db;
|
||
|
|
||
|
public function __construct($database) {
|
||
|
$this->db = $database;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 获取网站TDK信息
|
||
|
*/
|
||
|
public function getWebsiteInfo($url) {
|
||
|
// 确保URL包含协议
|
||
|
if (!preg_match('/^https?:\/\//i', $url)) {
|
||
|
$url = 'http://' . $url;
|
||
|
}
|
||
|
|
||
|
$result = [
|
||
|
'title' => '',
|
||
|
'description' => '',
|
||
|
'keywords' => '',
|
||
|
'url' => $url,
|
||
|
'success' => false
|
||
|
];
|
||
|
|
||
|
try {
|
||
|
$context = stream_context_create([
|
||
|
'http' => [
|
||
|
'timeout' => 10,
|
||
|
'user_agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
|
||
|
]
|
||
|
]);
|
||
|
|
||
|
$html = @file_get_contents($url, false, $context);
|
||
|
|
||
|
if ($html === false) {
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
// 转换编码
|
||
|
$html = mb_convert_encoding($html, 'UTF-8', 'auto');
|
||
|
|
||
|
// 解析HTML
|
||
|
$dom = new DOMDocument();
|
||
|
@$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
|
||
|
|
||
|
// 获取title
|
||
|
$titles = $dom->getElementsByTagName('title');
|
||
|
if ($titles->length > 0) {
|
||
|
$result['title'] = trim($titles->item(0)->textContent);
|
||
|
}
|
||
|
|
||
|
// 获取meta标签
|
||
|
$metas = $dom->getElementsByTagName('meta');
|
||
|
foreach ($metas as $meta) {
|
||
|
$name = $meta->getAttribute('name');
|
||
|
$property = $meta->getAttribute('property');
|
||
|
$content = $meta->getAttribute('content');
|
||
|
|
||
|
if (strtolower($name) === 'description' || strtolower($property) === 'og:description') {
|
||
|
if (empty($result['description'])) {
|
||
|
$result['description'] = trim($content);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (strtolower($name) === 'keywords') {
|
||
|
$result['keywords'] = trim($content);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$result['success'] = true;
|
||
|
|
||
|
} catch (Exception $e) {
|
||
|
// 静默处理错误
|
||
|
}
|
||
|
|
||
|
return $result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 检查IP提交限制
|
||
|
*/
|
||
|
public function checkIPLimit($ip) {
|
||
|
$today = date('Y-m-d');
|
||
|
|
||
|
$stmt = $this->db->prepare("
|
||
|
SELECT count FROM ip_submissions
|
||
|
WHERE ip_address = ? AND submission_date = ?
|
||
|
");
|
||
|
$stmt->execute([$ip, $today]);
|
||
|
$result = $stmt->fetch();
|
||
|
|
||
|
if ($result) {
|
||
|
return $result['count'] < 3;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 记录IP提交
|
||
|
*/
|
||
|
public function recordIPSubmission($ip) {
|
||
|
$today = date('Y-m-d');
|
||
|
|
||
|
$stmt = $this->db->prepare("
|
||
|
INSERT INTO ip_submissions (ip_address, submission_date, count)
|
||
|
VALUES (?, ?, 1)
|
||
|
ON DUPLICATE KEY UPDATE count = count + 1
|
||
|
");
|
||
|
|
||
|
try {
|
||
|
$stmt->execute([$ip, $today]);
|
||
|
} catch (PDOException $e) {
|
||
|
// SQLite兼容处理
|
||
|
$check = $this->db->prepare("
|
||
|
SELECT count FROM ip_submissions
|
||
|
WHERE ip_address = ? AND submission_date = ?
|
||
|
");
|
||
|
$check->execute([$ip, $today]);
|
||
|
$existing = $check->fetch();
|
||
|
|
||
|
if ($existing) {
|
||
|
$update = $this->db->prepare("
|
||
|
UPDATE ip_submissions
|
||
|
SET count = count + 1
|
||
|
WHERE ip_address = ? AND submission_date = ?
|
||
|
");
|
||
|
$update->execute([$ip, $today]);
|
||
|
} else {
|
||
|
$insert = $this->db->prepare("
|
||
|
INSERT INTO ip_submissions (ip_address, submission_date, count)
|
||
|
VALUES (?, ?, 1)
|
||
|
");
|
||
|
$insert->execute([$ip, $today]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 检查网址重复
|
||
|
*/
|
||
|
public function checkWebsiteDuplicate($url) {
|
||
|
// 标准化URL
|
||
|
$normalized_url = $this->normalizeUrl($url);
|
||
|
$domain = $this->extractDomain($url);
|
||
|
|
||
|
$stmt = $this->db->prepare("
|
||
|
SELECT id FROM website_submissions
|
||
|
WHERE url = ? OR url LIKE ?
|
||
|
");
|
||
|
$stmt->execute([$normalized_url, '%' . $domain . '%']);
|
||
|
|
||
|
return $stmt->fetch() !== false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 检查APP重复
|
||
|
*/
|
||
|
public function checkAppDuplicate($name, $platform) {
|
||
|
$stmt = $this->db->prepare("
|
||
|
SELECT id FROM app_submissions
|
||
|
WHERE name = ? AND platform = ?
|
||
|
");
|
||
|
$stmt->execute([$name, $platform]);
|
||
|
|
||
|
return $stmt->fetch() !== false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 标准化URL
|
||
|
*/
|
||
|
private function normalizeUrl($url) {
|
||
|
// 移除协议
|
||
|
$url = preg_replace('/^https?:\/\//i', '', $url);
|
||
|
// 移除www
|
||
|
$url = preg_replace('/^www\./i', '', $url);
|
||
|
// 移除尾部斜杠
|
||
|
$url = rtrim($url, '/');
|
||
|
// 转换为小写
|
||
|
$url = strtolower($url);
|
||
|
|
||
|
return $url;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 提取域名
|
||
|
*/
|
||
|
private function extractDomain($url) {
|
||
|
$parsed = parse_url($url);
|
||
|
$host = isset($parsed['host']) ? $parsed['host'] : $url;
|
||
|
|
||
|
// 移除www
|
||
|
$host = preg_replace('/^www\./i', '', $host);
|
||
|
|
||
|
return strtolower($host);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 获取客户端IP
|
||
|
*/
|
||
|
public static function getClientIP() {
|
||
|
$ip_keys = ['HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'HTTP_CLIENT_IP', 'REMOTE_ADDR'];
|
||
|
|
||
|
foreach ($ip_keys as $key) {
|
||
|
if (!empty($_SERVER[$key])) {
|
||
|
$ip = $_SERVER[$key];
|
||
|
if (strpos($ip, ',') !== false) {
|
||
|
$ip = trim(explode(',', $ip)[0]);
|
||
|
}
|
||
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||
|
return $ip;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 生成验证码
|
||
|
*/
|
||
|
public static function generateCaptcha() {
|
||
|
session_start();
|
||
|
|
||
|
$code = '';
|
||
|
$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||
|
for ($i = 0; $i < 4; $i++) {
|
||
|
$code .= $chars[rand(0, strlen($chars) - 1)];
|
||
|
}
|
||
|
|
||
|
$_SESSION['captcha'] = $code;
|
||
|
|
||
|
// 创建图片
|
||
|
$image = imagecreate(100, 40);
|
||
|
$bg_color = imagecolorallocate($image, 255, 255, 255);
|
||
|
$text_color = imagecolorallocate($image, 0, 0, 0);
|
||
|
$line_color = imagecolorallocate($image, 200, 200, 200);
|
||
|
|
||
|
// 添加干扰线
|
||
|
for ($i = 0; $i < 5; $i++) {
|
||
|
imageline($image, rand(0, 100), rand(0, 40), rand(0, 100), rand(0, 40), $line_color);
|
||
|
}
|
||
|
|
||
|
// 添加文字
|
||
|
imagestring($image, 5, 25, 12, $code, $text_color);
|
||
|
|
||
|
header('Content-Type: image/png');
|
||
|
imagepng($image);
|
||
|
imagedestroy($image);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 验证验证码
|
||
|
*/
|
||
|
public static function verifyCaptcha($input) {
|
||
|
session_start();
|
||
|
return isset($_SESSION['captcha']) && strtoupper($input) === $_SESSION['captcha'];
|
||
|
}
|
||
|
}
|
||
|
?>
|