prefix . 'friend_links';
// 检查表是否存在
if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
wp_die('友情链接表不存在,请先添加一些链接。');
}
$links = $wpdb->get_results("SELECT * FROM $table_name ORDER BY sort_order ASC");
// 检查是否有数据
if (empty($links)) {
wp_die('没有找到任何链接数据,请先添加一些链接。');
}
// 清除所有输出缓冲
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');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Content-Transfer-Encoding: binary');
$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),
flm_sanitize_export_text($link->description)
));
}
fclose($output);
exit;
}
}
// 自动获取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 '
💡 提示:卸载插件时会删除数据,禁用插件不会丢失数据。
';
// 显示数据库修复结果
if (isset($_GET['flm_fix_success'])) {
echo '✅ 数据库修复成功!description字段已添加,现在可以正常保存链接信息了。
';
} elseif (isset($_GET['flm_fix_error'])) {
echo '';
} elseif (isset($_GET['flm_fix_exists'])) {
echo '';
}
// 数据库修复按钮
echo '';
// 处理表单提交
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']);
// 验证URL格式
if (!filter_var($url, FILTER_VALIDATE_URL)) {
echo '';
break;
}
$auto_get_icon = isset($_POST['auto_get_icon']) ? true : false;
$icon = '';
if ($auto_get_icon) {
$icon = flm_get_favicon($url);
} elseif (!empty($_POST['icon'])) {
$icon = esc_url_raw($_POST['icon']);
}
$description = !empty($_POST['description']) ? sanitize_textarea_field($_POST['description']) : '';
$existing = $wpdb->get_row($wpdb->prepare(
"SELECT id FROM $table_name WHERE url = %s",
$url
));
if (!$existing) {
// 获取当前最大的sort_order值
$max_sort_order = $wpdb->get_var("SELECT MAX(sort_order) FROM $table_name");
$new_sort_order = $max_sort_order ? intval($max_sort_order) + 1 : 0;
$wpdb->insert($table_name, array(
'name' => $name,
'url' => $url,
'icon' => $icon,
'description' => $description,
'sort_order' => $new_sort_order
));
echo '';
} else {
echo '';
}
}
break;
case 'update_links':
if (!empty($_POST['link_ids'])) {
$update_errors = 0;
$update_count = 0;
// 直接使用数组格式
$link_ids = array_values($_POST['link_ids']);
$link_names = isset($_POST['link_names']) ? array_values($_POST['link_names']) : array();
$link_urls = isset($_POST['link_urls']) ? array_values($_POST['link_urls']) : array();
$link_icons = isset($_POST['link_icons']) ? array_values($_POST['link_icons']) : array();
$link_descriptions = isset($_POST['link_descriptions']) ? array_values($_POST['link_descriptions']) : array();
foreach ($link_ids as $index => $id) {
// 确保数组索引存在
if (!isset($link_names[$index]) || !isset($link_urls[$index])) {
$update_errors++;
continue;
}
$name = sanitize_text_field($link_names[$index]);
$url = esc_url_raw($link_urls[$index]);
// 验证URL格式
if (!filter_var($url, FILTER_VALIDATE_URL)) {
$update_errors++;
continue;
}
$icon = isset($link_icons[$index]) ? esc_url_raw($link_icons[$index]) : '';
$description = isset($link_descriptions[$index]) ? sanitize_textarea_field($link_descriptions[$index]) : '';
$update_data = array(
'name' => $name,
'url' => $url,
'icon' => $icon,
'description' => $description,
'sort_order' => $index
);
$result = $wpdb->update($table_name, $update_data, array('id' => intval($id)));
if ($result === false) {
echo '数据库错误:ID ' . $id . ' 更新失败: ' . $wpdb->last_error . '
';
$update_errors++;
} else {
$update_count++;
}
}
if ($update_errors > 0) {
echo '更新完成!成功更新 ' . $update_count . ' 条链接,跳过 ' . $update_errors . ' 条记录
';
} else {
echo '链接更新成功!共更新 ' . $update_count . ' 条记录
';
}
}
break;
case 'delete_link':
if (!empty($_POST['link_id'])) {
$wpdb->delete($table_name, array('id' => intval($_POST['link_id'])));
echo '';
}
break;
case 'export_links':
// 使用WordPress的admin_url进行重定向导出
$export_url = admin_url('admin.php?page=friend-links-manager&action=export&nonce=' . wp_create_nonce('flm_export_nonce'));
wp_redirect($export_url);
exit;
break;
case 'save_settings':
$desktop_columns = isset($_POST['desktop_columns']) ? intval($_POST['desktop_columns']) : 3;
$random_display = isset($_POST['random_display']) ? 1 : 0;
$show_descriptions = isset($_POST['show_descriptions']) ? 1 : 0;
update_option('flm_desktop_columns', $desktop_columns);
update_option('flm_random_display', $random_display);
update_option('flm_show_descriptions', $show_descriptions);
echo '';
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);
$sort_order = 0;
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]);
$description = isset($data[3]) ? sanitize_textarea_field($data[3]) : '';
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,
'description' => $description
), array('id' => $existing->id));
$update_count++;
} else {
$wpdb->insert($table_name, array(
'name' => $name,
'url' => $url,
'icon' => $icon,
'description' => $description,
'sort_order' => $sort_order
));
$import_count++;
}
$sort_order++;
}
}
fclose($handle);
$message = sprintf(
'导入完成!新增 %d 条链接,更新 %d 条已有链接',
$import_count,
$update_count
);
if ($error_count > 0) {
$message .= sprintf(',跳过 %d 条格式不正确的记录', $error_count);
}
echo '';
}
break;
case 'save_settings':
$desktop_columns = isset($_POST['desktop_columns']) ? intval($_POST['desktop_columns']) : 3;
$random_display = isset($_POST['random_display']) ? 1 : 0;
$show_descriptions = isset($_POST['show_descriptions']) ? 1 : 0;
update_option('flm_desktop_columns', $desktop_columns);
update_option('flm_random_display', $random_display);
update_option('flm_show_descriptions', $show_descriptions);
echo '';
break;
}
}
// 获取所有链接
$links = $wpdb->get_results("SELECT * FROM $table_name ORDER BY sort_order ASC");
?>
友情链接管理
链接列表
显示设置
prefix . 'friend_links';
$wpdb->delete($table_name, array('id' => intval($_POST['link_id'])));
wp_send_json_success();
}
wp_send_json_error();
}
// 处理AJAX排序更新请求
add_action('wp_ajax_flm_update_sort_order', 'flm_ajax_update_sort_order');
function flm_ajax_update_sort_order() {
check_ajax_referer('flm_nonce', 'nonce');
if (!empty($_POST['link_ids']) && is_array($_POST['link_ids'])) {
global $wpdb;
$table_name = $wpdb->prefix . 'friend_links';
foreach ($_POST['link_ids'] as $index => $link_id) {
$link_id = intval($link_id);
if ($link_id > 0) {
$wpdb->update($table_name,
array('sort_order' => $index),
array('id' => $link_id),
array('%d'),
array('%d')
);
}
}
wp_send_json_success();
}
wp_send_json_error();
}
// 处理AJAX批量删除请求
add_action('wp_ajax_flm_batch_delete_links', 'flm_ajax_batch_delete_links');
function flm_ajax_batch_delete_links() {
check_ajax_referer('flm_nonce', 'nonce');
if (!empty($_POST['link_ids']) && is_array($_POST['link_ids'])) {
global $wpdb;
$table_name = $wpdb->prefix . 'friend_links';
$deleted_count = 0;
$error_count = 0;
foreach ($_POST['link_ids'] as $link_id) {
$link_id = intval($link_id);
if ($link_id > 0) {
$result = $wpdb->delete($table_name, array('id' => $link_id), array('%d'));
if ($result !== false) {
$deleted_count++;
} else {
$error_count++;
}
}
}
if ($deleted_count > 0) {
wp_send_json_success(array(
'deleted_count' => $deleted_count,
'error_count' => $error_count
));
} else {
wp_send_json_error('没有链接被删除');
}
}
wp_send_json_error('无效的请求参数');
}