What is the most efficient way to get a part of a remote XML file via PHP?

前端 未结 2 742
粉色の甜心
粉色の甜心 2021-01-19 05:31

I\'m trying to get a portion of a remote XML file, in this case longitude and latitude for a zip code via Google Maps. This is the function I am currently using:

<         


        
相关标签:
2条回答
  • 2021-01-19 06:17

    Unless the service provides this functionality you can't request for a partial response based on a selector (e.g. XPath / CSS).

    Regarding efficiency, I would recommend breaking down the request time as detailed as possible to figure out why a certain request takes a while. cURL has pretty good support for this, e.g.:

    $zip = urlencode('1 infinite loop');
    $ch = curl_init("http://maps.googleapis.com/maps/api/geocode/xml?address={$zip}&sensor=false");
    curl_exec($ch);
    print_r(curl_getinfo($ch));
    

    This yields an array with all the meta data of your request:

    Array
    (
        ...
        [total_time] => 0.11955
        [namelookup_time] => 0.02996
        [connect_time] => 0.035803
        [pretransfer_time] => 0.035874
        ...
        [size_upload] => 0
        [size_download] => 1737
        [speed_download] => 14529
        [speed_upload] => 0
        [download_content_length] => -1
        [upload_content_length] => 0
        [starttransfer_time] => 0.119444
        [redirect_time] => 0
        ...
    )
    

    With this data you can craft the appropriate approach to handle the issue. Caching the responses may alleviate the request times for oft repeated searches, but it may not work for your particular case.

    0 讨论(0)
  • 2021-01-19 06:24

    What is the most efficient way to get a part of a remote XML file via PHP?

    This question can not be specifically answered as this has many implications.

    Actually you're dealing with a remote service here. I normally suggest to always wrap / proxy these (compare: The Daily Mistake: Not to Proxy Remote Services). This is because they always come with many implications. You partly do this already by wrapping the data-retrieval into a function:

    function slug_get_coordinates( $zip ) {
        $url = "http://maps.googleapis.com/maps/api/geocode/xml?address={$zip}&sensor=false";
        $result = simplexml_load_file( $url );
        $coordinates = $result->result->geometry->location;
        return $coordinates;
    }
    

    However this single function is not enough to deal with all problems such a service can come with. E.g. the remote location might just be down - of which such a response timeout could qualify - or as you experience it as well, it just takes too long.

    So you are basically not satisfied with the quality of service.

    As it's common with remote services that you can not fully control them and you have little influence on the quality of service, wrapping it has the benefits that you can deal with such problems within the wrapper so to shield the rest of your application logic from all these implications.

    This requires you not only to encapsulate the parsing of the data (like you started to do with the function you have), but as well the retrieval (the remote request). You also need to have error handling which is missing in your function. Another hint here is to design for failure. E.g. have your application still work, even the information you try to retrieve (to add) is missing.

    Another benefit of such a proxy is, that you can implement debugging functionality there-in. For example, with the code you've provided, I have no problem at all to retrieve the data quickly:

    $zip = '55416';
    
    $start = microtime(true);
    
    slug_get_coordinates($zip)->asXML('php://output');
    
    printf("\n----\nTook %.5f seconds\n", microtime(true) - $start);
    

    Output:

    <location>
        <lat>44.9465193</lat>
        <lng>-93.3439291</lng>
       </location>
    ----
    Took 0.11873 seconds
    

    If you need to look deeper into the remote request, you can hook into PHP's stream notifications. I've compiled a StreamNotifyPrinter which does the legwork for that and which can be easily registered:

    $zip = '55416';
    
    $notifier = new StreamNotifyPrinter();
    libxml_set_streams_context($notifier->registerOnContext());
    
    $start = microtime(true);
    
    slug_get_coordinates($zip)->asXML('php://output');
    
    printf("\n----\nTook %.5f seconds\n", microtime(true) - $start);
    

    Output:

    2014-07-12T09:07:40.146422+0000 [0.00000] Connected...
    2014-07-12T09:07:40.228122+0000 [0.08170] Found the mime-type: application/xml; charset=UTF-8
    2014-07-12T09:07:40.228251+0000 [0.08183] Made some progress, downloaded 0 so far
    2014-07-12T09:07:40.228341+0000 [0.08192] Made some progress, downloaded 757 so far
    <location>
        <lat>44.9465193</lat>
        <lng>-93.3439291</lng>
       </location>
    ----
    Took 0.11873 seconds
    

    If this information is not enough, you might want to switch the transport layer (e.g. with Curl as Jack suggested, which has a more specialized API for debugging the request; see Php - Debugging Curl).

    To the last resort: In case you can not solve the problem through trouble-shooting, having it wrapped properly might make it easy to replace the remote-service with a better working database. But perhaps checkout if geo-coordinates are actually well working with ZIP codes: Where can I obtain an up-to-date list of US ZIP Codes with Latitude and Longitude Geocodes?.

    0 讨论(0)
提交回复
热议问题