php获取用户真实IP和防刷机制的实例代码


Posted in PHP onNovember 28, 2018

一. 如何获取用户IP地址

public static function getClientIp()
 {
 if (getenv('HTTP_CLIENT_IP')) {
  $ip = getenv('HTTP_CLIENT_IP');
 }
 if (getenv('HTTP_X_REAL_IP')) {
  $ip = getenv('HTTP_X_REAL_IP');
 } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
  $ip = getenv('HTTP_X_FORWARDED_FOR');
  $ips = explode(',', $ip);
  $ip = $ips[0];
 } elseif (getenv('REMOTE_ADDR')) {
  $ip = getenv('REMOTE_ADDR');
 } else {
  $ip = '0.0.0.0';
 }

 return $ip;
 }

 注意:

$_SERVER和getenv的区别,getenv不支持IIS的isapi方式运行的php
getenv(“REMOTE_ADDR”)函数在 apache下能正常获取ip地址,而在iis中没有作用,而$_SERVER['REMOTE_ADDR']函数,既可在apache中成功获取访客的ip地址,在iis下也同样有效

一、关于 REMOTE_ADDR

这个变量获取到的是《直接来源》的 IP 地址,所谓《直接来源》指的是直接请求该地址的客户端 IP 。这个 IP 在单服务器的情况下,很准确的是客户端 IP ,无法伪造。当然并不是所有的程序都一定是单服务器,比如在采用负载均衡的情况(比如采用 haproxy 或者 nginx 进行负载均衡),这个 IP 就是转发机器的 IP ,因为过程是客户端->负载均衡->服务端。是由负载均衡直接访问的服务端而不是客户端。

二、关于 HTTP_X_FORWARDED_FOR 和 HTTP_CLIENT_IP
基于《一》,在负载均衡的情况下直接使用 REMOTE_ADDR 是无法获取客户端 IP 的,这就是一个问题,必须解决。于是就衍生出了负载均衡端将客户端 IP 加入到 HEAD 中发送给服务端,让服务端可以获取到客户端的真实 IP 。当然也就产生了各位所说的伪造,毕竟 HEAD 除了协议里固定的那几个数据,其他数据都是可自定义的。

三、为何网上找到获取客户端 IP 的代码都要依次获取 HTTP_CLIENT_IP 、 HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR
基于《一》和《二》以及对程序通用性的考虑,所以才这样做。 假设你在程序里直接写死了 REMOTE_ADDR ,有一天你们的程序需要做负载均衡了,那么你有得改了。当然如果你想这么做也行,看个人爱好和应用场景。也可以封装一个只有 REMOTE_ADDR 的方法,等到需要的时候改这一个方法就行了。

总结:

HTTP_CLIENT_IP: 头是有的,只是未成标准,不一定服务器都实现了。

X-Forwarded-For(XFF):  是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段, 格式:clientip,proxy1,proxy2

REMOTE_ADDR: 是可靠的, 它是最后一个跟你的服务器握手的IP,可能是用户的代理服务器,也可能是自己的反向代理。

X-Forwarded-For 和 X-Real-IP区别:

X-Forwarded-For是用于记录代理信息的,每经过一级代理(匿名代理除外),代理服务器都会把这次请求的来源IP追加在X-Forwarded-For中, 而X-Real-IP,没有相关标准, 其值在不同的代理环境不固定

关于此的更多讨论可以参考:https://www.douban.com/group/topic/27482290/

1. 负载均衡情况:

php获取用户真实IP和防刷机制的实例代码

生产环境中很多服务器隐藏在负载均衡节点后面,你通过REMOTE_ADDR只能获取到负载均衡节点的ip地址,一般的负载均衡节点会把前端实际的ip地址通过HTTP_CLIENT_IP或者HTTP_X_FORWARDED_FOR这两种http头传递过来。

后端再去读取这个值就是真实可信的,因为它是负载均衡节点告诉你的而不是客户端。但当你的服务器直接暴露在客户端前面的时候,请不要信任这两种读取方法,只需要读取REMOTE_ADDR就行了

2. CDN的情况:

php获取用户真实IP和防刷机制的实例代码

所以对于我们获取用户的IP,应该截取http_x_forwarded_for的第一个有效IP(非unknown)。

多层代理时,和cdn方式类似。

注意:

无论是REMOTE_ADDR还是HTTP_FORWARDED_FOR,这些头消息未必能够取得到,因为不同的浏览器不同的网络设备可能发送不同的IP头消息

 二. 防止IP注入攻击

加入以下代码防止IP注入攻击:

// IP地址合法验证, 防止通过IP注入攻击
$long = sprintf("%u", ip2long($ip));
$ip = $long ? array($ip, $long) : array('0.0.0.0', 0);

一般获取IP后更新到数据库代码如: $sql="update t_users set login_ip='".get_client_ip()."' where ..." ,而如果接收到的ip地址是: xxx.xxx.xxx.xxx';delete from t_users;--  ,代入参数SQL语句就变成了: "update t_users set login_ip='xxx.xxx.xxx.xxx';delete from t_users;-- where ...

所以获取IP地址后,务必使用正则等对IP地址的有效性进行验证,另外一定要使用参数化SQL命令

 解析:

sprintf() 函数把格式化的字符串写入变量中。
•%u - 不包含正负号的十进制数(大于等于 0)

int ip2long ( string $ip_address ) :

返回IP地址转换后的数字 或 FALSE 如果 ip_address 是无效的。

注意 :

例子说明打印一个转换后的地址使用 printf() 在PHP4和PHP5的功能:

<?php
$ip = gethostbyname('www.example.com');
$long = ip2long($ip);
if ($long == -1 || $long === FALSE) {
 echo 'Invalid IP, please try again';
} else {
 echo $ip . "\n";  // 192.0.34.166
 echo $long . "\n";  // -1073732954
 printf("%u\n", ip2long($ip)); // 3221234342
}
?>

1. 因为PHP的 integer 类型是有符号,并且有许多的IP地址讲导致在32位系统的情况下为负数, 你需要使用 "%u" 进行转换通过 sprintf() 或printf() 得到的字符串来表示无符号的IP地址。

2. ip2long() 将返回 FALSE 在IP是 255.255.255.255 的情况,版本为 PHP 5 <= 5.0.2. 在修复后 PHP 5.0.3 会返回 -1 (与PHP4相同)

三. 防刷机制

对于获取到IP后我们可以做一些防刷操作:

//ip限额
$ip = getClientIp();
$ipKey = "activity_key_{$ip}";
if (!frequencyCheckWithTimesInCache($ipKey, $duration, $limitTimes)) {
 return false;
}
return true;
// 限制id,在$second时间内,最多请求$times次 

public static function frequencyCheckWithTimesInCache($id, $second, $times)
 {
 $value = Yii::app()->cache->get($id);
 if (!$value) {
  $data[] = time();
  Yii::app()->cache->set($id, json_encode($data), $second);

  return true;
 }
 $data = json_decode($value, true);
 if (count($data) + 1 <= $times) {
  $data[] = time();
  Yii::app()->cache->set($id, json_encode($data), $second);

  return true;
 }

 if (time() - $data[0] > $second) {
  array_shift($data);
  $data[] = time();
  Yii::app()->cache->set($id, json_encode($data), $second);

  return true;
 }

 return false;
 }

举例:

限制每小时请求不超过50次

if (!frequencyCheckWithTimesInCache('times_uid_' . $uid, 3600, 50)) {
  return '请求过于频繁';
 }

防刷升级限制设备号:

//设备号 一个设备号最多只能抽奖3次
 if(! empty($deviceId)){
  $deviceUseChance = Yii::app()->db->createCommand()
   ->select('count(id)')->from('activity00167_log')
   ->where('device_id=:deviceId',['deviceId'=>$deviceId])
   ->queryScalar();
  $deviceChance = 3 - $deviceUseChance;
 }

对于获取IP地址还可以在大数据分析用户的地理位置,比如做一些精准投放等工作。

总结

以上所述是小编给大家介绍的php获取用户真实IP和防刷机制的实例代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

PHP 相关文章推荐
创建配置文件 用PHP写出自己的BLOG系统 2
Apr 12 PHP
PHP XML error parsing SOAP payload on line 1
Jun 17 PHP
php操作JSON格式数据的实现代码
Dec 24 PHP
基于PHP Web开发MVC框架的Smarty使用说明
Apr 19 PHP
兼容各大浏览器带关闭按钮的漂浮多组图片广告代码
Jun 05 PHP
ThinkPHP模板自定义标签使用方法
Jun 26 PHP
详解PHP中cookie和session的区别及cookie和session用法小结
Jun 12 PHP
Yii实现复选框批量操作实例代码
Mar 15 PHP
PHP基于方差和标准差计算学生成绩的稳定性示例
Jul 04 PHP
PHP PDOStatement::rowCount讲解
Feb 01 PHP
PHP基于mcript扩展实现对称加密功能示例
Feb 21 PHP
PHP获取学生成绩的方法
Nov 17 PHP
PHP实现小程序批量通知推送
Nov 27 #PHP
Laravel学习笔记之Artisan命令生成自定义模板的方法
Nov 22 #PHP
关于PHP虚拟主机概念及如何选择稳定的PHP虚拟主机
Nov 20 #PHP
phpMyAdmin通过密码漏洞留后门文件
Nov 20 #PHP
ThinkPHP5 的简单搭建和使用详解
Nov 15 #PHP
关于php unset对json_encode的影响详解
Nov 14 #PHP
PHP集成环境XAMPP的安装与配置
Nov 13 #PHP
You might like
php中ob_get_length缓冲与获取缓冲长度实例
2014/11/20 PHP
php简单socket服务器客户端代码实例
2015/05/18 PHP
mac系统下安装多个php并自由切换的方法详解
2017/04/21 PHP
tp5(thinkPHP5)操作mongoDB数据库的方法
2018/01/20 PHP
javascript中的prototype属性使用说明(函数功能扩展)
2010/08/16 Javascript
网易JS面试题与Javascript词法作用域说明
2010/11/09 Javascript
jQuery源码分析-04 选择器-Sizzle-工作原理分析
2011/11/14 Javascript
JQuery中使用Ajax赋值给全局变量失败异常的解决方法
2014/08/18 Javascript
js+jquery实现图片裁剪功能
2015/01/02 Javascript
jquery判断单选按钮radio是否选中的方法
2015/05/05 Javascript
seajs加载jquery时提示$ is not a function该怎么解决
2015/10/23 Javascript
javascript弹出窗口实现代码
2015/11/12 Javascript
AngularJS Bootstrap详细介绍及实例代码
2016/07/28 Javascript
jQuery 全选 全不选 事件绑定的实现代码
2017/01/23 Javascript
jquery 实时监听输入框值变化的完美方法(必看)
2017/01/26 Javascript
js实现九宫格的随机颜色跳转
2017/02/19 Javascript
vue之将echart封装为组件
2018/06/02 Javascript
详解微信小程序开发聊天室—实时聊天,支持图片预览
2019/05/20 Javascript
js类的继承定义与用法分析
2019/06/21 Javascript
jQuery实现本地存储
2020/12/22 jQuery
python设置windows桌面壁纸的实现代码
2013/01/28 Python
Python中优化NumPy包使用性能的教程
2015/04/23 Python
Python采用Django开发自己的博客系统
2020/09/29 Python
Python正则表达式匹配中文用法示例
2017/01/17 Python
python snownlp情感分析简易demo(分享)
2017/06/04 Python
Python实现动态加载模块、类、函数的方法分析
2017/07/18 Python
Python整型运算之布尔型、标准整型、长整型操作示例
2017/07/21 Python
Python数据结构与算法之图的广度优先与深度优先搜索算法示例
2017/12/14 Python
python+splinter自动刷新抢票功能
2018/09/25 Python
TensorFlow 读取CSV数据的实例
2020/02/05 Python
Python导入模块包原理及相关注意事项
2020/03/25 Python
Python函数递归调用实现原理实例解析
2020/08/11 Python
HTML5边玩边学(3)像素和颜色
2010/09/21 HTML / CSS
食品卫生管理制度
2015/08/06 职场文书
检讨书范文
2019/04/16 职场文书
导游词之千岛湖
2019/09/23 职场文书