$wpdb->insert仅本地生效,线上主机无法保存数据问题排查
WordPress插件AJAX数据插入失败排查与修复(20i主机环境)
问题现象
开发了一款捕获访客数据的WordPress插件,通过AJAX调用$wpdb->insert将数据存入自定义表:
- 本地环境运行正常,
$wpdb->insert返回true - 部署到20i主机后,AJAX提交的数据无记录,后台可正常显示phpMyAdmin插入的数据
- 无错误日志、控制台无报错
核心排查方向与修复步骤
1. 强制开启调试日志
20i主机默认可能关闭了WordPress调试,先开启日志排查具体错误:
在wp-config.php中添加:
define('WP_DEBUG', true); define('WP_DEBUG_LOG', true); define('WP_DEBUG_DISPLAY', false);
错误会写入wp-content/debug.log,查看是否有数据库插入相关的报错。
2. 补全AJAX请求的Nonce验证
原代码未做Nonce验证,部分主机的安全机制会拦截无验证的AJAX请求:
后端修改(保存函数)
function io_tarot_readings_visitors_database_save() { global $wpdb; // 验证请求合法性 if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'io_tarot_visitors_nonce')) { wp_send_json_error('请求验证失败'); wp_die(); } $email = sanitize_email($_POST['email']); $url = sanitize_url($_POST['url']); $datetime = $_POST['datetime']; // 校验数据有效性 if (empty($email) || !is_email($email)) { wp_send_json_error('邮箱格式无效'); wp_die(); } if (empty($datetime) || !preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $datetime)) { wp_send_json_error('日期格式错误,需为YYYY-MM-DD HH:MM:SS'); wp_die(); } $table = $wpdb->prefix.'io_tarot_reading_visitors'; $data = array( 'email' => $email, 'url' => $url, 'date' => $datetime ); // 执行插入并返回结果 $result = $wpdb->insert($table, $data); if ($result !== false) { wp_send_json_success('数据保存成功'); } else { wp_send_json_error('保存失败: ' . $wpdb->last_error); } wp_die(); // 必须终止AJAX请求 } add_action('wp_ajax_io_tarot_readings_visitors_database_save', 'io_tarot_readings_visitors_database_save'); add_action('wp_ajax_nopriv_io_tarot_readings_visitors_database_save', 'io_tarot_readings_visitors_database_save');
前端修改(添加Nonce字段)
在提交表单或AJAX触发页面添加Nonce:
<?php wp_nonce_field('io_tarot_visitors_nonce', 'nonce'); ?>
AJAX请求携带Nonce(以jQuery为例):
jQuery.post( ajaxurl, { action: 'io_tarot_readings_visitors_database_save', email: jQuery('#visitor-email').val(), url: window.location.href, datetime: new Date().toISOString().slice(0, 19).replace('T', ' '), nonce: jQuery('input[name="nonce"]').val() }, function(response) { console.log(response.data); // 查看响应结果,方便调试 } );
3. 修复数据库表字段限制
原建表语句中url字段长度仅为55字符,若访客URL超过长度会导致插入失败:
// 修改建表SQL中的url字段 $sql = "CREATE TABLE $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, email varchar(250) NOT NULL, url varchar(255) DEFAULT '' NOT NULL, // 改为255或更长 date datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, // 替换无效默认值,适配MySQL严格模式 PRIMARY KEY (id) ) $charset_collate;";
注意:修改表结构后需要重新激活插件,或直接在phpMyAdmin中修改字段。
4. 检查主机安全机制
20i主机自带ModSecurity等安全防护,可能拦截了AJAX请求:
- 登录20i主机后台,查看安全日志是否有相关拦截记录
- 临时关闭ModSecurity测试,若恢复正常则添加规则白名单
5. 验证数据库写入权限
虽然后台能读取数据,但写入权限可能受限:
- 通过phpMyAdmin使用WordPress数据库用户执行
INSERT语句,测试是否能写入 - 若写入失败,联系20i主机客服调整数据库用户权限
原代码参考
// Create Visitors database table on activation function io_tarot_readings_visitors_database_create() { // Allow access to the $wpdb variable global $wpdb; // Set the table name $table_name = $wpdb->prefix . 'io_tarot_reading_visitors'; // Set the charset $charset_collate = $wpdb->get_charset_collate(); // Create the SQL query $sql = "CREATE TABLE $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, email varchar(250) NOT NULL, url varchar(55) DEFAULT '' NOT NULL, date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, PRIMARY KEY (id) ) $charset_collate;"; require_once ABSPATH . 'wp-admin/includes/upgrade.php'; dbDelta($sql); } register_activation_hook(__FILE__, 'io_tarot_readings_visitors_database_create'); // Visitor capture database save function io_tarot_readings_visitors_database_save() { // Allow access to the $wpdb variable global $wpdb; // Set $_POST variables $email = sanitize_email($_POST['email']); $url = sanitize_url($_POST['url']); $datetime = $_POST['datetime']; // Set table name $table = $wpdb->prefix.'io_tarot_reading_visitors'; // Set data to save $data = array( 'email' => $email, 'url' => $url, 'date' => $datetime ); // Save to database $wpdb->insert($table, $data); } add_action('wp_ajax_io_tarot_readings_visitors_database_save', 'io_tarot_readings_visitors_database_save'); add_action('wp_ajax_nopriv_io_tarot_readings_visitors_database_save', 'io_tarot_readings_visitors_database_save'); // Export visitor capture data as CSV function io_tarot_readings_visitors_export_csv() { // Check if export button is pressed if(isset($_POST['visitor-capture-export'])) { // Allow access to $wpdb variable global $wpdb; // Set the SQL query $sql = "SELECT * FROM {$wpdb->prefix}io_tarot_reading_visitors"; // Get the database rows $rows = $wpdb->get_results($sql, 'ARRAY_A'); // Check if there are existing rows if($rows) { $csv_fields = array(); $csv_fields[] = "first_column"; $csv_fields[] = 'second_column'; // Set filename $output_filename = get_bloginfo('name').' - IO Tarot Readings Visitor Data - '.date('Y-m-d H:i:s').'.csv'; $output_handle = @fopen('php://output', 'w'); // Set headers header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); header('Content-Description: File Transfer'); header('Content-type: text/csv'); header('Content-Disposition: attachment; filename=' . $output_filename); header('Expires: 0'); header('Pragma: public'); $first = true; foreach($rows as $row) { // Process the header row if($first) { $titles = array(); foreach ($row as $key => $val) { $titles[] = $key; } fputcsv($output_handle, $titles); $first = false; } $leadArray = (array) $row; // Add row to file fputcsv($output_handle, $leadArray); } // Close output file stream fclose($output_handle); die(); } } } add_action('admin_init', 'io_tarot_readings_visitors_export_csv'); // Visitor capture database delete function io_tarot_readings_visitors_delete_data() { // Check if delete button is pressed if(isset($_POST['visitor-capture-delete'])) { // Allow access to the $wpdb variable global $wpdb; // Set table name $table = $wpdb->prefix.'io_tarot_reading_visitors'; // Run the SQL query to truncate the table $delete = $wpdb->query("TRUNCATE TABLE $table"); } } add_action('admin_init', 'io_tarot_readings_visitors_delete_data');
内容的提问来源于stack exchange,提问作者Lee
相关产品推荐
相关产品推荐

