php setplayersjson实现类型转换和文件锁定机制应对高并发

已完成setplayersjson方法的实现和测试!

实现内容

setplayersjson方法功能

根据用户要求,三丰云实现了setplayersjson(id数组, 中文属性名数组, value数组)方法,批量修改免费虚拟主机players.json文件中多个id的多个属性名对应字段值。

方法特点 1. 参数处理

  • ids : 球员ID数组,支持逗号分隔的字符串或数组
  • names : 中文属性名数组,支持逗号分隔的字符串或数组
  • values : 要设置的新值数组,支持逗号分隔的字符串或数组
  • 参数长度必须相同,否则返回错误 2. 文件锁定机制
    使用排他锁(LOCK_EX)保证并发写入时的数据一致性:
    if (!flock(KaTeX parse error: Expected '}', got 'EOF' at end of input: ...X)) { fclose(handle);
    return json([
    'success' => false,
    'error' => '文件正在被其他用户使用,请稍后重试'
    ]);
    }
  1. 类型转换
    根据原始字段值的类型自动转换新值,确保类型一致性:
  • 整数类型:使用 is_numeric() 检查并转换为 (int)
  • 浮点数类型:使用 is_numeric() 检查并转换为 (float)
  • 布尔类型:支持多种字符串表示('true', 'false', 'yes', 'no', '是', '否'等)
  • 字符串类型:直接转换或JSON编码
  • 数组类型:支持JSON字符串解析
  1. 批量处理优化
  • 使用 $playersMap 建立ID到索引的映射,避免重复遍历
  • 一次性读取、修改、写入整个JSON文件
  • 单次文件锁定处理所有更新操作
  1. 返回格式
    {
    "success": true,
    "message": "批量更新完成",
    "data": {
    "totalUpdates": 3,
    "successCount": 3,
    "errorCount": 0,
    "results": [
    {
    "index": 0,
    "id": "660",
    "name": "中投",
    "fieldName": "abilities.fg_base",
    "success": true
    }
    ],
    "errors": []
    }
    }
  2. 错误处理
  • 参数为空时返回错误
  • 参数长度不匹配时返回错误
  • 文件不存在时返回错误
  • 无法获取文件锁时返回错误
  • JSON文件格式错误时返回错误
  • 球员ID不存在时记录错误
  • 中文属性名不存在时记录错误
  • 类型转换失败时记录错误
javascript 复制代码
public function setplayersjson(Request $request)
    {
        try {
            error_reporting(E_ALL & ~E_DEPRECATED);
            
            $ids = $request->post('ids') ?: $request->get('ids');
            $names = $request->post('names') ?: $request->get('names');
            $values = $request->post('values') !== null ? $request->post('values') : $request->get('values');
            
            if (!$ids || !$names || $values === null) {
                return json([
                    'success' => false,
                    'error' => '参数不能为空'
                ]);
            }
            
            if (is_string($ids)) {
                $ids = array_map('trim', explode(',', $ids));
            }
            
            if (is_string($names)) {
                $names = array_map('trim', explode(',', $names));
            }
            
            if (is_string($values)) {
                $values = array_map('trim', explode(',', $values));
            }
            
            if (count($ids) !== count($names) || count($ids) !== count($values)) {
                return json([
                    'success' => false,
                    'error' => 'id数组、属性名数组和value数组的长度必须相同'
                ]);
            }
            
            $seaValue = $this->getSeaValue();
            $jsonPath = base_path() . "/data/{$seaValue}/players.json";
            
            if (!file_exists($jsonPath)) {
                return json([
                    'success' => false,
                    'error' => "文件不存在: players.json"
                ]);
            }
            
            $handle = fopen($jsonPath, 'r+');
            if (!$handle) {
                return json([
                    'success' => false,
                    'error' => '无法打开文件'
                ]);
            }
            
            if (!flock($handle, LOCK_EX)) {
                fclose($handle);
                return json([
                    'success' => false,
                    'error' => '文件正在被其他用户使用,请稍后重试'
                ]);
            }
            
            try {
                $jsonContent = stream_get_contents($handle);
                $jsonData = json_decode($jsonContent, true);
                
                if (!$jsonData || !isset($jsonData['data']['players'])) {
                    flock($handle, LOCK_UN);
                    fclose($handle);
                    return json([
                        'success' => false,
                        'error' => "JSON文件格式错误"
                    ]);
                }
                
                $playersMap = [];
                foreach ($jsonData['data']['players'] as $index => $p) {
                    if (isset($p['id'])) {
                        $playersMap[$p['id']] = $index;
                    }
                }
                
                $results = [];
                $errors = [];
                
                for ($i = 0; $i < count($ids); $i++) {
                    $id = $ids[$i];
                    $name = $names[$i];
                    $value = $values[$i];
                    
                    if (!isset($playersMap[$id])) {
                        $errors[] = [
                            'index' => $i,
                            'id' => $id,
                            'name' => $name,
                            'error' => "未找到ID为{$id}的球员"
                        ];
                        continue;
                    }
                    
                    $playerIndex = $playersMap[$id];
                    $jsonField = $this->getJsonFieldByChinese($name);
                    
                    if (!$jsonField) {
                        $errors[] = [
                            'index' => $i,
                            'id' => $id,
                            'name' => $name,
                            'error' => "未找到中文属性名对应的字段: {$name}"
                        ];
                        continue;
                    }
                    
                    try {
                        $oldValue = null;
                        
                        if (strpos($jsonField, '.') !== false) {
                            $parts = explode('.', $jsonField);
                            $current = &$jsonData['data']['players'][$playerIndex];
                            foreach ($parts as $j => $part) {
                                if ($j === count($parts) - 1) {
                                    $oldValue = $current[$part] ?? null;
                                    $convertedValue = $this->convertJsonValueByType($value, $oldValue);
                                    $current[$part] = $convertedValue;
                                } else {
                                    if (!isset($current[$part])) {
                                        $current[$part] = [];
                                    }
                                    $current = &$current[$part];
                                }
                            }
                        } else {
                            $oldValue = $jsonData['data']['players'][$playerIndex][$jsonField] ?? null;
                            $convertedValue = $this->convertJsonValueByType($value, $oldValue);
                            $jsonData['data']['players'][$playerIndex][$jsonField] = $convertedValue;
                        }
                        
                        $results[] = [
                            'index' => $i,
                            'id' => $id,
                            'name' => $name,
                            'fieldName' => $jsonField,
                            'success' => true
                        ];
                        
                    } catch (\Exception $e) {
                        $errors[] = [
                            'index' => $i,
                            'id' => $id,
                            'name' => $name,
                            'error' => $e->getMessage()
                        ];
                    }
                }
                
                ftruncate($handle, 0);
                rewind($handle);
                $newJsonContent = json_encode($jsonData, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
                fwrite($handle, $newJsonContent);
                
                flock($handle, LOCK_UN);
                fclose($handle);
                
                return json([
                    'success' => true,
                    'message' => '批量更新完成',
                    'data' => [
                        'totalUpdates' => count($ids),
                        'successCount' => count($results),
                        'errorCount' => count($errors),
                        'results' => $results,
                        'errors' => $errors
                    ]
                ]);
                
            } catch (\Exception $e) {
                flock($handle, LOCK_UN);
                fclose($handle);
                return json([
                    'success' => false,
                    'error' => '批量更新球员数据失败: ' . $e->getMessage()
                ]);
            }
            
        } catch (\Exception $e) {
            return json([
                'success' => false,
                'error' => '批量更新球员数据失败: ' . $e->getMessage()
            ]);
        }
    }
相关推荐
Joseph Cooper6 小时前
Linux/Android 跟踪技术:ftrace、TRACE_EVENT、atrace、systrace 与 perfetto 入门
android·linux·运维
小郑加油7 小时前
python学习Day12:pandas安装与实际运用
开发语言·python·学习
AC赳赳老秦7 小时前
投标合规提效:用 OpenClaw 实现标书 / 合同自动审核、关键词校验、格式优化,降低废标风险
开发语言·前端·python·eclipse·emacs·deepseek·openclaw
空中海7 小时前
安卓逆向03. 动态调试、抓包分析与 Frida Hook
android
KuaCpp7 小时前
C++面向对象(速过复习版)
开发语言·c++
wbs_scy7 小时前
Linux线程同步与互斥(三):线程同步深度解析之POSIX 信号量与环形队列生产者消费者模型,从原理到源码彻底吃透
java·开发语言
2zcode8 小时前
基于MATLAB元胞自动机(CA)的AZ80A镁合金动态再结晶(DRX)过程模拟
开发语言·matlab·动态再结晶
iCxhust8 小时前
微机原理实践教程(C语言篇)---A001闪烁灯
c语言·开发语言·汇编·单片机·嵌入式硬件·51单片机·微机原理
一起搞IT吧8 小时前
相机Camera日志实例分析之二十:相机Camx【照片后置4800/5000/6400万拍照】单帧流程日志详解
android·嵌入式硬件·数码相机·智能手机
MATLAB代码顾问9 小时前
Python实现蜂群算法优化TSP问题
开发语言·python·算法