PHP 利用 redis 做统计缓存mysql的压力

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<?php
header("Content-Type:text/html;charset=utf-8");
include 'lib/mysql.class.php';
$mysql_obj = mysql::getConn();
//redis
$redis = new Redis();
$redis->pconnect('127.0.0.1', 6379);

if(isset($_SERVER['HTTP_REFERER'])){
$url_md5 = md5($_SERVER['HTTP_REFERER']);
}
$adve_key = 'adve';
$adve_key_exists = 'adve_exists';
if(!$redis->exists($adve_key_exists)){
$list = $mysql_obj->fetch_array("select * from user_online_adve");
if($list){
foreach ($list as $key => $value) {
$url_hash = md5($value['adve_url']);
$adve_hash_key = $adve_key.":".$url_hash;
$id = $value['id'];
$redis->set($adve_hash_key,$id);
$redis->set($adve_key_exists,true);
//$redis->hmset($adve_hash_key, array('id' =>$id));
//print_r($redis->get($adve_hash_key));
}
}
}
$adve_new_key = $adve_key.':'.$url_md5;
if($redis->exists($adve_new_key)){
$adve_plus = $adve_new_key.":plus" ;

if(!$redis->exists($adve_plus)){
$redis->set($adve_plus,1);
}else{
$redis->incr($adve_plus);
$num = $redis->get($adve_plus);
if($num >10){
$id = $redis->get($adve_new_key);
// insert to sql;
$mysql_obj->query("update user_online_adve set adve_num=adve_num+$num where id=$id");
$redis->set($adve_plus,1);
}
}
}
header('HTTP/1.0 301 Moved Permanently');
header('Location: https://itunes.apple.com/cn/app/san-guo-zhi15-ba-wangno-da-lu/id694974270?mt=8');


/*
if(){
$adve_plus = $adve_key.":plus" ;
if($redis->exists($adve_plus)){
$redis->incr($adve_plus);
}else{
$redis->set($adve_plus,1);
}
echo $redis->get($adve_plus);
}

foreach ($list as $key => $value) {
$url_hash = md5($value['adve_url']);
$id = $value['id'];
$adve_num = $value['adve_num'];
$adve_plus = $adve_key.":plus" ;
if($redis->exists($adve_plus)){
$redis->incr($adve_plus);
}else{
$redis->set($adve_plus,1);
}
echo $redis->get($adve_plus);
//if($redis->)
//$redis->hmset($adve_key, array('id' =>$id, 'adve_num'=>$adve_num));
//print_r($redis->hmget("adve:$url_hash", array('adve_num')));
}


print_r($list);
*/

转载自 http://www.cnblogs.com/jackluo/p/3401999.html

php class中public,private,protected,static的区别,以及实例

一,public,private,protected的区别
public:权限是最大的,可以内部调用,实例调用等。
protected: 受保护类型,用于本类和继承类调用。
private: 私有类型,只有在本类中使用。

二,实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
error_reporting(E_ALL);

class test{
public $public;
private $private;
protected $protected;
static $instance;
public  function __construct(){
$this->public    = 'public     <br>';
$this->private   = 'private    <br>';
$this->protected = 'protected  <br>';
}
static function tank(){
if (!isset(self::$instance[get_class()]))
{
$c = get_class();
self::$instance = new $c;
}

return self::$instance;
}    

public function pub_function() {
echo "you request public function<br>";
echo $this->public;
echo $this->private;        //private,内部可以调用
echo $this->protected;      //protected,内部可以调用
$this->pri_function();      //private方法,内部可以调用
$this->pro_function();      //protected方法,内部可以调用
}
protected  function pro_function(){
echo "you request protected function<br>";
}
private function pri_function(){
echo "you request private function<br>";
}
}

$test = test::tank();
echo $test->public;
echo $test->private;    //Fatal error: Cannot access private property test::$private
echo $test->protected;  //Fatal error: Cannot access protected property test::$protected
$test->pub_function();
$test->pro_function();  //Fatal error: Call to protected method test::pro_function() from context
$test->pri_function();  //Fatal error: Call to private method test::pri_function() from context

?>

从上面的例子中,我们可以看出,
public: 可以class内部调用,可以实例化调用。
private: 可以class内部调用,实例化调用报错。
protected: 可以class内部调用,实例化调用报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php

class test{
public $public;
private $private;
protected $protected;
static $instance;

public  function __construct(){
$this->public    = 'public     <br>';
$this->private   = 'private    <br>';
$this->protected = 'protected  <br>';
}
protected function tank(){                          //私有方法不能继承,换成public,protected
if (!isset(self::$instance[get_class()]))
{
$c = get_class();
self::$instance = new $c;
}
return self::$instance;
}    

public function pub_function() {
echo "you request public function<br>";
echo $this->public;
}
protected  function pro_function(){
echo "you request protected function<br>";
echo $this->protected;
}
private function pri_function(){
echo "you request private function<br>";
echo $this->private;
}
}

class test1 extends test{

public function __construct(){
parent::tank();
parent::__construct();
}
public function tank(){
echo $this->public;
echo $this->private;       //Notice: Undefined property: test1::$private
echo $this->protected;
$this->pub_function();
$this->pro_function();
$this->pri_function();    //Fatal error: Call to private method test::pri_function() from context 'test1'
}

public  function pro_extends_function(){
echo "you request extends_protected function<br>";
}
public function pri_extends_function(){
echo "you request extends_private function<br>";
}
}

error_reporting(E_ALL);
$test = new test1();
$test -> tank();       //子类和父类有相同名字的属性和方法,实例化子类时,子类的中的属性和方法会盖掉父类的。

?>

从上面的例子中,我们可以看出,
public: test中的public可以被继承。
private: test中的private不可以被继承。
protected: test中的protected可以被继承。
static: test中的static可以被继承。

转载自 http://blog.163.com/wz_pk007/blog/static/170627050201143104938560/

MySQL的if,case语句使用总结

Mysql的if既可以作为表达式用,也可在存储过程中作为流程控制语句使用,如下是做为表达式使用:

IF表达式

1
IF(expr1,expr2,expr3)

如果 expr1 是TRUE (expr1 <> 0 and expr1 <> NULL),则 IF()的返回值为expr2; 否则返回值则为 expr3。IF() 的返回值为数字值或字符串值,具体情况视其所在语境而定。

1
select *,if(sva=1,"男","女") as ssva from taname where sva != ""

作为表达式的if也可以用CASE when来实现:

1
select CASE sva WHEN 1 THEN '男' ELSE '女' END as ssva from taname where sva != ''

在第一个方案的返回结果中, value=compare-value。而第二个方案的返回结果是第一种情况的真实结果。如果没有匹配的结果值,则返回结果为ELSE后的结果,如果没有ELSE 部分,则返回值为 NULL。
例如:

1
2
3
4
SELECT CASE 1 WHEN 1 THEN 'one'
WHEN 2 THEN 'two'
ELSE 'more' END
as testCol

将输出one

IFNULL(expr1,expr2)
假如expr1 不为 NULL,则 IFNULL() 的返回值为 expr1; 否则其返回值为 expr2。IFNULL()的返回值是数字或是字符串,具体情况取决于其所使用的语境。

1
2
3
4
5
6
7
8
9
10
11
mysql> SELECT IFNULL(1,0);
-> 1

mysql> SELECT IFNULL(NULL,10);
-> 10

mysql> SELECT IFNULL(1/0,10);
-> 10

mysql> SELECT IFNULL(1/0,'yes');
-> 'yes'

IFNULL(expr1,expr2) 的默认结果值为两个表达式中更加“通用”的一个,顺序为STRING、 REAL或 INTEGER。

IF ELSE 做为流程控制语句使用
if实现条件判断,满足不同条件执行不同的操作,这个我们只要学编程的都知道if的作用了,下面我们来看看mysql 存储过程中的if是如何使用的吧。

1
2
3
4
5
6
7
IF search_condition THEN 
statement_list
[ELSEIF search_condition THEN]
statement_list ...
[ELSE
statement_list]
END IF

与PHP中的IF语句类似,当IF中条件search_condition成立时,执行THEN后的statement_list语句,否则判断ELSEIF中的条件,成立则执行其后的statement_list语句,否则继续判断其他分支。当所有分支的条件均不成立时,执行ELSE分支。search_condition是一个条件表达式,可以由“=、<、<=、>、>=、!=”等条件运算符组成,并且可以使用AND、OR、NOT对多个表达式进行组合。
例如,建立一个存储过程,该存储过程通过学生学号(student_no)和课程编号(course_no)查询其成绩(grade),返回成绩和成绩的等级,成绩大于90分的为A级,小于90分大于等于80分的为B级,小于80分大于等于70分的为C级,依次到E级。那么,创建存储过程的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
create procedure dbname.proc_getGrade  
(stu_no varchar(20),cour_no varchar(10))
BEGIN
declare stu_grade float;
select grade into stu_grade from grade where student_no=stu_no and course_no=cour_no;
if stu_grade>=90 then
select stu_grade,'A';
elseif stu_grade<90 and stu_grade>=80 then
select stu_grade,'B';
elseif stu_grade<80 and stu_grade>=70 then
select stu_grade,'C';
elseif stu_grade70 and stu_grade>=60 then
select stu_grade,'D';
else
select stu_grade,'E';
end if;
END

注意:IF作为一条语句,在END IF后需要加上分号“;”以表示语句结束,其他语句如CASE、LOOP等也是相同的。

转载自 http://outofmemory.cn/code-snippet/1149/MySQL-if-case-statement-usage-summary

请别在朋友圈侮辱我的智商

我改相信谁
我读书少,我流量不多。每当我手机上网被你们逼着看看你们转的这些脑残无语乱七八糟的秘籍攻略心灵鸡汤什么的就无比心痛感觉被你们强奸了一百遍啊一百遍!深深的感受到有些人的智商真是无下限,家长老师把你们拉扯到这么大不容易你们自己却连独立思考的精神也没有,我很无奈,我很想哭。
有东西
1、蓝翔就是搭了谣言丑闻的顺风车,他家的挖机水平和别家也差不多;
2、苹果 6 里的自带地图里钓鱼岛是中国的,高速公路上日本车还是可以加油的;
3、羚羊才不会接力跳悬崖,金鱼的记忆才不止七秒;
记忆
4、腾讯才不管你一条信息转发多少次,腾讯老总的女儿也好儿子也好私生子也好不会为你冲Q币;
5、你大概得吃三百斤虾和十几瓶维生素C才能发生轻微砷中毒,少女被割肾的故事起源于美国远播海外;
6、在 ATM 上倒着输入密码只会被告知密码错误,你倒是可以试试倒输三次,当然,你密码正输倒输都一样的不在此列;
比例
7、喝一辈子汽水只会超重不会得白血病,吃再多米线只会因明胶而发育不良不会长所谓的细菌虫;
8、人乳放置几十年变的血红是因为密封不当而混进了红曲菌你们就不要用这个来赞美你妈了;
9、把大蒜扔进油锅里怎么炸都不会变红更别提鉴别地沟油了;
地沟油
10、由于头皮和头骨的阻隔,手机对大脑的辐射微乎其微请不要把手机说得有核辐射似的;
11、上网之后洗脸只能洗掉你脸上的灰毕竟电磁辐射是电磁波而不是什么颗粒,在电脑桌旁摆一盆仙人掌也不能吸收均匀发散的辐射,把电脑屏幕调成绿色该近视还得近视,空军从未流传过治疗近视的方法否则你让眼镜商怎么活。
12、你的任何手机输入什么数字都不会为你启动备用电池,毕竟你手机根本就不存在什么备用电池;
13、金陵十三钗根本未在日本上映还谈什么票房,南京大屠杀纪念日是 12 月 13 日而不是 9 月 12 日也不是 5 月 12 日你妹的你的近代史是怎么学的;
牙膏
14、牙膏管底部有个绿色色块的是纯天然牙膏黑色的就是全化学物质的,拜托那个色块只是生产线上的标记爱整啥颜色就是啥颜色,要不厂家给你整支从头到脚从里到外全是绿色的牙膏连牙齿都可以给你刷绿的好不好;
15、那些说你手机或者电脑收到一张带有“女人必看”、“男人必看”、“不男不女必看”之类的图片或者工资料整方案什么文件的,在任何环境下一旦打开你的手机就会爆炸电脑就会冒黑烟你的隐私艳照就会满天飞第二天你就红过冠希哥的,病毒真正侵入的是你的榆木脑袋而不是你的手机电脑,另外,冠希哥无人可以超越你尽可放心;
16、中国 10 大名老中医的各类偏方最近疯转,有人转的是徐文兵有人转的是叫于彤,内容一样年纪一样都是 98 岁,第一条就是香蕉皮 30 克晒干煎水可以降血压看到这第一条我就笑了。大家就不会自己去百度一下徐文兵吗?他 1966 年出生我的数学老师死的早 66 年出生的人今年多大我不会算,但肯定不是 TM 的 98 岁,干脆你说太上老君说我倒真心信了神仙说的谁敢不信是不是,我只说一句话得了病你还是去医院比较靠谱除非你想早点去见马克思。
马克思
17、最近电影亲爱的让大家爱心爆棚,什么加油站一辆卖天津大麻花的货车正在加油最后发现堆放麻花扳子下传来了 9 个孩子的哭叫声,原来卖天津大麻花的还兼职卖人卖器官真是吓得你一脸的狗血,我就想问问你妹的你看过卖天津大麻花的标准制式车辆没有 9 个 10 岁的孩子你给我塞进去看看,我真想把这个谣言一个字一个字的塞进你巨大的菊花里,真 9 个孩子被关着一个个器官切着卖那不成了中国第一大案了你也太小看警察蜀黎的能力了。
18、那些被人喷了一口烟点了一下穴瞪了一小眼就迷迷糊糊被人骗走钱财骗走身体骗走一切的人,大都是贪财爱占小便宜结果鸡飞蛋打上当了也哒屁无法和老公老婆家人孩子交代了,急中生智把自己被猪油蒙了心的行为都怪到这些武侠穿越修仙小说中才会出现的事情上去,你要信了你的智力大概也是-250。
实在是有太多谣言,八妹加上脚趾头都数不过来了,还是自己看图吧!
1、微波炉辐射会致癌
致癌
2、柿子和蟹、虾和水果、豆浆和鸡蛋等混吃会中毒
食物
3、酸性体质能致病
致病
4、指甲月牙越多越健康
指甲
5、宿便是健康杀手
宿便
6、孕妇必须穿防辐射服
孕妇
7、可乐杀精
精子
8、购物小票会致癌
购物票
9、柠檬水能减肥抗癌
柠檬水
这还没完呢~赶紧上个厕所咱继续!
手机 7 大谣言大起底!你被忽悠了吗?
一、55 秒通话等于 1 分钟?
时钟
【传言】不要赶着凑够 1 分钟通话。很多人打电话时候常会为正好赶在 1 分钟前结束而庆幸,其实,在你通话到 55 秒的时候就已经算 1 分钟了,所以 55 秒-1 分钟的通话其实是算你两分钟的钱。
【求证】国内统一执行打满 1 分钟时计下 1 分钟的费用。但不排除有个例的情况出现,就像有些加油站部分工作人员,通过不当手段短斤少两。但从技术上来说,在这个方面偷费,也很难做到。
【结论】这条流传已久的“经验”,原来是假的。
二、手机都有“隐形电池”?
yinxing.webp
【传言】你的手机电量不足了,为了让它能够继续使用,按3370#键,手机会重新启动,启动完毕后,你就会发现电量增加了 50%。
【实验】在一部电量不足三星手机上,依次输入
3370#键,手机无任何反应,然后点送发射键,手机显示“UsSd 代码运行中”。这几个字还未仔细看清,又直接跳转为“连接问题或无效 MMI 代码*确定”,再按下确定键,手机复原为初始状态。换用多部其他各型号手机,均是如此。
【求证】网络辟谣称,在我们生活的这个三次元世界里,隐形电池是不存在的。拆开一部手机,你会发现内部没有任何“隐形电池”存在的踪影,而且手机厂家也完全没有理由去设置这样一项功能。
【结论】这一条也是假的!
三、没卡也能打“110”?
110
【传言】全世界的手机都可以拨打的共同紧急救援号码是 112,假如你发现自己所在地区无信号覆盖,同时你又遇到了紧急状况,用你的手机拨打 112 准没错,因为这时候你的手机会自动搜索所有可用的网络并建立起紧急呼叫。
【实验】拿掉手机卡,小e尝试拨打了 110、119 等紧急电话,结果表明,拨打这些号码时,会有语音提示,但并未接通。也就是说,在无卡状态下,手机并不能实现电话报警。
【求证】网络答案称,国内呼叫 112 并无实际作用,它会自动转接一个语音提示,“匪警请拨 110,火警请拨 119……”而呼叫 110、119、120 等中国紧急号码还是需要手机接入 SIM 卡提供商的网络,与普通通话一样。
尽管这种做法符合 GSM 的规范,但是为了更好的实施紧急救援,还有待国内服务商完善。
【结论】这一条其实不完全算是“谣言”,但在国内没有实际用处,若在国外遇险,可尝试使用这种方法求救。
四、手机一格电,辐射大千倍?
辐射
【传言】手机剩一格时不要使用:收讯满格与只剩一格时相比,发射强度竟然相差 1000 倍以上。
【求证】通常人们说的手机辐射强度是指手机的发信功率,也就是手机发射出来承载着语音和数据信号的电磁波的功率。这个强度与手机的剩余电量没有任何关系,但和手机信号的强度有一定的关系。
手机信号的强弱,与基站远近有关,也受高山阻挡或其他信号干扰的影响,这与电量关系不大。这个传言的始作俑者应该是混淆了手机“一格电”和“一格信号”这两种情况。
【结论】完全不靠谱。
五、手机连线远程开车锁?
车锁
【传言】车用遥控器落在车里,通过手机通话远程遥控开锁。
【求证】对此,网络辟谣称:汽车遥控器发射的电波频率大多集中在 315Mhz 和 433Mhz 左右,而无论 2G 还是 3G 手机,使用的电波频率都高于这个数值,两者“语言不同”。
【结论】简单讲,这条传言是假的!
六、边充电边接电话危险?
充电
【传言】当手机正在充电时,请勿接电话!原因是手机在充电时,接听会有潜在危险。
【求证】经过安全测试的手机不会发生此类情况,充电时接听也是安全的。但不排除没有使用原装设备充电导致手机发热、爆炸等极端情况发生。
【结论】直接用交流电充电时,最好拔下电源再接听。
七、关机也会泄露行踪?
【传言】手机即使在关机状态,只要有电池,远程的程序就能激活它,暴露你的坐标。万全的办法就是将手机的电池取出,彻底断绝电源。
【求证】这条流言的产生估计是受了许多高科技谍战电影的影响。窃听技术的发展历史悠久且被各国情报部门所青睐,最新的技术对大多数人来说都不可能了解到,也让这条流言难以证伪。但至少我们普通人无需担心,因为普通的手机是不具备这种功能的。
【结论】通常情况下,无需担心。

转载自 http://www.sum16.com/please-dont-insult-my-intelligence-in-the-circle-of-friends.html

解决json_encode中文UNICODE转码问题

前段时间做东西时用到了 json,php 自带的 json_encode 会将 unicode 字符转码,以 \uxxxx 的形式输出,这样不方便调试,并且,不方便插入数据库(mysql 会自动去掉反斜杠,变成 uxxxx)。于是在网上找到了如下两种解决方案:

  1. JSON_UNESCAPED_UNICODE:
    该方法只适用于 php 5.4 及以上版本,使用方法:

    1
    2
    <?php
    echo json_encode("中文", JSON_UNESCAPED_UNICODE);
  2. 自己写 function 处理:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    function ch_json_encode($data) {

    function ch_urlencode($data) {
    if (is_array($data) || is_object($data)) {
    foreach ($data as $k => $v) {
    if (is_scalar($v)) {
    if (is_array($data)) {
    $data[$k] = urlencode($v);
    } else if (is_object($data)) {
    $data->$k = urlencode($v);
    }
    } else if (is_array($data)) {
    $data[$k] = ch_urlencode($v); //递归调用该函数
    } else if (is_object($data)) {
    $data->$k = ch_urlencode($v);
    }
    }
    }
    return $data;
    }

    $ret = ch_urlencode($data);
    $ret = json_encode($ret);
    return urldecode($ret);
    }

个人觉得第二种方法有 bug,以前有过输出 \’ 的经历。

参考 http://blog.csdn.net/lanqiao825/article/details/26700809http://blog.sina.com.cn/s/blog_6ad6243801016zqo.html

mysql中You can't specify target table for update in FROM clause错误

mysql中You can’t specify target table for update in FROM clause错误的意思是说,不能先select出同一表中的某些值,再update这个表(在同一语句中)。 例如下面这个sql:

1
2
3
4
5
6
7
8
delete from tbl where id in 
(
select max(id) from tbl a where EXISTS
(
select 1 from tbl b where a.tac=b.tac group by tac HAVING count(1)>1
)
group by tac
)

改写成下面就行了:

1
2
3
4
5
6
7
8
9
10
11
delete from tbl where id in 
(
select a.id from
(
select max(id) id from tbl a where EXISTS
(
select 1 from tbl b where a.tac=b.tac group by tac HAVING count(1)>1
)
group by tac
) a
)

也就是说将select出的结果再通过中间表select一遍,这样就规避了错误。注意,这个问题只出现于mysql,mssql和oracle不会出现此问题。

转载自:http://blog.csdn.net/priestmoon/article/details/8016121

使用 php 连接 websocket 服务器

  最近在写一个问卷调查(也可以投票用)系统,因为有一个大屏幕需要实时显示结果,于是用了 websocket。考虑到投票用户用的浏览器可能不支持 websocket,于是就只写了一个普通的表单,向 websocket 传消息的任务就交给了 php。百度了下,找到了个现成的客户端(PHP Websocket 客户端 - 下载频道 - CSDN.NET),但是下载下来以后试了下发现无法正常使用,于是调整了它的 header,server 端则打印出通讯的 log,结果发现,连接是可以正常建立的,发送数据却失败。查了下资料(关于websocket - 轩脉刃 - 博客园),发现源码中的 senddata 的 function 是错误的,它没有对数据进行处理就直接发送了。发现问题后,我根据通讯协议对源码做了如下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
public function sendData($data)
{
// send actual data:
fwrite($this->_Socket, $this->encode($data)) or die('Error:' . $errno . ':' . $errstr);
$wsData = fread($this->_Socket, 2000);
$retData = trim($wsData,chr(0).chr(255));
return $retData;
}

private function encode( $data ) {
$data = is_array( $data ) || is_object( $data ) ? json_encode( $data ) : (string) $data;
$len = strlen( $data );
$mask=array();
for ($j=0;$j<4;$j++) {
$mask[]=mt_rand(1,255);
}
$head[0] = 129;
if ( $len <= 125 ) {
$head[1] = $len;
} elseif ( $len <= 65535 ) {
$split = str_split( sprintf('%016b', $len ), 8 );
$head[1] = 126;
$head[2] = bindec( $split[0] );
$head[3] = bindec( $split[1] );
} else {
$split = str_split( sprintf('%064b', $len ), 8 );
$head[1] = 127;
for ( $i = 0; $i < 8; $i++ ) {
$head[$i+2] = bindec( $split[$i] );
}
if ( $head[2] > 127 ) {
return false;
}
}
$head[1]+=128;
$head=array_merge($head,$mask);
foreach( $head as $k => $v ) {
$head[$k] = chr( $v );
}

$mask_data='';
for ($j=0;$j<$len;$j++) {
$mask_data.=chr(ord($data[$j]) ^ $mask[$j % 4]);
}
return implode('', $head ) . $mask_data;
}

private function _connect($host, $port)
{
$key1 = $this->_generateRandomString(32);
$key2 = $this->_generateRandomString(32);
$key3 = $this->_generateRandomString(8, false, true);

$header = "GET ws://".$host.":".$port."/ HTTP/1.1\r\n";
$header.= "Host: ".$host.":".$port."\r\n";
$header.= "Connection: Upgrade\r\n";
$header.= "Pragma: no-cache\r\n";
$header.= "Cache-Control: no-cache\r\n";
$header.= "Upgrade: websocket\r\n";
$header.= "Sec-WebSocket-Version: 13\r\n";
$header.= "User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36\r\n";
$header.= "Accept-Encoding: gzip, deflate, sdch\r\n";
$header.= "Accept-Language: zh-CN,zh;q=0.8\r\n";
$header.= "Sec-WebSocket-Key: " . $key1 . "\r\n";
$header.= "Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n";
$header.= "\r\n";


$this->_Socket = fsockopen($host, $port, $errno, $errstr, 2);
fwrite($this->_Socket, $header) or die('Error: ' . $errno . ':' . $errstr);
$response = fread($this->_Socket, 2000);

/**
* @todo: check response here. Currently not implemented cause "2 key handshake" is already deprecated.
* See: http://en.wikipedia.org/wiki/WebSocket#WebSocket_Protocol_Handshake
*/

return true;
}

  替换源码中的 sendData 与 _connect 并添加 encode function 即可,因为修改之前的源码是别人发布的,所以下载见文章开头的 csdn 链接。

使用Raspberry Pi作为无线路由器

鉴于之前的教程过于麻烦。。自己也从头试了一下,发现有点问题,于是本人决定全部推倒重写一遍(注:本文采用的无线网卡为 TP-LINK WN823N,RTL8192CU 芯片)

另外,文章中用了 vi 编辑器,树莓派自带 vim-tiny,有点反人类,apt-get install vim 解决问题

参考了以下两篇文章(如果只按照其中的一篇来都不会成功,所以整理了一下):

一、安装dhcp服务和ap热点服务

1
apt-get install isc-dhcp-server hostapd

二、配置无线网络
本文搭建的无线网络使用了 192.168.51 网段,如有需要,请自行修改,后文同

1
vi /etc/network/interfaces

1
2
3
4
5
6
7
8
9
10
11
auto lo

iface lo inet loopback
iface eth0 inet dhcp

allow-hotplug wlan0
iface wlan0 inet static
address 192.168.51.1
netmask 255.255.255.0

iface default inet dhcp

三、修改 DHCP Server 设置

1
vi /etc/dhcp/dhcpd.conf

在最后添加,注意是在最后:

1
2
3
4
5
6
subnet 192.168.51.0 netmask 255.255.255.0 {
range 192.168.51.100 192.168.51.254;
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.51.255;
option routers 192.168.51.1;
}

四、打开内核的网卡转发能力

1
vi /etc/sysctl.conf

将 net.ipv4.ip_forward=1 的注释去掉

五、重新编译 hostapd 使其支持 RTL8192CU 芯片的无线网卡

1
2
3
4
wget http://futa.ooo/uploads/2015/01/RTL8188-hostapd-master.zip
unzip RTL8188-hostapd-master.zip
cd RTL8188-hostapd-master/hostapd
make;make install

六、修改 iptables 的 nat 规则并保存

1
2
3
4
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
iptables-save > /etc/iptables.ipv4.nat

开机自动加载 iptables 规则:

1
vi /etc/rc.local

在 exit 0; 前面添加

1
iptables-restore</etc/iptables.ipv4.nat

七、修改无线网络的设置

1
vi /etc/hostapd/hostapd.conf

只需要改两行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Basic configuration

interface=wlan0
ssid=sxbxjhwm_raspberry # SSID,修改
channel=1
#bridge=br0

# WPA and WPA2 configuration

macaddr_acl=0
auth_algs=1
ignore_broadcast_ssid=0
wpa=3
wpa_passphrase=87654321 # 密码,修改
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP
rsn_pairwise=CCMP

# Hardware configuration

driver=rtl871xdrv
ieee80211n=1
hw_mode=g
device_name=RTL8192CU
manufacturer=Realtek

P.S. 如果 DHCP 获取不到 IP,需要添加自启动:

1
vi /etc/rc.local

在 exit 0 之前添加以下代码:

1
2
3
4
5
ifdown wlan0
ifup wlan0
ifconfig wlan0 192.168.51.1 netmask 255.255.255.0
service isc-dhcp-server restart
service hostapd restart


实验成功,效果图:
QQ截图20150116205540
QQ图片20150116205445
QQ图片20150116205452
QQ图片20150116205458

Linux umount 报 device is busy 的处理方法

今天在IDC 辐射了半天,又弄了套DG。 在Linux 挂盘这块也小学了两招。

一. umout 移动硬盘
开始用sftp 将安装文件copy到服务器的时候,速度太慢了,500k/s。几个G的东西,copy 这些就要半个多小时,扛不住,拿移动硬盘来copy了。 结果移动硬盘的格式不对。 是NTFS 格式,Linux 识别不了。 只能格式化成FAT32的。 而GG 的win7 系统又不具备格式化成FAT32的功能。 有点小变态。让同事在XP 下帮我格式化了。

安装文件copy到服务器后,同事直接将移动硬盘从服务器上拔下来了。 导致的结果是,用df 命令查看,挂载的移动硬盘还存在。

1
2
3
4
5
6
7
[root@qs-wg-db1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
/dev/sdb3 125G 3.3G 115G 3% /
/dev/sdb1 99M 12M 82M 13% /boot
tmpfs 3.9G 0 3.9G 0% /dev/shm
/dev/sda1 275G 72G 189G 28% /u01
/dev/sdc1 10G 2.0G 8.1G 20% /datatmp

就是这个/dev/sdc1。

这时使用umount 命令,会提示设备忙,无法挂载。

处理方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@qs-wg-db1 ~]# fuser -km /datatmp
[root@qs-wg-db1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
/dev/sdb3 125G 3.3G 115G 3% /
/dev/sdb1 99M 12M 82M 13% /boot
tmpfs 3.9G 0 3.9G 0% /dev/shm
/dev/sda1 275G 72G 189G 28% /u01
/dev/sdc1 10G 2.0G 8.1G 20% /datatmp
[root@qs-wg-db1 ~]# umount /datatmp
[root@qs-wg-db1 ~]# df -lh
Filesystem Size Used Avail Use% Mounted on
/dev/sdb3 125G 3.3G 115G 3% /
/dev/sdb1 99M 12M 82M 13% /boot
tmpfs 3.9G 0 3.9G 0% /dev/shm
/dev/sda1 275G 72G 189G 28% /u01

成功umount了。

二. umount 光驱
安装DB 之前,检查了一下相关包,少了3个。 从系统安装盘上找了包,安装了一下。 当时是直接将/dev/cdrom mount 到了/mnt目录。 也是图个方便。 结果收工时去拿盘,光驱弹不出来。 同事让我把cdrom umout掉。 同样的提示,设备忙。

处理方法:

1
2
[root@qs-wg-db1 ~]#fuser –km /dev/cdrom
[root@qs-wg-db1 ~]#eject -- 弹出光驱

在网上搜了一下,正确挂载CD-ROM的方法应该如下:

1
2
3
4
# mkdir cdrom
# mount /dev/cdrom /mnt/cdrom
或者
# mount /dev/cdrom /media/cdrom

直接挂载在/mnt,/media等系统目录下,在umount时会出现出错信息“umount: /mnt/cdrom: device is busy”的情况。

如果一个文件系统处于“busy”状态的时候,不能卸载该文件系统。如下情况将导致文件系统处于“busy”状态:
1) 文件系统上面有打开的文件
2) 某个进程的工作目录在此文件系统上
3) 文件系统上面的缓存文件正在被使用

三. fuser 命令
前面2个umout 都使用了这个fuser 命令。 man了一下这个命令。 内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
[root@qs-wg-db1 ~]# man fuser
FUSER(1) User Commands FUSER(1)

NAME
fuser - identify processes using files or sockets

SYNOPSIS
fuser [-a|-s|-c] [-4|-6] [-n space ] [-k [-i] [-signal ] ] [-muvf] name
fuser -l
fuser -V

DESCRIPTION
fuser displays the PIDs of processes using the specified files or file systems. In the default display mode, each file name is followed by a letter denoting the type
of access:
c current directory.
e executable being run.
f open file. f is omitted in default display mode.
F open file for writing. F is omitted in default display mode.
r root directory.
m mmap'ed file or shared library.

fuser returns a non-zero return code if none of the specified files is accessed or in case of a fatal error. If at least one access has been found, fuser returns zero.
In order to look up processes using TCP and UDP sockets, the corresponding name space has to be selected with the -n option. By default fuser will look in both IPv6 and IPv4 sockets. To change the default, behavior, use the -4 and -6 options. The socket(s) can be specified by the local and remote port, and the remote address. All fields are optional, but commas in front of missing fields must be present:
[lcl_port][,[rmt_host][,[rmt_port]]]
Either symbolic or numeric values can be used for IP addresses and port numbers.

fuser outputs only the PIDs to stdout, everything else is sent to stderr.

OPTIONS
-a Show all files specified on the command line. By default, only files that are accessed by at least one process are shown.
-c Same as -m option, used for POSIX compatibility.
-f Silently ignored, used for POSIX compatibility.
-k Kill processes accessing the file. Unless changed with -signal, SIGKILL is sent. An fuser process never kills itself, but may kill other fuser processes. The effective user ID of the process executing fuser is set to its real user ID before attempting to kill.
-i Ask the user for confirmation before killing a process. This option is silently ignored if -k is not present too.
-l List all known signal names.
-m name specifies a file on a mounted file system or a block device that is mounted. All processes accessing files on that file system are listed. If adirectory file is specified, it is automatically changed to name/. to use any file system that might be mounted on that directory.

-n space Select a different name space. The name spaces file (file names, the default), udp (local UDP ports), and tcp (local TCP ports) are supported. For ports, either the port number or the symbolic name can be specified. If there is no ambiguity, the shortcut notation name/Ispace (e.g. 80/tcp ) can be used.
-s Silent operation. -u and -v are ignored in this mode. -a must not be used with -s.
-signal Use the specified signal instead of SIGKILL when killing processes. Signals can be specified either by name (e.g. -HUP) or by number (e.g. -1). This option is silently ignored if the -k option is not used.
-u Append the user name of the process owner to each PID.
-v Verbose mode. Processes are shown in a ps-like style. The fields PID, USER and COMMAND are similar to ps. ACCESS shows how the process accesses the file. If the access is by the kernel (e.g. in the case of a mount point, awap file, etc.), kernel is shown instead of the PID.
-V Display version information.
-4 Search only for IPv4 sockets. This option must not be used with the -6 option and only has an effect with the tcp and udp namespaces.
-6 Search only for IPv6 sockets. This option must not be used with the -4 option and only has an effect with the tcp and udp namespaces.
- Reset all options and set the signal back to SIGKILL.
FILES
/proc location of the proc file system

fuser 命令显示访问某个文件的进程的PID. 其中-k 和 -m 参数上面红色部分有说明。-k 是kill 访问这个文件的进程。 没有进程访问,就可以成功umount了.

转载自 http://blog.csdn.net/tianlesoftware/article/details/6194295

移动端重构系列10——侧边栏导航

本系列文章,如果没有特别说明,兼容安卓4.0.4+

panel一般用来做侧边栏导航,铺满整屏高度,有两种展现形式:第一种直接盖在整块内容栏(包括header和footer部分)上面,如图一;第二种把整块内容栏推开panel的宽度,如图二
panel1
panel2

设计结构如下:

1
2
3
4
5
6
7
<header class="header"></header>
<div class="wrap-page">
<section class="page"></section>
...
</div>
<footer class="footer"></footer>
<section class="panel"></section>

第一种实现方案:
demo 1
先将panel通过translate偏移负的本身宽度,离开可视区域,然后通过切换active这个class来实现无偏移。当然除此之外,top和bottom的0实现了100%高度,z-index要保证大于header和footer的层级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$panelWidth:      120px !default;
.panel{
position: absolute;
top: 0;
bottom: 0;
left: 0;
z-index: 980;
width: $panelWidth;
background-color: #333;
@include translate3d(-$panelWidth, 0, 0);
@extend %transition-transform;
}
.panel.active{
@include translate3d(0, 0, 0);
}

同样我们也可以通过给body添加删除class如panel-active来控制panel的位置。

第二种实现方案
demo 2,在demo1的基础上根据第二种方案顺便处理下了当panel出现时,内容禁止滚动
因为需要实现整块内容栏(包括header和footer部分)偏移panel的宽度,所以第一反应是应该有个div把整块内容栏包裹下,如下:

1
2
3
4
5
6
7
8
9
<div class="wrap-container">
<header class="header"></header>
<div class="wrap-page">
<section class="page"></section>
...
</div>
<footer class="footer"></footer>
</div>
<section class="panel"></section>

多了一层结构,看起来有点不爽,不过使用起来还是很爽的。首先panel偏移负的本身宽度,接下来通过控制wrap-container的class来实现内容栏偏移panel的宽度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.panel{
position: absolute;
top: 0;
bottom: 0;
left: 0;
z-index: $zIndexOverlay;
width: $panelWidth;
background-color: #333;
@include translate3d(-$panelWidth, 0, 0);
}
.wrap-container{
@extend %transition-transform;
}
.wrap-container.panel-active{
@include translate3d($panelWidth, 0, 0);
}

既然这里需要一个父元素来实现一个偏移,为什么body不可以呢?所以果断干掉wrap-container,恢复最初的结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.panel{
position: absolute;
top: 0;
bottom: 0;
left: 0;
z-index: $zIndexOverlay;
width: $panelWidth;
background-color: #333;
@include translate3d(-$panelWidth, 0, 0);
}
body.has-panel{
@extend %transition-transform;
}
body.panel-active{
@include translate3d($panelWidth, 0, 0);
}

总结
一般来说使用比较多的还是第二种方案,因为第一种直接把左边的那个点击图标遮盖住了。而panel实际使用的时候还是挺不太好办的,因为左边的第一个icon一般都是放首页,返回什么的,当然适用不适用还是根据各自业务需要走

转载自:http://www.w3cplus.com/mobile/mobile-terminal-refactoring-sidebar-menu.html