
本文详解在 MODX 环境下正确处理 GeoJSON(含多维坐标数组)的编码、存储与还原全流程,重点解决因模板解析器误解析双中括号 [[ 导致坐标丢失的问题,并提供兼容 MySQL LONGTEXT 字段的安全实践方案。
本文详解在 modx 环境下正确处理 geojson(含多维坐标数组)的编码、存储与还原全流程,重点解决因模板解析器误解析双中括号 `[[` 导致坐标丢失的问题,并提供兼容 mysql `longtext` 字段的安全实践方案。
GeoJSON 是地理空间数据的标准交换格式,其核心特征之一是深度嵌套的坐标结构(如 MultiPolygon 中的 [[[[lon,lat],...]], [[[lon,lat],...]]])。当这类数据通过 PHP 存入数据库并再次读取时,若未规避框架层的模板解析干扰,极易出现坐标数组“消失”的假象——实际并非 JSON 编码失败,而是输出阶段被意外截断或转义。
? 问题根源:MODX 模板引擎的双中括号冲突
MODX 使用 [[...]] 作为占位符语法(如 [[snippetName]] 或 [[*chunkName]])进行动态内容渲染。而 GeoJSON 的多边形坐标天然包含连续双中括号结构(例如 "coordinates": [[[[...]]]]),当 MODX 在输出或日志处理过程中扫描字符串时,会将 [[ 误判为模板指令起始符,进而尝试解析不存在的 snippet,最终导致后续内容被静默丢弃或输出中断——这正是 json_encode($data) 返回空 coordinates 字段的根本原因。
✅ 正确解决方案:双重防护策略
1. 存储阶段:预编码 + 显式 JSON 标记
避免直接存储原始 PHP 数组,而应在入库前完成 完整 JSON 序列化,并确保字符串完整性:
// 导入时:先 decode → 处理 → 再 encode 存入数据库
$jsondata = json_decode(file_get_contents('us-states.json'), true);
foreach ($jsondata['features'] as $feature) {
$updateObj = $this->modx->getObject('CatalogStates', ['name' => $feature['properties']['NAME']]);
if ($updateObj) {
// 关键:使用 JSON_UNESCAPED_UNICODE + JSON_PRETTY_PRINT 提升可读性与兼容性
$encodedFeature = json_encode([$feature], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
$updateObj->set('feature', $encodedFeature); // 存为字符串,非数组
$updateObj->save();
}
}⚠️ 注意:$updateObj->set('feature', json_encode(...)) 必须传入字符串,而非数组。MODX 的 set() 方法若接收数组,可能触发内部序列化逻辑,增加解析风险。
立即学习“PHP免费学习笔记(深入)”;
Json Schema Toolkit下载使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
2. 读取阶段:严格反序列化 + 验证
从数据库取出后,必须调用 json_decode() 还原为 PHP 结构,不可直接使用对象属性:
public function getGeoJson() {
$criteria = $this->modx->newQuery('CatalogStates');
$criteria->where(['id:IN' => [1, 2]]);
if ($states = $this->modx->getCollection('CatalogStates', $criteria)) {
$geojsonFeatures = [];
foreach ($states as $state) {
// 关键:从数据库读取的是 JSON 字符串,必须显式 decode
$featureStr = $state->get('feature'); // 返回字符串,如 '{"type":"Feature",...}'
$featureData = json_decode($featureStr, true);
// 验证解码结果
if (json_last_error() !== JSON_ERROR_NONE) {
error_log("Invalid JSON in feature ID " . $state->get('id'));
continue;
}
// 安全提取坐标(支持 MultiPolygon 多层嵌套)
$coordinates = $featureData[0]['geometry']['coordinates'] ?? null;
if (is_array($coordinates) && !empty($coordinates)) {
echo "Coordinates count: " . count($coordinates) . "\n";
// 可选:重新 encode 用于前端传输
echo json_encode(['features' => [$featureData[0]]], JSON_UNESCAPED_UNICODE) . "\n";
}
}
return $geojsonFeatures;
}
}3. 输出防护(可选但推荐):禁用 MODX 自动解析
若需直接输出 GeoJSON 字符串(如 API 接口),应绕过 MODX 模板渲染链:
// 在处理器中直接输出,避免任何 MODX 输出过滤
$this->modx->sendChunk('application/json', json_encode($output, JSON_UNESCAPED_UNICODE));
exit;或在 MODX 模板中使用 [[!...]](不缓存)+ [[~...]](不解析)组合规避处理。
? 总结与最佳实践
- 永远不要依赖 MODX 对 JSON 字符串的“自动理解”:它不是 JSON-aware 框架,所有 GeoJSON 必须显式 json_decode/json_encode。
- 存储即 JSON 字符串:使用 LONGTEXT 字段存储 json_encode() 后的纯字符串,而非 PHP 数组。
- 读取必反序列化:$obj->get('field') 返回字符串,需 json_decode(..., true) 转为数组。
- 启用 JSON_UNESCAPED_UNICODE:保留中文等 Unicode 字符(如 "prov_name_fr": "Québec")。
- 避免 JSON_PRETTY_PRINT 用于生产 API:仅用于调试;正式接口使用紧凑格式提升性能。
- 验证 json_last_error():每次 json_decode() 后检查错误,防止静默失败。
遵循以上流程,即可在 MODX + MySQL 环境中 100% 安全地持久化与还原任意复杂度的 GeoJSON 数据,彻底规避坐标丢失陷阱。



















