【问题标题】:PHP cURL routine returning Warning messagePHP cURL 例程返回警告消息
【发布时间】:2021-10-22 15:51:00
【问题描述】:

当我单击一个按钮时,该按钮被编程为从 Protected Planet 的 API 接收数据,我收到一个似乎无法解决的错误。我已经看到isset() 解决方案,但不知道它们是否适用于我的情况,因为我在设置中建议他们从数据库请求密码/登录请求。

我收到此错误:

<br />
<b>Warning</b>:  Trying to access array offset on value of type null in <b>C:\xampp\htdocs\project1\libs\php\getProtectedPlanet.php</b> on line <b>25</b><br />
{"status":{"code":"200","name":"ok","description":"success","returnedIn":"101 ms"},"output":null}

Url 正在返回预期的结果。

<?php

    ini_set('display_errors', 'On');
    error_reporting(E_ALL);

    $executionStartTime = microtime(true);

    $url='http://api.protectedplanet.net/v3/countries/' . $_REQUEST['iso'] . '?token=[REDACTED API TOKEN]';

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_URL,$url);

    $result=curl_exec($ch);

    curl_close($ch);

    $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['output'] = $decode["statistics"];
    
    header('Content-Type: application/json; charset=UTF-8');

    echo json_encode($output); 

?>

示例返回 json:

{"country":{
    "name":"Canada",
    "iso_3":"CAN",
    "id":"CAN",
    "geojson":{
        "type":"Feature",
        "properties":{
            "fill-opacity":0.7,
            "stroke-width":0.05,
            "stroke":"#40541b",
            "fill":"#83ad35",
            "marker-color":"#2B3146"
        },
        "geometry":{
            "type":"Polygon",
            "coordinates":[
                [[-141.006,41.669],[-141.006,83.117],[-52.617,83.117],[-52.617,41.669],[-141.006,41.669]]
            ]
        }
    },
    "statistics":{
        "pa_land_area":1185787.371,
        "pa_marine_area":504723.3908,
        "land_area":9955032.941,
        "percentage_pa_land_cover":11.91143608,
        "percentage_pa_marine_cover":8.857775688,
        "marine_area":5698082.708,
        "polygons_count":9110,
        "points_count":20},
        "pame_statistics":{
            "assessments":74,
            "assessed_pas":60,
            "pame_pa_land_area":307619.9491,
            "pame_percentage_pa_land_cover":3.090094805,
            "pame_pa_marine_area":6980.110537,
            "pame_percentage_pa_marine_cover":0.122499287
        },
        "region":{
            "name":"North America","iso":"NA"
        },
        "pas_count":9130,
        "pas_national_count":7958,
        "pas_regional_count":0,
        "pas_international_count":64,
        "pas_with_iucn_category_count":9130,
        "pas_with_iucn_category_percentage":100.0,
        "links": ...data truncated

我主要想访问"statistics" 键。

ajax 调用开始:

var getProtectedPlanetAPI = function() {
    console.log("Button clicked");
    console.log(isoa3);

    $.ajax({
        url: "libs/php/getProtectedPlanet.php",
        type: 'POST',
        dataType: 'json',
        data: {
            iso: isoa3
        },
        success: function(result) {...

正确的 iso 记录到控制台

【问题讨论】:

  • 您是否已验证 cURL 正在返回有效响应? IE:var_dump($result); 在尝试处理数组/响应之前
  • 我收到了301 Moved Permanently 回复。
  • 你需要 curl 配置中的另一个选项 - CURLOPT_FOLLOWLOCATION ~ 设置为 true
  • 顺便说一句,api端点是安全的SSL,所以url应该是https,你应该真正使用正确的选项来处理curl中的SSL,而不是打开自己到MITM
  • 啊,你帮我解决了这个问题,太棒了,谢谢!关于 cURL 中 SLL 的正确选项,哪里是最好的阅读资源?我已将 CURLOPT_SSL_VERIFYPEER 设置为 true,但我想这只是众多预防措施之一?

标签: php ajax curl


【解决方案1】:

一旦cacert.pem 的有效副本已下载并存储在合适的位置,一个示例函数可以使 curl 工作稍微容易一些 (IMO)。右键单击并选择“将链接另存为”等

该函数接受 3 个参数,但许多任务实际上只需要 $url。函数中的设置适用于大多数事情,但在运行时很容易通过在 $options 参数中为它们设置不同的值来覆盖。 $headers 参数可用于发送 Authorisation 类型标头等。

要访问 json 数据中的 statistics,您需要先查看 country,然后查看 statistics - 使用 Object 表示法更容易使用,因为您只需使用 -&gt; 即可访问数据中的元素 ~ 所以:$json-&gt;country-&gt;statistics

<?php
        
    function curl( $url=NULL, $options=NULL, $headers=false ){
        /*
            https://curl.haxx.se/docs/caextract.html
            
            # download own copy of cacert.pem from internet
            # save in suitable location, edit below path.           
        */
        $cacert='c:/wwwroot/cacert.pem';
        $vbh = fopen('php://temp', 'w+');

        
        $res=array(
            'response'  =>  NULL,
            'info'      =>  array( 'http_code' => 100 ),
            'headers'   =>  NULL,
            'errors'    =>  NULL
        );
        if( is_null( $url ) ) return (object)$res;

        session_write_close();

        /* Initialise curl request object */
        $curl=curl_init();
        if( parse_url( $url,PHP_URL_SCHEME )=='https' ){
            curl_setopt( $curl, CURLOPT_SSL_VERIFYPEER, true );
            curl_setopt( $curl, CURLOPT_SSL_VERIFYHOST, 2 );
            curl_setopt( $curl, CURLOPT_CAINFO, $cacert );
            curl_setopt( $curl, CURLOPT_CAPATH, $cacert );
        }

        /* Define standard options */
        curl_setopt( $curl, CURLOPT_URL,trim( $url ) );
        curl_setopt( $curl, CURLOPT_AUTOREFERER, true );
        curl_setopt( $curl, CURLOPT_FOLLOWLOCATION, true );
        curl_setopt( $curl, CURLOPT_FAILONERROR, true );
        curl_setopt( $curl, CURLOPT_HEADER, false );
        curl_setopt( $curl, CURLINFO_HEADER_OUT, false );
        curl_setopt( $curl, CURLOPT_RETURNTRANSFER, true );
        curl_setopt( $curl, CURLOPT_BINARYTRANSFER, true );
        curl_setopt( $curl, CURLOPT_CONNECTTIMEOUT, 20 );
        curl_setopt( $curl, CURLOPT_TIMEOUT, 60 );
        curl_setopt( $curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.38 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.38' );
        curl_setopt( $curl, CURLOPT_MAXREDIRS, 10 );
        curl_setopt( $curl, CURLOPT_ENCODING, '' );
        
        curl_setopt( $curl, CURLOPT_VERBOSE, true );
        curl_setopt( $curl, CURLOPT_NOPROGRESS, true );
        curl_setopt( $curl, CURLOPT_STDERR, $vbh );
        

        /* Assign runtime parameters as options */
        if( isset( $options ) && is_array( $options ) ){
            foreach( $options as $param => $value ) curl_setopt( $curl, $param, $value );
        }
        
        if( $headers && is_array( $headers ) ){
            curl_setopt( $curl, CURLOPT_HTTPHEADER, $headers );
        }

        /* Execute the request and store responses */
        $res=(object)array(
            'response'  =>  curl_exec( $curl ),
            'info'      =>  (object)curl_getinfo( $curl ),
            'errors'    =>  curl_error( $curl )
        );
        rewind( $vbh );
        $res->verbose=stream_get_contents( $vbh );
        fclose( $vbh );
        curl_close( $curl );
        return $res;
    }
?>

然后,实际使用它:

<?php
    $start=microtime( true );
    $url=sprintf( 'https://api.protectedplanet.net/v3/countries/%s?token=%s', $_REQUEST['iso'], API_TOKEN );
    $res=curl( $url );
    
    if( $res->info->http_code==200 ){
        $json=json_decode( $res->response );
        $output=array(
            'output'    =>  $json->country->statistics,
            'status'    =>  array(
                'code'          =>  200,
                'name'          =>  'ok',
                'description'   =>  'success',
                'returnedIn'    =>  intval( ( microtime( true ) - $start ) * 1000 ) . 'ms'
            )
        );
    }else{
        $output=$res;
    }
    
    
    header('Content-Type: application/json; charset=UTF-8');
    exit( json_encode( $output ) );
?>

【讨论】:

  • 哎呀,那条评论的格式真的不太好。我很抱歉,我会打开一个聊天或其他什么,但可惜我缺乏声誉......现在!
  • 更新,我设法试错了我的主要问题! (删除了第一条评论,因为我无法再编辑它)我有一个简单的问题,如果可以,因为我正在慢慢地将我的旧 PHP cURL 代码更改为您提供的代码。我将如何解析接收到我的 js 脚本中的数据?我有许多针对不同 API 的不同 PHP 例程,如何在所有 .php 文件中实现function curl 最好?
  • 将其传递给 javascript 取决于您的应用程序设计 - 是否通过 ajax 在 page load 或后期加载?
【解决方案2】:

你需要改变

$output['output'] = $decode["statistics"];

$output['output'] = $decode['country']['statistics'];

根据返回的json。

【讨论】:

  • 不幸的是,我仍然遇到同样的错误
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-31
  • 2018-05-06
  • 2015-05-18
  • 2019-08-07
  • 1970-01-01
相关资源
最近更新 更多