Hello World


  • 首页

  • 归档

  • 标签

Git配置和常用命令

发表于 2015-06-25 | 分类于 工具

Git配置

1
2
3
4
5
6
7
8
git config --global user.name "hunng"
git config --global user.email "huangthink@gmail.com"
git config --global color.ui true
git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch
git config -l # 列举所有配置

用户的git配置文件在~/.gitconfig,我的配置:

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
cat .gitconfig
[user]
email = huangthink@gmail.com
name = hunng
[color]
ui = auto
[color "branch"]
current = yellow reverse
local = yellow
remote = green
[color "diff"]
meta = yellow bold
frag = magenta bold
old = red bold
new = green bold
[color "status"]
added = yellow
changed = green
untracked = cyan
[alias]
st = "status"
co = checkout
ls = "ls-files"
ci = commit
br = branch
rt = reset --hard
unstage = reset HEAD
uncommit = reset --soft HEAD^
l = log --pretty=oneline --abbrev-commit --graph --decorate
amend = commit --amend
who = shortlog -n -s --no-merges
g = grep -n --color -E
cp = cherry-pick -x
cb = checkout -b
[core]
filemode = true

Git常用命令

查看、帮助命令

1
2
3
git help <command> # 显示command的help
git show # 显示某次提交的内容
git show $id

查看提交记录

1
2
3
4
5
6
7
8
9
10
git log
git log <file> # 查看该文件每次提交记录
git log -p <file> # 显示版本历史,以及版本间的内容差异
git log -p -2 # 查看最近两次详细修改内容的diff
git log --stat # 查看提交统计信息
git log --since="6 hours" # 显示最近6小时提交
git log --before="2 days" # 显示2天前提交
git log -1 HEAD~3 # 显示比HEAD早3个提交的那个提交
git log -1 HEAD^^^
git reflog # 查看操作记录

添加、提交、删除、找回,重置修改文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
git co -- <file> # 抛弃工作区修改
git co . # 抛弃工作区修改
git co HEAD <file> # 抛弃工作目录区中文件的修改
git add <file> # 将工作文件修改提交到本地暂存区
git add . # 将所有修改过的工作文件提交暂存区
git rm <file> # 从版本库中删除文件
git rm <file> --cached # 从版本库中删除文件,但不删除文件
git reset <file> # 从暂存区恢复到工作文件
git reset -- . # 从暂存区恢复到工作文件
git reset --hard HEAD^ # 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改
git reset --hard <commit id> # 恢复到某一次提交的状态
git reset HEAD <file> # 抛弃暂存区中文件的修改
git ci <file>
git ci .
git ci -a # 将git add, git rm和git ci等操作都合并在一起做
git ci -am "some comments"
git ci --amend # 修改最后一次提交记录
git revert <$id> # 恢复某次提交的状态,恢复动作本身也创建了一次提交对象
git revert HEAD # 恢复最后一次提交的状态

查看文件diff

1
2
3
4
5
6
7
git diff <file> # 比较当前文件和暂存区文件差异
git diff
git diff <$id1> <$id2> # 比较两次提交之间的差异
git diff <branch1>..<branch2> # 在两个分支之间比较
git diff --staged # 比较暂存区和版本库差异
git diff --cached # 比较暂存区和版本库差异
git diff --stat # 仅仅比较统计信息

Git 本地分支管理

查看、切换、创建和删除分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
git br -r # 查看远程分支
git br -v # 查看各个分支最后提交信息
git br -a # 列出所有分支
git br --merged # 查看已经被合并到当前分支的分支
git br --no-merged # 查看尚未被合并到当前分支的分支
git br <new_branch> # 基于当前分支创建新的分支
git br <new_branch> <start_point> # 基于另一个起点(分支名称,提交名称或则标签名称),创建新的分支
git br -f <existing_branch> <start_point> # 创建同名新分支,覆盖已有分支
git br -d <branch> # 删除某个分支
git br -D <branch> # 强制删除某个分支 (未被合并的分支被删除的时候需要强制)
git co <branch> # 切换到某个分支
git co -b <new_branch> # 创建新的分支,并且切换过去
git co -b <new_branch> <branch> # 基于branch创建新的new_branch
git co -m <existing_branch> <new_branch> # 移动或重命名分支,当新分支不存在时
git co -M <existing_branch> <new_branch> # 移动或重命名分支,当新分支存在时就覆盖
git co $id # 把某次历史提交记录checkout出来,但无分支信息,切换到其他分支会自动删除
git co $id -b <new_branch> # 把某次历史提交记录checkout出来,创建成一个分支

分支合并和rebase

1
2
3
4
5
6
7
git merge <branch> # 将branch分支合并到当前分支
git merge origin/master --no-ff # 不要Fast-Foward合并,这样可以生成merge提交
git merge --no-commit <branch> # 合并但不提交
git merge --squash <branch> # 把一条分支上的内容合并到另一个分支上的一个提交
git rebase master <branch> # 将master rebase到branch,相当于:
git co <branch> && git rebase master && git co master && git merge <branch>

Git补丁管理

1
2
3
4
git diff > ../sync.patch # 生成补丁
git apply ../sync.patch # 打补丁
git apply --check ../sync.patch # 测试补丁能否成功
git format-patch -X # 根据提交的log生成patch,X为数字,表示最近的几个日志

Git暂存管理

1
2
3
4
git stash # 暂存
git stash list # 列所有stash
git stash apply # 恢复暂存的内容
git stash drop # 删除暂存区

Git远程分支管理

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
git pull # 抓取远程仓库所有分支更新并合并到本地
git pull --no-ff # 抓取远程仓库所有分支更新并合并到本地,不要快进合并
git fetch origin # 抓取远程仓库所有更新
git fetch origin remote-branch:local-branch #抓取remote-branch分支的更新
git fetch origin --tags # 抓取远程上的所有分支
git checkout -b <new-branch> <remote_tag> # 抓取远程上的分支
git merge origin/master # 将远程主分支合并到本地当前分支
git co --track origin/branch # 跟踪某个远程分支创建相应的本地分支
git co -b <local_branch> origin/<remote_branch> # 基于远程分支创建本地分支,功能同上
git push # push所有分支
git push origin master # 将本地主分支推到远程主分支
git push -u origin master # 将本地主分支推到远程(如无远程主分支则创建,用于初始化远程仓库)
git push origin <local_branch> # 创建远程分支, origin是远程仓库名
git push origin <local_branch>:<remote_branch> # 创建远程分支
git push origin :<remote_branch> #先删除本地分支(git br -d <branch>),然后再push删除远程分支
#### Git远程仓库管理
```bash
git remote -v # 查看远程服务器地址和仓库名称
git remote show origin # 查看远程服务器仓库状态
git remote add origin git@github:XXX/test.git # 添加远程仓库地址
git remote set-url origin git@github.com:XXX/test.git # 设置远程仓库地址(用于修改远程仓库地址)
git remote rm <repository> # 删除远程仓库
git remote set-head origin master # 设置远程仓库的HEAD指向master分支
git branch --set-upstream master origin/master
git branch --set-upstream develop origin/develop

实例

打patch过程

1
2
3
4
git add .
git status
git diff --cached >XXX.patch
git ci -m 'add patch'

多终端管理器tmux使用详解

发表于 2015-06-19 | 分类于 工具

tmux是一个优秀的终端复用软件,类似GNU Screen,但来自于OpenBSD,采用BSD授权。使用它最直观的好处就是,通过一个终端登录远程主机并运行tmux后,在其中可以开启多个控制台而无需再“浪费”多余的终端来连接这台远程主机;当然其功能远不止于此。

ubuntu可以使用sudo apt-get install tmux来安装。安装完成后输入命令tmux即可打开软件,界面十分简单,类似一个下方带有状态栏的终端控制台;但根据tmux的定义,在开启了tmux服务器后,会首先创建一个会话,而这个会话则会首先创建一个窗口,其中仅包含一个面板;也就是说,这里看到的所谓终端控制台应该称作tmux的一个面板,虽然其使用方法与终端控制台完全相同。

tmux使用C/S模型构建,主要包括以下单元模块:




















server 服务器。输入tmux命令时就开启了一个服务器。
session 会话。一个服务器可以包含多个会话。
window 窗口。一个会话可以包含多个窗口。
pane 面板。一个窗口可以包含多个面板。

会话

1
2
3
4
tmux new -s session #建立会话
tmux new -s session -d #在后台建立会话
tmux ls #列出会话
tmux attach -t session #进入某个会话

操作

类似各种平铺式窗口管理器,tmux使用键盘操作,常用快捷键包括:















































































































































Ctrl+b 激活控制台;此时以下按键生效
系统操作 ? 列出所有快捷键;按q返回
d 脱离当前会话;这样可以暂时返回Shell界面,输入tmux attach能够重新进入之前的会话
D 选择要脱离的会话;在同时开启了多个会话时使用
Ctrl+z 挂起当前会话
r 强制重绘未脱离的会话
s 选择并切换会话;在同时开启了多个会话时使用
: 进入命令行模式;此时可以输入支持的命令,例如kill-server可以关闭服务器
[ 进入复制模式;此时的操作与vi/emacs相同,按q/Esc退出
~ 列出提示信息缓存;其中包含了之前tmux返回的各种提示信息
窗口操作 c 创建新窗口
& 关闭当前窗口
数字键 切换至指定窗口
p 切换至上一窗口
n 切换至下一窗口
l 在前后两个窗口间互相切换
w 通过窗口列表切换窗口
, 重命名当前窗口;这样便于识别
. 修改当前窗口编号;相当于窗口重新排序
f 在所有窗口中查找指定文本
面板操作 ” 将当前面板平分为上下两块
% 将当前面板平分为左右两块
x 关闭当前面板
! 将当前面板置于新窗口;即新建一个窗口,其中仅包含当前面板
Ctrl+方向键 以1个单元格为单位移动边缘以调整当前面板大小
Alt+方向键 以5个单元格为单位移动边缘以调整当前面板大小
Space 在预置的面板布局中循环切换;依次包括even-horizontal、even-vertical、main-horizontal、main-vertical、tiled
q 显示面板编号
o 在当前窗口中选择下一面板
方向键 移动光标以选择面板
{ 向前置换当前面板
} 向后置换当前面板
Alt+o 逆时针旋转当前窗口的面板
Ctrl+o 顺时针旋转当前窗口的面板

配置

tmux的系统级配置文件为/etc/tmux.conf,用户级配置文件为~/.tmux.conf。没有该文件新建一个即可。配置文件实际上就是tmux的命令集合,也就是说每行配置均可在进入命令行模式后输入生效。

注意:更改配置之后需要重启tmux或者进入命令模式(按按键前缀后再按: )输入 source-file ~/.tmux.conf即可。

1
2
#将ctrl-r键设置为加载配置文件,并显示"reloaded!"信息
bind C-r source-file ~/.tmux.conf \; display "Reloaded!"

copy-mode(复制模式)

a.PREFIX [ 进入复制模式
b.按 space 开始复制,移动光标选择复制区域
c.按 Enter 复制并退出copy-mode。
d.将光标移动到指定位置,按 PREIFX ] 粘贴

在~/.tmux.conf中加入如下行,否则在VIM中复制模式无法完成操作

1
setw -g mode-keys vi

重新连接到之前的窗口

1
tmux attach

不过如果没有会话会提示:

1
no sessions

修改Tmux配置如果无分离终端则新建,在.tmux.conf加入如下行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#将ctrl-r键设置为加载配置文件,并显示"reloaded!"信息
bind C-r source-file ~/.tmux.conf \; display "Reloaded!"
#tmux attach 如果无分离终端则新建
new-session
#此类配置可以在命令行模式中输入show-options -g查询
set-option -g status-keys vi #操作状态栏时的默认键盘布局;可以设置为vi或emacs
set-option -g status-utf8 on #开启状态栏的UTF-8支持
#此类设置可以在命令行模式中输入show-window-options -g查询
set-window-option -g mode-keys vi #复制模式中的默认键盘布局;可以设置为vi或emacs
set-window-option -g utf8 on #开启窗口的UTF-8支持
#选择分割的窗格,不需要松开ctrl键,多次跳转更方便
bind C-k selectp -U # 选择上窗格
bind C-j selectp -D # 选择下窗格
bind C-h selectp -L # 选择左窗格
bind C-l selectp -R # 选择右窗格
#执行命令,比如 Manpage
bind m command-prompt "splitw -h 'exec man %%'"

Start tmux on every shell login

1
vi ~/.bashrc

添加:

1
2
3
# If not running interactively, do not do anything
[[ $- != *i* ]] && return
[[ $TERM != screen* ]] && exec tmux

详细参考:https://wiki.archlinux.org/index.php/Tmux#Start_tmux_on_every_shell_login

这样做,会使每一个该用户下的终端都进入tmux。如果需要ssh到其他机子上,进入其上的tmux 或 screen,会导致快捷键冲突以及显示混乱。

参考:

1.https://wiki.freebsdchina.org/software/t/tmux?utm_source=twitterfeed&utm_medium=twitter
2.http://linuxtoy.org/archives/from-screen-to-tmux.html
3.http://linuxtoy.org/archives/from-screen-to-tmux.html
4.http://os.51cto.com/art/200908/144275.htm
5.http://blog.onovps.com/archives/tmux-attach.html
6.http://tmux.sourceforge.net/
7.http://www.cnblogs.com/congbo/archive/2012/08/30/2649420.html

一道经典的JavaScript试题

发表于 2015-06-17 | 分类于 技术
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var add = function (m) {
var temp = function (n) {
return add(m + n);
}
temp.toString = function () {
return m;
}
return temp;
};
add(3)(4)(5); // 12
add(3)(6)(9)(25); // 43

这个add函数可以无限次调用循环调用,并且把所有传进去的值相加,最后返回相加总数。这道题咋一看有点特别,但代码量极其少而精,重点技术在于:作用域、交替、匿名函数、toString的巧妙。
让我们来解释这个过程:add(3)(4)(5)

  1. 先执行add(3),此时m=3,并且返回temp函数
  2. 执行temp(4),这个函数内执行add(m+n),n是此次传进来的数值4,m值还是上一步中的3,所以add(m+n)=add(3+4)=add(7),此时m=7,并且返回temp函数
  3. 执行temp(5),这个函数内执行add(m+n),n是此次传进来的数值5,m值还是上一步中的7,所以add(m+n)=add(7+5)=add(12),此时m=12,并且返回temp函数
  4. 串的方法,因此代码中temp函数的toString函数return m值,而m值是最后一步执行函数时的值m=12,所以返回值是12。

看到这其实就很明白了,代码中temp.toString的重写只是为了函数不执行时能够返回最后运算的结果值,所以这个地方是可以任意修改的,你让它返回什么它就返回什么,比如改写:

1
2
3
temp.toString = function () {
return "total : " + m;
}

执行结果:

1
2
>>> add(3)(4)(5);
total : 12

MySQL分表分区

发表于 2015-06-03 | 分类于 技术

垂直分表

垂直分表就是一个包含有很多列的表拆分成多个表,比如表A包含20个字段,现在拆分成表A1和A2,两个表各十个字段(具体如何拆根据业务来选择)。

优势:在高并发的情境下,可以减少表锁和行锁的次数。

劣势:在数据记录非常大的情况下,读写速度还是会遇到瓶颈。

水平分表

假如某个网站,它的数据库的某个表已经达到了上亿条记录,那么此时如果通过select去查询,在没有索引的情况下,他的查询会非常慢,那么就可以通过hash算法将这个表分成10个子表(此时每个表的 的数据量只有1000万条了)。同时生成一个总表,记录各个子表的信息,假如查询一条id=100的记录,它不再需要全表扫描,而是通过总表找到该记录在哪个对应的子表上,然后再去相应的表做检索,这样就降低了IO压力。

劣势:会给前端程序应用程序的SQL代码的维护带来很大的麻烦,这时候可以使用MySQL的Merge存储引擎实现分表。

用Merge存储引擎分表,对应用程序的SQL语句来说是透明的,不需要修改任何代码。

1
2
3
4
5
6
7
CREATE TABLE t1 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, message CHAR(20));
CREATE TABLE t2 ( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, message CHAR(20));
INSERT INTO t1 (message) VALUES ('Testing'),('table'),('t1');
INSERT INTO t2 (message) VALUES ('Testing'),('table'),('t2');
CREATE TABLE total (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, message CHAR(20)) ENGINE=MERGE UNION=(t1,t2) INSERT_METHOD=LAST;

实际上merge存储引擎是一个虚拟的表,对应的实际表必须是myisam类型的表,如果你的mysql是5.1以上版本,默认数据库使用的事InnoDB存储引擎的,所以在创建total时,t1和t2表必须是myisam存储引擎的。

如果需要定期增加分表,只需要修改merge表的union即可。

1
2
CREATE TABLE t3( a INT NOT NULL AUTO_INCREMENT PRIMARY KEY, message CHAR(20));
ALTER TABLE total UNION=(t1,t2,t3)

横向分区

举例说明:假如有100W条数据,分成十份,前10W条数据放到第一个分区,第二个10W条数据放到第二个分区,依此类推。取出一条数据的时候,这条数据包含了表结构中的所有字段,横向分区并没有改变表的结构。

分区表分为RANGE,LIST,HASH,KEY四种类型,并且分区表的索引是可以局部针对分区表建立的
创建分区表

1
2
3
4
5
6
7
8
9
10
CREATE TABLE sales (
id INT AUTO_INCREMENT,
amount DOUBLE NOT NULL,
order_day DATETIME NOT NULL,
PRIMARY KEY(id, order_day)
) ENGINE=Innodb PARTITION BY RANGE(YEAR(order_day)) (
PARTITION p_2010 VALUES LESS THAN (2010),
PARTITION p_2011 VALUES LESS THAN (2011),
PARTITION p_2012 VALUES LESS THAN (2012),
PARTITION p_catchall VALUES LESS THAN MAXVALUE);

纵向分区

举例说明:在设计用户表的时候,开始的时候没有考虑好,而把个人的所有信息都放到了一张表里面去,这个表里面就会有比较大的字段,如个人简介,而这些简介呢,也许不会有好多人去看,所以等到有人要看的时候,再去查找,分表的时候,可以把这样的大字段,分开来

完整的一张表,都对应三个文件,一个.MYD数据文件,.MYI索引文件,.frm表结构文件。

常用正则表达式

发表于 2015-05-25 | 分类于 技术

说明:正则表达式通常用于两种任务:1.验证,2.搜索/替换。用于验证时,通常需要在前后分别加上^和$,以匹配整个待验证字符串;搜索/替换时是否加上此限定则根据搜索的要求而定,此外,也有可能要在前后加上\b而不是^和$。此表所列的常用正则表达式,除个别外均未在前后加上任何限定,请根据需要,自行处理。






























































































说明 正则表达式
网址(URL) [a-zA-z]+://[^\s]
IP地址(IP Address) ((2[0-4]\d|25[0-5]|[01]?\d\d?).){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
电子邮件(Email) \w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)
QQ号码 [1-9]\d{4,}
HTML标记(包含内容或自闭合) <(.)(.)>.<\/\1>|<(.) \/>
密码(由数字/大写字母/小写字母/标点符号组成,四种都必有,8位以上) (?=^.{8,}$)(?=.\d)(?=.\W+)(?=.[A-Z])(?=.[a-z])(?!.\n).$
日期(年-月-日) (\d{4}|\d{2})-((1[0-2])|(0?[1-9]))-(([12][0-9])|(3[01])|(0?[1-9]))
日期(月/日/年) ((1[0-2])|(0?[1-9]))/(([12][0-9])|(3[01])|(0?[1-9]))/(\d{4}|\d{2})
时间(小时:分钟, 24小时制) ((1|0?)[0-9]|2[0-3]):([0-5][0-9])
汉字(字符) [\u4e00-\u9fa5]
中文及全角标点符号(字符) [\u3000-\u301e\ufe10-\ufe19\ufe30-\ufe44\ufe50-\ufe6b\uff01-\uffee]
中国大陆固定电话号码 (\d{4}-|\d{3}-)?(\d{8}|\d{7})
中国大陆手机号码 1\d{10}
中国大陆邮政编码 [1-9]\d{5}
中国大陆身份证号(15位或18位) \d{15}(\d\d[0-9xX])?
非负整数(正整数或零) \d+
正整数 [0-9][1-9][0-9]
负整数 -[0-9][1-9][0-9]
整数 -?\d+
小数 (-?\d+)(.\d+)?
不包含abc的单词 \b((?!abc)\w)+\b

史上最全Vim快捷键键位图 -- 入门到进阶

发表于 2015-05-19 | 分类于 工具

作者:卢钧轶(cenalulu)
本文原文地址:http://cenalulu.github.io<!--0-->


经典版

下面这个键位图应该是大家最常看见的经典版了。其实这个版本是一系列的入门教程键位图的组合结果。要查看不同编辑模式下的键位图,可以看这里打包下载
此外,这里还有简体中文版。

classic


入门版

基本操作的入门版。原版出处还有keynote版本可供DIY以及其他相关有用的cheatsheet。

entry


进阶版

下图是300DPI的超清大图,另外查看原文还有更多版本:黑白,低分辨率,色盲等

advanced


增强版

下图是一个更新时间较新的现代版,含有的信息也更丰富。原文链接

morden


文字版

原文链接
text
text

Python 判断汉字

发表于 2015-04-02 | 分类于 技术

使用 unicode 范围 \u4e00 - \u9fff 来判别汉字

unicode 分配给汉字(中日韩越统一表意文字)的范围为 4E00-9FFF

1
2
3
4
def ishan(text):
# for python 2.x, 3.3+
# sample: ishan(u'一') == True, ishan(u'我&&你') == False
return all(u'\u4e00' <= char <= u'\u9fff' for char in text)

原生JS实现AJAX

发表于 2015-03-23 | 分类于 技术

1. 原生Ajax

ajax的技术核心是 XMLHttpRequest 对象;
ajax 请求过程:创建 XMLHttpRequest 对象、连接服务器、发送请求、接收响应数据;

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
ajax({
url: "./test_xhr.php", //请求地址
type: "POST", //请求方式
data: {
name: "super",
age: 20
}, //请求参数
dataType: "json",
success: function(response, xml) {
// 此处放成功后执行的代码
},
fail: function(status) {
// 此处放失败后执行的代码
}
});
function ajax(options) {
options = options || {};
options.type = (options.type || "GET").toUpperCase();
options.dataType = options.dataType || "json";
var params = formatParams(options.data);
//创建 - 非IE6 - 第一步
if (window.XMLHttpRequest) {
var xhr = new XMLHttpRequest();
} else { //IE6及其以下版本浏览器
var xhr = new ActiveXObject('Microsoft.XMLHTTP');
}
//接收 - 第三步
xhr.onreadystatechange = function() {
// readyState值说明
// 0,初始化,XHR对象已经创建,还未执行open
// 1,载入,已经调用open方法,但是还没发送请求
// 2,载入完成,请求已经发送完成
// 3,交互,可以接收到部分数据
// 4,完成
// status值说明
// 200:成功
// 404:没有发现文件、查询或URl
// 500:服务器产生内部错误
if (xhr.readyState == 4) {
var status = xhr.status;
if (status >= 200 && status < 300) {
options.success && options.success(xhr.responseText, xhr.responseXML);
} else {
options.fail && options.fail(status);
}
}
}
//连接 和 发送 - 第二步
if (options.type == "GET") {
xhr.open("GET", options.url + "?" + params, true);
xhr.send(null);
} else if (options.type == "POST") {
xhr.open("POST", options.url, true);
//设置表单提交时的内容类型
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.send(params);
}
}
//格式化参数
function formatParams(data) {
var arr = [];
for (var name in data) {
arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name]));
}
arr.push(("v=" + Math.random()).replace("."));
return arr.join("&");
}

参考

  1. 原生JS实现AJAX、JSONP及DOM加载完成事件

Mysql复制表(表结构、索引、数据)

发表于 2015-03-23 | 分类于 技术

Mysql复制表+主键(表结构、索引和主键、数据)

mysql> create table test_users like users;
复制表结构和索引到test_users (新表:test_users 原表:users)

mysql> insert into test_users (select * from users);
复制数据,两步加起来才能创建一个和users完全一样(表结构、索引和主键、数据)的表。

mysql> create table test_users select * from users;
(只复制表数据,以及表结构)

mysql> create table test_users select names from users;
复制users表里的names数据、结构到新表 test_users

判断服务器是否支持断点续传

发表于 2015-03-16 | 分类于 技术

通常情况下,Web服务器(如Apache)会默认开启对断点续传的支持。因此,如果直接通过Web服务器来提供文件的下载,可以不必做特别的配置,即可享受到断点续传的好处。断点续传是在发起HTTP请求的时候加入RANGE头来告诉服务器客户端已经下载了多少字节。等所有这些请求都返回之后,再把得到的内容一块一块的拼接起来得到完整的资源。

1.判断服务器是否支持断点续传

1
2
wget -S http://www.example.com/test.zip 2>&1 | grep 'Accept-Ranges'
Accept-Ranges: bytes

输出结果 Accept-Ranges: bytes ,说明服务器支持按字节下载。

2.curl 命令发送字节范围下载

1
curl -–range 0-99 http://www.example.com/test.zip > t.zip

3.FileDownload.class.php

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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<?php  
class FileDownload{
  
private $_speed = 512;  
  
  
/** 下载
* @param String  $file   要下载的文件路径
* @param String  $name   文件名称,为空则与下载的文件名称一样
* @param boolean $reload 是否开启断点续传
*/  
public function download($file, $name='', $reload=false)
{  
if(file_exists($file))
{  
if($name=='')
{  
$name = basename($file);  
}  
  
$fp = fopen($file, 'rb');  
$file_size = filesize($file);  
$ranges = $this->getRange($file_size);  
  
header('cache-control:public');  
header('content-type:application/octet-stream');  
header('content-disposition:attachment; filename='.$name);  
  
if($reload && $ranges!=null)
{ // 使用续传  
header('HTTP/1.1 206 Partial Content');  
header('Accept-Ranges:bytes');  
  
// 剩余长度  
header(sprintf('content-length:%u',$ranges['end']-$ranges['start']));  
  
// range信息  
header(sprintf('content-range:bytes %s-%s/%s', $ranges['start'], $ranges['end'], $file_size));  
  
// fp指针跳到断点位置  
fseek($fp, sprintf('%u', $ranges['start']));  
}else{  
header('HTTP/1.1 200 OK');  
header('content-length:'.$file_size);  
}  
  
while(!feof($fp))
{  
echo fread($fp, round($this->_speed*1024,0));  
ob_flush();  
//sleep(1); // 用于测试,减慢下载速度  
}  
  
($fp!=null) && fclose($fp);  
  
}else{  
return '';  
}  
}  
  
  
/** 设置下载速度
* @param int $speed
*/  
public function setSpeed($speed)
{  
if(is_numeric($speed) && $speed>16 && $speed<4096)
{  
$this->_speed = $speed;  
}  
}  
  
  
/** 获取header range信息
* @param  int   $file_size 文件大小
* @return Array
*/  
private function getRange($file_size)
{  
if(isset($_SERVER['HTTP_RANGE']) && !empty($_SERVER['HTTP_RANGE']))
{  
$range = $_SERVER['HTTP_RANGE'];  
$range = preg_replace('/[\s|,].*/', '', $range);  
$range = explode('-', substr($range, 6));  
if(count($range)<2)
{  
$range[1] = $file_size;  
}  
$range = array_combine(array('start','end'), $range);  
if(empty($range['start']))
{  
$range['start'] = 0;  
}  
if(empty($range['end']))
{  
$range['end'] = $file_size;  
}  
return $range;  
}  
return null;  
}  
  
} // class end  
  
?>

demo

1
2
3
4
5
6
7
8
9
10
11
12
<?php  
require('FileDownload.class.php');  
$file = 'book.zip';  
$name = time().'.zip';  
$obj = new FileDownload();  
$flag = $obj->download($file, $name);  
//$flag = $obj->download($file, $name, true); // 断点续传  
  
if(!$flag){  
echo 'file not exists';  
}  
?>

4.Discuz!论坛软件的attachment.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
$range = 0;
if($readmod == 4)
{
dheader('Accept-Ranges: bytes');
if(!emptyempty($_SERVER['HTTP_RANGE']))
{
list($range) = explode('-',(str_replace('bytes=', '', $_SERVER['HTTP_RANGE'])));
$rangesize = ($filesize - $range) > 0 ? ($filesize - $range) : 0;
dheader('Content-Length: '.$rangesize);
dheader('HTTP/1.1 206 Partial Content');
dheader('Content-Range: bytes='.$range.'-'.($filesize-1).'/'.($filesize));
}
}  
?>
1234
DW

DW

37 日志
5 分类
20 标签
© 2018 DW
由 Hexo 强力驱动
主题 - NexT.Muse