Skocz do zawartości
PrzMas

GeoIp (API)

Rekomendowane odpowiedzi

W niniejszym temacie publikuję skrypt na pozyskiwanie geolokalizacji adresu IP
z bazy danych serwisu ip-api.com, za pośrednictwem API.

 

Implementacje użytych funkcji:

Spoiler

stock ip2long(ip[])
{
  new res= 0x00000000, oct= 0;
  for(new idx= 0, val= 0, len= strlen(ip); oct < 4 && idx < len; oct++, idx++, val= 0)
  {
    for(new i= idx, j= 2; i < len-1; i++)
    {
      if (i-idx >= j) return 0x00000000;
      else if ('0' <= ip[i] <= '9') idx++;
      else if (ip[i] == '*') { j= 1; val= 0x00; break; }
      else if (ip[i] == '.') { idx= i; break; }
      else return 0x00000000;
    }
    if (ip[idx] == '.' && (idx == 0 || ip[--idx] == '.')) return 0x00000000;
    if (ip[idx] != '*') for(new i= idx, exp= 1; i >= 0 && ip[i] != '.'; i--)
    {
      if (!('0' <= ip[i] <= '9') || idx-i > 2) return 0x00000000;
      val += (ip[i]-'0')*exp; exp *= 10;
      if (val > 0xff) return 0x00000000;
    }
    res <<= 8; res += val; idx++;
  }

  if (oct < 4) return 0x00000000
  else return res << ((4-oct)*8);
}

[temat]

Spoiler

stock strtok(dst[], src[], &idx, key= ' ', pos= 0, dst_sz= sizeof dst, src_ln= -1) // string to key
{
  if (pos >= dst_sz) return 0;

  new start= idx;
  for(new len= (src_ln < 0)?(strlen(src)):(src_ln); 0 <= idx < len; idx++)
  {
    if (!(0 <= idx-start < dst_sz)) return idx-start;
    if (src[idx] == 0x00 || src[idx] == 0x0D || src[idx] == 0x0A || src[idx] == key) break; // NULL, CR, LF, key
    dst[pos+idx-start]= src[idx];
  }

  dst[pos+idx-start]= 0; // EoS

  return pos+(idx++)-start;
}

 

Spoiler

stock json_getval(dest[], src[], field[], start= 0, dest_sz= sizeof dest)
{
  new slen= strlen(src);
  new flen= strlen(field);
  if (slen == 0 || flen == 0) return start;

  new idx= strfind(src, field, true, start);
  if (idx >= 0) idx += flen;
  else return start;

  dest[0]= 0;

  for(; idx < slen; idx++)
  {
    if (src[idx] == '"' || src[idx] == ':' || src[idx] == ' ') continue;
    else if (src[idx] == ',') return idx;
    else break;
  }

  new dlen= strtok(dest, src, idx, '"', 0, dest_sz, slen);
  if (dest[dlen-1] == ',') { dest[--dlen]= 0; idx--; }

  return dlen;
}

 

Spoiler

stock utf8_decode(str[], len= -1)
{
  if (len == 0) return 0;
  new slen= (len < 0)?(strlen(str)):(len);

  for(new i= 1; i < slen; i++)
  {
    switch(str[i-1])
    {
      case '0'..'9','A'..'Z','a'..'z': continue;

      case 0xC3: switch(str[i])
      {
        case 0x80..0xBF: str[i-1]= str[i]+0x40;
        default: continue;
      }
      case 0xC4: switch(str[i])
      {
        case 0x84: str[i-1]= 'Ą';
        case 0x85: str[i-1]= 'ą';
        case 0x86: str[i-1]= 'Ć';
        case 0x87: str[i-1]= 'ć';
        case 0x98: str[i-1]= 'Ę';
        case 0x99: str[i-1]= 'ę';
        default: continue;
      }
      case 0xC5: switch(str[i])
      {
        case 0x81: str[i-1]= 'Ł';
        case 0x82: str[i-1]= 'ł';
        case 0x83: str[i-1]= 'Ń';
        case 0x84: str[i-1]= 'ń';
        case 0x9A: str[i-1]= 'Ś';
        case 0x9B: str[i-1]= 'ś';
        case 0xB9: str[i-1]= 'Ź';
        case 0xBA: str[i-1]= 'ź';
        case 0xBB: str[i-1]= 'Ż';
        case 0xBC: str[i-1]= 'ż';
        default: continue;
      }

      default: continue;
    }

    strdel(str, i, i+1); slen--;
  }

  return slen;
}

Tylko dla polskich znaków!

 

Skrypt właściwy:

Spoiler

#include <a_samp>
#include <a_http>

// implementacje wyżej wymienionych funkcji
  
forward internal_OnGetPlayerGeoIp(playerid, http_code, data[]);
public internal_OnGetPlayerGeoIp(playerid, http_code, data[])
{
  if (http_code != 200) return;

  new ip[IP_MAXLEN+1]; json_getval(ip, data, "query");
  new timezone[32]; json_getval(timezone, data, "timezone");
  new country[32]; json_getval(country, data, "country"); utf8_decode(country);
  new city[32]; json_getval(city, data, "city"); utf8_decode(city);
  new isp[48]; json_getval(isp, data, "as"); utf8_decode(isp);
  new org[48]; json_getval(org, data, "org"); utf8_decode(org);

  CallRemoteFunction("OnGetPlayerGeoIp", "dssssss", playerid,ip,(timezone[0]!=0)?("null"):(timezone),(country[0]!=0)?("null"):(country),(city[0]!=0)?("null"):(city),(isp[0]!=0)?("null"):(isp),(org[0]!=0)?("null"):(org));
}

forward remote_GetPlayerGeoIp(playerid, ip[]);
public remote_GetPlayerGeoIp(playerid, ip[])
{
  if (!IsPlayerConnected(playerid)) return false;
  new ip2= ip2long(ip);
  if (ip2 == 0x00000000 || ip2 == 0x7f000001) return false; // 0.0.0.0, 127.0.0.1

  new url[32];
  format(url, sizeof(url), "ip-api.com/json/%s", ip);
  return HTTP(playerid, HTTP_GET, url, "", "internal_OnGetPlayerGeoIp");
}

public OnFilterScriptInit()
{
  // ...

  return 1;
}

public OnFilterScriptExit()
{
  // ...

  return 1;
}

 

 

Sposób użycia:

Spoiler

forward OnGetPlayerGeoIp(playerid, ip[], timezone[], country[], city[], isp[], org[]);
stock GetPlayerGeoIp(playerid, ip[]) return CallRemoteFunction("remote_GetPlayerGeoIp", "ds", playerid,ip);

public OnPlayerConnect(playerid)
{
  new ip[15+1]; GetPlayerIp(playerid, ip, sizeof(ip));
  GetPlayerGeoIp(playerid, ip);

  return 1;
}

public OnGetPlayerGeoIp(playerid, ip[], timezone[], country[], city[], isp[], org[])
{
  // wyświetlenie zwróconych informacji
}

 

Myślę, że choć jest trochę kodu to nie ma tu czego objaśniać, skoro sposób użycia jest dość prosty i skuteczny.
Proszę o wspomnienie mnie jako autora niniejszego skryptu :rolleyes:

Skrypt alternatywny

Edytowane przez PrzMas

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

Dobre, jednak mogłeś to dodać w formie include, a funkcje, które są w tym użyte dać pod #if defined ;)
Dodatkowo mały hook dla OnPlayerConnect i cała zabawa dla początkującego to "#include <geoip>".

Udostępnij tę odpowiedź


Odnośnik do odpowiedzi
Udostępnij na innych stronach

  • Przeglądający   0 użytkowników

    Brak zarejestrowanych użytkowników przeglądających tę stronę.

×