已完成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’ => ‘文件正在被其他用户使用,请稍后重试’
]);
}
- 类型转换
根据原始字段值的类型自动转换新值,确保类型一致性:
- 整数类型:使用 is_numeric() 检查并转换为 (int)
- 浮点数类型:使用 is_numeric() 检查并转换为 (float)
- 布尔类型:支持多种字符串表示(‘true’, ‘false’, ‘yes’, ‘no’, ‘是’, '否’等)
- 字符串类型:直接转换或JSON编码
- 数组类型:支持JSON字符串解析
- 批量处理优化
- 使用 $playersMap 建立ID到索引的映射,避免重复遍历
- 一次性读取、修改、写入整个JSON文件
- 单次文件锁定处理所有更新操作
- 返回格式
{
“success”: true,
“message”: “批量更新完成”,
“data”: {
“totalUpdates”: 3,
“successCount”: 3,
“errorCount”: 0,
“results”: [
{
“index”: 0,
“id”: “660”,
“name”: “中投”,
“fieldName”: “abilities.fg_base”,
“success”: true
}
],
“errors”: []
}
} - 错误处理
- 参数为空时返回错误
- 参数长度不匹配时返回错误
- 文件不存在时返回错误
- 无法获取文件锁时返回错误
- JSON文件格式错误时返回错误
- 球员ID不存在时记录错误
- 中文属性名不存在时记录错误
- 类型转换失败时记录错误
publicfunctionsetplayersjson(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){returnjson(['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)){returnjson(['success'=>false,'error'=>'id数组、属性名数组和value数组的长度必须相同']);}$seaValue=$this->getSeaValue();$jsonPath=base_path()."/data/{$seaValue}/players.json";if(!file_exists($jsonPath)){returnjson(['success'=>false,'error'=>"文件不存在: players.json"]);}$handle=fopen($jsonPath,'r+');if(!$handle){returnjson(['success'=>false,'error'=>'无法打开文件']);}if(!flock($handle,LOCK_EX)){fclose($handle);returnjson(['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);returnjson(['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($partsas$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);returnjson(['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);returnjson(['success'=>false,'error'=>'批量更新球员数据失败: '.$e->getMessage()]);}}catch(\Exception $e){returnjson(['success'=>false,'error'=>'批量更新球员数据失败: '.$e->getMessage()]);}}