2023-02-15T15:21:39.png

背景需求

在部署网站的时候,有时候需要做个个性一点的,比如谈个小窗,并显示访客IP位置信息。
2023-02-15T15:55:30.png
网上免费的IP位置api少之又少,之前搜狐有个接口,小站也是使用了近两年多,但22年底开始发现异常,他们的接口经常崩溃……于是乎,站长有了自己写api的想法。

想法很美好,现实很残忍。从有想法到最后成品上线,站长也是拖拖拉拉的……庆幸的是最终上线了……
目前接口开放给个人站长免费测试使用:IT小圈IP接口 点击左边链接查看接口文档


设计思路

  • 数据库: mariadb
  • 接收脚本:php
  • 接收方式:post
  • 后台逻辑脚本:Shell
  • 系统平台:Linux ,需要 jq 工具
  • 站长注册使用接口,需要验证邮箱的有效性和网址的所有权

开发测试

  • 请求json

    {
    "dtime": "2023-01-30 01:15:33",
    "ukey": "643b4682ddc002b6aec7d178084bbad79bb5093b5b80246af3d43aacd4a57187",
    "ip": "2409:8924:5266:116b:45f:8f2d:a32b:d92c",
    "md5": "05f3dc8a944412ff7d5d692d35924548"
    }
  • 接口返回json

    {
    "Code": "Good",
    "iptype": "IPv6",
    "ip": "2409:8924:5266:116b:45f:8f2d:a32b:d92c",
    "isp": "中国移动无线基站网络",
    "ip_location": "中国江苏省苏州市常熟市",
    "data_src": "IT小圈API",
    "jzstr": "蓦然回首,几个春秋;凉风依旧,岁月不休",
    "Datatime": "2023-02-08 02:33:17"
    }
  • getip.php 部分代码

    <?php
    header('Content-Type:application/json; charset=utf-8');
    header('Access-Control-Allow-Origin:*');
    // 判断请求方式,如果是 GET 直接返回 404
    if ( $_SERVER['REQUEST_METHOD'] != 'POST' ){
      header('HTTP/1.1 404 Not Found');
      header("status: 404 Not Found");
      echo "当前页面仅支持 POST 访问";
      exit();
    }
    // 接收json数据
    $json_input = file_get_contents('php://input');
    ?>
  • Shell 脚本部分代码

    // 主脚本 main_chec.sh  由 getip.php直接调用
    #!/bin/bash
    
    . scripts/public.sh
    . scripts/ip_check.sh
    
    json_data="${1}"
    ukey=$(echo ${json_data} | jq -r .ukey | tr -d ' ')
    cip=$(echo ${json_data} | jq -r .ip | tr -d ' ')
    dtime=$(echo ${json_data} | jq -r .dtime)
    md5=$(echo ${json_data} | jq -r .md5 | tr -d ' ')
    logs_time=$(date "+%F %H:%M:%S")
    
    ## echo ${json_data} > json.txt
    if [ $(echo -n "${json_data}" | jq ". | length") -ne 4 ];then
    sendMsg 1 "Json 消息体长度不符"
    fi
    if [[ ! -n "${dtime}" ]] && [[ ! -n "${ukey}" ]] && [[ ! -n "${cip}" ]] && [[ ! -n "${md5}" ]];then
    sendMsg 1 "Json 主体 'ukey,ip,dtime,md5' 值不能为空"
    fi
    
    ## Time check
    if [ $(( $(date -d "${dtime}" "+%s") + 60 )) -lt $(date "+%s") ];then
    sendMsg 1 "请求超时或时间系统错误"
    fi
    
    ## user check
    userinfo=$(sql "select CONCAT('[',GROUP_CONCAT(JSON_OBJECT('ukey',ukey,'utype',utype,'endtime',endtime,'uenable',uenable,'daymax',daymax,'daycount',daycount)),']') as reluast from ${db_name}.ipuser where  ukey='${ukey}'" | grep ']')
    echo "${userinfo}" | grep -q -w "${ukey}"
    if [ $? -ne 0 ] ;then
    sendMsg 1 "用户key ${ukey} 错误或不存在,请检查或注册"
    fi
    
    if [ $(echo "${userinfo}" | jq -r .[0].uenable) -ne 1 ];then
    sendMsg 1 "用户key ${ukey} 已被禁用,请联系管理员开通"
    fi
    
    if [ $(echo "${userinfo}" | jq -r .[0].daymax) -lt $(echo "${userinfo}" | jq -r .[0].daycount) ];then
    sendMsg 1 "用户key ${ukey} 日请求量已超,请明日再尝试"
    fi
    endtime=$(echo "${userinfo}" | jq -r .[0].endtime)
    if [ $(date -d "${endtime}" "+%s") -lt $(date "+%s") ];then
    sendMsg 1 "用户key ${ukey} 已过有效期,请联系管理员处理"
    fi
    if [ $(echo "${userinfo}" | jq -r .[0].daymax) -ne 999 ];then
    daycount=$(echo "${userinfo}" | jq -r .[0].daycount)
    n=$(( ${daycount} + 1 ))
    sql "update ${db_name}.ipuser set daycount='${n}' where ukey='${ukey}'"
    fi
    
    // ip 查询脚本 ip_check.sh  由 main_chec.sh 调用
    #!/bin/bash
    
    function returnMsg(){
    echo -n "{\"Code\":\"Good\",${1},\"jzstr\":\"${jzstr}\",\"Datatime\":\"$(date '+%F %H:%M:%S')\"}"
    }
    
    function isp_v4(){
    if echo "${isp}" | grep -q '电信';then
      isp='中国电信'
    elif echo "${isp}" | grep -q '联通';then
      isp='中国联通'
    elif echo "${isp}" | grep -q '移动';then
      isp='中国移动'
    elif  echo "${isp}" | grep -q '阿里巴巴';then
      isp='阿里数据中心'
    elif  echo "${isp}" | grep -q 'tencent';then
      isp='腾讯数据中心'
    else
      isp='未知运营商'
    fi
    
    }
    function ip4(){
    if [ $( echo -n ${1} | grep -E '^192.168') ];then
      str=$(returnMsg "\"iptype\":\"IPv4\",\"ip\":\"${cip}\",\"infocode\":\"局域网IP\",\"ip_location\":\"局域网IP\",\"lat\":\"局域网IP\",\"data_src\":\"局域网API\"")
    else
      ipint=$(php scripts/ip.php 1 "${cip}")
      ip_str=$(sql "select CONCAT('[',GROUP_CONCAT(JSON_OBJECT('ip',ipv4,'lat',lat,'lo',local,'isp',isp)),']') as reluast from ${db_name}.ipv4 where ipv4='${ipint}'" | grep ']')
      if echo "${ip_str}" | grep -q -w "${ipint}";then
        lat=$(echo ${ip_str} | jq -r .[0].lat)
        lo=$(echo ${ip_str} | jq -r .[0].lo)
        isp=$(echo ${ip_str} | jq -r .[0].isp)
        str=$(returnMsg "\"iptype\":\"IPv4\",\"ip\":\"${cip}\",\"isp\":\"${isp}\",\"ip_location\":\"${lo}\",\"lat\":\"${lat}\",\"data_src\":\"IT小圈API\"")
      else
        ip_data=$(curl -s "${gmap_url}${cip}&key=${gmap_key}")
        location=$(echo ${ip_data} | jq -r '.country,.province,.city,.district' | tr -d '\n')
        lat=$(echo ${ip_data} | jq -r '.location')
        isp=$(echo ${ip_data} | jq -r '.isp')
        isp_v4
        str=$(returnMsg "\"iptype\":\"IPv4\",\"ip\":\"${cip}\",\"isp\":\"${isp}\",\"ip_location\":\"$location\",\"lat\":\"${lat}\",\"data_src\":\"高德API\"")
        intime=$(date "+%F %H:%M:%S")
        if echo ${location} | grep -q '中国';then
          sql "insert into ${db_name}.ipv4 values('${intime}','${ipint}','${lat}','${location}','${isp}');"
        fi
      fi
    fi
    ip_json="${str//null/}"
    }
    
    function ip6_isp(){
    lo_6=$(echo -n "${lo}" | awk '{print $1}')
    isp_6=$(echo -n "${lo}" | awk '{print $2}')
    }
    function ip6(){
    ip6_str=$(sql "select CONCAT('[',GROUP_CONCAT(JSON_OBJECT('ip',ipv6,'lo',local,'isp',isp)),']') as reluast from ${db_name}.ipv6 where ipv6='${cip}'" | grep ']')
    if echo "${ip6_str}" | grep -q -w "${cip}";then
      lo_6=$(echo "${ip6_str}" | jq -r .[0].lo)
      # ip6_isp
      isp_6=$(echo "${ip6_str}" | jq -r .[0].isp)
      str=$(returnMsg "\"iptype\":\"IPv6\",\"ip\":\"${cip}\",\"isp\":\"${isp_6}\",\"ip_location\":\"${lo_6}\",\"data_src\":\"IT小圈API\"")
    else
      url="${ipv6_url}${cip}"
      lo=$(curl -s ${url} | tr -d '\\t' | jq -r .daa.locaion)
      ip6_isp
      str=$(returnMsg "\"iptype\":\"IPv6\",\"ip\":\"${cip}\",\"isp\":\"${isp_6}\",\"ip_location\":\"${lo_6}\",\"data_src\":\"IPv6临时API\"")
      intime=$(date "+%F %H:%M:%S")
      if echo ${lo} | grep -q '中国';then
        sql "insert into ${db_name}.ipv6 values('${intime}','${cip}','${lo_6}','${isp_6}');"
      fi
    fi
    ip_json="${str//null/}"
    }
    
  • 用户管理部分

    • 用户注册

      // php 接收注册代码
      <?php
      header('Content-Type:application/json; charset=utf-8');
      if ( $_SERVER['REQUEST_METHOD'] != 'POST' ){
      header('HTTP/1.1 404 Not Found');
      header("status: 404 Not Found");
      echo "当前页面仅支持 POST 访问";
      exit();
      }
      $json_input = file_get_contents('php://input');
      $result_data=exec("bash scripts/useradd.sh '$json_input'");
      $result_data = json_decode($result_data,true);
      echo json_encode($result_data,JSON_UNESCAPED_UNICODE);
      ?>
    • 用户验证

      // 主要用于验证注册邮箱的有效性
      <?php
      if ( $_SERVER['REQUEST_METHOD'] != 'GET' ){
      header('HTTP/1.1 404 Not Found');
      header("status: 404 Not Found");
      echo "当前页面仅支持 GET 访问";
      exit();
      }
      $ukey = $_GET['ukey'];
      $dtime = $_GET['dtime'];
      if ( ! array_key_exists ('ukey',$_GET) || ! array_key_exists ('dtime',$_GET) ){
      header('HTTP/1.1 404 Not Found');
      header("status: 404 Not Found");
      exit();
      }
      $ukey = $_GET['ukey'];
      $dtime = $_GET['dtime'];
      $r_data = json_decode(exec("bash scripts/usercheck.sh '$ukey' '$dtime'"),true);
      echo '<script>alert("'.$r_data['Datatime'].'\n'.$r_data['Msg'].'");</script>';
      ?>
  • 发送邮箱

    • 邮箱发送考虑到格式问题,这里主要用到 PHPMailer
      2023-02-15T16:00:57.png
      2023-02-15T16:01:43.png

总结

  • 整体来说开发还算顺利
  • 其实整个开发也是可以基于php来开发的,只是我比较偏向shell脚本,所以更多就用了shell
  • 用户验证之前想过验证码问题,但是后面考虑一下,借鉴目前各大厂在注册时都会发送一个验证邮件的方法,所以验证码也就不用了,这样整体逻辑还比较容易实现
  • 代码写多了,现在喜欢写 function 了,在调用的时候真心的方便
  • 代码是考虑开源的,但还没有完全测试通过,待测试通过后会公布出来

上述就是我这次的接口开发,不管干啥首先你得清楚你需要啥、你手里有啥,然后再组织逻辑,最后逐一去实现!!

「 希望熬过一切,星光璀璨 」

流年小站,感谢有您的支持

「 道路坎坷,感谢有您 ---来自 anYun 的感谢 」

使用微信扫描二维码完成支付

2023-02-15
已阅:6529 人/次

 
 
 
分享是一种美德 x
打开微信,右上角的"+"选择"扫一扫"
使用“扫一扫”将博文分享至朋友圈吧

本文由 anYun 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=3oibnoh9lo6cs

还不快抢沙发

添加新评论

Myssl安全认证