l1n6yun's Blog

记录学习的技能和遇到的问题

设置cookie

1
2
3
4
5
6
7
function setCookie(name,value) 
{
var Days = 30;
var exp = new Date();
exp.setTime(exp.getTime() + Days*24*60*60*1000);
document.cookie = name + "="+ escape (value) + ";expires=" + exp.toGMTString();
}

读取cookie

1
2
3
4
5
function getCookie(name) 
{
var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
   return (arr=document.cookie.match(reg))?unescape(arr[2]):null;
}

删除cookie(将cookie设置过期即可)

1
2
3
4
5
6
7
8
function delCookie(name) 
{
var exp = new Date();
exp.setTime(exp.getTime() - 1);
var cval=getCookie(name);
if(cval!=null)
document.cookie= name + "="+cval+";expires="+exp.toGMTString();
}

escape(string) 函数可对字符串进行编码,这样就可以在所有的计算机上读取该字符串。
unescape(string) 函数可对通过 escape() 编码的字符串进行解码。

正则表达式(Regular Expression)是一种文本模式,包含普通字符(列如,a 到 z 之间的字母)和特殊字符(元字符)。

正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串。

正则表达式 - 语法

普通字符串

字符 描述
[ABC] 匹配 [...] 中的所有字符。例如用 /[lny]/g 来匹配字符串 “l1n6yun”,可以匹配到 l,n,y,n
[!ABC] 匹配除了 [!...] 中的所有字符。例如 /[^lny]/g 来匹配字符串 “l1n6yun”,可以匹配到 1,6,u
[A-Z] [a-z] [A-Z] 表示一个区间,匹配所有大写字母。[a-z] 表示匹配所有小写字母。
. 匹配除换行符 ( \r\n) 之外的任何单字符,相当于 [^\r\n]
[\s\S] 匹配所有。\s 是匹配所有空白符,包含换行,\S 非空白符,不包含换行
\w 匹配字母、数字、下划线。等价于 [A-Za-z0-9_]

非打印字符

字符 描述
\cx 匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Za-z 之一。否则,将 c 视为一个原义的 ‘c’ 字符。
\f 匹配一个换页符。等价于 \x0c\cL
\n 匹配一个换行符。等价于 \x0a\cJ
\r 匹配一个回车符。等价于 \x0d\cM
\s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [\f\n\r\t\v]。注意 Unicode 正则表达式会匹配全角空格符。
\S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]
\t 匹配一个制表符。等价于 \x09\cI
\v 匹配一个垂直制表符。等价于 \x0b\cK
\xn 匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,’\x41’ 匹配 “A”。’\x041’ 则等价于 ‘\x04’ & “1”。正则表达式中可以使用 ASCII 编码。
\n 标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。
\nm 标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n 和 m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm。
\nml 如果 n 为八进制数字 (0-3),且 m 和 l 均为八进制数字 (0-7),则匹配八进制转义值 nml。
\un 匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)。

特殊字符

特别字符 描述
$ 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n’ 或 ‘\r’。要匹配 $ 字符本身,请使用 $。
( ) 标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 ( 和 )。
* 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 *。
+ 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。
. 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 . 。
[ 标记一个中括号表达式的开始。要匹配 [,请使用 [。
? 匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 ?。
\ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n’ 匹配字符 ‘n’。’\n’ 匹配换行符。序列 ‘\‘ 匹配 “",而 ‘(‘ 则匹配 “(“。
^ 匹配输入字符串的开始位置,除非在方括号表达式中使用,当该符号在方括号表达式中使用时,表示不接受该方括号表达式中的字符集合。要匹配 ^ 字符本身,请使用 ^。
{ 标记限定符表达式的开始。要匹配 {,请使用 {。
| 指明两项之间的一个选择。要匹配 |,请使用 |。

限定符

字符 描述
* 匹配前面的子表达式零次或多次。***** 等价于 {0,}
+ 匹配前面的子表达式一次或多次。+ 等价于 {1,}
? 匹配前面的子表达式零次或一次。? 等价于 {0,1}
{n} n 是一个非负整数。匹配确定的 n 次。
{n,} n 是一个非负整数。至少匹配n 次。
{n,m} m 和 n 均为非负整数,其中 n <= m。

*+ 限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个 ? 就可以实现非贪婪或最小的匹配。

定位符

定位符使您能够将正则表达式固定到行首或行尾。他们还使您能够创建这样的正则表达式,这些正则表达式出现在一个单词内、在一个单词的开头或者一个单词的结尾。

字符 描述
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与 \n 或 \r 之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与 \n 或 \r 之前的位置匹配。
\b 匹配一个单词边界,即字与空格间的位置。例如”Hello World”,结果”\dHello\d \dWorld\d”
\B 非单词边界匹配。例如”Hello World”,结果”H\Be\Bl\Bl\Bo W\Bo\Br\Bl\Bd”

选择

用圆括号 () 将所有选择项括起来,相邻的选择项之间用 | 分割。

1
/([1-9])([a-z]+)/g
表达式 描述
exp1(?=exp2) 查找 exp2 前面的 exp1
(?<=exp2)exp1 查找 exp2 后面的 exp1
exp1(?!exp2) 查找后面不是 exp2 的 exp1
(?<!exp2)exp1 查找前面不是 exp2 的 exp1

反向引用

对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 \n 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。

可以使用非捕获元字符 ?:?=?! 来重写捕获,忽略对相关匹配的保存。

反向引用的最简单的、最有用的应用之一,是提供查找文本中两个相同的相邻单词的匹配项的能力。以下面的句子为例:

1
Is is the cost of of gasoline going up up?

上面的句子很显然有多个重复的单词。如果能设计一种方法定位该句子,而不必查找每个单词的重复出现,那该有多好。下面的正则表达式使用单个子表达式来实现这一点:

1
2
3
var str = "Is is the cost of of gasoline going up up";
var patt1 = /\b([a-z]+) \1\b/igm;
document.write(str.match(patt1));

捕获的表达式,正如 [a-z]+ 指定的,包括一个或多个字母。正则表达式的第二部分是对以前捕获的子匹配项的引用,即,单词的第二个匹配项正好由括号表达式匹配。\1 指定第一个子匹配项。

单词边界元字符确保只检测整个单词。否则,诸如 “is issued” 或 “this is” 之类的词组将不能正确地被此表达式识别。

正则表达式后面的全局标记 g 指定将该表达式应用到输入字符串中能够查找到的尽可能多的匹配。

表达式的结尾处的不区分大小写 i 标记指定不区分大小写。

多行标记 m 指定换行符的两边可能出现潜在的匹配。

正则表达式 - 修饰符

标记也称为修饰符,正则表达式的标记用于指定额外的匹配策略。

1
/pattern/flags

下表列出了正则表达式常用的修饰符

修饰符 含义 描述
i ignore - 不区分大小写 将匹配设置为不区分大小写,搜索时不区分大小写: A 和 a 没有区别。
g global - 全局匹配 查找所有的匹配项。
m multi line - 多行匹配 使边界字符 ^$ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。
s 特殊字符圆点 . 中包含换行符 \n 默认情况下的圆点 . 是匹配除换行符 \n 之外的任何字符,加上 s 修饰符之后, . 中包含换行符 \n。

最近想离线浏览一个网站,发现 wget 和 HTTrack 这两个工具都挺好用的。一个命令行操作,一个图形界面,各有各的优势。

遇到的场景

事情是这样的,某天看到一篇很棒的教程网站,内容特别丰富,但是那个网站偶尔会挂,而且有时候网速还特别慢。我就想着,要是能把它整个下载下来离线看就好了。

方式一:wget

wget 是个命令行工具,Linux 系统基本都自带。之前一直知道它可以下载文件,没想到还能直接把整个网站”搬”到本地来。

基本用法

最简单的镜像命令:

1
wget --mirror https://example.com

不过这样下载下来的链接还是指向原网站的,点击就跳转走了,体验不太好。所以一般我会加几个参数:

1
wget --mirror --convert-links --adjust-extension --page-requisites --no-parent https://example.com

看着一长串参数有点吓人,其实就是告诉 wget:

  • --mirror:开启镜像模式,会递归下载
  • --convert-links:把链接转换成本地链接,这样点击就不会跳到原网站了
  • --adjust-extension:自动加上正确的文件后缀
  • --page-requisites:把 CSS、图片这些资源也一起下载
  • --no-parent:不要往上跑到父目录去

有个简写的形式,好记多了:

1
wget -mkEpnp https://example.com

踩过的坑

刚开始用的时候踩了几个坑:

下载太多层级。有些网站链接四通八达,不加限制的话可能会下载一大堆不需要的东西。可以用 -l 参数限制深度:

1
wget -r -l 2 https://example.com  # 只下载2层

被服务器封 IP。wget 默认下载速度很快,有些服务器会认为是在攻击。所以最好加点延迟:

1
wget --mirror --wait=2 --limit-rate=200k https://example.com

这样每次请求之间等 2 秒,速度限制在 200KB/s,服务器就不会觉得你在搞事情了。

优点与局限

wget 的优点是简单直接,一行命令搞定,Linux 系统自带不用安装。缺点是只有命令行,不熟悉终端的话上手有点门槛。

另外,wget 对动态渲染的网站支持不太好。现在很多网站内容是通过 JavaScript 动态加载的,这种网站 wget 只能抓到空的 HTML 框架。

方式二:HTTrack

HTTrack 是一个专门做网站镜像的工具,有图形界面,用起来比 wget 友好很多。

安装

  • Windows:去官网下载安装包,一路下一步就行
  • Linux:sudo apt install httrack
  • Mac:brew install httrack

图形界面使用

安装后打开 HTTrack,跟着向导走就行:

  1. 新建项目,起个名字
  2. 选择保存路径
  3. 输入要镜像的网址
  4. 点击开始,等待完成

整个过程点点鼠标就搞定了,完全不需要记命令。

命令行使用

HTTrack 也支持命令行:

1
httrack https://example.com -O ./mirrored-site

-O 参数指定保存目录。如果需要更多控制,可以加参数:

1
httrack https://example.com -O ./mirrored-site -r2 -s0
  • -r2:递归深度为 2
  • -s0:不跟随外部链接

优点与局限

HTTrack 的优点是有图形界面,操作直观,配置选项丰富,还可以暂停续传。缺点是体积比 wget 大,需要单独安装。

和 wget 一样,HTTrack 对 JavaScript 渲染的内容也支持有限。

小结

两个工具各有千秋:

  • wget:命令行党首选,轻量、快速、Linux 自带
  • HTTrack:图形界面友好,适合不想折腾命令行的朋友

对了,镜像网站的时候记得看看人家网站的 robots.txt 和使用条款,别给人家服务器造成太大压力,也不要拿去干不好的事情哈。

在使用 Git 进行版本控制时,很多开发者都会遇到一个常见问题:空目录无法被 Git 直接跟踪和提交。这是因为 Git 的设计理念是跟踪文件的变更,而非目录本身 —— 如果一个目录下没有任何文件,Git 会默认忽略它,导致团队协作时目录结构无法同步。别担心,本文将分享 3 种经过实践验证的解决方案,帮你优雅解决空目录提交问题。

一、推荐方案:使用.gitkeep 文件(最通用)

这是开发中最常用的方法,虽然.gitkeep并非 Git 官方定义的标准文件,但已被 Laravel、Vue 等主流框架广泛采用,成为行业惯例。

核心原理

Git 会跟踪包含文件的目录结构。通过在空目录中创建一个名为.gitkeep的占位文件,就能强制 Git 识别并保留该目录,且不会影响目录的后续使用。

操作步骤(含示例)

  1. 创建空目录及占位文件

    无论是单个空目录还是多级空目录,都可以通过简单命令创建:

    1
    2
    3
    4
    5
    6
    7
    # 创建单个空目录并添加.gitkeep
    mkdir -p project/logs/
    touch project/logs/.gitkeep

    # 创建多级空目录并添加.gitkeep
    mkdir -p src/utils/temp/
    touch src/utils/temp/.gitkeep
  2. 提交到 Git 仓库

    常规的addcommit操作即可完成跟踪:

    1
    2
    git add project/logs/.gitkeep
    git commit -m "Track logs directory with .gitkeep"
  3. 批量处理所有空目录(高效技巧)

    如果项目中有多个空目录,手动创建太繁琐,可通过find命令批量处理:

    1
    find . -type d -empty -exec touch {}/.gitkeep \;

    这条命令会自动查找项目中所有空目录,并在每个目录下创建.gitkeep文件。

核心优势

  • 命名直观:看到.gitkeep就知道是用于保留目录的占位文件
  • 无副作用:仅作为占位符,不影响目录后续文件的添加和跟踪
  • 兼容性强:所有 Git 版本均支持,团队协作无门槛

二、灵活方案:.gitignore 反向配置

如果你的空目录未来需要添加文件,但又想提前保留目录结构,同时避免误跟踪无关文件,这种方法再合适不过。

核心原理

利用.gitignore的忽略规则:先配置忽略目录内所有文件(*),再通过反向规则(!.gitignore)排除自身,让 Git 仅跟踪.gitignore文件,从而间接保留目录结构。

操作步骤

  1. 创建特殊配置的.gitignore 文件

    在需要跟踪的空目录下创建.gitignore,并写入以下内容:

    1
    2
    3
    4
    # 忽略当前目录下所有文件
    *
    # 不忽略.gitignore文件本身
    !.gitignore
  2. 提交配置文件

    1
    2
    git add path/to/empty_dir/.gitignore
    git commit -m "Track empty directory via .gitignore"

适用场景

  • 目录未来会添加文件,但需要明确忽略规则(如日志目录、缓存目录)
  • 避免团队成员误提交目录内的临时文件

核心优势

  • 规则清晰:通过配置文件明确目录的忽略策略
  • 一劳永逸:后续添加符合规则的文件时,无需修改配置

三、语义化方案:添加 README 文档

如果空目录的用途需要向团队说明(比如 “预留目录”“临时文件目录”),这种方法既能保留目录,又能提供文档价值,一举两得。

核心原理

在空目录中放置README.md文件,Git 会跟踪该文档,从而保留目录结构。同时,README 文件可以详细说明目录的用途、使用规范等,提升项目可维护性。

操作步骤

  1. 创建带说明的 README 文件

    1
    2
    # 写入目录说明(可根据实际需求修改内容)
    echo "This directory is reserved for future cache files. Do not delete it." > path/to/empty_dir/README.md
  2. 提交文档文件

    1
    2
    git add path/to/empty_dir/README.md
    git commit -m "Add README to explain empty directory purpose"

适用场景

  • 开源项目中的预留目录(需向贡献者说明用途)
  • 团队协作中需要明确目录职责的场景
  • 需长期保留且用途固定的空目录

核心优势

  • 语义化强:通过文档直接说明目录用途,减少沟通成本
  • 附加价值:提升项目文档完整性,便于新人快速上手

三种方案对比:怎么选?

方法 核心文件 适用场景 核心优点
.gitkeep占位文件 .gitkeep 通用场景、快速保留目录 操作简单、兼容性强、无副作用
.gitignore反向配置 .gitignore 需忽略未来文件的目录 规则明确、一劳永逸
README文档 README.md 需说明用途的目录 语义化清晰、提供文档价值

注意事项(避坑指南)

  1. 命名规范.gitkeep是行业惯例,不建议自定义名称(如.keep),避免团队认知不一致
  2. 前缀禁忌:除.gitignore外,不要使用.git前缀命名文件(Git 会默认忽略此类文件,导致配置失效)
  3. 目录删除:如果后续需要删除已跟踪的空目录,需先删除目录内的占位文件(.gitkeep/.gitignore/README),再删除目录并提交
  4. 批量处理:使用find命令批量创建.gitkeep时,注意目录权限(避免无写入权限导致命令执行失败)

总结

Git 不直接支持空目录跟踪,但通过 “添加占位文件” 的核心思路,我们可以根据实际需求选择不同方案:

  • 快速解决、通用场景:优先选.gitkeep
  • 需忽略规则、未来加文件:选.gitignore反向配置
  • 需说明用途、提升可维护性:选README文档

MPM(多路处理模块)

常见:

  1. perfork 预处理进程方式
  2. worker 工作者模式
  3. winnt 在windows使用

案例:把apache的最大并发数配置成1000个

首先确认apache的mpm方式

1
cmd>httpd.exe -l #可以看到是什么模式了

这里就看 mpm_xxx.c 这个 xxx 就是那个了

修改httpd.conf文件

搜索 mpm ,找到 Server-pool management(MPM specific)

去掉 # Include conf/extra/httpd-mpm.conf

修改 conf/extra/httpd-mpm.conf 文件

prefork模式就修改这里

1
2
3
4
5
6
7
<IfModule mpm_prefork_module>
StartServers 5 # 预先开启的进程
MinSpareServers 5 # 最小预留5个
MaxSpareServers 10 # 最大留10
MaxClients 150 # 最多并发多少个 *
MaxRequestsPerChild 0 # 最多请求多少次 0不限制
</IfModule>

winnt模式

1
2
3
4
<IfModule mpm_winnt_module>
ThreadsPerChild 150 # 最大并发数 *
MaxRequestsPerChild 0 # 最多处理多少次请求 0不限制
</IfModule>

修改后面有*的那个字段的数值然后重新启动 apache

说明:配置到多大,不一定就可能支撑这么大的并发,考虑到本身 apache 所在的机器硬件性能(如:内存,CPU,硬盘IO)

系统是 linux/unix ,配置 perfork

1
2
3
4
5
6
7
<IfModule mpm_prefork_module>
StartServers 5
MinSpareServers 5
MaxSpareServers 10
MaxClients 150 *#并发量
MaxRequestsPerChild 0
</IfModule>

给大家一个合理的建议配置,对大部份网站,中型网站配置

1
2
3
4
5
6
7
8
<IfModule mpm_prefork_module>
StartServers 5 # 预先启动
MinSpareServers 5
MaxSpareServers 10 # 最大空闲进程
ServerLimit 1500 *# 用于修改apache编程参数
MaxClients 1000 *# 最大并发数
MaxRequestsPerChild 0
</IfModule>

注:apache2.2以后才有的ServerLimit这个参数,其中ServerLimit数值大于MaxClients数值

如果网站的pv值百万

1
2
ServerLimit 2500 *# 用于修改apache编程参数
MaxClients 2000 *# 最大并发数

注:调到这就是极限了,要是网站访问还是大,哪就要增加apache服务器了

Oh My Zsh is an open source, community-driven framework for managing your [zsh](http://www.zsh.org/) configuration.

阅读全文 »

有时候,我们还需要一些高级功能,比如在网页上显示数学公式。

新建一个文件themes/pacman/layout/_partial/mathjax.ejs,找到mathjax的调用代码复制到文件。

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


<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
processEscapes: true
}
});
</script>

<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
}
});
</script>

<script type="text/x-mathjax-config">
MathJax.Hub.Queue(function() {
var all = MathJax.Hub.getAllJax(), i;
for(i=0; i < all.length; i += 1) {
all[i].SourceElement().parentNode.className += ' has-jax';
}
});
</script>

<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>

在themes/pacman/layout/_partial/after_footer.ejs 的最后一行,增加对mathjax的引用,详细内容请查看源代码。

我们修改文章:source/_posts/新的开始.md

增加公式:

1
2
## 公式
$$J\_\alpha(x)=\sum _{m=0}^\infty \frac{(-1)^ m}{m! \, \Gamma (m + \alpha + 1)}{\left({\frac{x}{2}}\right)}^{2 m + \alpha }$$

查看效果:

公式

$$J_\alpha(x)=\sum _{m=0}^\infty \frac{(-1)^ m}{m! , \Gamma (m + \alpha + 1)}{\left({\frac{x}{2}}\right)}^{2 m + \alpha }$$

利用php导出excel我们大多会直接生成.xls文件,这种方便快捷。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function createtable($list,$filename){
header("Content-type:application/vnd.ms-excel");
header("Content-Disposition:filename=".$filename.".xls");

$strexport="编号\t姓名\t性别\t年龄\r";
foreach ($list as $row){
$strexport.=$row['id']."\t";
$strexport.=$row['username']."\t";
$strexport.=$row['sex']."\t";
$strexport.=$row['age']."\r";
}

$strexport=iconv('UTF-8',"GB2312//IGNORE",$strexport);
exit($strexport);
}

基于这个我们可以将方法封装一下:

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
/**
* 创建(导出)Excel数据表格
* @param array $list 要导出的数组格式的数据
* @param string $filename 导出的Excel表格数据表的文件名
* @param array $header Excel表格的表头
* @param array $index $list数组中与Excel表格表头$header中每个项目对应的字段的名字(key值)
* 比如: $header = array('编号','姓名','性别','年龄');
* $index = array('id','username','sex','age');
* $list = array(array('id'=>1,'username'=>'YQJ','sex'=>'男','age'=>24));
* @return [array] [数组]
*/
protected function createtable($list,$filename,$header=array(),$index = array()){
header("Content-type:application/vnd.ms-excel");
header("Content-Disposition:filename=".$filename.".xls");
$teble_header = implode("\t",$header);
$strexport = $teble_header."\r";
foreach ($list as $row){
foreach($index as $val){
$strexport.=$row[$val]."\t";
}
$strexport.="\r";
}
$strexport=iconv('UTF-8',"GB2312//IGNORE",$strexport);
exit($strexport);
}

方法调用:

1
2
3
4
$filename = '提现记录'.date('YmdHis');  
$header = array('会员','编号','联系电话','开户名','开户行','申请金额','手续费','实际金额','申请时间');
$index = array('username','vipnum','mobile','checkname','bank','money','handling_charge','real_money','applytime');
$this->createtable($cash,$filename,$header,$index);

这种方式生成Excel文件,生成速度很快,但是有缺点是:

  1. 单纯的生成Excel文件,生成的文件没有样式,单元格属性(填充色,宽度,高度,边框颜色…)不能自定义。
  2. 生成的文件虽然可以打开,但是兼容性很差,每次打开,都会报一个警告。

前言:当我们想要实现几个小伙伴合作开发同一个项目,或者建立一个资源分享平台的时候,GIT就是一个很好的选择。当然,既然是一个共有平台,那么把这个平台放到个人计算机上明显是不合适的,因此就要在服务器上搭建GIT了。另一个需求是,我们在本地开发,然后推送到服务器上,并且自动同步到web站点目录,这样就可以直接看到网页效果了,这就要实现自动同步。下面我带领大家实现这么一个功能。

如果条件允许的话,大家可以跟着做的(注:我的服务器是centos 7,lamp环境)。

一、在服务器上安装git:

1
2
//yum安装
yum install -y git

在安装完之后你可以运行git进行测试,看看是否安装成功。

二、在服务器上创建裸版本库:

ps:远程仓库通常只是一个裸仓库(bare repository) — 即一个没有当前工作目录的仓库。因为该仓库只是一个合作媒介,所以不需要从硬盘上取出最新版本的快照;仓库里存放的仅仅是 Git 的数据。简单地说,裸仓库就是你工作目录中 .git 子目录内的内容

我们就在 /home/testgit/ 下创建一个叫 sample.git的裸仓库吧:

1
2
3
4
mkdir /home/testgit
cd /home/testgit
git init --bare sample.git
//这里 git init 是初始化空仓库的意思,而参数 --bare 是代表创建裸仓库,这个参数一定记得带上

当运行完上面的最后一句命令时,会有提示:Initialized empty Git repository in /home/testgit/sample.git/
如果你得不到该结果,可能就要回头检查哪一步出问题了

三、创建web站点目录www

现在我的 web 站点目录在 /home/www

四、在本地克隆服务器上的裸仓库:

前提:本地已安装git

打开 git bash ,我打算在我的D盘下创建一个名为 lsgogit 的版本库

1
2
cd /d
git clone git@115.159.146.94:/home/testgit/sample.git lsgogit

在这里如果没有配置公钥的话,会提示输入密码,但是我们可能并不知道密码,那就配置公钥咯:
1、查看自己计算机的公钥:

//查看是否有了ssh密钥,如果没有密钥则不会有此文件夹
cd ~/.ssh
ls -al
//如果列出了authorized_keys2 id_dsa known_hosts config id_dsa.pub 则证明你拥有公钥。

我们需要寻找一对以 id_dsa 或 id_rsa 命名的文件,其中一个带有 .pub 扩展名。 .pub 文件是你的公钥,另一个则是私钥。 如果找不到这样的文件(或者根本没有 .ssh 目录),你可以通过运行 ssh-keygen 程序来创建它们。在 Linux/Mac 系统中,ssh-keygen 随 SSH 软件包提供;在 Windows 上,该程序包含于 MSysGit 软件包中。

首先 ssh-keygen 会确认密钥的存储位置(默认是 .ssh/id_rsa),然后它会要求你输入两次密钥口令。如果你不想在使用密钥时输入口令,将其留空即可。

现在,进行了上述操作的用户需要将各自的公钥发送给任意一个 Git 服务器管理员(假设服务器正在使用基于公钥的 SSH 验证设置)。 他们所要做的就是复制各自的 .pub 文件内容,并将其通过邮件发送。 公钥看起来是这样的:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAcnTC3A++ginnxr2dvtQa881abjGIzk99KQVg/sPpqvtT3espFKBs/wqrJ9naIPtCswKDMg2tBVgJzg5FimDjI44O072qAftRcjU2EEySlGDDetREOvcDxqcXzf6cAdhnKlYcPk8s46oC+SxhK0zAFZCZNc7z9GcEPOC+ESIettycDw/Bo11WfxAWS0hky2F3rYh5CRr8j7BKRsAvEaAyKwzmM9X0XCRniC2pD0ObX0/SjPwq9Q5/Vjg03muiSo5Bm/xmuHkwb4/uQglBwnaSqEr6YkL9xLMoNsQaJ1TAvTrEaZLNhWzN8iaPyKZMJEzPLX1NgeEx9AEae39N+NsJ LSGO@zhongjin

现在我们回到服务器管理员的身份

由于前面安装git的时候,centos会默认创建一个git用户(其他系统貌似需要手动创建),我们进入/home/git/.ssh,里面有一个名为 authorized_keys 的文件,我们分别将其他开发者的公钥(全选、复制、不能更改!)添加到该文件去,一个开发者的公钥分一行。

现在我们看看有两个开发者(个人电脑分别是zhongjin 和 jinjinzhong)的authorized_keys文件:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAcnTC3A++ginnxr2dvtQa881abjGIzk99KQVg/sPpqvtT3espFKBs/wqrJ9naIPtCswKDMg2tBVgJzg5FimDjI44O072qAftRcjU2EEySlGDDetREOvcDxqcXzf6cAdhnKlYcPk8s46oC+SxhK0zAFZCZNc7z9GcEPOC+ESIettycDw/Bo11WfxAWS0hky2F3rYh5CRr8j7BKRsAvEaAyKwzmM9X0XCRniC2pD0ObX0/SjPwq9Q5/Vjg03muiSo5Bm/xmuHkwb4/uQglBwnaSqEr6YkL9xLMoNsQaJ1TAvTrEaZLNhWzN8iaPyKZMJEzPLX1NgeEx9AEae39N+NsJ LSGO@zhongjin
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAcnTC3A++ginnxr2dvtQa881abjGIzk99KQVg/sPpqvtT3espFKBs/wqrJ9naIPtCswKDMg2tBVgJzg5FimDjI44O072qAftRcjU2EEySlGDDetREOvcDxqcXzf6cAdhnKlYcPk8s46oC+SxhK0zAFZCZNc7z9GcEPOC+ESIettycDw/Bo11WfxAWS0hky2F3rYh5CRr8j7BKRsAvEaAyKwzmM9X0XCRniC2pD0ObX0/SjPwq9Q5/Vjg03muiSo5Bm/xmuHkwb4/uQglBwnaSqEr6YkL9xLMoNsQaJ1TAvTrEaZLNhWzN8iaPyKZMJEzPLX1NgeEx9AEae39N+NsJ LSGO@jinjinzhong

至此,我们就可以实现不用输密码克隆远程仓库了:

1
2
cd /d
git clone git@115.159.146.94:/home/testgit/sample.git lsgogit

命令运行完后,lsgogit现在就是一个空的仓库了,现在我们可以在该仓库下添加文件,然后push到远程仓库了。

1
2
3
4
5
cd lsgogit
touch index.php
git add index.php
git commit -m "test commit"
git push origin master

如果在这里推送失败了,极有可能是因为服务器的权限问题,就比如之前我们建的 testgit 文件夹,在这里我的解决方法是:

chown -R git:git testgit

将testgit文件夹以及下面的子文件夹都赋给了git,这样就保证了推送成功。

第一次push可能会有一些提示,因为裸版本库还什么都没有,你可能需要 git push origin master写全命令,之后就没必要了,直接 git push 就可以了。

到目前为止,我们完成了第一个任务,实现了一个共享平台,既可拉取数据,又可以推送数据。

四、实现自动同步到站点目录(www)

就比如刚才我们往远程仓库推送了index.php文件,虽然提示推送成功,但是我们现在在服务器端还看不到效果,心理总是不爽。又比如我写了个html页面,我想在站点中马上看到,那自动同步就派上用场了。

自动同步功能用到的是 git 的钩子功能,

服务器端:进入裸仓库:/home/testgit/sample.git

1
2
3
4
5
6
7
8
9
10
11
cd /home/testgit/sample.git
cd hooks
//这里我们创建post-receive文件
vim post-receive
//在该文件里输入以下内容
#!/bin/bash
git --work-tree=/home/www checkout -f
//保存退出后,将该文件用户及用户组都设置成git
chown git:git post-receive
//由于该文件其实就是一个shell文件,我们还应该为其设置可执行权限
chmod +x post-receive

现在我们可以在本地计算机中修改index.php文件,或者添加一个新文件,提交到远程仓库,然后到/home/www下面,看看有没有我们刚才提交的文件。

如果你在Git推送的工程中发现推送成功 但是在www目录下并没有自己的代码,这时候你可要注意了:这是由于文件夹的权限的原因造成的! 假设你的www目录的所属的用户组为root,你可以将你的git用户加入这个组;并给git添加写入权限,或者其他解决方法,反正你要服务器上的git用户有权限进入www文件夹。

之前的项目都是”包工头“文乔学长完成这个过程,现在终于掌握了,有点小高兴。。。

本文章参考了

  1. AiDandai 服务器上的 Git.md
  2. git推送到服务器自动同步到站点目录

扩展地址:http://docs.php.net/manual/zh/book.pthreads.php

注意事项

php5.3 或以上,且为线程安全版本。apache 和 php 使用的编译器必须一致。

通过 phpinfo() 查看 Thread Safetyenabled 则为线程安全版。

通过 phpinfo() 查看 Compiler 项可以知道使用的编译器。本人的为:MSVC9 (Visual C++ 2008)。

本人使用环境

32位 windows xp sp3 ,wampserver2.2d(php5.3.10-vc9 + apache2.2.21-vc9)。

下载 pthreads 扩展

下载地址:http://windows.php.net/downloads/pecl/releases/pthreads

根据本人环境,我下载的是 pthreads-2.0.8-5.3-ts-vc9-x86 。

2.0.8 代表 pthreads 的版本。
5.3 代表 php 的版本。
ts 表示 php 要线程安全版本的。
vc9 表示 php 要 Visual C++ 2008 编译器编译的。
x86 则表示32位的

安装 pthreads 扩展

复制 php_pthreads.dll 到目录 bin\php\ext\ 下面。(本人路径D:\wamp\bin\php\php5.3.10\ext)

复制 pthreadVC2.dll 到目录 bin\php\ 下面。(本人路径D:\wamp\bin\php\php5.3.10)

复制 pthreadVC2.dll 到目录 C:\windows\system32 下面。

打开 php 配置文件 php.ini。在后面加上 extension=php_pthreads.dll

提示!Windows系统需要将 pthreadVC2.dll 所在路径加入到 PATH 环境变量中。

我的电脑—>鼠标右键—>属性—>高级—>环境变量—>系统变量—>找到名称为 Path 的—>编辑—>在变量值最后面加上 pthreadVC2.dll 的完整路径(本人的为C:\WINDOWS\system32\pthreadVC2.dll)。

测试 pthreads 扩展

1
2
3
4
5
6
7
8
9
10
11
12
13
class AsyncOperation extends \Thread {
public function __construct($arg){
$this->arg = $arg;
}
public function run(){
if($this->arg){
printf("Hello %s\n", $this->arg);
}
}
}
$thread = new AsyncOperation("World");
if($thread->start())
$thread->join();

运行以上代码出现 Hello World ,说明 pthreads 扩展安装成功!

0%