$name = "eg";
$key = "dfjmdfodeofreoldofldlfldddddfdfer25";
function test()
{
include_once "config.php";
echo $name;
}
for($i=0;$i<=5;$i++) {
test();
//include_once循环调用时,只有第一次能正常输出值;
}
1、[2013-07-27] 技术分享,sql索引优化。
MySQL技术内幕:InnoDB存储引擎(第2版)
http://product.china-pub.com/3767802
http://blog.codinglabs.org/articles/theory-of-mysql-index.html
XSS http://tmxk.org/forum-51-1.html
XSS的推荐这个:http://www.wooyun.org/whitehats/%E5%BF%83%E4%BC%A4%E7%9A%84%E7%98%A6%E5%AD%90
memcached全面剖析
http://tech.idv2.com/2008/08/17/memcached-pdf/
一致性hash算法的解释
http://blog.csdn.net/heiyeshuwu/article/details/8250041
2、[2013-08-29] mysql创建用户并授权。
#创建用户
CREATE USER username@localhost IDENTIFIED BY 'password';
#授权
grant select,insert,update,delete,create,drop,alter on db.* to username@localhost Identified by "password";
flush privileges;
3、[2013-09-02] web程序伪造IP
以前一直以为ip可以随便伪造,其实HTTP_X_FORWARDED_FOR,HTTP_CLIENT_IP这些可以伪造,但REMOTE_ADDR是服务器和客户端握手后建立了tcp连接,根据socket中的ip赋值的。协议底层决定的,应该没法伪造。
我来说说,你贴的获取IP代码是错误的PHP代码,php程序员很少涉及底层的东西,所以这种错误代码才会在php界里流传。你给的那段代码有很大的安全隐患,很容易被用来刷票,伪造IP等。很多php写的程序里正是错误地用了你的那段代码来判断IP,导致安全隐患。当然,你的CURL正是利用了这个漏洞。
- 获取IP只需要一句话,$_SERVER["REMOTE_ADDR"]这就足够了,没必要也不应该获取代理IP地址,REMOTE_ADDR是服务器和客户端握手后建立的tcp连接的数据帧里的,在应用层是无法修改的。当然,也不是绝对没有办法伪造的,IP协议可以完全自定义传输的数据,路由器这层也能伪造,但对于WEB程序员来说,是底层的东西,无法修改和伪造的。
这里说的是最大程序上的,如果伪造者拥有很多代理IP,那就没话说了
在PHP 中使用 $_SERVER["REMOTE_ADDR"] 来取得客户端的 IP 地址,但如果客户端是使用代理服务器来访问,那取到的就是代理服务器的 IP 地址,而不是真正的客户端 IP 地址。要想透过代理服务器取得客户端的真实 IP 地址,就要使用 $_SERVER["HTTP_X_FORWARDED_FOR"] 来读取。
不过要注意的事,并不是每个代理服务器都能用 $_SERVER["HTTP_X_FORWARDED_FOR"] 来读取客户端的真实 IP,有些用此方法读取到的仍然是代理服务器的 IP。
4、[2013-10-08] Discuz! X2.5 添加自定义数据调用模块
具体操作如下:
一、添加数据调用程序
1> 在 source/class/block/ 目录下新建文件夹如 :news
二、进入后台-工具-更新缓存,一定要勾选“DIY 模块分类缓存”,然后开始更新。
三、进入后台-门户-模块模板,在这个下添加你对应的模板
5、[2013-10-08] php中的$_POST是经过处理的
account=好的123&amount=10&sign=0G4%2F2zwBkuc%2FJD把这些数据POST提交
用$_POST接收到的是一个urldecode后的数组。
$HTTP_RAW_POST_DATA 包含 POST 提交的原始数据。
what is exaclty raw POST data?
Answer:
$_POST can be said as and outcome after splitting the $HTTP_RAW_POST_DATA, php splits the raw post data and formats in the way we see it in the $_POST For example:
$HTTP_RAW_POST_DATA looks something like this
key1=value1&key2=value2
then $_POST would look like this:
$_POST = array(
"key1" => "value1",
"key2" => "value2",);
To get the Raw Post Data:
<?php $postdata = file_get_contents("php://input"); ?>
Please see the notes here:
http://us.php.net/manual/en/wrappers.php
6、[2013-10-16] php推送消息,http协议,socket
socket连接和http连接的区别
HTTP协议:简单对象访问协议,对应于应用层 ,HTTP协议是基于TCP连接的
tcp协议: 对应于传输层
ip协议: 对应于网络层
TCP/IP是传输层协议,主要解决数据如何在网络中传输;而HTTP是应用层协议,主要解决如何包装数据。
Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。
http连接:http连接就是所谓的短连接,即客户端向服务器端发送一次请求,服务器端响应后连接即会断掉;
socket连接:socket连接就是所谓的长连接,理论上客户端和服务器端一旦建立起连接将不会主动断掉;但是由于各种环境因素可能会是连接断开,比如说:服务器端或客户端主机down了,网络故障,或者两者之间长时间没有数据传输,网络防火墙可能会断开该连接以释放网络资源。所以当一个socket连接中没有数据的传输,那么为了维持连接需要发送心跳消息~~具体心跳消息格式是开发者自己定义的
PHP中Push(推送)技术的探讨 http://vistaswx.com/blog/article/php-server-push
7、[2013-11-06] 一道PHP笔试题
问题
请找出下面代码中的问题,修复并优化。
<?php
//批量注册用户,每次>100个。
//注册新用户,要求用户名与email不能与以前的重复。
$mysqli = new Mysqli($host, $user, $pass);
for ($i=0; $i<count($_POST['user_info']); $i++) {
$info = $_POST['user_info'][$i];
$re_1 = $mysqli->query("SELECT * FROM `demo` WHERE `uname`=$info['uname']");
$re_2 = $mysqli->query("SELECT * FROM `demo` WHERE `email`=$info['email']");
if (!$re_1 || !$re_2) {
$mysqli->query("INSERT INTO `demo` (`uname`, `email`) VALUES('$info['email']', '$info['uname']')");
}
}
答案
基础:应该把count提到循环外。
基础:在字符串中拼装数组时候应该用 { 与 } 括起来。
基础:!$re_1 || $re_2应该是!$re_1 && !$re_2或者!($re_1 || $re_2)。
基础:insert语句的values部分两个字段顺序错了。
性能:uname与email两个语句应该拼装成一个OR语句。
性能:应该把所有SELECT拼装一个Sql,然后去除冲突的,再把剩余的通过批量插入的方式通过一条Sql插入。
性能:for应该该用foreach。
安全:参数没有过滤,但回答htmlspecialchars\addslashes而非mysqli->real_escape_string的减分。
其它:query前没有USE database之类的操作,没有SET NAMES,能回答上来的比较细心。
其它:没有错误处理。
一般如果都能回答上来的话应该就是可以毕业的phper了,之后再在面试中交流经验等方面。
我现在面试中都会出笔试,一般非常少,也很简单,就一道或两道。 很多时候这比面试更能反映问题。即便经验超级丰富,但没人想要也不想要一个连基本语法 都没掌握的人。
如果大家有更好的经验,还望分享一二。
8、[2013-11-06] addslashes 与 mysql_real_escape_string 的区别
下面讲述下三者之间的区别、关系:
1、addslashes 与 mysql_real_escape_string,同样的作用是经过转义后,可直接插入数据库, 国内很多PHP coder是使用addslashes函数防止SQL注入,但是其实,最好的还是建议大家使用后者来转义数据。
举例说明:addslashes的问题在于黑客可以用0xbf27来代替单引号,而addslashes只是将0xbf27修改为0xbf5c27,成为一个有效的多字节字符,其中的0xbf5c仍会被看作是单引号,所以addslashes无法成功拦截。
两者何时用:addslashes也不是毫无用处,它是用于单字节字符串的处理,多字节字符还是用mysql_real_escape_string更加安全。
2、magic_quotes_gpc的说明,在首次客户端运行时,可用第一条的举例,对 magic_quotes_gpc 进行 $_['name'] 判断,可转义处理。
3、 mysql_real_escape_string和mysql_escape_string这2个函数的区别:
mysql_real_escape_string 必须在(PHP 5以上、PHP 4 >= 4.3.0)版本的情况下才能使用。否则只能用 mysql_escape_string 。
两者的区别是:mysql_real_escape_string 考虑到连接的当前字符集,而mysql_escape_string 不考虑。
4、实际开发中,正确的逻辑处理,如下:
首先,检查 magic_quotes_gpc 是否配置为自动转义斜线,若为on,应该调用stripslashes去掉$_REQUEST、$_GET,$_POST、$_COOKIE的转义斜线;
然后,查询/写入/更新数据至mysql时,再使用mysql_real_escape_string进行字符转义。
例子:
<?php
foreach ($_COOKIE as $key => $value) {
if(get_magic_quotes_gpc()) $_COOKIE[$key]=stripslashes($value);
$_COOKIE[$key] = mysql_real_escape_string($value);
}
?>
9、[2013-11-27] ob系列函数用法
刷新PHP程序的缓冲,而不论PHP执行在何种情况下(CGI ,web服务器等等)。该函数将当前为止程序的所有输出发送到用户的浏览器。
flush() 函数不会对服务器或客户端浏览器的缓存模式产生影响。因此,必须同时使用 ob_flush() 和 flush() 函数来刷新输出缓冲。
个别web服务器程序,特别是Win32下的web服务器程序,在发送结果到浏览器之前,仍然会缓存脚本的输出,直到程序结束为止。
有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致 flush()函数产生的结果不会立即被发送到客户端浏览器。
甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape 浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在接受到 </table> 标记之前,不会显示出整个表格。
一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。
header( 'Content-type: text/html; charset=utf-8' );
echo 'Begin ...<br />';
for( $i = 0 ; $i < 20 ; $i++ )
{
echo $i . '<br />';
flush();
ob_flush();
sleep(1);
}
echo 'End ...<br />';
不输出前面的内容
xxxxxxx
<?php
echo 123123;
ob_clean();
echo '555555';
上面这段代码只输出55555,前面的被清除。
10、[2014-01-07]discuzx2.5储存xss漏洞
discuzx2.5出错xss漏洞,回帖时,上传swf路径链接:
http://cnhonkerarmy.com\u0022\u003e\u003c\u0069\u0066\u0072\u0061\u006d\u0065\u002f\u006f\u006e\u006c\u006f\u0061\u0064\u003d\u0061\u006c\u0065\u0072\u0074\u0028\u0064\u006f\u0063\u0075\u006d\u0065\u006e\u0074\u002e\u0063\u006f\u006f\u006b\u0069\u0065\u0029\u003e/1.swf
能绕过过滤。
修复:source/function/function_discuzcode.php页面,parseflash等方法$url = str_replace('\u', '/u', $url);
参考:一种新型的绕过XSS防御的方法http://zone.wooyun.org/content/1253
11、[2014-05-16]discuzx2.5各种XSS漏洞
一、qq互联插件 dom xss漏洞
证明:http://bbs.xxxx.com/connect.php?receive=yes&mod=login&op=callback&referer=xyz\u0027.replace(/.%2b/,/javascript:alert(511265478)/.source);//
修复方案:http://www.discuz.net/thread-3216330-1-1.html
|
二、Flash xss 跨站请求伪造漏洞
漏洞证明:http://bbs.xxxx.com/static/image/common/swfupload.swf?movieName=%22])}catch(e){if(!window.x){window.x=1;alert(/xss/)}}//
http://bbs.xxxx.com/static/image/common/flvplayer.swf?file=1.flv&linkfromdisplay=true&link=javascript:alert(document.cookie);
修复方案:http://bbs.anquan.org/forum.php?mod=viewthread&tid=17438
升级最新版swfupload.swf,flvplayer.swf文件即可
12、[2014-05-24]观察者模式场景和实例
3.1php设计模式-观测者模式
*3.1.1概念:其实观察者模式这是一种较为容易去理解的一种模式吧,它是一种事件系统,意味着
* 这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类
* 可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间紧密耦合的另一种方法
*3.1.2关键点:
* 1.被观察者->追加观察者;->一处观察者;->满足条件时通知观察者;->观察条件
* 2.观察者 ->接受观察方法
*3.1.3缺点:
*3.1.4观察者模式在PHP中的应用场合:在web开发中观察者应用的方面很多
* 典型的:用户注册(验证邮件,用户信息激活),购物网站下单时邮件/短信通知等
*3.1.5php内部的支持
SplSubject 接口,它代表着被观察的对象,
* 其结构:
* interface SplSubject
* {
* public function attach(SplObserver $observer);
* public function detach(SplObserver $observer);
* public function notify();
* }
* SplObserver 接口,它代表着充当观察者的对象,
* 其结构:
* interface SplObserver
* {
* public function update(SplSubject $subject);
* }
*/
/\*\*
*用户登陆-诠释观察者模式
*/
class User implements SplSubject
{
//注册观察者
public $observers = array();
//动作类型
CONST OBSERVER_TYPE_REGISTER = 1;//注册
CONST OBSERVER_TYPE_EDIT = 2;//编辑
/\*\*
*追加观察者
*@param SplObserver $observer 观察者
*@param int $type 观察类型
*/
public function attach(SplObserver $observer, $type)
{
$this->observers[$type][] = $observer;
}
/\*\*
*去除观察者
*@param SplObserver $observer 观察者
*@param int $type 观察类型
*/
public function detach(SplObserver $observer, $type)
{
if($idx = array_search($observer, $this->observers[$type], true))
{
unset($this->observers[$type][$idx]);
}
}
/\*\*
*满足条件时通知观察者
*@param int $type 观察类型
*/
public function notify($type)
{
if(!empty($this->observers[$type]))
{
foreach($this->observers[$type] as $observer)
{
$observer->update($this);
}
}
}
/\*\*
*添加用户
*@param str $username 用户名
*@param str $password 密码
*@param str $email 邮箱
*@return bool
*/
public function addUser()
{
//执行sql
//数据库插入成功
$res = true;
//调用通知观察者
$this->notify(self::OBSERVER_TYPE_REGISTER);
return $res;
}
/\*\*
*用户信息编辑
*@param str $username 用户名
*@param str $password 密码
*@param str $email 邮箱
*@return bool
*/
public function addUser()
{
//执行sql
//数据库更新成功
$res = true;
//调用通知观察者
$this->notify(self::OBSERVER_TYPE_EDIT);
return $res;
}
}
/\*\*
*观察者-发送邮件
*/
class Send_Mail implements SplObserver
{
/\**
*相应被观察者的变更信息
*@param SplSubject $subject
*/
public function update(SplSubject $subject)
{
$this->sendMail($subject->email, $title, $content);
}
/\*\*
*发送邮件
*@param str $email 邮箱地址
*@param str $title 邮件标题
*@param str $content 邮件内容
*/
public function sendEmail($email, $title, $content)
{
//调用邮件接口,发送邮件
}
}
?>
13、[2014-05-30] 工作中遇到的mysql 查询优化。
1、强制索引 force index
user_exchange表有400W数据
SELECT account,user_id,SUM(amount) AS `asum` FROM user_exchange WHERE DATETIME >= 1401379200 AND DATETIME <= 1401465599 GROUP BY user_id ORDER BY `asum` DESC
上面这条语句 耗时10秒,命中的索引是user_id。
SELECT account,user_id,SUM(amount) AS `asum` FROM user_exchange FORCE INDEX (DATETIME) WHERE 1 = 1 AND DATETIME >= 1401379200 AND DATETIME <= 1401465599 GROUP BY user_id ORDER BY `asum` DESC
这条查询加了强制datetime索引,查询时间不到0.5秒,命中datetime索引。
2、
14、[2014-07-02] PHP的一些函数和方法
1、http_build_query()的相反函数,http_build_query在PHP5中是一个很常用的函数,用来生成URL编码的查询字符串。parse_str("id=23&name=John Adams",$myArray); 是它的相反处理函数
2、include_once导入文件变量配置文件时,如果函数内循环调用,由于变量作用域的问题,会获取不到变量值,改为include就可以了。
config.php
$name = "eg";
$key = "dfjmdfodeofreoldofldlfldddddfdfer25";
test.php
function test()
{
include_once "config.php";
echo $name;
}
for($i=0;$i<=5;$i++) {
test();
//include_once循环调用时,只有第一次能正常输出值;
}
15、[2014-07-08] php发送http head请求
PHP发送HEAD方法请求
HEAD方法在99%的web服务中支持(不完全统计,默认都是HEAD、POST、GET,除了某些极其特殊的应用会限制HEAD方法),HEAD方法有很多用途,比如探测网页的状态(HTTP头部信息,404,403,200)。PHP的灵活性,可以很容易地实现HTTP的HEAD方法。
1、Socket实现:
(直接手写HEAD请求)
2、CURL实现:
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); // HTTP request is 'HEAD'
OR
curl_setopt($ch, CURLOPT_NOBODY, true);
3、get_header()
stream_context_set_default(array('http'=>array('method'=>'HEAD')));
print_r(get_headers('http://www.baidu.com'),0);
经测试,默认情况下 get_headers()发送的请求不是HEAD而是GET,所以最好加上一个全局的HTTP方法配置。但是如果下文中有要使用远程GET或者POST方法的,最好别使用此种方法。
4、HTTP模块中的http_head()方法
16、[2014-07-15] 链表查询设置某字段的默认值IF(uoa.sub_source,uoa.sub_source,0)
链表查询是,某记录在子表不存在时,字段会显示为null,设置默认值的方法。IF(uoa.sub_source,uoa.sub_source,0),解析:如果存在sub_source则sub_source否则0。相当于:uoa.sub_source?uoa.sub_source:0
SELECT DATE(FROM_UNIXTIME(update_time)) AS date, IF(uoa.sub_source,uoa.sub_source,0) AS sub_source
FROM user_order AS uo LEFT JOIN user_order_additional AS uoa ON uo.order_id = uoa.order_id
WHERE status = 1 AND update_time >= 1405350000 AND update_time <= 1405353599 GROUP BY report_date
17、[2014-07-16] CI 框架的一些用法
页面缓存:
启用缓存功能,只需要将下面的代码放入你的任何一个控制器(controller)的方法(function)内:
$this->output->cache(n);
其中 n 是你希望缓存更新的 分钟 数。可以使用 m/60 来精确到秒,例如 1/60 ,则是精确到 1秒
上面的代码可以放到任何一个 function 里面。他的出现顺序对缓存并没有影响,所以将它放在你认为最合乎逻辑的地方。一旦上面的代码放到了控制器的方法中,页面就会被缓存。
警告: 由于CI存储缓存文件的方式,只有通过 view 文件的输出才能被缓存。
注意: 在缓存文件产生之前,请确保 application/cache 文件夹可写。
基准测试:
测试基准类可以在 控制器, 视图,或者 模型.中使用,用法如下:
- 标记一个开始点
- 标记一个结束点
- 运行elapsed_time函数显示结果
下面是一个代码示例:
$this->benchmark->mark('code_start');
// Some code happens here
$this->benchmark->mark('code_end');
echo $this->benchmark->elapsed_time('code_start', 'code_end');
注意:单词“code_start”和“code_end”是任意的,他们是简单的单词用来做为两个标记。你可以使用你想用的任意单词,并且你可以设置多个标记,参考下面的这些代码:
18、[2014-12-08] nginx中的rewrite到外部url会导致post的参数丢失
nginx中的rewrite到外部url会导致post的参数丢失,所以放弃该方案。(内部的rewrit是不会丢失post数据)
原因:
(1)post的时候,参数是存放在message body中传递的,对于内部的url调转,因为是相同的一次请求,所以message body(request body)没变,所以post数据不会丢失。
(2)而对于外部跳转,实际上是一次302,即用户在请求了一次,所以第二次就不会post第一次的数据了。
具体如下:你post数据之后,匹配到rewrite之后,因为是外部的url,用户会看到一个302,之后请求的url就变成了get。。那么之前post的数据就丢失了(因为用户没有再提交一次数据)
2、需要传递post参数,需要使用proxy_pass。同时,因为proxy之前的url和proxy的url不同,需要做location,并需要在在proxy_pass中写全路径参考例子如下
思考了为啥proxy_pass能传递post的参数:因为对于用户而言,就只是一个请求,所以request body没变。nginx会将该request body传递到后续的server
19、[2014-12-16] SQL注入的危害。
关于安全性,本文可总结出一下几点:
1、对用户输入的内容要时刻保持警惕。
2、只有客户端的验证等于没有验证。
3、永远不要把服务器错误信息暴露给用户。
除此之外,我还要补充几点:
1、SQL注入不仅能通过输入框,还能通过Url达到目的。
2、除了服务器错误页面,还有其他办法获取到数据库信息。
3、可通过软件模拟注入行为,这种方式盗取信息的速度要比你想象中快的多。
4、漏洞跟语言平台无关,并非asp才有注入漏洞而asp.net就没有注入漏洞,一切要看设计者是否用心。
参考链接:
http://www.cnblogs.com/hkncd/archive/2012/03/31/2426274.html
http://php.net/manual/zh/security.database.sql-injection.php
20、[2014-12-16] 实现批量更新。
UPDATE `user` SET `money` =
CASE
WHEN `id` = 79 THEN `money`+1.02
WHEN `id` = 80 THEN `money`+2.10
ELSE `money` END
WHERE `id` IN (79,80)
/**
* 批量更新
* @param $data
* @return bool|string
*/
public function updates($data)
{
if(!is_array($data)){
return false;
}
$sql = "UPDATE `{$this->_tableName}` SET `point_num` = CASE ";
$ids = array();
foreach($data as $k=>$v){
$ids[] = $v['id'];
$sql .= " WHEN `id` = {$v['id']} THEN `point_num`+{$v['point_num']}";
}
$sql .= " ELSE `point_num` END WHERE `id` IN (".implode(',',$ids).")";
return $this->query_sql($sql)->affected_rows();
}
21、[2015-01-20] Cookie的HttpOnly和Secure属性作用
今天和总监、同事又讨论起关于Session共享的解决方案问题,讨论到因为Tomcat自带的Session机制在集群时难以做到真正的集群。因为使用Tomcat自带的Session机制,难以做到在集群中节点共享,一般是通过Nginx反向代理使用Hash、固定IP等解决方案,并不能避免单节点崩溃时不能继续提供服务的问题。虽然这种可以解决压力的问题,但是当一直为某IP或通过Hash来分配服务的某台服务器挂了,则它负责服务的客户就都访问不了了(Session失效,只能重新调度分配到其他服务器,这时要重新生成会话)。讨论到的可用的解决方案是Cookie + Redis,然后又讨论了Cookie的安全性问题。然后同事问了下HttpOnly这个在浏览器里打勾的作用,然后自己按以前了解到的资料来回答了一下,大概是说:不能通过Javascript来修改带有HttpOnly属性的Cookie,只能通过服务器来修改。但是看到总监却可以通过JS来修改带有HttpOnly属性的Cookie,这让我产生了怀疑自己的正确性。
不过还好,事后向总监确认了一下,原来他是通过删除旧的带有HttpOnly属性的Cookie,然后才用JS添加一个同名同值没有HttpOnly属性来测试。所以,我之前说的大概是对的,但是不够系统,所以再次查了下资料来系统整理一下,与君分享。
下面两个属性都属于Cookie安全方面考虑的。这要视浏览器或服务端有没有支持。
Secure
Cookie的Secure属性,意味着保持Cookie通信只限于加密传输,指示浏览器仅仅在通过安全/加密连接才能使用该Cookie。如果一个Web服务器从一个非安全连接里设置了一个带有secure属性的Cookie,当Cookie被发送到客户端时,它仍然能通过中间人攻击来拦截。
HttpOnly
Cookie的HttpOnly属性,指示浏览器不要在除HTTP(和 HTTPS)请求之外暴露Cookie。一个有HttpOnly属性的Cookie,不能通过非HTTP方式来访问,例如通过调用JavaScript(例如,引用 document.cookie),因此,不可能通过跨域脚本(一种非常普通的攻击技术)来偷走这种Cookie。尤其是Facebook 和 Google 正在广泛地使用HttpOnly属性。