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()
            ]);
        }
    }
相关推荐
前端 贾公子3 小时前
uniapp中@input修改input内容不生效 | 过滤赋值无效 | 连续非法字符不更新的问题
开发语言·前端·javascript
五阿哥永琪3 小时前
从零读懂 Java 函数式接口:Function、Consumer、Supplier、Predicate
java·开发语言
533_3 小时前
[vxe-table] 表头:点击出现输入框
android·java·javascript
写不来代码的草莓熊3 小时前
el-date-picker ,自定义输入数字自动转换显示yyyy-mm-dd HH:mm:ss格式 【仅双日历 datetimerange专用】
开发语言·前端·javascript
邹阿涛涛涛涛涛涛3 小时前
Jetpack Compose Modifier 深度解析:从链式调用到 Modifier.Node
android
I疯子3 小时前
2026-04-13 打卡第 6 天
开发语言·python
断眉的派大星3 小时前
值传递和引用传递
开发语言
大邳草民3 小时前
Python 对象模型与属性访问机制
开发语言·笔记·python
xyq20243 小时前
Swift 下标脚本
开发语言