0

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 
5
  • Please offer us the data from $response, what your current output is, why it is not right, and what your exact desired output is. The foreach()... block seems like it should be in the else portion of your if ($response === FALSE) : condition block. Or more succinctly: if (!$response = csv2Array(@stream_get_contents($fp))) {... return ... } else { foreach () ...} Commented Mar 11, 2018 at 2:08
  • if (!$fp) : should be an early return too. Commented Mar 11, 2018 at 2:13
  • I updated my original question with raw output of $response which isn't what I thought it was. The way this is working now, it is giving me everything I want but it is actually giving too much and in the wrong order. It is showing every possible value when I want only those in $showfields and, in fact, I don't need any at all that are empty (those with nothing to the right of :). So it seems that the array that the API provides needs to be modified and split into a new array at : but unfortunately I am too uneducated with this type of array manipulation! Commented Mar 11, 2018 at 2:31
  • ...wait, wait, wait. Are you receiving JSON and treating it like CSV? Are you able to receive CSV data? You need to decide which kind of data structure you want to work with. It appears to me that csv2Array() is mangling your JSON data. I can help you, but we need to back the bus up a bit. Please provide sample data from @stream_get_contents($fp) and from that data, please display your exact desired output from that input. I should be able to figure out the process in between those two points. Commented Mar 11, 2018 at 7:57
  • JSON is a parameter being passed into the function but I don’t believe it’s actually doing anything. Anyway, I’ll try to post the requested information. Commented Mar 11, 2018 at 8:04

2 Answers 2

0

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>
Sign up to request clarification or add additional context in comments.

6 Comments

It works great, thank you! However, it needs to be a bit more dynamic as there are many dozens of possible values so I either want to pre-choose those I need (and not show any without values) or show only those from the entire list of possibilities where there are values but doing the latter makes it difficult to sort them in any way.
@DonP I've rewritten my answer. Please have another look and let me know what still needs to be adjusted.
Didn’t see the updates until now and will check it out when I return as I am traveling at the moment. What I had posted below as an answer is actually working perfectly on my development system and is exactly what I want but crashes on the live server, possibly due to the live sever having earlier versions of PHP and Apache.
I re-posted my original question to reflect the working code's current issue with the live server. Note that it needs only VIN(s) passed into the function and will provide the needed output now without the need of an array of possible fields once I realized the scope of the available fields. It turned out that there were far too many to be able to pick a few so I opted to show any fields with a value instead. Still need help with the crashing on the live server and to make it work if passing in multiple VINs as a semicolon-separated list. Passing as an array is not an option.
Okay, I'll adjust my answer when I get a chance. You should really try to upgrade your php version asap. The short array syntax comes with php 5.4 and up: php.net/manual/en/migration54.new-features.php
|
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.