关于ip的那些事


编	写:袁	亮
时	间:2014-05-20
说	明:关于ip的那些事

一、ip传递过程
	1、【真实客户端】 ==> [多级代理服务器] ==> [CDN加速] ==> [前端代理nginx|squid] ==> 【apache】==> 【PHP】
	2、中文括号的是必然会经过的,英文括号是可能经过的
	3、标准的ip传递是REMOTE_ADDR和HTTP_X_FORWARDED_FOR,前一个跟当前服务连接的真实ip,后一个是请求到前一个ip之前,经过了哪些代理
	4、REMOTE_ADDR是不可伪造的,HTTP_X_FORWARDED_FOR是可以任意修改的
	5、按标准,每传递到下一层,都会将上一层的实际ip地址加入到HTTP_X_FORWARDED_FOR中,继续传递
	6、对每一层来说,只有上一层的时间地址是可信的(REMOTE_ADDR),HTTP_X_FORWARDED_FOR均有风险
	7、真实情况中,到了cdn或者前端代理之后,ip传递都是可信的(我们自己可控制),之前的都有篡改的危险

二、各服务的真实ip传递情况
	1、CDN 快网的cdn会将用户的实际地址或者代理服务器地址传递到后面的服务中
		$_SERVER["HTTP_USER_IP"]	【不用快网的时候可伪造】
		$_SERVER["HTTP_FW_ADDR"]	【不用快网的时候可伪造】
		测试了一个新的cdn测试,没有传递真实ip过来

	2、nginx代理的情况下,可以使用x_real_ip来获取真实ip(有cdn的时候,该值获取的是cdn的ip地址)
		$_SERVER["HTTP_X_REAL_IP"]	【不用nginx的时候可伪造】

	3、$_SERVER["HTTP_CLIENT_IP"] :代理服务器发送的客户端真实ip【可伪造】

三、现在使用的获取ip函数
	a、如果有HTTP_CLIENT_IP,则该ip为用户ip(可被伪造)
	b、如果有HTTP_X_FORWARDED_FOR,则将HTTP_CLIENT_IP也加入到HTTP_X_FORWARDED_FOR,判断HTTP_X_FORWARDED_FOR中的ip是否是内网的,取第一个非内网的ip为客户端真实ip
	c、经过以上两步还没有取到ip的话,则根据REMOTE_ADDR取用户的ip
	ps:该函数的问题在于,前面两个的ip都是可以被任意伪造改写,从而导致获取不到用户的真实ip情况

四、附:(线上使用的获取ip函数)
function getIp(){//获取IP函数
        $ip = false;
        if(!empty($_SERVER["HTTP_CLIENT_IP"])){
                $ip = $_SERVER["HTTP_CLIENT_IP"];
        }
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
                if ($ip) {
                        array_unshift($ips, $ip);
                        $ip = FALSE;
                }
                for ($i = 0; $i < count($ips); $i++) {
                        if (!preg_match("/^(10|172\.16|192\.168)\./", $ips[$i])) { // 判断是否内网的IP
                                $ip = $ips[$i];
                                break;
                        }
                }
        }
        return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
}



http 1.1 和 http1.0 主要区别


编	写:袁	亮
时	间:2016-01-12
说	明:http 1.1 和 http1.0 主要区别

一、持久链接keep-alive
	1、标准的1.0版本中,每次请求都必须重新建立连接、传输数据、关闭连接
		但有些http服务和浏览器也实现了Connection: Keep-Alive的功能
	2、在1.1版本,默认就是Connection: Keep-Alive
		可以在同一次TCP连接中,多次传输数据
		减少了重新建立连接的开销,特别是当一个网页中有很多图片、js、css等的时候会非常有用
		但这也有可能会导致TCP一直不释放,从而影响性能,需要权衡设置
		
二、增加了HOST
	1、在1.0版本中,不支持HOST,同一ip同一端口,只能供一个服务使用
	2、1.1版本中,支持HOST来创建虚拟主机

三、带宽优化
	1、1.1版本中,增加了RANGE头来实现断点续传,从而防止下载中断之后又要全部重新上传
	2、增加压缩,通过Accept-Encoding头来实现,减少数据传输

四、其他
	1、缓存策略
	2、新增http状态码
	3、身份认证、状态管理
	4、我们服务器上有些apache还是返回http 1.0,感觉不大正常
	
		
附:参考文档
1、http://blog.csdn.net/elifefly/article/details/3964766
2、http://www.cnblogs.com/qqzy168/p/3141849.html
3、http://www.cnblogs.com/huangfox/archive/2012/03/31/2426341.html
4、http://www.360doc.com/content/14/0730/09/1073512_398058058.shtml

file_get_contents了解:自定义http请求

编	写:袁	亮
时	间:2015-07-17
说	明:file_get_contents了解:自定义http请求

一、使用原因
	1、这是一个使用非常频繁的函数,对应的file_put_contents,都是文件操作中第一选择
	2、抓取网络内容,一般情况下,也是使用的这个,但遇到稍微麻烦点的,我们就觉得没法子了
	3、curl等能做的,其实file_get_contents也基本上都能做,只是大家不熟悉
	
二、简单范例,直接看php.net
	array(
		'method'=>"GET",
		'header'=>"Accept-language: en\r\n" .
				  "Cookie: foo=bar\r\n"
	  )
	);

	$context = stream_context_create($opts);

	// Open the file using the HTTP headers set above
	$file = file_get_contents('http://www.example.com/', false, $context);
	
三、核心函数 stream_context_create
	1、支持以下协议,生成相应资源流上下文
		http://php.net/manual/zh/wrappers.php
		file:// — 访问本地文件系统
		http:// — 访问 HTTP(s) 网址
		ftp:// — 访问 FTP(s) URLs
		php:// — 访问各个输入/输出流(I/O streams)
		zlib:// — 压缩流
		data:// — 数据(RFC 2397)
		glob:// — 查找匹配的文件路径模式
		phar:// — PHP 归档
		ssh2:// — Secure Shell 2
		rar:// — RAR
		ogg:// — 音频流
		expect:// — 处理交互式的流
	
	2、http资源流支持参数:
		http:http://php.net/manual/zh/context.http.php
		http协议支持的参数,基本都支持
		header头,post数据,user_agent,代理,超时,跟随重定向等等
		
	3、post数据设置范例
		$postdata = http_build_query(
			array(
				'var1' => 'some content',
				'var2' => 'doh'
			)
		);
		$opts = array('http' =>
			array(
				'method'  => 'POST',
				'header'  => 'Content-type: application/x-www-form-urlencoded',
				'content' => $postdata
			)
		);
		$context = stream_context_create($opts);
		$result = file_get_contents('http://example.com/submit.php', false, $context);
		

如何查看自己的内外网ip以及服务器ip

编	写:袁	亮
时	间:2015-07-17
说	明:如何查看自己的内外网ip以及服务器ip

一、查看自己的ip
	1、内网ip
		1.1 打开cmd命令行模式
		1.2 输入ipconfig 找到ipv4地址以及默认网关
		1.3 想要查看更详细的网络配置,比如mac地址等,输入ipconfig /all
	2、外网地址
		2.1 直接打开百度,输入ip,即可看到自己当前的ip以及归属地
		2.2 也可以上tool.ci123.com 查看
	
二、查看linux服务器地址
	1、命令行模式,直接输入ifconfig
	2、线上服务器有时候会执行不了,因为账号没权限
	3、每块网卡都会有相应的一段输出,看下说明即可

http协议基础:内网、外网

编	写:袁	亮
时	间:2015-07-17
说	明:http协议基础:内网、外网

一、前言:
	1、适合于计算机网络基本没学的同学
	2、了解为主
	
二、什么是内网ip,什么是外网ip
	1、广域网(WAN):
		Internet,这是一个世界通用的网络,这边可识别的ip就是我们常说的外网ip
		我们平时上的网络都是这个
		家里连接宽带等,其实就是连接到Internet上
	2、局域网(LAN):
		找了几台计算机,我们互相能识别,那么我们就组成了一个局域网
		我们互相之间能识别,但是其他人并不知道我们是谁是谁
		一般需要通过一台能连接到Internet的设备去上网,比如我们公司的内部网络,对其他人来说,我们公司的这些电脑都是同一个人
	3、为什么需要内网ip
		ipv4的ip地址,只能描述256*256*256*256台独立设备,而现在不够用了,因此需要内网ip
	
三、简单说明
	1、外网地址
		1.1 相当于绝对地址,比如中国,江苏,南京大学
		1.2 跟任何人说这个地址,都是唯一指向同一个
		1.3 外网ip,分3类:
			A类地址:0-127.***.***.***
			B类地址:128-191.***.***.***
			C类地址:192-223.***.***.***
	2、内网地址
		2.1 是一个相当地址,比如说4院3专业2班17号
		2.2 在不同的情况下,代表的是不同的
		2.3 因此不要出现在公司这边,直接连机房那边的局域网地址,完全是牛头不对马嘴
		2.4 内网地址分类,针对外网地址,每一类外网,都有其对应的内网地址格式:
			A类:10.***.***.***
			B类:172.16.***.***
			C类:192.168.***.***
			
四、内网中,也可以再嵌套内网
	1、我们公司,外网地址为:218.94.95.52
	2、内网192.168.0.***
	3、其中某台路由器的内网ip为192.168.0.8
		可以再设置一个内网,192.168.8.***的内网,可以连接256台各设备

五、程序获取ip地址
	function getIp(){//获取IP函数
		$ip = false;
		if(!empty($_SERVER["HTTP_CLIENT_IP"])){
			$ip = $_SERVER["HTTP_CLIENT_IP"];
		}
		if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
			$ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
			if ($ip) {
				array_unshift($ips, $ip);
				$ip = FALSE;
			}
			for ($i = 0; $i < count($ips); $i++) {
				if (!preg_match("/^(10|172\.16|192\.168)\./", $ips[$i])) { // 判断是否内网的IP
					$ip = $ips[$i];
					break;
				}
			}
		}
		return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
	}

fsockopen初阶:了解并使用

编	写:袁	亮
时	间:2015-07-16
说	明:fsockopen初阶:了解并使用

一、作用(简单使用)
	1、类似file_get_contents,curl,在程序中,发起一次网络请求,抓取数据或者调用接口等
	2、curl能干的事,这个也都能干
	3、在发起http请求的时候,会对http整个工作过程更熟悉,每一步都很清楚
	
二、工作流程
	1、使用fsockopen打开一个网络连接或者一个Unix套接字连接
	2、使用fwrite,传输请求头信息
	3、使用fgets读取响应
	4、使用fclose关闭套接字
	ps:一个完整的http请求,更清晰些,平时访问网页的时候,浏览器帮我们做的这些工作

三、使用条件
	1、php配置中开启 allow_url_fopen
		
四、简单范例,php.net
	
	$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
	if (!$fp) {
		echo "$errstr ($errno)
\n"; } else { $out = "GET / HTTP/1.1\r\n"; $out .= "Host: www.example.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); while (!feof($fp)) { echo fgets($fp, 128); } fclose($fp); }
五、函数封装 header("Content-Type:text/html;charset=utf-8;"); $data = fsockOpenHttp("http://local.ci123.com/yl/fsockopen/t.php",'POST',array('username'=>'yuanliang847','nickname'=>'暗夜御林')); var_export($data); //图片上传的暂未封装,可以自己看下firebug中上传图片时的请求信息,然后封装 function fsockOpenHttp($url, $method='GET', $postfields = NULL , $multi = false){ $url = trim($url); if(!$url){ return array('status'=>4001,'mess'=>'链接不能为空'); } $urlinfo = parse_url($url); if(!$urlinfo['host']){ return array('status'=>4002,'mess'=>'链接非法,请填写完整链接地址'); } if($urlinfo['scheme'] == 'https'){//判断是否是https请求 $port = 443; $version = '1.1'; $host = 'ssl://'.$urlinfo['host']; }else{ $port = 80; $version = '1.0'; $host = $urlinfo['host']; } $urlinfo['path'] = $urlinfo['path']?$urlinfo['path']:'/'; $header = "{$method} {$urlinfo['path']} HTTP/$version\r\n"; $header .= "Host: {$urlinfo['host']}\r\n"; if($multi){ //$header .= "Content-Type: multipart/form-data; boundary=\r\n"; }else{ $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; } if(strtolower($method) == 'post' ){ if(is_array($postfields)){ $postfields = http_build_query($postfields); } $header .= "Content-Length: ".strlen($postfields)."\r\n"; $header .= "Connection: Close\r\n\r\n"; $header .= $postfields; }else{ $header .= "Connection: Close\r\n\r\n"; } $ret = ''; $fp = fsockopen($host,$port,$errno,$errstr,30); if(!$fp){ return array('status'=>4003,'mess'=>'建立sock连接失败'); } fwrite ($fp, $header); while (!feof($fp)) { $ret .= fgets($fp, 4096); } fclose($fp); $info = split("\r\n\r\n",$ret); $t = array_slice($info,1); $returnInfo = implode('',$t); $head = $info[0]; $tmp = split("\r\n", $head); $tmp = split(" ", $tmp[0]); $http_status = $tmp[1]; $html = iconv("utf-8","utf-8//ignore",$returnInfo); return array( 'status' => '1', 'mess' => '请求成功', 'http_status'=> $http_status,//http响应头 'head' => $head,//完整返回头 'data' => $html//响应内容 ); }