ubuntu 下 /bin/sh 默认是dash,用ll /bin/sh就可以看出来sh是指向dash的链接,有时候会导致使用bash脚本的时候出问题。

如果遇到这个问题了,就要把sh指向bash。

可以用ln:ln -s /bin/bash /bin/sh

或者用sudo dpkg-reconfigure dash 选择否(no)

作者 yanjieee


转自:让网页定时关闭
下面是代码:直接复制,Chrome下,Ctrl+Shift+I,粘贴回车即可

javascript:console.log('%c本页面一小时后关闭', 'background-image:-webkit-gradient( linear, left top, right top, color-stop(0, #f22), color-stop(0.15, #f2f), color-stop(0.3, #22f), color-stop(0.45, #2ff), color-stop(0.6, #2f2),color-stop(0.75, #2f2), color-stop(0.9, #ff2), color-stop(1, #f22) );color:transparent;-webkit-background-clip: text;font-size:5em;');var t = 3600;function fun(){t--;console.warn(t+'秒');if(t<=0){window.opener = null;window.open('', '_self');window.close();clearInterval(inter);}}var inter = setInterval('fun()',1000);

代码这样看比较乱,其实加上换行,就很清楚明了了:(代码中的换行违反语法规则,这样写只是为了看起来方便)

console.log('%c本页面一小时后关闭', '
background-image:-webkit-gradient(
linear, left top, right top,
color-stop(0, #f22),
color-stop(0.15, #f2f),
color-stop(0.3, #22f),
color-stop(0.45, #2ff),
color-stop(0.6, #2f2),
color-stop(0.75, #2f2),
color-stop(0.9, #ff2),
color-stop(1, #f22)
);
color:transparent;
-webkit-background-clip: text;
font-size:5em;
');
var t = 3600;
function fun(){
t--;
console.warn(t+'秒');
if(t<=0){
window.opener = null;
window.open('', '_self');
window.close();
clearInterval(inter);
}
}
var inter = setInterval('fun()',1000);

转自:WordPress技巧:蜘蛛爬行分析页面的实现
自从博客上方导航条加了一个蜘蛛爬行页面以来,断断续续有人问如何实现,也分别断断续续地回答过,可能回答得也不完整,所以这次索性开帖写一下完整的实现过程。另外,tiandi想说的是,这个功能只是一个“看”,并没有SEO的优化效果。好了,让我们言归正传,开始一步一步实现。

第一步,生成网站访问日志,我们需要通过日志来获取蜘蛛爬行的记录,如何生成网站访问日志,请看《WordPress技巧:生成网站访问日志

第二步,有了日志,我们就得分析日志,从而得出哪些访问记录是属于用户正常访问的,哪些是属于蜘蛛爬行的。在主题的function里插入以下代码,目的是创建短代码spiderlogs,该段代码可用参数text,默认为yes,生成文本描述+圆饼图,如只需要显示圆饼图,则设置text为no即可。代码比较长,感兴趣的可以自己编辑蜘蛛的特征。

function get_spider_log($atts) {
    extract(shortcode_atts(array(
    'text' => 'yes'),$atts));
    $fh = fopen(site_url() ."/mylogs.txt", "r");
    $contents = "";
        while(!feof($fh)){
        $contents .= fread($fh, 8080);
    }
    fclose($fh);
    $str = "";
    $showtime=date("md");
    if($text == "yes") {
        $str.= "当天蜘蛛爬行记录:";    
        $str.= "<div style='background-color:#33A1C9;color:white;text-align:center;'>以下为国内常用蜘蛛。</div>";
    }
    $mytmp = array();
    //google
    $google = 0;
    if($text == "yes")
        $str.= "<a href=http://www.google.com/bot.html target=_blank>Google Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"Googlebot\/",$text);
    $google += $mytmp[0];
    $str.= $mytmp[1];
    $mytmp = show_spider_result($showtime,$contents,"Googlebot-Image\/",$text);
    $google += $mytmp[0];
    $str.= $mytmp[1];
    $mytmp = show_spider_result($showtime,$contents,"Googlebot-Mobile\/",$text);
    $google += $mytmp[0];
    $str.= $mytmp[1];
    $mytmp = show_spider_result($showtime,$contents,"Feedfetcher-Google",$text);
    $google += $mytmp[0];
    $str.= $mytmp[1];

    // baidu
    $baidu = 0;
    if($text == "yes")
        $str.= "<br><a href=http://www.baidu.com/search/spider.html target=_blank>Baidu Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"Baiduspider\/",$text);
    $baidu += $mytmp[0];
    $str.= $mytmp[1];
    $mytmp = show_spider_result($showtime,$contents,"Baiduspider-image",$text);
    $baidu += $mytmp[0];
    $str.= $mytmp[1];

    //bing
    $bing = 0;
    if($text == "yes")
        $str.= "<br><a href=http://www.bing.com/bingbot.htm target=_blank>bingbot Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"bingbot\/",$text);
    $bing += $mytmp[0];
    $str.= $mytmp[1];
    $mytmp = show_spider_result($showtime,$contents,"msnbot-media\/",$text);
    $bing += $mytmp[0];
    $str.= $mytmp[1];

    //sogou
    $sogou = 0;
    if($text == "yes")
        $str.= "<br><a href=http://www.sogou.com/docs/help/webmasters.htm#07 target=_blank>Sogou Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"Sogou web spider\/",$text);
    $sogou += $mytmp[0];
    $str.= $mytmp[1];

    //soso
    $soso = 0;
    if($text == "yes")
        $str.= "<br><a href=http://help.soso.com/webspider.htm target=_blank>Soso Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"Sosospider\/",$text);
    $soso += $mytmp[0];
    $str.= $mytmp[1];

    if($text == "yes")
        $str.= "<div style='background-color:#FA8072;color:white;text-align:center;'>以下为垃圾蜘蛛,可屏蔽抓取。</div>";
    //jike
    $else = 0;
    if($text == "yes")
        $str.= "<a href=http://shoulu.jike.com/spider.html target=_blank>Jike Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"JikeSpider",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];

    //easou
    if($text == "yes")
        $str.= "<br><a href=http://www.easou.com/search/spider.html target=_blank>Easou Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"EasouSpider",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];

    //yisou
    if($text == "yes")
        $str.= "<br>YisouSpider:";
    $mytmp = show_spider_result($showtime,$contents,"YisouSpider",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];

    if($text == "yes")
        $str.= "<br><a href=http://yandex.com/bots target=_blank>YandexBot Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"YandexBot\/",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];

    if($text == "yes")
        $str.= "<br><a href=http://go.mail.ru/help/robots target=_blank>Mail.RU Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"Mail.RU_Bot\/",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];

    if($text == "yes")
        $str.= "<br><a href=http://www.acoon.de/robot.asp target=_blank>AcoonBot Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"AcoonBot\/",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];

    if($text == "yes")
        $str.= "<br><a href=http://www.exabot.com/go/robot target=_blank>Exabot Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"Exabot\/",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];

    if($text == "yes")
        $str.= "<br><a href=http://www.seoprofiler.com/bot target=_blank>spbot Spider</a>: ";
    $mytmp = show_spider_result($showtime,$contents,"spbot\/",$text);
    $else += $mytmp[0];
    $str.= $mytmp[1];
    
    $str.= draw_canvas($google,$baidu,$bing,$sogou,$soso,$else);
    return $str;
}
function show_spider_result($time,$contents,$str,$text){
    $count = array();
    $count[0] = preg_match_all("/".$time."\d*\s\/\S*\s.*".$str."/",$contents,$mymatches);
    if($text == "yes") {
        $str = preg_replace("{\\\/}","",$str);
        $count[1].= "<br> 蜘蛛类型=>".$str.": 爬行次数=".$count[0];
        if($count[0] >0) {
            $tmp = substr($mymatches[0][$count[0]-1],4,6);
            $tmp = substr($tmp,0,2) .":" . substr($tmp,2,2) .":" .substr($tmp,4,2) ;
            $count[1].= " 最后爬行时间:". $tmp;
        }
    }
    return $count;
}
function draw_canvas($google,$baidu,$bing,$sogou,$soso,$else){
    $tmp = $google + $baidu + $bing + $sogou + $soso + $else;
    if($tmp == 0) {
        return "<br><br>数据不足,无法生成分析图。<br><br>";
    }
    $google2 = $google*100/$tmp;
    $baidu2 = $baidu*100/$tmp;
    $bing2 = $bing*100/$tmp;
    $sogou2 = $sogou*100/$tmp;
    $soso2 = $soso*100/$tmp;
    $else2 = $else*100/$tmp;
    $str.= "<br><div style='border-top: 1px solid #e6e6e6;'><br>
    <div style='float:left;width:150px;border-width:1px;border-style:groove;padding:15px;'><b>蜘蛛爬行分析图:</b><br>";
    $str.= "日期:" . date("Y-m-d");
    $str.= "<br>蜘蛛一共爬行". $tmp . "次:<br>";
    $str.= "<li><span style='color:#33A1C9;'>google:". $google ."次(". intval($google2) ."%)</span></li>";
    $str.= "<li><span style='color:#0033ff;'>baidu:". $baidu ."次(". intval($baidu2) ."%)</span></li>";
    $str.= "<li><span style='color:#872657;'>bing:". $bing ."次(". intval($bing2) ."%)</span></li>";
    $str.= "<li><span style='color:#FF9912;'>sogou:". $sogou ."次(". intval($sogou2) ."%)</span></li>";
    $str.= "<li><span style='color:#FF6347;'>soso:". $soso ."次(". intval($soso2) ."%)</span></li>";
    $str.= "<li><span style='color:#55aa00;'>else:". $else ."次(". (100 - intval($google2) - intval($baidu2) - intval($bing2) - intval($sogou2) - intval($soso2)) ."%)</span></li></div>";
    $str.=    "<img src = 'http://chart.apis.google.com/chart?cht=p3&chco=33A1C9,0033ff,872657,FF9912,FF6347,55aa00&chd=t:".$google2 .",".$baidu2.",".$bing2.",".$sogou2.",".$soso2.",".$else2."&chs=400x200&chl=google|baidu|bing|sogou|soso|else' /></div><br>";
    return $str;
}
add_shortcode('spiderlogs','get_spider_log');

第三步,也是最后一步,在任意页面,调用短代码[ spiderlogs ]即可,(实际使用中,请去除括号内的空格)。还有不明白的可以留言。


转载:WordPress技巧:只保留当天的网络日志
之前有一篇文章《WordPress技巧:生成网站日志》,不少读者看了后反映该日志每天都会追加生成,文件会越来越大,而tiandi自己的网站日志则是只保留一天,第二天会自动覆盖前一天的日志文件,那么如何只生成当天的日志文件呢?其实很简单,只要在原先代码的基础上加一个时间判定变OK了。

这里,我只列出上文中有关的function,原先的代码如下:

function make_log_file(){
        //log文件名
    $filename = 'mylogs.txt'; 
        //去除rc-ajax评论以及cron机制访问记录
    if(strstr($_SERVER["REQUEST_URI"],"rc-ajax")== false 
        && strstr($_SERVER["REQUEST_URI"],"wp-cron.php")== false ) {
        $word .= date('mdHis',$_SERVER['REQUEST_TIME'] + 3600*8) . " ";
                //访问页面
        $word .= $_SERVER["REQUEST_URI"] ." ";
                //协议
        $word .= $_SERVER['SERVER_PROTOCOL'] ." ";
                //方法,POST OR GET
        $word .= $_SERVER['REQUEST_METHOD'] . " ";
        //$word .= $_SERVER['HTTP_ACCEPT'] . " ";
                //获得浏览器信息
        $word .= getbrowser(). " ";
                //传递参数
        $word .= "[". $_SERVER['QUERY_STRING'] . "] ";
                //跳转地址
        $word .= $_SERVER['HTTP_REFERER'] . " ";
                //获取IP
        $word .= getIP() . " ";
        $word .= "\n";
        $fh = fopen($filename, "a");
        fwrite($fh, $word);    
        fclose($fh);
    }
}

将末尾部分的

$word .= getIP() . " ";
$word .= "\n";
$fh = fopen($filename, "a");
fwrite($fh, $word);    
fclose($fh);

替换为以下即可:

$word .= getIP() . " ";
$word .= "\n";
$day = date('md',$_SERVER['REQUEST_TIME'] + 3600*8);    
if (file_exists($filename)) {
$fh = fopen($filename, "r");
$data = fread($fh, 10);
if(substr($data,0,4) == $day) 
    $fh = fopen($filename, "a");
else 
    $fh = fopen($filename, "w");
fwrite($fh, $word);    
fclose($fh);

这样程序检测到当前日期和当前日志里的日期不一致时,就会自动覆盖日志,从而达到只保留当天日志的需求。至于如何保留指定天数的日志么,也很简单,这里tiandi只说下实现的方法,把上面的$day获得的时间和日志里的比大小,大于指定天数覆盖写入,否则追加写入。


转自:WordPress技巧:生成网站访问日志
今天tiandi分享一则wordpress技巧,让wordpress自己生成网站访问日志,日志内容可以自己定义,大致可以和主机供应商后台查询的日志差不多,这样就可以省去每次都要登录主机后台查询。

开打主题下的function,插入以下代码:

make_log_file();
function make_log_file(){
        //log文件名
    $filename = 'mylogs.txt'; 
        //去除rc-ajax评论以及cron机制访问记录
    if(strstr($_SERVER["REQUEST_URI"],"rc-ajax")== false 
        && strstr($_SERVER["REQUEST_URI"],"wp-cron.php")== false ) {
        $word .= date('mdHis',$_SERVER['REQUEST_TIME'] + 3600*8) . " ";
                //访问页面
        $word .= $_SERVER["REQUEST_URI"] ." ";
                //协议
        $word .= $_SERVER['SERVER_PROTOCOL'] ." ";
                //方法,POST OR GET
        $word .= $_SERVER['REQUEST_METHOD'] . " ";
        //$word .= $_SERVER['HTTP_ACCEPT'] . " ";
                //获得浏览器信息
        $word .= getbrowser(). " ";
                //传递参数
        $word .= "[". $_SERVER['QUERY_STRING'] . "] ";
                //跳转地址
        $word .= $_SERVER['HTTP_REFERER'] . " ";
                //获取IP
        $word .= getIP() . " ";
        $word .= "\n";
        $fh = fopen($filename, "a");
        fwrite($fh, $word);    
        fclose($fh);
    }
}
//获取IP地址,网上现成代码
function getIP() //get ip address
    {
        if (getenv('HTTP_CLIENT_IP')) 
        {
            $ip = getenv('HTTP_CLIENT_IP');
        } 
        else if (getenv('HTTP_X_FORWARDED_FOR')) 
        {
            $ip = getenv('HTTP_X_FORWARDED_FOR');
        } 
        else if (getenv('REMOTE_ADDR')) 
        {
            $ip = getenv('REMOTE_ADDR');
        } 
        else 
        {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
        return $ip;
    }
//获取浏览器信息,移动端,平板电脑数据还未加上。
 function getbrowser()
    {
        $Agent = $_SERVER['HTTP_USER_AGENT'];
        $browser = '';
        $browserver = '';

        if(ereg('Mozilla', $Agent) && ereg('Chrome', $Agent))
        {
            $temp = explode('(', $Agent);
            $Part = $temp[2];
            $temp = explode('/', $Part);
            $browserver = $temp[1];
            $temp = explode(' ', $browserver);
            $browserver = $temp[0];
            $browserver = $browserver;
            $browser = 'Chrome';
        }
        if(ereg('Mozilla', $Agent) && ereg('Firefox', $Agent))
        {
            $temp = explode('(', $Agent);
            $Part = $temp[1];
            $temp = explode('/', $Part);
            $browserver = $temp[2];
            $temp = explode(' ', $browserver);
            $browserver = $temp[0];
            $browserver = $browserver;
            $browser = 'Firefox';
        }
        if(ereg('Mozilla', $Agent) && ereg('Opera', $Agent)) 
        {
            $temp = explode('(', $Agent);
            $Part = $temp[1];
            $temp = explode(')', $Part);
            $browserver = $temp[1];
            $temp = explode(' ', $browserver);
            $browserver = $temp[2];
            $browserver = $browserver;
            $browser = 'Opera';
        }
        if(ereg('Mozilla', $Agent) && ereg('MSIE', $Agent))
        {
            $temp = explode('(', $Agent);
            $Part = $temp[1];
            $temp = explode(';', $Part);
            $Part = $temp[1];
            $temp = explode(' ', $Part);
            $browserver = $temp[2];
            $browserver = $browserver;
            $browser = 'Internet Explorer';
        }
        if($browser != '')
        {
            $browseinfo = $browser.' '.$browserver;
        } 
        else
        {
            $browseinfo = $_SERVER['HTTP_USER_AGENT'];
        }
        return $browseinfo;
    }

这样,在你的站点根目录上就会生成mylogs.txt文件,你通过http://你的域名/mylogs.txt可以直接访问。


转自:LNMP防止图片盗链的方法
今天再介绍下如何lnmp架构下防止图片被其他网站盗链。

首先要检查/etc/nginx/nginx.conf或/etc/nginx/conf.d/example.com.conf有没有如下代码:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ 
{ 
expires 30d; 
}

如果有的话把这段话删除,没有的话更好。

然后在/etc/nginx/conf.d/example.com.conf里添加如下防盗链代码:

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ 
{ 
valid_referers none blocked *.example.com *.youdao.com *.zhuaxia.com *.xianguo.com *.google.cn *.google.com *.google.com.tw *.google.com.sg *.google.com.hk *.bloglines.com image.soso.com cn.bing.com image.baidu.com *.feedburner.com *.feedsky.com; 
if ($invalid_referer) { 
rewrite ^/ http://www.tennfy.com/404.png; 
#return 404; 
} 
expires 30d; 
}

解释下以上代码:
第一行gif|jpg|jpeg|png……这些是您需要防止盗链的文件类型,您可以补充一些后缀类型;

第三行是你的网站的域名,就是说放行的域名,如果有多个,请添加,注意空格;

第五行是给盗链看到的图片,返回一个404.jpg,这个图片源地址是要可以外链的哦,不然,别人看到的也就一个XX。

保存文件,重启lnmp:

/etc/init.d/nginx restart

转载:Debian vps上开通最低权限的ssh账号
在某些特殊用途想,我们需要用到vps的ssh账号,但是直接使用root账户是不安全的,这时我们可以创建一个最低权限的ssh账户。

1,登陆VPS,创建一个登录脚本:

vi /bin/nologin.sh

文件中添加以下内容

#!/bin/sh
echo ""
echo "  ***********************************************************"
echo "  * Sorry,you can't Login by this way, press a key to exit. *" 
echo "  ***********************************************************"
echo ""
read x
exit

写完之后按esc,输入:wq回车保存。

2、为此文件添加执行权限:

chmod 755 /bin/nologin.sh

3、添加一个用户到nogroup组,并且指定它的启动脚本:

useradd username -g nogroup -s /bin/nologin.sh

其中username修改为你的用户名

修改密码

passwd username

根据提示输入两遍新密码即可创建成功。

4、删除该用户

userdel -r username

5、显示所有用户

awk -F: '{print $1}' /etc/passwd

(一)转载:定时备份VPS数据至Dropbox教程

之前介绍了Debian vps上使用axel多线程下载百度网盘资源,对应的是想介绍下如何将VPS上的数据上传至百度网盘上。不过百度网盘现在貌似关闭了PCS的API接口申请,使用起来比较麻烦。退而求其次,这里介绍下如何定时备份VPS数据至Dropbox中。

客户端法备份数据

1、安装及配置dropbox linux客户端

在VPS上安装linux命令行版本的dropbox:

32-bit:
cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86" | tar xzf -
 
64-bit:
cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86_64" | tar xzf -

下载完成之后,运行dropbox

~/.dropbox-dist/dropboxd

第一次运行该命令,会提示访问URL,通过访问该URL就可以绑定VPS与dropbox账号。此时查看命令行,会提示绑定成功。

绑定之后,root目录下会自动创建名为Dropbox的文件夹,Dropbox会自动同步该文件夹内的文件。

2、使用dropbox linux客户端同步vps数据

我们一般备份网站数据及数据库数据,正常情况下网站WEB目录不在root文件夹下,我们可以通过软连接指向网站WEB目录,而数据库数据可以通过命令行导出,并通过软连接指向该文件。

为了方便区分目录,可以在Dropbox文件夹下新建backups文件夹,用于备份数据。

1)定时备份网站数据
将网站WEB目录连接到/Dropbox/backups文件夹下,假定/var/www/wordpress为网站web目录

cd ~/Dropbox/backups
ln -s /var/www/wordpress

2)定时备份数据库文件
新建一个定时备份数据库文件的脚本

vi ~/backup/mysqlbackup.sh

脚本内容如下:

echo "start mysql back up "${date} >> /root/backup/backup.log
mysqldump -uroot -p123456 wordpress >/root/backup/mysqlback.sql

其中,root为数据库的用户名,123456为数据库密码,wordpress为数据库名。

添加可执行权限

chmod a+x ~/backup/mysqlbackup.sh

将mysqlback.sql连接到/Dropbox/backups文件夹下

#!/bin/sh
cd ~/Dropbox/backups
ln -s ~/backup/mysqlback.sql

定时执行备份脚本文件,输入

crontab -e

添加以下内容

* 3 * * *  /root/backup/mysqlbackup.sh

3)定时开闭dropbox linux客户端
dropbox一直开着会占用vps的内存资源,没有必要一直开着,可以利用脚本定时运行和关闭dropbox。

创建脚本 ~/backup/dropboxswitch.sh

vi ~/backup/dropboxswitch.sh

内容如下

#!/bin/sh
date=`date +%Y%m%d_%H:%M:%S`
 
start() {
        echo "starting dropbox "${date} >> /root/backup/backup.log
        /root/dropbox/.dropbox-dist/dropbox &
        }
 
stop() {
        echo "stoping dropbox "${date} >> /root/backup/backup.log
        pkill dropbox
        }
 
case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart)
        stop
        start
        ;;
  esac

添加可执行权限

chmod a+x ~/backup/dropboxswitch.sh

然后定时每天凌晨4点启动dropbox,6点关闭:

crontab -e

添加以下内容

* 4 * * * /root/backup/dropboxswitch.sh start
* 6 * * * /root/backup/dropboxswitc.sh stop

脚本法备份数据

1、创建Dropbox应用

首先,需要创建一个Dropbox应用,可以从该网址进行创建:https://www.dropbox.com/developers/apps/create

在这里,应用类型选择Dropbox API App,数据存储类型选择Files and datastores,权限选择Yes(应用只需要访问它创建的文件)。然后命名创建。

2、下载并执行dropbox_uploader.sh

dropbox_uploader 是一个第三方Dropbox备份脚本,首先下载脚本:

wget --no-check-certificate https://raw.githubusercontent.com/tennfy/Dropbox-Uploader/master/dropbox_uploader.sh
chmod a+x dropbox_uploader.sh

执行该脚本,绑定APP:

./dropbox_uploader.sh

根据提示输入Dropbox应用中的App key和App secret,许可类型选择a,确认y,复制给出的权限验证链接到浏览器,确认后回到终端按任意键完成。

之后可以执行下面的命令测试上传,提示Done就是绑定成功了:

./dropbox_uploader.sh upload /etc/passwd /backup/passwd.old

3、编写定时脚本

vi /root/backup.sh

内容如下:

#!/bin/bash
MYSQL_USER=root                            #mysql用户名
MYSQL_PASS=xxxxx                           #mysql密码
MYSQL_DATABASENAME=xxxxx                   #要备份的数据库名
WEB_DATA=/var/www/xxx                      #要备份的网站数据
#你要修改的地方从这里结束
# 定义备份存放目录
DROPBOX_DIR=/$(date +%Y-%m-%d) # Dropbox上的备份目录
LOCAL_BAK_DIR=/root/backup # 本地备份文件存放目录
#定义备份文件名字
DBBakName=Data_$(date +"%Y%m%d").tar.gz
WebBakName=Web_$(date +"%Y%m%d").tar.gz
# 定义旧数据名称
Old_DROPBOX_DIR=/$(date -d -3day +%Y-%m-%d)
OldDBBakName=Data_$(date -d -3day +"%Y%m%d").tar.gz
OldWebBakName=Web_$(date -d -3day +"%Y%m%d").tar.gz
#删除本地3天前的数据
rm -rf $LOCAL_BAK_DIR/$OldDBBakName $LOCAL_BAK_DIR/$OldWebBakName
./dropbox_uploader.sh delete $Old_DROPBOX_DIR/
#导出mysql数据库
mysqldump -u$MYSQL_USER -p$MYSQL_PASS $MYSQL_DATABASENAME > $LOCAL_BAK_DIR/wordpress.sql
#压缩数据库
tar zcvf $LOCAL_BAK_DIR/$DBBakName $LOCAL_BAK_DIR/wordpress.sql
rm -rf $LOCAL_BAK_DIR/wordpress.sql
#压缩网站数据
tar zcvf $LOCAL_BAK_DIR/$WebBakName $WEB_DATA
#开始上传
cd ~
./dropbox_uploader.sh upload $LOCAL_BAK_DIR/$DBBakName $DROPBOX_DIR/$DBBakName
./dropbox_uploader.sh upload $LOCAL_BAK_DIR/$WebBakName $DROPBOX_DIR/$WebBakName
echo -e "Backup Done!"

其中,用户可以根据自己的需求改编需要备份的目录,以及保留旧数据的时长(我这里设置的是3天)

如果mysql是编译安装,需要指定mysql的路径。

增加执行权限:

chmod +x /root/backup.sh

测试该备份脚本:

./backup.sh

4.设置定时任务

执行:

crontab –e

添加以下内容:

30 3 * * * /root/backup.sh

这样,就可以每天凌晨3:30自动备份到Dropbox了。

5.最后重启Crontab

service cron restart

重启之后就设置完成了

如果你不知道服务器当前时间,可以使用下面的命令,查看当前时间:

date -R

修改为当前时区

cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

即修改服务器时区为上海。

参考文章:
如何将VPS上的网站数据定时自动备份到Dropbox
利用dropbox备份vps数据

Dropbox用不了?

可以看看用快盘的:https://github.com/wujiwh/kuaipan_uploader

(二)如何将VPS上的网站数据定时自动备份到Dropbox

本文所讲内容为如何将网站上的文件以及数据库中的内容定时自动备份到Dropbox上。

1.创建Dropbox应用

首先,需要创建一个Dropbox应用(Dropbox目前需要翻墙),可以从该网址进行创建:https://www.dropbox.com/developers/apps/create

在这里,应用类型选择Dropbox API App,数据存储类型选择Files and datastores,权限选择Yes(应用只需要访问它创建的文件)。然后命名创建。

2.下载并执行dropbox_uploader.sh

dropbox_uploader 是一个第三方Dropbox备份脚本,首先下载脚本:

curl "https://raw.githubusercontent.com/andreafabrizi/Dropbox-Uploader/master/dropbox_uploader.sh" -o dropbox_uploader.sh

然后,为该脚本添加执行权限:

chmod +x dropbox_uploader.sh

执行该脚本,绑定APP:

./dropbox_uploader.sh

根据提示输入Dropbox应用中的App key和App secret,许可类型选择a,确认y,复制给出的权限验证链接到浏览器,确认后回到终端按任意键完成。
dropbox_uploader1
之后可以执行下面的命令测试上传,提示Done就是绑定成功了:

./dropbox_uploader.sh upload /etc/passwd /backup/passwd.old

3.编写备份脚本

编写定时备份脚本,取名为backup.sh。其代码如下:

#!/bin/bash
 
# 定义需要备份的目录
WEB_DIR=/home/www # 网站数据存放目录
 
# 定义备份存放目录
DROPBOX_DIR=/$(date +%Y-%m-%d) # Dropbox上的备份目录
LOCAL_BAK_DIR=/home/backup # 本地备份文件存放目录
 
# 定义备份文件名称
DBBakName=DB_$(date +%Y%m%d).tar.gz
WebBakName=Web_$(date +%Y%m%d).tar.gz
 
# 定义旧数据名称
Old_DROPBOX_DIR=/$(date -d -7day +%Y-%m-%d)
OldDBBakName=DB_$(date -d -10day +%Y%m%d).tar.gz
OldWebBakName=Web_$(date -d -10day +%Y%m%d).tar.gz
 
cd $LOCAL_BAK_DIR
 
#使用命令导出数据库
mongodump --out $LOCAL_BAK_DIR/mongodb/ --db bastogne
 
#压缩数据库文件合并为一个压缩文件
tar zcf $LOCAL_BAK_DIR/$DBBakName $LOCAL_BAK_DIR/mongodb
rm -rf $LOCAL_BAK_DIR/mongodb
 
#压缩网站数据
cd $WEB_DIR
tar zcf $LOCAL_BAK_DIR/$WebBakName ./*
 
cd ~
#开始上传
./dropbox_uploader.sh upload $LOCAL_BAK_DIR/$DBBakName $DROPBOX_DIR/$DBBakName
./dropbox_uploader.sh upload $LOCAL_BAK_DIR/$WebBakName $DROPBOX_DIR/$WebBakName
 
#删除旧数据
rm -rf $LOCAL_BAK_DIR/$OldDBBakName $LOCAL_BAK_DIR/$OldWebBakName
./dropbox_uploader.sh delete $Old_DROPBOX_DIR/
 
echo -e "Backup Done!"

其中,用户可以根据自己的需求改编需要备份的目录,以及保留旧数据的时长(比如我这里设置的是Dropbox保留7天,本地保留10天)。

接下来,为这个备份脚本增加执行权限:

chmod +x backup.sh

测试该备份脚本:

./backup.sh

4.设置定时任务

执行:

crontab –e

添加:

30 3 * * * /root/backup.sh

这样,就可以每天凌晨3:30自动备份到Dropbox了。

5.最后重启Crontab

service cron restart

重启之后就设置完成了

如果你不知道服务器当前时间,可以使用下面的命令,查看当前时间:

date -R

修改当前时区:

cp /usr/share/zoneinfo/主时区/次时区 /etc/localtime

例如:

cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

即修改服务器时区为上海。

6.Reference

本文部分内容参考自:

https://timeting.com/27/use-scripts-auto-backup-vps-to-dropbox/

http://www.pythoner.com/324.html

https://gist.github.com/tonek/5383455

3.全自动定时备份VPS数据到Dropbox

相关脚本

nano backup.sh

放到哪里无所谓,记得赋予执行权限就可以了chmod +x backup.sh

#!/bin/bash
# Settings
DROPBOX_DIR="/Backups" #Dropbox中的文件夹名称
BACKUP_SRC="/home/wwwroot/website /home/wwwroot/database" #需要备份的文件夹路径,可以同时指定多个,32MB.CN用了Sqlite数据库,Sqlite以文件形式存放,故也要备份
BACKUP_DST="/miniVPS" #用来存放备份的文件夹路径
MYSQL_SERVER="127.0.0.1" #连接本地MySQL
MYSQL_USER="root" #本地MySQL的用户
MYSQL_PASS="123456" #本地MySQL的密码

# Stop editing here
NOW=$(date +"%Y.%m.%d")
DESTFILE="$BACKUP_DST/$NOW.tgz"
LAST=$(date -d "2 months ago" +"%Y.%m.%d") #这里的时间可以根据需要进行修改,如"3 months ago"

# Backup files
ps -e | grep -c mysql
if [ $? -eq 0 ]; then
  echo "Dumping databases..."
  /web/mysql/bin/mysqldump -u $MYSQL_USER -h $MYSQL_SERVER -p$MYSQL_PASS --all-databases > "$BACKUP_DST/$NOW-Databases.sql" #这里的命令路径可以根据需要进行修改
else
  echo "ERROR. Now exiting..."
  exit 1
fi

if [ $? -eq 0 ]; then
  echo "Packing files..."
  tar -czf "$DESTFILE" $BACKUP_SRC "$BACKUP_DST/$NOW-Databases.sql"
else
  echo "ERROR. Now exiting..."
  exit 1
fi

if [ $? -eq 0 ]; then
  /home/backup/dropbox_uploader.sh upload "$DESTFILE" "$DROPBOX_DIR/$NOW.tgz" #这里的脚本路径可以根据需要进行修改
else
  echo "ERROR. Now exiting..."
  exit 1
fi

# Delete old files
if [ $? -eq 0 ]; then
  /home/backup/dropbox_uploader.sh delete "$DROPBOX_DIR/$LAST.tgz" #这里的脚本路径可以根据需要进行修改
else
  echo "ERROR. Now exiting..."
  exit 1
fi

if [ $? -eq 0 ]; then
  echo "Cleaning the backups..."
  rm -f "$BACKUP_DST/$NOW-Databases.sql"
  rm -f "$BACKUP_DST/$LAST.tgz"
else
  echo "ERROR. Now exiting..."
  exit 1
fi

其中的dropbox_uploader.sh是Dropbox上传下载脚本,
主页:http://www.andreafabrizi.it/?dropbox_uploader

apt-get install git
git clone http://github.com/andreafabrizi/Dropbox-Uploader.git
cd Dropbox-Uploader
chmod +x dropbox_uploader.sh
mv dropbox_uploader.sh /home/backup/

初始化脚本,并按照脚本中的提示到对应的Dropbox的网页中创建API,在脚本的交互界面中输入生成的Key

./dropbox_uploader.sh

申请Dropbox访问API

允许API访问你的Dropbox

初始化完成以后,便可以立即执行一次backup.sh脚本进行备份了

/home/backup/backup.sh

定时任务
光弄好了脚本可不行,没添加定时任务怎么定时备份。

crontab -e

设置为每天执行一次备份,具体时间可以根据需要进行修改

30 1 * * * sh /home/backup/bbackup.sh

from


转载:Debian vps进程监控并自动重启
使用过lnmp一键包的同学可能很多都遇到502错误,解决502错误比较好的一个方法是定时重启php进程。由于linux的机制,进程占用过多内存时会被kill掉,此时也需要重启该进程。今天tennfy来介绍下如何对debian vps中进程进行监控并自动重启。

进程监控脚本

1、确定进程名

运行想要监控的程序之后,执行以下命令:

ps -ef

会列出系统中所有的进程,在CMD一列里找到该程序对应的进程名。

2、进程监控脚本

在root目录下新建monitor脚本

vi /root/monitor.sh

添加以下内容,注意将procname替换为待监控的进程名,/etc/init.d/procname restart替换为该进程的重启命令

#! /bin/sh
 
proc_name="procname"                             # 待监控进程名
 
number=`ps -ef | grep $proc_name | grep -v grep | wc -l`
 
if [ $number -eq 0 ]                             # 判断进程是否存在
then 
    /etc/init.d/procname restart               # 重启进程的命令,请相应修改    
fi

添加完成后,输入:wq保存修改。

设置可执行权限

chmod a+x /root/monitor.sh

添加到crontab定时任务

设置好脚本之后,添加到crontab定时任务中,每分钟执行一次脚本

echo "* * * * * root /root/monitor.sh >/dev/null 2>&1" >>/etc/crontab
/etc/init.d/cron restart

小结

如果你希望监控多个进程程序,添加多个脚本即可,该方法非常实用,很多时候都能用到。


转载:WordPress彩色标签云的实现
今天介绍下彩色标签云的实现。标签云能够为读者提供发现更多有用信息的入口。在wordpess自带的小工具里也有标签云,但是相对来说比较单调。彩色标签云则看起来更加友好一些。

functions.php中代码:

//标签云
function colorCloud($text) { 
$text = preg_replace_callback('|<a (.+?)>|i', 'colorCloudCallback', $text); 
return $text; 
} 
function colorCloudCallback($matches) { 
$text = $matches[1]; 
$color = dechex(rand(0,16777215)); 
$pattern = '/style=(\'|\")(.*)(\'|\")/i'; 
$text = preg_replace($pattern, "style=\"color:#{$color};$2;\"", $text); 
return "<a $text>"; 
} 
add_filter('wp_tag_cloud', 'colorCloud', 1);

将以上代码放到functions.php中,方便在其他地方调用。

sidebar.php调用代码

在sidebar.php中调用如下代码:

<?php wp_tag_cloud('smallest=8&largest=24&number=50'); ?>

样式表什么的你可以自行优化,这里就不多讲了。


转载:wordpress评论添加数学验证码
如今wordpress中垃圾评论越来越多了,当然wordpress中的akismet工作的也很不错,但是它偶尔会出现误判。给博客加一个简单的数学验证码不失为一个好办法,唯一值得考虑的就是可能会影响用户的体验,所以本文针对这个情况通过记录cookie值,判断是否为老用户,从而实现博客评论只需填写一次验证码,这样就能大大提高用户体验。接下来介绍一下。

添加数学验证码

将以下代码添加到functions.php中:

//评论数学验证码
function spam_protection_math(){
//获取两个随机数, 范围0~9
$num1=rand(0,9);
$num2=rand(0,9);
//最终网页中的具体内容
echo "<p class='comment-form-author'><input type='text' name='sum' class='math_textfield' value='' size='25' tabindex='4'> $num1 + $num2 = ?"
."<input type='hidden' name='num1' value='$num1'>"
."<input type='hidden' name='num2' value='$num2'>"
."<label for='math' class='small'> 验证码</label></p>";
 
}
function spam_protection_pre($commentdata){
$sum=$_POST['sum'];//用户提交的计算结果
switch($sum){
//得到正确的计算结果则直接跳出
case $_POST['num1']+$_POST['num2']:break;
//未填写结果时的错误讯息
case null:wp_die('错误: 请输入验证码.');break;
//计算错误时的错误讯息
default:wp_die('错误: 验证码错误,请重试.');
}
return $commentdata;
}
if($comment_data['comment_type']==''){
add_filter('preprocess_comment','spam_protection_pre');
}
// 增加: 錯誤提示功能

spam_protection_math()

插入到你的评论框模板的合适位置,在网址信息下方,评论框上方。如下图所示:

判断是否评论过

先根据浏览器的Cookie来判断是不是已经评论过的,如果是已经发表评论的,则显示欢迎XX回来的字样,不需要再填写验证码。并且用户可以自由编辑自己的个人信息,php代码如下:

<?php if(isset($_COOKIE['comment_author_email_'.COOKIEHASH]) && isset($_COOKIE['comment_author_'.COOKIEHASH]))  : ?>
<?php $comment_author=$_COOKIE['comment_author_'.COOKIEHASH];  ?>
<div id="span-list">
<div id="commentwelcome">
<?php printf(__(' <span>%1s, 欢迎回来!</span>'), $comment_author); ?>
</div>
<div id="welcome">
<div id="welcome1">
<?php printf(__('<span>不是 %s ?</span> '), $comment_author); ?>
</div>
</div>
<div id="author_info">
//你的个人信息框代码,即姓名,邮箱,网址框,不需要加入数学验证码
</div>
</div>
<?php endif; ?>

为了方便编辑个人信息,本文采用了jquery控制个人信息框的出现和隐藏,首先要做的是给个人信息框也就是姓名,邮箱,网址加上以下div标签,这里不需要加入数学验证码,因为该用户已评论过:

<div id="author_info"></div>

jquery代码如下:

// 评论欢迎语
/*http://www.tennfy.com*/
     //开始
if($('input#author[value]').length>0){ //判断用户框是否有值
$("#author_info").css('display','none'); //将id为author_info的对象的display属性设为none,即隐藏
var change='<span id="show_author_info" style="cursor: pointer; color:#2970A6;display:block;">编辑信息 &raquo;</span>'; //定义change,style是定义CSS样式,让他有超链接的效果,color要根据你自己的来改,当然你也可以在CSS中定义#show_author_info来实现,这样是为了不用再去修改style.css而已!
var close='<span id="hide_author_info" style="cursor: pointer;color: #2970A6;">关闭 &raquo;</span>'; //定义close
$('#welcome').append(change); //在ID为welcome的对象里添加刚刚定义的change
$('#welcome').append(close); // 添加close
$('#hide_author_info').css('display','none'); //隐藏close
$('#show_author_info').click(function() { //鼠标点击change时发生的事件
$('#author_info').slideDown('slow'); //用户输入框向下滑出
$('#commentwelcome').css('display','none');//隐藏欢迎语
$('#welcome1').css('display','none');//隐藏欢迎语
$('#show_author_info').css('display','none'); //隐藏change
$('#hide_author_info').css('display','inline'); //显示close
$('#hide_author_info').click(function() { // 鼠标点击close时发生的事件
$('#author_info').slideUp('slow'); //用户输入框向上滑
$('#commentwelcome').css('display','inline');//显示欢迎语
$('#welcome1').css('display','inline');//显示欢迎语
$('#hide_author_info').css('display','none'); //隐藏close
$('#show_author_info').css('display','inline'); })})}

这里值得注意的是写代码的时候分为3个控制逻辑:1、判断用户是否为管理员2、判断用户是否以前评论过3、判断用户是否为新用户。以上代码为第二个控制逻辑。大概的思路为:

if 1
//出现欢迎管理员回来代码
elseif 2
//出现上文代码
else 
//出现个人评论框以及数学验证码代码 
end

小结

css样式需要根据主题的特点来写,通过记录cookie可以提高用户的体验,是一个比较好的办法。效果可以参见我的博客下方评论。


from php定位当前用户城市
今天上网浏览,看到了淘宝有个ip库,可供查询ip对应的地理位置,于是就想测试下。下面是代码。

<?php
$user_IP = ($_SERVER["HTTP_VIA"]) ? $_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"];
$user_IP = ($user_IP) ? $user_IP : $_SERVER["REMOTE_ADDR"];
$URL='http://ip.taobao.com/service/getIpInfo.php?ip='.$user_IP;
$fcontents = file_get_contents("$URL");
$contents=json_decode($fcontents);
 ?>
 <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>pr查询</title>
</head>
<body style="text-align:center;margin:200px auto;font-size:25px">     
 
    <?php
     echo '您来自: '.$contents->data->country.$contents->data->area.$contents->data->region.$contents->data->city.'  ip为'.$contents->data->ip;
     ?>
 
</body>
</html>

欢迎测试:php定位当前用户城市


Nginx中rewrite规则是很多人头痛的问题,最近tennfy就被codeigniter在nginx中的伪静态问题折磨了挺长时间。因此,tennfy在这篇文章介绍下nginx rewrite基础教程。

Nginx rewrite基本语法

Nginx的rewrite语法其实很简单.主要用到如下指令

set
if
return
break
rewrite

下面来挨个介绍下这几个命令。

1.set

set主要是用来设置变量。

2.if

if主要用来判断一些在rewrite语句中无法直接匹配的条件,比如检测文件存在与否,http header,cookie等。

其用法为:

用法:if(条件) {…}
 
- 当if表达式中的条件为true,则执行if块中的语句
 
- 当表达式只是一个变量时,如果值为空或者任何以0开头的字符串都会当作false
 
- 直接比较内容时,使用 = 和 !=
 
- 使用正则表达式匹配时,使用
 
      ~ 大小写敏感匹配 
      ~* 大小写不敏感匹配 
      !~ 大小写敏感不匹配 
      !~* 大小写不敏感不匹配 
 
- 使用-f,-d,-e,-x检测文件和目录
 
      -f 检测文件存在
      -d 检测目录存在
      -e 检测文件,目录或者符号链接存在
      -x 检测文件可执行

举例分析一下:

if ($http_user_agent ~ MSIE) {
  rewrite  ^(.*)$  /msie/$1  break;
}

如果UA包含”MSIE”,rewrite 请求到/msie目录下

if ($http_cookie ~* "id=([^;] +)(?:;|$)" ) {
  set  $id  $1;
}

如果cookie匹配正则,设置变量$id等于正则引用部分

if ($request_method = POST ) {
  return 405;
}

如果提交方法为POST,则返回状态405 (Method not allowed)

if (!-f $request_filename) {
  break;
  proxy_pass  http://127.0.0.1;
}

如果请求文件名不存在,则反向代理localhost

if ($args ~ post=140){
  rewrite ^ http://example.com/ permanent;
}

如果query string中包含”post=140″,永久重定向到example.com

3.return

return可用来直接设置HTTP返回状态,比如403,404等(301,302不可用return返回,这个下面会在rewrite提到)。

4.break

立即停止rewrite检测,跟下面讲到的rewrite的break flag功能是一样的,区别在于前者是一个语句,后者是rewrite语句的flag

5.rewrite

这是最为重要的知识点

用法: rewrite 正则 替换 标志位
 
其中标志位有四种
 
break – 停止rewrite检测,也就是说当含有break flag的rewrite语句被执行时,该语句就是rewrite的最终结果
last – 停止rewrite检测,但是跟break有本质的不同,last的语句不一定是最终结果,这点后面会跟nginx的location匹配一起提到
redirect – 返回302临时重定向,一般用于重定向到完整的URL(包含http:部分)
permanent – 返回301永久重定向,一般用于重定向到完整的URL(包含http:部分)

因为301和302不能简单的只单纯返回状态码,还必须有重定向的URL,这就是return指令无法返回301,302的原因了。作为替换,rewrite可以更灵活的使用redirect和permanent标志实现301和302。

举例说明:

rewrite  ^(/download/.*)/media/(.*)\..*$  $1/mp3/$2.mp3  last;

如果请求为 /download/eva/media/op1.mp3,则请求被rewrite到 /download/eva/mp3/op1.mp3。

rewrite在使用中还有很多值得注意的地方:

  • rewrite的生效区块为sever, location, if
  • rewrite只对相对路径进行匹配,不包含hostname
  • 使用相对路径rewrite时,会根据HTTP header中的HOST跟nginx的server_name匹配后进行rewrite,如果HOST不匹配或者没有HOST信息的话则rewrite到server_name设置的第一个域名,如果没有设置server_name的话,会使用本机的localhost进行rewrite
  • 前面提到过,rewrite的正则是不匹配query string的,所以默认情况下,query string是自动追加到rewrite后的地址上的,如果不想自动追加query string,则在rewrite地址的末尾添加?

    rewrite ^/users/(.*)$ /show?user=$1? last;

Nginx location 和 rewrite retry

nginx的rewrite有个很奇特的特性 — rewrite后的url会再次进行rewrite检查,最多重试10次,10次后还没有终止的话就会返回HTTP 500。

1、location基础

用过nginx的朋友都知道location区块,location区块有点像Apache中的RewriteBase,但对于nginx来说location是控制的级别而已,里面的内容不仅仅是rewrite。location是nginx用来处理对同一个server不同的请求地址使用独立的配置的方式。

举例说明:

location  = / {
  ....配置A
}
 
location  / {
  ....配置B
}
 
location ^~ /images/ {
  ....配置C
}
 
location ~* \.(gif|jpg|jpeg)$ {
  ....配置D
}

访问 / 会使用配置A
访问 /documents/document.html 会使用配置B
访问 /images/1.gif 会使用配置C
访问 /documents/1.jpg 会使用配置D

现在我们只需要明白一个情况: nginx可以有多个location并使用不同的配置。

2、location匹配命中规则

server区块中如果有包含rewrite规则,则会最先执行,而且只会执行一次, 然后再判断命中哪个location的配置,再去执行该location中的rewrite, 当该location中的rewrite执行完毕时,rewrite并不会停止,而是根据rewrite过的URL再次判断location并执行其中的配置。

location并非像rewrite那样逐条执行,而是有着匹配优先级的,当一条请求同时满足几个location的匹配时,其只会选择其一的配置执行.

其寻找的方法为:

1. 首先寻找所有的常量匹配,如location /, location /av/, 以相对路径自左向右匹配,匹配长度
   最高的会被使用

2. 然后按照配置文件中出现的顺序依次测试正则表达式,如 
   location ~ download\/$, location ~* \.wtf, 第一个匹配会被使用 

3. 如果没有匹配的正则,则使用之前的常量匹配

而下面几种方法当匹配时会立即终止其他location的尝试

1. = 完全匹配,location = /download/ 

2. ^~ 终止正则测试,如location ^~ /download/ 如果这条是最长匹配,则终止正则测试,这个符号
   只能匹配常量 

3. 在没有=或者^~的情况下,如果常量完全匹配,也会立即终止测试,比如请求为 /download/ 会完全
   命中
   location /download/而不继续其他的正则测试

总结:

1. 如果完全匹配(不管有没有=),尝试会立即终止

2. 以最长匹配测试各个常量,如果常量匹配并有 ^~, 尝试会终止
 
3. 按在配置文件中出现的顺序测试各个正则表达式 

4. 如果第3步有命中,则使用其匹配location,否则使用第2步的location

另外还可以定义一种特殊的named location,以@开头,如location @thisissparta 不过这种location定义不用于一般的处理,而是专门用于try_file, error_page的处理,这里不再深入.

举例说明:

location  = / {
  ....配置A
}
 
location  / {
  ....配置B
}
 
location ^~ /images/ {
  ....配置C
}
 
location ~* \.(gif|jpg|jpeg)$ {
  ....配置D
}

访问 / 会使用配置A -> 完全命中
访问 /documents/document.html 会使用配置B -> 匹配常量B,不匹配正则C和D,所以用B
访问 /images/1.gif 会使用配置C -> 匹配常量B,匹配正则C,使用首个命中的正则,所以用C
访问 /documents/1.jpg 会使用配置D -> 匹配常量B,不匹配正则C,匹配正则D,使用首个命中的正则,所以用D

3、rewrite retry

这里就存在一个问题,如果rewrite写的不正确的话,是会在location区块间造成无限循环的.所以nginx才会加一个最多重试10次的上限. 比如这个例子

location /download/ {
  rewrite  ^(/download/.*)/media/(.*)\..*$  $1/mp3/$2.mp3  last;
}

如果请求为 /download/eva/media/op1.mp3 则请求被rewrite到 /download/eva/mp3/op1.mp3

结果rewrite的结果重新命中了location /download/ 虽然这次并没有命中rewrite规则的正则表达式,但因为缺少终止rewrite的标志,其仍会不停重试download中rewrite规则直到达到10次上限返回HTTP 500。

这里需要介绍一下last标志位与break标志位的区别。

  • break是终止当前location的rewrite检测,而且不再进行location匹配
    – last是终止当前location的rewrite检测,但会继续重试location匹配并处理区块中的rewrite规则

举例说明:

location /download/ {
  rewrite  ^(/download/.*)/media/(.*)\..*$  $1/mp3/$2.mp3  ;
  rewrite  ^(/download/.*)/movie/(.*)\..*$  $1/avi/$2.mp3  ;
  rewrite  ^(/download/.*)/avvvv/(.*)\..*$  $1/rmvb/$2.mp3 ;
}

如果请求为 /download/acg/moive/UBW.avi

last的情况是: 在第2行rewrite处终止,并重试location /download..死循环
break的情况是: 在第2行rewrite处终止,其结果为最终的rewrite地址。

虽然如此,但是很多情况下还是需要使用last。典型的例子就是wordpress的permalink rewrite。

常见的情况下, wordpress的rewrite是放在location /下面,并将请求rewrite到/index.php

这时如果这里使用break就会出现问题,因为nginx返回的是没有解释的index.php的源码。

这里一定要使用last才可以在结束location / 的rewrite, 并再次命中location ~ .php$,将其交给fastcgi进行解释.其后返回给浏览器的才是解释过的html代码。

WordPress的Permalink+Supercache rewrite实现

这个rewrite写法其实是来自supercache作者本家的某个评论中,网上很容易查到,做了一些修改. 先给出该配置文件的全部内容..部分内容码掉了..绝对路径什么的你知道也没啥用对吧?

server {
    listen   80;
    server_name  cafeneko.info www.cafeneko.info;
 
    access_log  ***;
    error_log   *** ;
 
    root   ***;
    index  index.php;
 
    gzip_static on;
 
    if (-f $request_filename) {
        break;
    }
 
    set $supercache_file '';
    set $supercache_uri $request_uri;
 
    if ($request_method = POST) {
        set $supercache_uri '';
    }
 
    if ($query_string) {
        set $supercache_uri '';
    }
 
    if ($http_cookie ~* "comment_author_|wordpress_logged_|wp-postpass_" ) {
        set $supercache_uri '';
    }
 
    if ($supercache_uri ~ ^(.+)$) {
        set $supercache_file /wp-content/cache/supercache/$http_host/$1index.html;
    }
 
    if (-f $document_root$supercache_file) {
        rewrite ^(.*)$ $supercache_file break;
    }
 
    if (!-e $request_filename) {
        rewrite . /index.php last;
    }
 
    location ~ \.php$ {
 
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  ***$fastcgi_script_name;
        include        fastcgi_params;
    }
 
    location ~ /\.ht {
        deny  all;
    }
}

下面是解释:

gzip_static on;

如果浏览器支持gzip,则在压缩前先寻找是否存在压缩好的同名gz文件避免再次压缩浪费资源,配合supercache的压缩功能一起使用效果最好,相比supercache原生的Apache mod_rewrite实现,nginx的实现简单的多. Apache mod_rewrite足足用了两套看起来一模一样的条件判断来分别rewrite支持gzip压缩和不支持的情况.

if (-f $request_filename) {
    break;
}

如果是直接请求某个真实存在的文件,则用break语句停止rewrite检查

set $supercache_file '';
set $supercache_uri $request_uri;

用$request_uri初始化变量 $supercache_uri.

if ($request_method = POST) {
    set $supercache_uri '';
}

如果请求方式为POST,则不使用supercache.这里用清空$supercache_uri的方法来跳过检测,下面会看到

if ($query_string) {
    set $supercache_uri '';
}

因为使用了rewrite的原因,正常情况下不应该有query_string(一般只有后台才会出现query string),有的话则不使用supercache

if ($http_cookie ~* "comment_author_|wordpress_logged_|wp-postpass_" ) {
    set $supercache_uri '';
}

默认情况下,supercache是仅对unknown user使用的.其他诸如登录用户或者评论过的用户则不使用.

comment_author是测试评论用户的cookie, wordpress_logged是测试登录用户的cookie. wp-postpass不大清楚,字面上来看可能是曾经发表过文章的?只要cookie中含有这些字符串则条件成立.

原来的写法中检测登录用户cookie用的是wordpress_,但是我在测试中发现登入/登出以后还会有一个叫wordpress_test_cookie存在,不知道是什么作用,我也不清楚一般用户是否会产生这个cookie.由于考虑到登出以后这个cookie依然存在可能会影响到cache的判断,于是把这里改成了匹配wordpress_logged_

if ($supercache_uri ~ ^(.+)$) {
    set $supercache_file /wp-content/cache/supercache/$http_host$1index.html;
}

如果变量$supercache_uri不为空,则设置cache file的路径

这里稍微留意下$http_host$1index.html这串东西,其实写成 $http_host/$1/index.html 就好懂很多

以这个rewrite形式的url为例

domain.com/year/month/postname/

其中

$http_host = ‘domain.com’ , $1 = $request_uri = ‘/year/month/postname/’

$http_host$1index.html = ‘domain.com/year/month/postname/index.html’

$http_host/$1/index.html = ‘domain.com//year/month/postname//index.html’

虽然在调试过程中两者并没有不同,不过为了保持正确的路径,还是省略了中间的/符号.

最后上例rewrite后的url为

‘domain.com/wp-content/cache/supercache/domain.com/year/month/postname/index.html’

if (-f $document_root$supercache_file) {
    rewrite ^(.*)$ $supercache_file break;
}

检查cache文件是否存在,存在的话则执行rewrite,留意这里因为是rewrite到html静态文件,所以可以直接用break终止掉.

if (!-e $request_filename) {
    rewrite . /index.php last;
}

执行到此则说明不使用suercache,进行wordpress的permalink rewrite

检查请求的文件/目录是否存在,如果不存在则条件成立, rewrite到index.php

顺便说一句,当时这里这句rewrite看的我百思不得其解. .

只能匹配一个字符啊?这是什么意思?

一般情况下,想调试nginx rewrite最简单的方法就是把flag写成redirect,这样就能在浏览器地址栏里看到真实的rewrite地址.

然而对于permalink rewrite却不能用这种方法,因为一旦写成redirect以后,不管点什么链接,只要没有supercache,都是跳转回首页了.

后来看了一些文章才明白了rewrite的本质,其实是在保持请求地址不变的情况下,在服务器端将请求转到特定的页面.

乍一看supercache的性质有点像302到静态文件,所以可以用redirect调试.

但是permalink却是性质完全不同的rewrite,这跟wordpress的处理方式有关. 我研究不深就不多说了,简单说就是保持URL不变将请求rewrite到index.php,WP将分析其URL结构再对其并进行匹配(文章,页面,tag等),然后再构建页面. 所以其实这条rewrite。

rewrite . /index.php last;

说的是,任何请求都会被rewrite到index.php.因为”.”匹配任意字符,所以这条rewrite其实可以写成任何形式的能任意命中的正则.比如说

rewrite . /index.php last;
rewrite ^ /index.php last;
rewrite .* /index.php last;

效果都是一样的,都能做到permalink rewrite.

最后要提的就是有人可能注意到我的rewrite规则是放在server块中的.网上能找到的大多数关于wordpress的nginx rewrite规则都是放在location /下面的,但是上面我却放在了server块中,为何?

原因是WP或某个插件会在当前页面做一个POST的XHR请求,本来没什么特别,但问题就出在其XHR请求的URL结构上.

正常的permalink一般为: domain.com/year/month/postname/ 或者 domain.com/tags/tagname/ 之类.

但这个XHR请求的URL却是 domain.com/year/month/postname/index.php 或者 domain.com/tags/tagname/index.php

这样一来就命中了location ~ .php$而交给fastcgi,但因为根本没有做过rewrite其页面不可能存在,结果就是这个XHR返回一个404

鉴于location之间匹配优先级的原因,将主要的rewrite功能全部放进了server区块中,这样就得以保证在进行location匹配之前是一定做过rewrite的.

所以要解决这个问题最简单的方法就是把rewrite规则放在比location先执行的server块里面就可以了。

参考文章:Nginx Rewrite研究笔记


转载:ubuntu12.04安装LNMP环境
最近玩ubuntu,正好想在上面安装一个lnmp,好来测试博客代码什么的。下面记录下流程。
新建/var/www/目录,当然这个目录由你自己决定放在那里,做了修改之后要记得设置后面的nginx的代码。

sudo mkdir /var/www
sudo chmod -R 777 /var/www

安装nginx

apt-get install nginx-full

所有的配置文件都在/etc/nginx下,并且每个虚拟主机已经安排在了/etc/nginx/sites-available下
程序文件在/usr/sbin/nginx
日志放在了/var/log/nginx中
并已经在/etc/init.d/下创建了启动脚本nginx
默认的虚拟主机的目录设置在了/var/www/nginx-default

修改网站默认目录:

sudo vim /etc/nginx/sites-available/default

用下面的代码替换掉所有代码:

server {
    listen [::]:80 default ipv6only=on; ## listen for ipv6
    listen 80;
    server_name localhost;
    root /var/www/; #如果你修改上面的目录,这里做相应修改.
    location / {
    index index.php index.html index.htm;
    }
    location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    #    # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
    #
    #    # With php5-cgi alone:
       fastcgi_pass 127.0.0.1:9000;
    #    # With php5-fpm:
    #    fastcgi_pass unix:/var/run/php5-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
    }
    }

修改 /etc/nginx/fastcgi_params,直接在末尾添加以下内容:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_script_name;
fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

安装php和mysql

sudo apt-get install php5-fpm php5-gd php5-common php5-curl php5-imagick php5-mcrypt php5-memcache php5-mysql php5-cgi php5-cli

安装mysql

sudo apt-get install -y mysql-server mysql-client

注意:在安装过程中会要求创建Mysql 的root用户密码,请务必牢记数据库Mysql的超级密码。

修改php.ini文件:

sudo vim /etc/php5/fpm/php.ini

修改cgi.fix_pathinfo=1 为

cgi.fix_pathinfo=0

新建站点

sudo vim /etc/nginx/conf.d/example.com.conf

内容为

server {
    listen 80;
    #ipv6
    #listen [::]:80 default_server;
    root /var/www/example.com.net;
    #默认首页文件名
    index index.php index.html index.htm;
    #绑定域名
    server_name example.com;
    location / {
        try_files $uri $uri/ /index.html;
        #伪静态规则
    这里填写伪静态规则
    }
    #定义错误页面
    #error_page 404 /404.html;
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        include fastcgi_params;
    }
    }

重新启动 nginx 和 php-fpm

sudo /etc/init.d/nginx restart
sudo /etc/init.d/php5-fpm reload

使用phpmyadmin

最后关于mysql管理的问题,直接下载phpmyadmin源码包解压到/var/www/,浏览器打开:http://localhost/phpmyadmin/访问数据库,注意“phpmyadmin”的大小写。用户名和密码就是安装mysql时设置的用户名和密码。


转载:Nginx 配置文件nginx.conf的完整配置说明
今天来介绍下关于Nginx 配置文件nginx.conf 的具体内容

#定义Nginx运行的用户和用户组
user www www;
#工作进程,根据硬件调整,几核cpu,就配几个
worker_processes 5;
#全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]
error_log logs/error.log;
#pid文件位置
pid logs/nginx.pid;
worker_rlimit_nofile 8192;</code>
 
events {
#参考事件模型,use [ kqueue | rtsig | epoll | /dev/poll | select | poll ]; epoll模型是Linux 2.6以上版本内核中的高性能网络I/O模型
use epoll;
#工作进程的最大连接数量,根据硬件调整,和前面工作进程配合起来用,尽量大,但是别把cpu跑到100%就行
worker_connections 4096;
}
 
#设定http服务器
http {
#文件扩展名与文件类型映射表
include conf/mime.types;
#反向代理配置,可以打开proxy.conf看看
include /etc/nginx/proxy.conf;
#fastcgi配置,可以打开fastcgi.conf看看
include /etc/nginx/fastcgi.conf;
 
default_type application/octet-stream;
#日志的格式
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
#访问日志
access_log logs/access.log main;
sendfile on;
tcp_nopush on;
#根据实际情况调整,如果server很多,就调大一点
server_names_hash_bucket_size 128; # this seems to be required for some vhosts
 
#这个例子是fastcgi的例子,如果用fastcgi就要仔细看
server { # php/fastcgi
listen 80;
#域名,可以有多个
server_name domain1.com www.domain1.com;
#访问日志,和上面的级别不一样,应该是下级的覆盖上级的
access_log logs/domain1.access.log main;
root html;
 
location / {
index index.html index.htm index.php;
}
 
#所有php后缀的,都通过fastcgi发送到1025端口上
#上面include的fastcgi.conf在此应该是有作用,如果你不include,那么就把fastcgi.conf的配置项放在这个下面。
location ~ .php$ {
fastcgi_pass 127.0.0.1:1025;
}
}
 
#这个是反向代理的例子
server { # simple reverse-proxy
listen 80;
server_name domain2.com www.domain2.com;
access_log logs/domain2.access.log main;
 
#静态文件,nginx自己处理
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/virtual/big.server.com/htdocs;
#过期30天,静态文件不怎么更新,过期可以设大一点,如果频繁更新,则可以设置得小一点。
expires 30d;
}
 
#把请求转发给后台web服务器,反向代理和fastcgi的区别是,反向代理后面是web服务器,fastcgi后台是fasstcgi监听进程,当然,协议也不一样。
location / {
proxy_pass http://127.0.0.1:8080;
}
}
 
#upstream的负载均衡,weight是权重,可以根据机器配置定义权重。据说nginx可以根据后台响应时间调整。后台需要多个web服务器。
upstream big_server_com {
server 127.0.0.3:8000 weight=5;
server 127.0.0.3:8001 weight=5;
server 192.168.0.1:8000;
server 192.168.0.1:8001;
}
 
server {
listen 80;
server_name big.server.com;
access_log logs/big.server.access.log main;
 
location / {
proxy_pass http://big_server_com;
}
}
}