【问题标题】:Limiting and Ordering Values in Array限制和排序数组中的值
【发布时间】:2018-08-19 08:01:27
【问题描述】:

使用 NHTSA 的 API 中的一些代码、我自己的代码和来自该站点的想法,将其包装成一个函数,它工作得很好,但不能在我的实时服务器上运行。

在实时服务器上,它给出了一个错误,我最终使用我的实时服务器的 PHP 版本不支持的数组快捷方式解决了代码:

解析错误:语法错误,第 9 行 /home/pchome/public_html/verify/functions/sitefunctions.php 中出现意外的 '[',期待 ')'

这是这一行:

$postdata = http_build_query(["data" => $VINS, "format" => "JSON"]);

改成这个它可以工作,并且以相同的方式在其他几个地方更改了类似的代码:

$postdata = http_build_query(array("data" => $VINS, "format" => "JSON"));

有时(但并非总是)我可能希望将多个 VIN 作为分号分隔的列表传递给它。这种格式是不可改变的,那么需要什么来提供这个功能呢? (示例 VIN:3GNDA13D76S000000;5XYKT3A12CG000000

// Uses NHTSA API to decode VIN(s)
function decodeVINS($VINS) {
    if ($VINS) :
        $return = "";
        $postdata = http_build_query(array("data" => $VINS, "format" => "JSON"));
        $stream_options = array(
                            'http' => array(
                                'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
                                            "Content-Length: ".strlen($postdata)."\r\n",
                                'method' => "POST",
                                'content' => $postdata
                            )
                        );
        $context = stream_context_create($stream_options);
        $apiURL = "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/";

        $fp = @fopen($apiURL, 'rb', FALSE, $context);
        $results = array_column(json_decode(@stream_get_contents($fp),TRUE), '0');
        $results = $results[0];

        $output = "<blockquote>\n";
        $output .= "<div><strong>VIN: {$results['VIN']}</strong></div>\n";
        $output .= "<div><strong>ErrorCode: {$results['ErrorCode']}</strong></div>\n";

        if ($results['AdditionalErrorText']) :
            $output .= "<div><strong>AdditionalErrorText: {$results['AdditionalErrorText']}</strong></div>\n";
        endif;

        foreach ($results as $key => $val) :
            if ($val && $key != "VIN" && $key != "ErrorCode" && $key != "AdditionalErrorText") :
                $output .= "<div>$key: $val</div>";
            endif;
        endforeach;

        $output .= "</blockquote>\n\n";
    else :
        $output = "Enter VINs above separated by line breaks";
    endif;

    return $output;
}

。 . .它正在输出如下内容:

VIN: JB7FJ43S5KJ000911
ErrorCode: 0 - VIN decoded clean. Check Digit (9th position) is correct
BodyClass: Sport Utility Vehicle (SUV)/Multi Purpose Vehicle (MPV)
DisplacementCC: 3000
DisplacementCI: 183.0712322841
DisplacementL: 3
DriveType: 4WD/4-Wheel Drive/4x4
EngineConfiguration: V-Shaped
EngineCylinders: 6
FuelTypePrimary: Gasoline
GVWR: Class 1C: 4,001 - 5,000 lb (1,814 - 2,268 kg)
Make: DODGE
Manufacturer: MITSUBISHI MOTORS CORPORATION (MMC)
ManufacturerId: 1052
Model: Raider
ModelYear: 1989
PlantCity: Nagoya
PlantCompanyName: Nagoya #3
PlantCountry: Japan
VehicleType: TRUCK 

【问题讨论】:

  • 请向我们提供来自$response 的数据,您当前的输出是什么,为什么它不正确,以及您想要的确切输出是什么。 foreach()... 块似乎应该在if ($response === FALSE) : 条件块的else 部分中。或者更简洁:if (!$response = csv2Array(@stream_get_contents($fp))) {... return ... } else { foreach () ...}
  • if (!$fp) : 也应该是早期的return
  • 我用 $response 的原始输出更新了我原来的问题,这不是我想的那样。现在的工作方式,它给了我我想要的一切,但它实际上给了太多而且顺序错误。当我只需要 $showfields 中的那些时,它会显示所有可能的值,事实上,我根本不需要任何空的(那些在 : 右侧没有任何内容的值)。因此,API 提供的数组似乎需要在 : 处修改并拆分为一个新数组,但不幸的是,我对这种类型的数组操作太没教养了!
  • ...等等,等等,等等。您是否接收 JSON 并将其视为 CSV?您可以接收 CSV 数据吗?您需要决定要使用哪种数据结构。在我看来,csv2Array() 正在破坏您的 JSON 数据。我可以帮你,但我们需要让公共汽车倒车一点。请提供来自@stream_get_contents($fp) 的样本数据,并从该数据中,请显示该输入的确切期望输出。我应该能够弄清楚这两点之间的过程。
  • JSON 是传递给函数的参数,但我不相信它实际上在做任何事情。无论如何,我会尝试发布所要求的信息。

标签: php arrays sorting limiting


【解决方案1】:

现在一切正常,这是最终版本!根据需要,仅显示具有值的行,并且可以在一次提交中处理多个 VIN。该函数是从一个简单的表单调用的,该表单具有一个用于输入 VIN 的文本区域以及一个提交按钮。

// Uses NHTSA API to decode VIN(s)
function decodeVINS($VINS) {
    // sample VINs 3GNDA13D76S000000;5XYKT3A12CG000000
    if ($VINS) :
        $postdata = http_build_query(array("data" => $VINS, "format" => "JSON"));
        $stream_options = array(
                            'http' => array(
                                'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
                                            "Content-Length: ".strlen($postdata)."\r\n",
                                'method' => "POST",
                                'content' => $postdata
                            )
                        );
        $context = stream_context_create($stream_options);
        $apiURL = "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/";

        $fp = @fopen($apiURL, 'rb', FALSE, $context);
        $returnValue = json_decode(@stream_get_contents($fp),TRUE);
        if(!isset($returnValue['Results'])):
            echo "Invalid return data or no return data. Exiting";
            return FALSE;
        endif;
        $results = $returnValue['Results'];

        if(!is_array($results)):
            $results = array($results);
        endif;

        $output = '';
        foreach($results as $result):
            $output .= "<blockquote>\n";
            $output .= "<div><strong>VIN: {$result['VIN']}</strong></div>\n";
            $output .= "<div><strong>ErrorCode: {$result['ErrorCode']}</strong></div>\n";

            if ($result['AdditionalErrorText']) :
                $output .= "<div><strong>AdditionalErrorText: {$result['AdditionalErrorText']}</strong></div>\n";
            endif;

            foreach ($result as $key => $val) :
                if ($val && $key != "VIN" && $key != "ErrorCode" && $key != "AdditionalErrorText") :
                    $output .= "<div>$key: $val</div>";
                endif;
            endforeach;
            $output .= "</blockquote>\n\n";
        endforeach;
    else :
        $output = "Enter VINs above separated by line breaks";
    endif;

    return $output;
}

【讨论】:

    【解决方案2】:

    在我看来,使用 JSON 而不是 CSV 会更容易/直接/稳定。

    我在自定义函数调用中添加了一个参数 ($fields),它将指示如何隔离和排序您的数据。

    我还修改了第一个参数 ($VINs),将其作为数组而不是分号分隔的字符串传递。我希望这可以简化您的处理过程——如果没有,欢迎您回退到原始字符串格式并删除我的 implode(";",$VINs) 调用。

    代码:(Demo)

    function searchByVINs ($VINs,$fields) {
        // test multi-VIN batching via textarea at bottom of https://vpic.nhtsa.dot.gov/api/
        $stream_options_content = http_build_query(["data" => implode(";", $VINS), "format" => "JSON"]);
        $stream_options = [
            'http' => [
                'header' => "Content-Type: application/x-www-form-urlencoded\r\n".
                            "Content-Length: ".strlen($postdata)."\r\n",
                'method' => "POST",
                'content' => $postdata
            ]
        ];
        $context = stream_context_create($stream_options);
        $apiURL = "https://vpic.nhtsa.dot.gov/api/vehicles/DecodeVINValuesBatch/";
    
        if (!$fp = @fopen($apiURL, "rb", FALSE, $context)) {
            return ["success" => false, "response" => "Unable to open stream"];
        }
    
        if (!$response = stream_get_contents($fp),true)) {
            return ["success" => false, "response" => "Unable to receive streamed data"];
        }
    
        if(($data = @json_decode($response,true)) === null && json_last_error()!==JSON_ERROR_NONE){
            return ["success" => false, "response" => "Unable to parse streamed data"];
        }
    
        if (!isset($data["Message"]) || $data["Message"] != "Results returned successfully") {
            return ["success" => false, "response" => "Received unsuccessful dataset"];
        }
    
        $return = [];
        $keys = array_flip($fields);
        foreach ($data["Results"] as $dataset) {
            $isolated = array_intersect_key($dataset,$keys);  // only retain the elements with keys that match $fields values
            $sorted = array_replace($keys,$isolated);  // order the dataset by order of elements in $fields
            $return[] = $sorted;
        }
    
        return ["success" => true, "response" => $return];
    }
    
    
    $VINs = ["3GNDA13D76S000000", "5XYKT3A12CG000000"];
    $fields = ["VIN", "ModelYear", "Make", "FuelTypePrimary", "DriveType", "BodyClass"];
    $response = searchByVINs($VINs,$fields);
    
    if (!$response["success"]) {
        echo "Oops, the api call failed. {$response["response"]}";
    } else {
        foreach ($response["response"] as $item){
            echo "<div>";
            foreach ($item as $key => $value) {
                echo "<div>$key: $value</div>";
            }
            echo "</div>";
        }
    }
    

    输出(来自模拟演示)

    <div>
        <div>VIN: 3GNDA13D76S000000</div>
        <div>ModelYear: 2006</div>
        <div>Make: CHEVROLET</div>
        <div>FuelTypePrimary: Gasoline</div>
        <div>DriveType: </div>
        <div>BodyClass: Wagon</div>
    </div>
    <div>
        <div>VIN: 5XYKT3A12CG000000</div>
        <div>ModelYear: 2012</div>
        <div>Make: KIA</div>
        <div>FuelTypePrimary: Gasoline</div>
        <div>DriveType: 4x2</div>
        <div>BodyClass: Wagon</div>
    </div>
    

    【讨论】:

    • 效果很好,谢谢!但是,它需要更具动态性,因为有许多可能的值,所以我要么想预先选择我需要的那些(并且不显示任何没有值的值),要么只显示整个可能性列表中存在的那些值,但做后者使得很难以任何方式对它们进行排序。
    • @DonP 我已经重写了我的答案。请再看看,让我知道还有什么需要调整的。
    • 直到现在才看到更新,当我回来时会检查它,因为我现在正在旅行。我在下面发布的答案实际上在我的开发系统上运行良好,这正是我想要的,但在实时服务器上崩溃,可能是由于实时服务器具有早期版本的 PHP 和 Apache。
    • 我重新发布了我原来的问题,以反映工作代码与实时服务器的当前问题。请注意,它只需要将 VIN(s) 传递到函数中,并且一旦我意识到可用字段的范围,它现在将提供所需的输出,而无需可能的字段数组。结果发现太多了,无法选择一些,所以我选择显示任何带有值的字段。如果将多个 VIN 作为分号分隔的列表传递,仍然需要帮助解决实时服务器上的崩溃问题并使其正常工作。作为数组传递不是一种选择。
    • 好的,有机会我会调整答案。你真的应该尽快升级你的 php 版本。 php 5.4 及更高版本附带短数组语法:php.net/manual/en/migration54.new-features.php
    猜你喜欢
    • 2016-02-25
    • 2022-08-04
    • 2020-02-29
    • 2021-12-23
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多