Files
friend-links-manager/includes/admin-page.php
LinRuiqi 4299b8de55 commit
2025-08-03 10:16:48 +08:00

378 lines
16 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
// 添加管理菜单
add_action('admin_menu', 'flm_add_admin_menu');
function flm_add_admin_menu() {
add_menu_page(
'友情链接管理',
'友情链接',
'manage_options',
'friend-links-manager',
'flm_admin_page',
'dashicons-admin-links',
30
);
}
// 自动获取favicon
function flm_get_favicon($url) {
$domain = parse_url($url, PHP_URL_HOST);
if ($domain) {
$domain = preg_replace('/^www\./', '', $domain);
return 'https://favicon.im/' . urlencode($domain);
}
return '';
}
// 极端严格的URL清理用于导出
function flm_sanitize_export_url($url) {
if (empty($url)) return '';
// 先解码HTML实体
$url = html_entity_decode($url);
// 移除所有HTML标签和特殊字符
$url = strip_tags($url);
$url = str_replace(array("\r", "\n", "\t", "\\", "'", '"', " ", "<", ">"), '', $url);
// 使用正则提取纯URL
if (preg_match('/(https?:\/\/[^\s\"\'<>]+)/i', $url, $matches)) {
$url = $matches[1];
}
// 最终过滤和验证
$url = filter_var($url, FILTER_SANITIZE_URL);
if (!preg_match('/^https?:\/\//i', $url)) {
$url = 'http://' . ltrim($url, '/');
}
return rtrim($url, '/');
}
// 极端严格的文本清理(用于导出)
function flm_sanitize_export_text($text) {
if (empty($text)) return '';
// 彻底移除所有HTML/JavaScript代码
$text = html_entity_decode($text);
$text = strip_tags($text);
$text = str_replace(array("\r", "\n", "\t", "\\", "'", '"', "<", ">"), '', $text);
return sanitize_text_field($text);
}
// 管理页面内容
function flm_admin_page() {
global $wpdb;
$table_name = $wpdb->prefix . 'friend_links';
// 显示警告信息
echo '<div class="notice notice-warning"><p><strong>警告:</strong>禁用该插件将删除所有链接数据请在禁用前导出包含链接的CSV文件</p></div>';
// 处理表单提交
if (isset($_POST['flm_action'])) {
check_admin_referer('flm_nonce');
switch ($_POST['flm_action']) {
case 'add_link':
if (!empty($_POST['name']) && !empty($_POST['url'])) {
$name = sanitize_text_field($_POST['name']);
$url = esc_url_raw($_POST['url']);
$icon = !empty($_POST['icon']) ? esc_url_raw($_POST['icon']) : flm_get_favicon($url);
$existing = $wpdb->get_row($wpdb->prepare(
"SELECT id FROM $table_name WHERE url = %s",
$url
));
if (!$existing) {
$wpdb->insert($table_name, array(
'name' => $name,
'url' => $url,
'icon' => $icon,
'sort_order' => 0
));
echo '<div class="notice notice-success"><p>链接添加成功!</p></div>';
} else {
echo '<div class="notice notice-error"><p>该URL的链接已存在</p></div>';
}
}
break;
case 'update_links':
if (!empty($_POST['link_ids'])) {
foreach ($_POST['link_ids'] as $index => $id) {
$wpdb->update($table_name, array(
'name' => sanitize_text_field($_POST['link_names'][$index]),
'url' => esc_url_raw($_POST['link_urls'][$index]),
'icon' => esc_url_raw($_POST['link_icons'][$index]),
'sort_order' => $index
), array('id' => intval($id)));
}
echo '<div class="notice notice-success"><p>链接更新成功!</p></div>';
}
break;
case 'delete_link':
if (!empty($_POST['link_id'])) {
$wpdb->delete($table_name, array('id' => intval($_POST['link_id'])));
echo '<div class="notice notice-success"><p>链接删除成功!</p></div>';
}
break;
case 'export_links':
$links = $wpdb->get_results("SELECT name, url, icon FROM $table_name ORDER BY sort_order ASC");
// 清除所有输出缓冲
while (ob_get_level()) {
ob_end_clean();
}
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename=friend-links-export-' . date('Y-m-d') . '.csv');
header('Pragma: no-cache');
header('Expires: 0');
$output = fopen('php://output', 'w');
// 添加BOM头解决中文乱码
fwrite($output, chr(0xEF).chr(0xBB).chr(0xBF));
// 只写入三列标题
fputcsv($output, array(
'网站名称',
'网站URL',
'图标URL'
));
foreach ($links as $link) {
// 对每列数据应用极端清理
fputcsv($output, array(
flm_sanitize_export_text($link->name),
flm_sanitize_export_url($link->url),
flm_sanitize_export_url($link->icon)
));
}
fclose($output);
exit;
break;
case 'import_links':
if (!empty($_FILES['import_file']['tmp_name'])) {
$file = $_FILES['import_file']['tmp_name'];
$handle = fopen($file, 'r');
$import_count = 0;
$update_count = 0;
$error_count = 0;
// 跳过标题行
fgetcsv($handle);
while (($data = fgetcsv($handle)) !== false) {
if (count($data) < 2 || empty($data[0]) || empty($data[1])) {
$error_count++;
continue;
}
$name = sanitize_text_field($data[0]);
$url = esc_url_raw($data[1]);
$icon = isset($data[2]) ? esc_url_raw($data[2]) : flm_get_favicon($data[1]);
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$error_count++;
continue;
}
if (!empty($name) && !empty($url)) {
$existing = $wpdb->get_row($wpdb->prepare(
"SELECT id FROM $table_name WHERE url = %s",
$url
));
if ($existing) {
$wpdb->update($table_name, array(
'name' => $name,
'icon' => $icon
), array('id' => $existing->id));
$update_count++;
} else {
$wpdb->insert($table_name, array(
'name' => $name,
'url' => $url,
'icon' => $icon,
'sort_order' => 0
));
$import_count++;
}
}
}
fclose($handle);
$message = sprintf(
'导入完成!新增 %d 条链接,更新 %d 条已有链接',
$import_count,
$update_count
);
if ($error_count > 0) {
$message .= sprintf(',跳过 %d 条格式不正确的记录', $error_count);
}
echo '<div class="notice notice-success"><p>' . $message . '</p></div>';
}
break;
}
}
// 获取所有链接
$links = $wpdb->get_results("SELECT * FROM $table_name ORDER BY sort_order ASC");
?>
<div class="wrap">
<h1>友情链接管理</h1>
<div class="flm-admin-container">
<!-- 添加新链接表单 -->
<div class="flm-add-form">
<h2>添加新链接</h2>
<form method="post">
<?php wp_nonce_field('flm_nonce'); ?>
<input type="hidden" name="flm_action" value="add_link">
<div class="form-group">
<label for="name">网站名称 (必填)</label>
<input type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="url">网站URL (必填)</label>
<input type="url" id="url" name="url" required>
</div>
<div class="form-group">
<label for="icon">网站图标URL (可选)</label>
<input type="url" id="icon" name="icon">
<p class="description">留空将自动获取favicon</p>
</div>
<button type="submit" class="button button-primary">添加链接</button>
</form>
</div>
<!-- 链接列表 -->
<div class="flm-links-list">
<h2>链接列表</h2>
<form method="post" id="flm-links-form">
<?php wp_nonce_field('flm_nonce'); ?>
<input type="hidden" name="flm_action" value="update_links">
<ul id="flm-sortable-links">
<?php foreach ($links as $link): ?>
<li class="flm-link-item">
<input type="hidden" name="link_ids[]" value="<?php echo $link->id; ?>">
<div class="flm-link-preview">
<?php if ($link->icon): ?>
<img src="<?php echo esc_url($link->icon); ?>" alt="<?php echo esc_attr($link->name); ?>" class="flm-link-icon">
<?php endif; ?>
<span class="flm-link-name"><?php echo esc_html($link->name); ?></span>
</div>
<div class="flm-link-fields">
<div class="form-group">
<label>网站名称</label>
<input type="text" name="link_names[]" value="<?php echo esc_attr($link->name); ?>" required>
</div>
<div class="form-group">
<label>网站URL</label>
<input type="url" name="link_urls[]" value="<?php echo esc_attr($link->url); ?>" required>
</div>
<div class="form-group">
<label>网站图标URL</label>
<input type="url" name="link_icons[]" value="<?php echo esc_attr($link->icon); ?>">
</div>
</div>
<div class="flm-link-actions">
<button type="button" class="button flm-delete-link" data-link-id="<?php echo $link->id; ?>">删除</button>
</div>
</li>
<?php endforeach; ?>
</ul>
<?php if (!empty($links)): ?>
<button type="submit" class="button button-primary">保存更改</button>
<?php endif; ?>
</form>
<!-- 导入导出 -->
<div class="flm-import-export">
<h3>导入/导出</h3>
<div class="flm-export">
<form method="post">
<?php wp_nonce_field('flm_nonce'); ?>
<input type="hidden" name="flm_action" value="export_links">
<button type="submit" class="button">导出为CSV</button>
<p class="description">导出的CSV文件将只包含三列数据网站名称、网站URL、图标URL</p>
</form>
</div>
<div class="flm-import">
<form method="post" enctype="multipart/form-data">
<?php wp_nonce_field('flm_nonce'); ?>
<input type="hidden" name="flm_action" value="import_links">
<div class="form-group">
<label for="import_file">选择CSV文件</label>
<input type="file" id="import_file" name="import_file" accept=".csv" required>
<p class="description">请选择包含三列数据的CSV文件网站名称、网站URL、图标URL</p>
</div>
<button type="submit" class="button button-primary">导入链接</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
jQuery(document).ready(function($) {
// 使链接可排序
$('#flm-sortable-links').sortable();
// 删除链接
$('.flm-delete-link').on('click', function() {
if (confirm('确定要删除这个链接吗?')) {
var linkId = $(this).data('link-id');
var $form = $('#flm-links-form');
$form.append('<input type="hidden" name="flm_action" value="delete_link">');
$form.append('<input type="hidden" name="link_id" value="' + linkId + '">');
$form.submit();
}
});
});
</script>
<?php
}
// 处理AJAX删除请求
add_action('wp_ajax_flm_delete_link', 'flm_ajax_delete_link');
function flm_ajax_delete_link() {
check_ajax_referer('flm_nonce', 'nonce');
if (!empty($_POST['link_id'])) {
global $wpdb;
$table_name = $wpdb->prefix . 'friend_links';
$wpdb->delete($table_name, array('id' => intval($_POST['link_id'])));
wp_send_json_success();
}
wp_send_json_error();
}