You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP搜索countryBorders.geo.json匹配iso_a3返回边界坐标问题求解

问题描述

TL;DR: 这个任务看起来完全没有必要,我对此表示抱歉。

概述

我已经完成了一个作品集项目,但不符合规范要求,所以需要按照指引重写大部分代码。
这是一个使用leaflet.js开发的地名词典网站项目,要求必须使用jQuery、原生JavaScript和PHP程序访问多个API,填充不同的Bootstrap模态框。我已经完成的版本我个人认为完全满足这个作品集项目的需求。
你可以在这里访问测试: https://kizzysinar.co.uk/project1/index.html

我拿到了countryBorders.geo.json文件,其中包含多个地理要素,结构如下:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "name": "Bahamas",
        "iso_a2": "BS",
        "iso_a3": "BHS",
        "iso_n3": "044"
      },
      "geometry": {
        "type": "MultiPolygon",
        "coordinates": [
          [
            [
              [-77.53466,23.75975],
              [-77.78,23.71],
              [-78.03405,24.28615],
              [-78.40848, 24.57564],
              [-78.19087,25.2103],
              [-77.89,25.17],
              [-77.54,24.34],
              [-77.53466,23.75975]
            ]
          ],
          [
            [
              [-77.82,26.58],
              [-78.91,26.42],
              [-78.98,26.79],
              [-78.51,26.87],
              [-77.85,26.84],
              [-77.82,26.58]
            ]
          ],
          [
            [
              [-77,26.59],
              [-77.17255,25.87918],
              [-77.35641,26.00735],
              [-77.34,26.53],
              [-77.78802,26.92516],
              [-77.79,27.04],
              [-77,26.59]
            ]
          ]
        ]
      }
    }, 
    {..... 更多要素
  ]
}

我原本的实现是直接用这个文件填充<select>下拉选项、生成地图边界,具体用法如下:

  1. 填充<select>下拉框:
result['data'].features.forEach(function (feature) {
                $("<option>", {
                    value: feature.properties.iso_a3,
                    text: feature.properties.name
                }).appendTo("#countrySelect")
  1. 由于是本地存储文件,我用leaflet.ajax解析countryBorders.geo.json中的坐标,为每个feature生成分面图层:
var geoJSONLayer = new L.GeoJSON.AJAX('vendors/json/countryBorders.geo.json',{
    style: myStyle, 
    onEachFeature: onEachFeature
}).addTo(mymap);

用户选择国家时,我会将选中项的value: feature.properties.iso_a3通过AJAX请求发送到REST Countries API,用返回的经纬度设置地图视图:

function setView() {
    $.ajax({
        url: "libs/php/locateCountry.php",
        type: 'POST',
        dataType: 'json',
        data: {
            iso: $('#countrySelect option:selected').val()
        },
        success: function(result) {

            if (result.status.name == "ok") {

                mymap.setView(result['coordinates']);

            }
      
        },

需求变更

现在要求必须通过jQuery/AJAX请求PHP接口,访问本地存储的countryBorders.geo.json,返回与指定iso_a3匹配的坐标。
具体流程要求:用户选择国家后,将选中项的value: iso_a3通过AJAX发送给getCountryBorders.php,PHP用file_get_contents读取JSON文件,匹配feature.properties.iso_a3 == 传入的iso参数,返回对应的边界坐标,AJAX请求成功后用返回的坐标生成L.geoJSON图层,触发Bootstrap模态框。
流程梳理:<select>/<option:selected> -> value: iso_a3 -> AJAX 携带iso: iso_a3发起请求 -> PHP读取countryBorders.geo.json -> 匹配feature.properties.iso_a3 == 'iso' -> 返回边界坐标 -> AJAX success回调生成对应国家的L.geoJSON边界图层。

现有代码及报错

示例PHP参考代码

<?php
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);

    $executionStartTime = microtime(true);

    $result=file_get_contents('C:\xampp\htdocs\project1\vendors\json\countryBorders.geo.json');

    $decode = json_decode($result,true);    

    $output['status']['code'] = "200";
    $output['status']['name'] = "ok";
    $output['status']['description'] = "success";
    $output['status']['returnedIn'] = intval((microtime(true) - $executionStartTime) * 1000) . " ms";
    $output['data'] = $decode;

    header('Content-Type: application/json; charset=UTF-8');

    echo json_encode($output); 
?>

自行编写的PHP代码(有问题)

<?php
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);

    $start=microtime( true );
    $file=file_get_contents('vendors\json\countryBorders.geo.json');

    $json=json_decode($file, true);

    foreach ($json->features->properties as $object) {
        if ($object->iso_a3 == $_REQUEST['iso']) {
            $output=array(
                'border'    => $object->coordinates,
                'status'    =>  array(
                    'code'          =>  200,
                    'name'          =>  'ok',
                    'description'   =>  'success',
                    'returnedIn'    =>  intval( ( microtime( true ) - $start ) * 1000 ) . 'ms'   
                ),
            ); 
        } else {
            $output=$json;
        }
    }

    header('Content-Type: application/json; charset=UTF-8');
    exit( json_encode( $output ) );
    
?>

前端AJAX代码

function setView() {
    $.ajax({
        url: "libs/php/getCountryBorders.php",
        type: 'POST',
        dataType: 'json',
        data: {
            iso: $('#countrySelect option:selected').val() //从option的value中获取iso编码
        },
        success: function(result) {

            if (result.status.name == "ok") {

                console.log(result['border']); //当前仅打印返回结果

            }
      
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log(jqXHR);
        }
    });
};

报错信息

{readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
script.js:69 parsererror
script.js:70 SyntaxError: Unexpected token < in JSON at position 0
    at parse (<anonymous>)
    at jquery.min.js:2
    at l (jquery.min.js:2
    at XMLHttpRequest.<anonymous> (jquery.min.js:2)

解决方案

错误原因

  1. json_decode($file, true)第二个参数为true时返回的是关联数组,不是对象,不能用->访问属性,必须用[]
  2. 遍历层级错误:应该遍历$json['features']数组,每个元素的iso_a3存放在$feature['properties']['iso_a3'],坐标存放在$feature['geometry']['coordinates']
  3. 原有遍历逻辑错误:每次循环都会覆盖$output变量,未匹配到对应国家时返回了整个JSON结构,格式和前端预期不符
  4. 路径用反斜杠仅兼容Windows,建议换成正斜杠避免跨环境问题

修正后的PHP代码

<?php
ini_set('display_errors', 'On');
error_reporting(E_ALL);

$start = microtime(true);
// 可根据自己的项目路径调整为绝对路径,避免相对路径定位错误
$jsonPath = 'C:/xampp/htdocs/project1/vendors/json/countryBorders.geo.json';
$fileContent = file_get_contents($jsonPath);
$jsonData = json_decode($fileContent, true);

// 初始化默认返回结果
$output = [
    'status' => [
        'code' => 404,
        'name' => 'error',
        'description' => '未匹配到对应国家边界',
        'returnedIn' => intval((microtime(true) - $start) * 1000) . 'ms'
    ]
];

// 遍历features数组匹配iso_a3
foreach ($jsonData['features'] as $feature) {
    if ($feature['properties']['iso_a3'] === $_REQUEST['iso']) {
        $output['border'] = $feature['geometry']['coordinates'];
        $output['status'] = [
            'code' => 200,
            'name' => 'ok',
            'description' => 'success',
            'returnedIn' => intval((microtime(true) - $start) * 1000) . 'ms'
        ];
        // 匹配到就终止循环,不需要继续遍历
        break;
    }
}

header('Content-Type: application/json; charset=UTF-8');
echo json_encode($output);
exit;
?>

内容的提问来源于stack exchange,提问作者Ranisimo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 06:15:01