Plugin Directory

Changeset 2782903


Ignore:
Timestamp:
09/11/2022 05:17:06 AM (4 years ago)
Author:
jwz
Message:

Version 1.1

Location:
geolocate-comments
Files:
2 edited
3 copied

Legend:

Unmodified
Added
Removed
  • geolocate-comments/tags/1.1/geolocate-comments.php

    r2738898 r2782903  
    33Plugin Name: Geolocate Comments
    44Plugin URI: https://www.jwz.org/geolocate-comments/
    5 Version: 1.0
     5Version: 1.1
    66Description: Save the geolocation when a new comment is posted.
    77Author: Jamie Zawinski
     
    4848// Returns an array with geolcation details, such as they are, or undef.
    4949//
    50 function geolocate_ip($ip) {
     50function geolocate_ip ($ip) {
    5151
    5252  global $geolocate_comments_plugin_name;
     
    6969  if (!count($urls)) return;
    7070
    71   $url = $urls[rand() % count($urls)];
     71  $i = rand() % count($urls);
     72  $url = $urls[$i];
    7273  $url = preg_replace ('/%s/', $ip, $url);
    7374
    74   $response = wp_remote_get ($url);
    75   $code = wp_remote_retrieve_response_code ($response);
    76   if (! preg_match ('/^2\d\d/', $code)) {
    77     error_log ("geolocate: error $code: $url");
     75  $retries = 5;         // Retry if we get a null response back.
     76  while ($retries > 0) {
     77
     78    $err = '';
     79    $response = wp_remote_get ($url);
     80
     81    $code = wp_remote_retrieve_response_code ($response);
     82    if (! preg_match ('/^2\d\d/', $code)) {
     83      $err = ($err ? "$err: " : "") . "error" . ($code ? " $code" : "");
     84    }
     85
     86    $txt = wp_remote_retrieve_body ($response);
     87    if ($txt) break;
     88
     89    $err = ($err ? "$err: " : "") . "null response";
     90    $retries--;
     91    if ($retries > 0)
     92      sleep (1);
     93  }
     94
     95  // Retrieve the JSON even if not 2xx, as it might contain an error message.
     96  //
     97  $json = null;
     98  if ($txt) {
     99    $json = json_decode ($txt, true);
     100    if (!$json && !$err) {
     101      $err = (($err ? "$err: " : "") .
     102              "JSON parse error: $json: " . json_last_error_msg());
     103    }
     104  }
     105
     106  if ($json) {
     107    $errmsg = ($json['response'] ? $json['response'] :   // ip2location.com
     108               ($json['message'] ? $json['message']  :   // ipbase.com
     109                ''));
     110    if (preg_match ('/^OK/i', $errmsg))
     111      $errmsg = '';
     112    if ($errmsg)
     113      $err = ($err ? "$err: " : "") . "error: $errmsg";
     114  }
     115
     116  if ($err) {
     117    error_log ("geolocate: $err: $url");
    78118    return;
    79119  }
    80120
    81   $txt = wp_remote_retrieve_body ($response);
    82   if (!$txt) {
    83     error_log ("geolocate: null response: $url");
    84     return;
    85   }
    86 
    87   $json = json_decode ($txt, true);
    88   if (!$json) {
    89     error_log ("JSON parse error: $url: $json: " . json_last_error_msg());
    90     return;
    91   }
    92 
    93   if (preg_match ('/ip2location\.com/', $url) &&
    94       ($json['response'] ?? '') != 'OK') {
    95     error_log ("geolocate: bad response: $url: $txt");
     121  if ($json['data']) {
     122    $json = $json['data'];  // ipbase.com/v2/ rather than ipbase.com/json/
    96123  }
    97124
     
    127154    $city = "";
    128155    if ($loc) {
     156
     157      // ipbase.com/json/%s returns flat data with keys:
     158      //   { ip, country_code, country_name, region_code, region_name, city,
     159      //     zip_code, time_zone, latitude, longitude, metro_code }
     160      //
     161      // But ipbase.com/v2/info/?ip= returns much more verbose nested data:
     162      //   { data: { location: { country: { name_translated: "..."
     163      //
     164      // And both screw up Unicode: "Bratislavsk\u{FFFD}".
     165      //
     166      if (is_array ($loc['location'] ?? null)) {
     167        $loc2 = $loc['location'];
     168        foreach (array('country', 'region', 'city') as $f) {
     169          if (is_array ($loc2[$f] ?? null)) {
     170            $loc[$f . '_name'] = $loc2[$f]['name_translated'] ?? null;
     171          }
     172        }
     173      }
     174
    129175      $country = $loc['country_name'] ?? '';
    130       $state   = $loc['region_name'] ?? '';
    131       $city    = $loc['city_name'] ?? '';
     176      $state   = $loc['region_name']  ?? '';
     177      $city    = $loc['city_name']    ?? '';
    132178      if (!$city)
    133179        $city  = $loc['city'] ?? '';
     
    177223  $ip = $comment->comment_author_IP;
    178224  if (!$ip) return;
     225  $loc = get_comment_meta ($id, 'geolocation', true);
     226  if ($loc) return;
    179227  $loc = geolocate_ip ($ip);
    180228  if (!$loc) return;
     
    289337}
    290338
     339// Format the raw JSON from the geolocation service into something vaguely
     340// human-readable.
     341//
     342function geolocate_pretty_print_json ($a) {
     343  $s = array();
     344  foreach ($a as $key => $val) {
     345
     346    if ($key == 'languages' || $key == 'currencies' ||  // Omit these, boring
     347        $key == 'timezones' || $key == 'timezone' ||
     348        $key == 'connection' || $key == 'continent')
     349      continue;
     350
     351    $s[] = ("<B>" . htmlspecialchars($key) . ":</B> " .
     352            (is_array ($val)
     353             ? "{" . geolocate_pretty_print_json ($val) . "}"
     354             : ($val === true ? 'true' :
     355                ($val === false ? 'false' :
     356                 ($val === null ? 'null' :
     357                  htmlspecialchars ($val))))));
     358  }
     359  return implode ('; ', $s);
     360}
     361
    291362function geolocate_meta_box_cb ($comment) {
    292363  $loc = get_comment_meta ($comment->comment_ID, 'geolocation', true);
     
    299370    unset($loc['ip']);
    300371    $loc['IP'] = $ip;
    301     $s = array();
    302     foreach ($loc as $key => $val) {
    303       $s[] = "<B>" . htmlspecialchars($key) . ":</B> " .
    304              htmlspecialchars($val);
    305     }
    306     print implode ('; ', $s);
     372    print geolocate_pretty_print_json ($loc);
    307373  }
    308374}
  • geolocate-comments/tags/1.1/readme.txt

    r2738898 r2782903  
    44Tags: Geolocation, Comments
    55Requires at least: 2.7
    6 Tested up to: 6.0
    7 Stable tag: 1.0
     6Tested up to: 6.0.2
     7Stable tag: 1.1
    88License: MIT
    99
     
    3131* Created
    3232
     33= 1.1 =
     34* Retry on network failures.
     35* Support a few other sites.
     36
  • geolocate-comments/trunk/geolocate-comments.php

    r2738898 r2782903  
    33Plugin Name: Geolocate Comments
    44Plugin URI: https://www.jwz.org/geolocate-comments/
    5 Version: 1.0
     5Version: 1.1
    66Description: Save the geolocation when a new comment is posted.
    77Author: Jamie Zawinski
     
    4848// Returns an array with geolcation details, such as they are, or undef.
    4949//
    50 function geolocate_ip($ip) {
     50function geolocate_ip ($ip) {
    5151
    5252  global $geolocate_comments_plugin_name;
     
    6969  if (!count($urls)) return;
    7070
    71   $url = $urls[rand() % count($urls)];
     71  $i = rand() % count($urls);
     72  $url = $urls[$i];
    7273  $url = preg_replace ('/%s/', $ip, $url);
    7374
    74   $response = wp_remote_get ($url);
    75   $code = wp_remote_retrieve_response_code ($response);
    76   if (! preg_match ('/^2\d\d/', $code)) {
    77     error_log ("geolocate: error $code: $url");
     75  $retries = 5;         // Retry if we get a null response back.
     76  while ($retries > 0) {
     77
     78    $err = '';
     79    $response = wp_remote_get ($url);
     80
     81    $code = wp_remote_retrieve_response_code ($response);
     82    if (! preg_match ('/^2\d\d/', $code)) {
     83      $err = ($err ? "$err: " : "") . "error" . ($code ? " $code" : "");
     84    }
     85
     86    $txt = wp_remote_retrieve_body ($response);
     87    if ($txt) break;
     88
     89    $err = ($err ? "$err: " : "") . "null response";
     90    $retries--;
     91    if ($retries > 0)
     92      sleep (1);
     93  }
     94
     95  // Retrieve the JSON even if not 2xx, as it might contain an error message.
     96  //
     97  $json = null;
     98  if ($txt) {
     99    $json = json_decode ($txt, true);
     100    if (!$json && !$err) {
     101      $err = (($err ? "$err: " : "") .
     102              "JSON parse error: $json: " . json_last_error_msg());
     103    }
     104  }
     105
     106  if ($json) {
     107    $errmsg = ($json['response'] ? $json['response'] :   // ip2location.com
     108               ($json['message'] ? $json['message']  :   // ipbase.com
     109                ''));
     110    if (preg_match ('/^OK/i', $errmsg))
     111      $errmsg = '';
     112    if ($errmsg)
     113      $err = ($err ? "$err: " : "") . "error: $errmsg";
     114  }
     115
     116  if ($err) {
     117    error_log ("geolocate: $err: $url");
    78118    return;
    79119  }
    80120
    81   $txt = wp_remote_retrieve_body ($response);
    82   if (!$txt) {
    83     error_log ("geolocate: null response: $url");
    84     return;
    85   }
    86 
    87   $json = json_decode ($txt, true);
    88   if (!$json) {
    89     error_log ("JSON parse error: $url: $json: " . json_last_error_msg());
    90     return;
    91   }
    92 
    93   if (preg_match ('/ip2location\.com/', $url) &&
    94       ($json['response'] ?? '') != 'OK') {
    95     error_log ("geolocate: bad response: $url: $txt");
     121  if ($json['data']) {
     122    $json = $json['data'];  // ipbase.com/v2/ rather than ipbase.com/json/
    96123  }
    97124
     
    127154    $city = "";
    128155    if ($loc) {
     156
     157      // ipbase.com/json/%s returns flat data with keys:
     158      //   { ip, country_code, country_name, region_code, region_name, city,
     159      //     zip_code, time_zone, latitude, longitude, metro_code }
     160      //
     161      // But ipbase.com/v2/info/?ip= returns much more verbose nested data:
     162      //   { data: { location: { country: { name_translated: "..."
     163      //
     164      // And both screw up Unicode: "Bratislavsk\u{FFFD}".
     165      //
     166      if (is_array ($loc['location'] ?? null)) {
     167        $loc2 = $loc['location'];
     168        foreach (array('country', 'region', 'city') as $f) {
     169          if (is_array ($loc2[$f] ?? null)) {
     170            $loc[$f . '_name'] = $loc2[$f]['name_translated'] ?? null;
     171          }
     172        }
     173      }
     174
    129175      $country = $loc['country_name'] ?? '';
    130       $state   = $loc['region_name'] ?? '';
    131       $city    = $loc['city_name'] ?? '';
     176      $state   = $loc['region_name']  ?? '';
     177      $city    = $loc['city_name']    ?? '';
    132178      if (!$city)
    133179        $city  = $loc['city'] ?? '';
     
    177223  $ip = $comment->comment_author_IP;
    178224  if (!$ip) return;
     225  $loc = get_comment_meta ($id, 'geolocation', true);
     226  if ($loc) return;
    179227  $loc = geolocate_ip ($ip);
    180228  if (!$loc) return;
     
    289337}
    290338
     339// Format the raw JSON from the geolocation service into something vaguely
     340// human-readable.
     341//
     342function geolocate_pretty_print_json ($a) {
     343  $s = array();
     344  foreach ($a as $key => $val) {
     345
     346    if ($key == 'languages' || $key == 'currencies' ||  // Omit these, boring
     347        $key == 'timezones' || $key == 'timezone' ||
     348        $key == 'connection' || $key == 'continent')
     349      continue;
     350
     351    $s[] = ("<B>" . htmlspecialchars($key) . ":</B> " .
     352            (is_array ($val)
     353             ? "{" . geolocate_pretty_print_json ($val) . "}"
     354             : ($val === true ? 'true' :
     355                ($val === false ? 'false' :
     356                 ($val === null ? 'null' :
     357                  htmlspecialchars ($val))))));
     358  }
     359  return implode ('; ', $s);
     360}
     361
    291362function geolocate_meta_box_cb ($comment) {
    292363  $loc = get_comment_meta ($comment->comment_ID, 'geolocation', true);
     
    299370    unset($loc['ip']);
    300371    $loc['IP'] = $ip;
    301     $s = array();
    302     foreach ($loc as $key => $val) {
    303       $s[] = "<B>" . htmlspecialchars($key) . ":</B> " .
    304              htmlspecialchars($val);
    305     }
    306     print implode ('; ', $s);
     372    print geolocate_pretty_print_json ($loc);
    307373  }
    308374}
  • geolocate-comments/trunk/readme.txt

    r2738898 r2782903  
    44Tags: Geolocation, Comments
    55Requires at least: 2.7
    6 Tested up to: 6.0
    7 Stable tag: 1.0
     6Tested up to: 6.0.2
     7Stable tag: 1.1
    88License: MIT
    99
     
    3131* Created
    3232
     33= 1.1 =
     34* Retry on network failures.
     35* Support a few other sites.
     36
Note: See TracChangeset for help on using the changeset viewer.