WordPress车辆CSV导入PHP进程超时致网站崩溃求助
WordPress Avada主题下CSV导入脚本无限运行耗尽资源导致网站崩溃
问题背景
反复出现的棘手问题,多次修复后仍复发,最终导致网站崩溃,暂无法确定根源。
环境与场景
- WordPress网站
- 主题:Avada
- 自定义PHP脚本,每3小时从CSV文件导入车辆数据,用于网站车辆搜索功能
已尝试操作
- 调整导入代码,但因信息不足无法确认是否为代码问题
- 提升所有PHP资源配置,但脚本进程仍无限运行,最终耗尽服务器资源导致网站崩溃
相关日志截图


自定义导入代码
function fn_import_csv(){ define('EXECUTION', uniqid()); echo "Execution ".EXECUTION."<br><br>"; update_option('inventory_update', current_time('m/d/Y h:i A')); //update settings field $file = fopen(ABSPATH."inventory/MP7220_website.csv", "r"); fgetcsv($file); //skip first row while (($data = fgetcsv($file)) !== FALSE){ //check if INSERT or UPDATE $rsCheck = array('posts_per_page' => 1, 'post_type' => 'inventory', 'post_status' => 'any', 'meta_query' => array('relation' => 'AND', array('key' => 'stock','value' => $data[1], 'compare' => '='))); $arCheck = get_posts($rsCheck); $title = $data[4]." ".$data[5]." ".$data[6]." ".$data[10]." ".$data[16]; if(count($arCheck) == 0){ //insert inventory echo "<b style='color:#2271b1'>INSERT</b> <i>".$data[1]."</i> - ".$title."<br>"; $id = wp_insert_post(array('post_title' => $title, 'post_type'=>'inventory', 'post_status' => 'publish')); $photosPieces = explode(";", $data[28]); $photos = ""; for($i = 0; $i < count($photosPieces); $i++){ $photos .= "<img src='".$photosPieces[$i]."' style='height:100px!important'>"; } add_post_meta($id, 'photos', $photos); add_post_meta($id, 'photos_urls', $data[28]); add_post_meta($id, 'has_photos', (count($photosPieces) == "1") ? "N" : "Y"); add_post_meta($id, 'stock', $data[1]); add_post_meta($id, 'price', $data[19]); add_post_meta($id, 'vin', $data[2]); add_post_meta($id, 'newused', $data[3]); add_post_meta($id, 'year', $data[4]); add_post_meta($id, 'make', $data[5]); add_post_meta($id, 'model', $data[6]); add_post_meta($id, 'model_code', $data[7]); add_post_meta($id, 'body', $data[8]); add_post_meta($id, 'transmission', $data[9]); add_post_meta($id, 'series', $data[10]); add_post_meta($id, 'series_detail', $data[11]); add_post_meta($id, 'door_count', $data[12]); add_post_meta($id, 'odometer', $data[13]); add_post_meta($id, 'engine_cylinder_ct', $data[14]); add_post_meta($id, 'engine_displacement', $data[15]); add_post_meta($id, 'drivetrain_desc', $data[16]); add_post_meta($id, 'color', $data[17]); add_post_meta($id, 'interior_color', $data[18]); add_post_meta($id, 'description', $data[23]); add_post_meta($id, 'features', $data[24]); add_post_meta($id, 'city_mpg', $data[25]); add_post_meta($id, 'highway_mpg', $data[26]); add_post_meta($id, 'engine', $data[31]); add_post_meta($id, 'fuel', $data[32]); add_post_meta($id, 'execution', EXECUTION); add_post_meta($id, 'lock_price_field', "No"); add_post_meta($id, 'pre_owned', "No"); add_post_meta($id, '_yoast_wpseo_metadesc', $title." ".$data[17]." for sale. Visit Major World in Long Island City #NY serving Queens, Brooklyn and Bronx #".$data[2]); }else{ //update inventory $ar = json_decode(json_encode($arCheck), true); echo "<b style='color:#4fb347'>UPDATE</b> <i>".$ar[0]["ID"]." - ".$data[1]."</i> - ".$title."<br>"; $id = $ar[0]["ID"]; $photosPieces = explode(";", $data[28]); $photos = ""; for($i = 0; $i < count($photosPieces); $i++){ $photos .= "<img src='".$photosPieces[$i]."' style='height:100px!important'>"; } wp_update_post(array('ID' => $id, 'post_title' => $title)); update_post_meta($id, 'photos', $photos); update_post_meta($id, 'photos_urls', $data[28]); update_post_meta($id, 'has_photos', (count($photosPieces) == "1") ? "N" : "Y"); update_post_meta($id, 'stock', $data[1]); if(get_field("lock_price_field", $id) == "No" || get_field("lock_price_field", $id) == ""){ //only update the price if it is not locked update_post_meta($id, 'price', $data[19]); } update_post_meta($id, 'vin', $data[2]); update_post_meta($id, 'newused', $data[3]); update_post_meta($id, 'year', $data[4]); update_post_meta($id, 'make', $data[5]); update_post_meta($id, 'model', $data[6]); update_post_meta($id, 'model_code', $data[7]); update_post_meta($id, 'body', $data[8]); update_post_meta($id, 'transmission', $data[9]); update_post_meta($id, 'series', $data[10]); update_post_meta($id, 'series_detail', $data[11]); update_post_meta($id, 'door_count', $data[12]); update_post_meta($id, 'odometer', $data[13]); update_post_meta($id, 'engine_cylinder_ct', $data[14]); update_post_meta($id, 'engine_displacement', $data[15]); update_post_meta($id, 'drivetrain_desc', $data[16]); update_post_meta($id, 'color', $data[17]); update_post_meta($id, 'interior_color', $data[18]); update_post_meta($id, 'description', $data[23]); update_post_meta($id, 'features', $data[24]); update_post_meta($id, 'city_mpg', $data[25]); update_post_meta($id, 'highway_mpg', $data[26]); update_post_meta($id, 'engine', $data[31]); update_post_meta($id, 'fuel', $data[32]); update_post_meta($id, '_yoast_wpseo_metadesc', $title." ".$data[17]." for sale. Visit Major World in Long Island City #NY serving Queens, Brooklyn and Bronx #".$data[2]); update_post_meta($id, 'execution', EXECUTION); } }//end while fclose($file); //remove vehicles $argsD = array( 'posts_per_page' => -1, 'post_type' => 'inventory', 'post_status' => 'any', 'suppress_filters' => false, 'meta_query' => array( 'relation' => 'AND', array( 'key' => 'execution', 'value' => EXECUTION, 'compare' => '!=' ) ), ); $postsDelete = get_posts($argsD); echo "<br><br><h4>TO BE DELETED - <i>".EXECUTION."</i></h4>"; //(".count($postsDelete).") foreach ($postsDelete as $arD){ echo "- ".$arD->post_title." ".$arD->ID."<br>"; wp_delete_post($arD->ID); } //end remove vehicles wp_die(); //necessary to prevent 0 from being printed exit(); }//end import CSV
排查方向与解决方案
一、脚本无限运行核心排查点
CSV文件读取异常
- 检查CSV格式是否存在错误(如换行符不一致、未转义引号),导致
fgetcsv无法识别行边界进入死循环。可在循环内添加日志定位异常行:static $row_num = 1; error_log("Processing row {$row_num}: " . print_r($data, true)); $row_num++; - 确认CSV文件路径、权限是否正常,避免文件无法打开或读取异常。
- 检查CSV格式是否存在错误(如换行符不一致、未转义引号),导致
数据库查询性能瓶颈
- 每次循环调用
get_posts查询库存,未给stock字段建立索引,导致大量重复查询拖慢进程。给wp_postmeta表的meta_key='stock'建立联合索引(meta_key+meta_value)。 - 删除环节
get_posts($argsD)一次性查询所有待删数据,数据量大时占用内存过高,改为分批删除:$argsD['posts_per_page'] = 50; $page = 1; do { $argsD['paged'] = $page; $postsDelete = get_posts($argsD); foreach ($postsDelete as $arD) { wp_delete_post($arD->ID, true); // 直接永久删除,跳过回收站 } $page++; } while (!empty($postsDelete));
- 每次循环调用
WordPress钩子资源消耗
wp_insert_post/wp_update_post触发大量主题/插件钩子(如Avada字段处理、Yoast SEO元数据更新),累积消耗资源。导入前临时禁用钩子:// 导入前禁用钩子 remove_all_actions('save_post'); remove_all_actions('wp_insert_post');
二、脚本优化措施
分批处理数据
设置批次大小(如50条),避免内存溢出:$batch_size = 50; $current_batch = 0; while (($data = fgetcsv($file)) !== FALSE){ $current_batch++; // 处理当前行逻辑 if ($current_batch >= $batch_size) { wp_cache_flush(); gc_collect_cycles(); $current_batch = 0; } }替换低效函数
- 用
get_post_meta替代get_field,减少ACF查询开销:if (get_post_meta($id, 'lock_price_field', true) == "No" || get_post_meta($id, 'lock_price_field', true) == "") { update_post_meta($id, 'price', $data[19]); } - 直接用
$arCheck[0]->ID代替json_decode(json_encode($arCheck), true),减少序列化/反序列化操作。
- 用
添加超时控制
在脚本开头设置执行超时,防止无限运行:set_time_limit(300); // 设置5分钟超时,按需调整日志与监控
- 替换echo输出为文件日志,避免输出缓冲异常:
function log_import($message) { error_log("[Inventory Import] " . $message . "\n", 3, ABSPATH . 'inventory_import.log'); } // 替换echo为log_import调用 - 监控服务器进程,确认脚本是真的无限循环还是处理速度过慢。
- 替换echo输出为文件日志,避免输出缓冲异常:
三、环境层面优化
- 确认PHP的
max_execution_time、memory_limit设置是否生效,避免被服务器面板覆盖。 - 改用系统级Cron替代WP Cron,避免WP Cron依赖网站访问触发导致的脚本重叠执行。
内容的提问来源于stack exchange,提问作者Elite Strategies
相关产品推荐
相关产品推荐

