Limiting and Ordering Values in Array

192 Views Asked by At

Using some code from NHTSA's API, my own and ideas from this site, wrapping it into a function, it is working just fine but would not run on my live server.

On the live server, it was giving an error which I finally solved to the code using an array shortcut not supported by my live server's PHP version:

Parse error: syntax error, unexpected '[', expecting ')' in /home/pchome/public_html/verify/functions/sitefunctions.php on line 9

which is this line:

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

Changed to this it works and also changed similar code in several other places in the same manner:

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

Occasionally (but not always) I may want to pass multiple VINs to it as a semicolon-separated list. This format is not changeable so what is needed to give this functionality? (Sample VINs: 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;
}

. . . and it is outputting something like this:

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 
2

There are 2 best solutions below

0
AudioBubble On BEST ANSWER

All working now so here is the final version! As needed, shows only rows with values and can handle multiple VINs in one submission. The function is called from a simple form that has a textarea for entering the VINs, along with a Submit button.

// 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;
}
6
mickmackusa On

Working with JSON instead of CSV, in my opinion, is going to be much easier/direct/stable.

I have added a parameter ($fields) to the custom function call which will dictate how to isolate and sort your data.

I have also modified the first parameter ($VINs), to be passed as an array instead of a semicolon delimited string. This I hope simplifies your processing -- if it doesn't you are welcome to fallback to your original string format and remove my implode(";",$VINs) call.

Code: (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>";
    }
}

Output (from mocked demo)

<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>