月度归档:2013年10月

利用.htaccess文件保护wordpress不被恶意骚扰

最近越来越多的站长关注wordpress网站的安全了,正好小V也最近也没什么教程好更新的,就写点有关于wordpress网站安全防护的教程吧。今天小V教大家使用.htaccess文件保护wordpress站点不被恶意访客骚扰。

首先是垃圾评论,一直以来wordpress垃圾评论就是各大wordpress站长头疼的问题,很多垃圾评论都是软件直接利用wp-comments-post.php文件来直接提交的,那么我们可以利用.htaccess文件来屏蔽wp-comments-post.php被直接访问,代码如下:(2013.10.31更新:下面有位网友提问说用了小V的.htaccess防垃圾评论代码出现访问错误,这里小V提示下代码中的yourdomainname.com要替换成自己的域名。)

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
RewriteCond %{HTTP_REFERER} !.*yourdomainname.com.* [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule (.*) ^http://%{REMOTE_ADDR}/$ [R=301,L]
</IfModule>

接下来是防sql注入等恶意请求:

Options +FollowSymLinks
RewriteEngine On
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ index.php [F,L]

之前小V曾说过wordpress有个爆路径的漏洞,参考这篇文章:《wordpress防黑教程之预防全版本通杀爆绝对路径漏洞》,其实我们可以利用.htaccess来禁止某系目录下的php文件被直接访问,以/wp-content/themes/目录为例:

<Directory "/example/htdocs/wp-content/themes/">
       <Files *php>
           Order allow,deny
           Deny from all
       </Files>
   </Directory>

接下来是保护上传文件夹的安全,我们可以用.htaccess文件来禁止在wordpress默认文件上传目录中运行php文件,代码如下:

<Directory "/example/htdocs/wp-content/uploads/2015/">
        php_admin_flag engine off
    </Directory>

以上部分代码可以根据个人网站情况做适当修改。

wordpress会员系统开发手记:添加不同权限的会员等级角色

小V看了下后台文章发现都299篇文章了,干脆咬牙再更新一篇文章让网站文章数量在今晚就突破300大关吧,正好最近wordpress会员系统这个话题在wordpress圈子也挺火热的先翻翻wordpress看看有什么可写的~翻过文档后发现默认的wordpress会员系统才五中角色:管理员、编辑、作者、投稿者和订阅者,而且权限也限制的很死。接下来小V就教大家如何给默认的wordpress会员系统添加更多角色,并且分配权限。

假设小V要给v7v3.com添加一个评论审核员(评论审核员需要能管理评论的权限,但不需要编辑文章的权限。)那么首先打开functions.php文件在其中加入以下代码:

add_role('site_developer', '评论审核员', array(
    'read' => true, //文章阅读权限
    'moderate_comments' => true, //编辑、删除、修改评论权限
    'edit_posts' => false //编辑文章权限
));

这样一来wordpress后台的用户分组里就多了一个评论审核员用户组了,接下来下小V在说下一些常见的wordpress权限字段。

read 阅读文章
moderate_comments 管理评论
delete_posts 删除文章
edit_posts 编辑文章
delete_published_posts 删除已发布文章
publish_posts 发布文章
upload_files 上传文件
edit_published_posts 编辑已发布文章
read_private_pages 阅读私有页面
edit_private_pages 编辑私有页面
delete_private_pages 删除私有页面
read_private_posts 阅读私有文章
edit_private_posts 编辑私有文章
delete_private_posts 删除私有文章
delete_users 删除用户
edit_users 编辑用户
edit_themes 编辑主题
edit_plugins 编辑插件

更多wordpress权限说明参见:http://codex.wordpress.org/Roles_and_Capabilities

PS:补充下add_role这个函数在生效后会自动消失,而新用户角色的设置是添加到数据库中(表 wp_options 的 wp_user_roles 字段中),所以想删除用户角色的话可以使用remove_role函数删除,以本文添加的用户组为例:

remove_role('site_developer');

将以上代码加入到functions.php文件即可删除之前添加的评论审核员角色了。下面说明下系统默认的几个用户组:

订阅者:subscriber 投稿者:contributor 作者:author 编辑:editor 管理员:administrator (管理员角色请勿删除!!)

非插件实现wordpress显示当前在线人数

今天小V在各大wordpress网站闲逛时发现一个很不错的前台显示当前在线人数的功能,翻翻了正好找到实现该功能的代码,就特地转来给大伙看看,下面是效果图:

非插件实现wordpress显示当前在线人数-wordpress教程-代码笔记

下面小V来说说如何实现wordpress前台显示当前在线人数的方法:

首先是HTML代码,在页面上放置一个显示当前在线人数的div#total以及一个用于展示访客地区分布的列表#onlinelist,默认我们在列表中放置一张与加载动画图片,后面我们用jQuery控制当鼠标滑向时展示详细列表。

<div class="demo"> 
      <div id="total">当前在线:<span id="onlinenum"></span></div> 
    <ul id="onlinelist"> 
        <li><img src="loader.gif"/></li> 
    </ul> 
</div>

然后是css渲染效果:

.demo{width:150px; margin:20px auto; font-size:14px} 
#total{padding:6px 10px; background:#090 url(arr.png) no-repeat right top; color:#fff;  
cursor:pointer; -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px;  
-moz-box-shadow:0 0 3px #ccc; -webkit-box-shadow:0 0 3px #ccc;box-shadow:0 0 3px #ccc;} 
#onlinelist{background:#f7f7f7; border:1px solid #d3d3d3; display:none; -moz-border-radius:5px;  
-webkit-border-radius:5px; border-radius:5px; -moz-box-shadow:0 0 3px #ccc;  
-webkit-box-shadow:0 0 3px #ccc;box-shadow:0 0 3px #ccc;} 
#onlinelist li{height:20px; line-height:20px;padding:4px 6px;border-bottom:1px dotted #d9d9d9} 
#onlinelist li span{float:right} 
#onlinelist li:hover{background:#fff}

准备一张数据表online,用来记录访客IP、地区及访问时间。整个示例统计过程都依赖这张表,其结构如下:

CREATE TABLE IF NOT EXISTS `online` ( 
  `id` int(11) NOT NULL AUTO_INCREMENT, 
  `ip` varchar(30) NOT NULL, 
  `province` varchar(64) NOT NULL, 
  `addtime` int(10) NOT NULL DEFAULT '0', 
  PRIMARY KEY (`id`) 
) ENGINE=MyISAM  DEFAULT CHARSET=utf8;

online.php用来记录访客信息,包括IP地址和地区。首先检测数据表中是否有访客IP记录,如果有,则只更新访问时间,否则,获取用户省份区域,并将用户IP即省份区域插入到表中。在此,可以判断是否存在访客的cookie记录,如果不存在则向新浪IP地址库请求获取访客的区域信息,并设置cookie值和过期时间。最后,我们删除表中已经过期的记录,统计总记录数并输出,详细请看代码注释。

include_once('connect.php'); //连接数据库 
    
$ip = get_client_ip(); //获取客户端IP 
$time = time(); 
//查询表中是否有ip为当前访客IP的记录 
$query = mysql_query("select id from online where ip='$ip'"); 
if(!mysql_num_rows($query)){//如果不存在访客IP 
    if($_COOKIE['geoData']){//如果存在cookie,则获取用户的区域 
        $province = $_COOKIE['geoData']; //区域(省份) 
    }else{ 
        $api = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=json&ip=$ip"; 
        $json = file_get_contents($api);//调用新浪IP地址库 
        $arr = json_decode($json,true);//解析json 
        $province = $arr['province'];//获取省份 
        setcookie('geoData',$province,$time+600); //设置cookie,设置过期时间为10分钟 
    } 
    //将访客信息插入到数据表中 
    mysql_query("insert into online (ip,province,addtime) values ('$ip','$province','$time')"); 
}else{//如果存在,则更新该用户访问时间 
    mysql_query("update online set addtime='$time' where ip='$ip'"); 
} 
//删除已过期的记录 
$outtime = $time-600; 
mysql_query("delete from online where addtime< $outtime"); 
//统计总记录数,即在线用户数 
list($totalOnline) = mysql_fetch_array(mysql_query("select count(*) from online"));  
echo $totalOnline;//输出在线总数 
mysql_close();

函数get_client_ip()用来获取用户真实IP。

function get_client_ip() { 
    if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) 
        $ip = getenv("HTTP_CLIENT_IP"); 
    else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"),  
"unknown")) 
        $ip = getenv("HTTP_X_FORWARDED_FOR"); 
    else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) 
        $ip = getenv("REMOTE_ADDR"); 
    else if (isset ($_SERVER['REMOTE_ADDR']) &&  
$_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) 
        $ip = $_SERVER['REMOTE_ADDR']; 
    else
        $ip = "unknown"; 
    return ($ip); 
}

geo.php用来统计各省份(区域)访客人数分布。通过查询数据库,并按省份分组排序即可,注意我们将最终的数据集以JSON的形式输出,便于前端ajax交互。

include_once('connect.php');//连接数据库 
//查询区域统计 
$sql = "select province,count(*) as total from online group by province order by total desc"; 
$result = mysql_query($sql); 
while($row=mysql_fetch_array($result)){ 
    $list[] = array( 
        'province' => $row['province'], 
        'total' => $row['total'] 
    );     
} 
echo json_encode($list);//以json格式输出

前端页面需要做的是,页面加载时展示访客总数,即使用ajax请求online.php即可。然后当鼠标滑向统计箭头时,通过ajax请求geo.php获取各区域省份的在线人数,并以下拉的方式展现效果。

$(function(){ 
    $("#onlinenum").load("online.php"); 
     
    $(".demo").hover(function(){ 
        $("#onlinelist").slideDown("fast"); 
        var str = ''; 
        $.getJSON("geo.php",function(json){ 
            $.each(json,function(index,array){ 
                str = str + "<li><span>"+array['total']+"</span>"+array['province']+"</li>"; 
            }); 
            $("#onlinelist").html(str); 
        }); 
    },function(){ 
        $("#onlinelist").slideUp("fast"); 
    }); 
});

最后,该示例依赖jquery,所以别忘了在页面中请先加载jquery库,目前已经到jquery-1.9.1版本了。
  下载源文件

本文转自:zhushuiwen.com

WordPress 3.7正式版发布

半个月前刚发布了 WordPress 3.6.1,今天就发布 WordPress 3.7,速度真够快的。WordPress 3.7 更新的功能不会很多,主要还是解决之前的很多未处理的 Bug,真正大升级的版本应该是 WordPress 3.8。

WordPress 3.7 主要更新的功能如下:

  • 原生语言包;本地化版本的 WordPress 将获得更快和更完整的翻译。 WordPress3.7中增加了自动安装正确的语言文件,并保持他们的支持。

  • 小版本的自动升级,比如从 3.7 自动升级到 3.7.1

  • 改进用户密码的增强措施

  • 提高搜索结果的相关性,根据匹配程度排序结果,而不是发布日期,比如,标题中含有搜索关键词的文章将提前

  • 多站点模式改进函数 wp_get_sites() 获取网络中的站点,无需直接查询数据库

  • 新增日期查询函数,快速按照时间获取文章,具体如下:

此外,WordPress 3.7 为 WP_Query 类增加一个根据日期查询调用文章数据的 ‘date_query’ 参数,简单举几个例子:

// 获取周一至周五 上午9点至下午5点 发布的10篇最近的文章
$some_posts = new WP_Query( array(
    'date_query' => array(
        array(
            'hour' => 9,
            'compare' => '>=',
        ),
        array(
            'hour' => 17,
            'compare' => '<=',
        ),
        array(
            'dayofweek' => array( 2, 6 ),
            'compare' => 'BETWEEN',
        ),
    ),
    'posts_per_page' => 10,
) );
  
// 获取 2013-6-1 至 2012-8-31 的文章
// Note that strtotime()-compatible strings can be used
$some_posts = new WP_Query( array(
    'date_query' => array(
        array(
            // String via strtotime()
            'after'     => 'June 1st, 2013',
            // Or if you want, an array
            'before'    => array(
                'year'  => 2013,
                'month' => 8,
                'day'   => 31,
            ),
            'inclusive' => true,
        ),
    ),
    'posts_per_page' => -1,
) );
  
// 调用一年前发布,近一个月更新过的文章
$some_posts = new WP_Query( array(
    'date_query' => array(
        array(
            'column' => 'post_date_gmt',
            'before' => '1 year ago',
        ),
        array(
            'column' => 'post_modified_gmt',
            'after'  => '1 month ago',
        )
    ),
    'posts_per_page' => -1,
) );

wordpress主题制作必备代码:网站数据统计代码

很多时候小V在制作wordpress主题时需要在网站的获取网站的数据信息例如:文章数量、评论数量之类的。之前小V一直是依靠直接读取数据库内容来获取这些数据的,今天找到利用wordpress内置的函数来调用的方法,特地写篇备忘录。

日志总数:
<?php $count_posts = wp_count_posts(); echo $published_posts = $count_posts->publish;?>
草稿数目:
<?php $count_posts = wp_count_posts(); echo $draft_posts = $count_posts->draft; ?>
评论总数:
<?php echo $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->comments");?>
成立时间:
<?php echo floor((time()-strtotime("2013-6-25"))/86400); ?>
标签总数:
<?php echo $count_tags = wp_count_terms('post_tag'); ?>
页面总数:
<?php $count_pages = wp_count_posts('page'); echo $page_posts = $count_pages->publish; ?>
分类总数:
<?php echo $count_categories = wp_count_terms('category'); ?>
链接总数:
<?php $link = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->links WHERE link_visible = 'Y'"); echo $link; ?>
用户总数:
<?php $users = $wpdb->get_var("SELECT COUNT(ID) FROM $wpdb->users"); echo $users; ?>
最后更新:
<?php $last = $wpdb->get_results("SELECT MAX(post_modified) AS MAX_m FROM $wpdb->posts WHERE (post_type = 'post' OR post_type = 'page') AND (post_status = 'publish' OR post_status = 'private')");$last = date('Y-n-j', strtotime($last[0]->MAX_m));echo $last; ?>

代码用法很简单,只需要将显示的内容添加到需要显示的模板文件里即可实现。

wordpress主题恶意代码检测插件:Theme Authenticity Checker (TAC)

相信很多wordpress站长在菜鸟时期都用过网上下载的免费wordpress主题,而有些来路不明的wordpress模板主题在安装时顺带把一些恶意代码或者后门一并安装到网站了,所以我们使用网上下载的wordpress主题之前一定要先检测主题是否带有恶意代码或者后门。但是对于菜鸟来说检测主题中是否带有后门以及恶意代码简直就是难于登天,那么今天小V就来介绍一款wordpress主题恶意代码检测插件:Theme Authenticity Checker (TAC)。安装Theme Authenticity Checker (TAC)插件后直接启用无需设置,将主题上传至网站即可在启用主题的界面看到代码检测选项,鼠标轻轻一点即可检测主题代码安全性!

wordpress网站终极防黑手册,全方位保护网站安全(二)

接着上一篇文章《wordpress网站终极防黑手册,全方位保护网站安全(一)》小V继续来谈谈wordpress系统的一些已知安全隐患。老鸟级别的wordpress站长一定知道不管在任何版本的wordpress程序上作者存档页面的固定链接都是不能修改的,而且一旦站长开启伪静态后,只要直接访问

abc.com/?author=$id
(PS:id为用户的数字id)

则wordpress会直接转跳到

abc.com/author/用户帐号/

这种形式的链接,这将直接暴露出网站用户的登录帐号,存在着一定的安全隐患。(PS:管理员的ID都是1-5这五个数字,直接一试管理员帐号就暴露了,然后密码字典你懂的wordpress网站终极防黑手册,全方位保护网站安全(二)-wordpress教程-代码笔记。)

查看wordpress源文件发现作者存档页面链接是这样获取的:

/**
 * Retrieve the URL to the author page for the user with the ID provided.
 *
 * @since 2.1.0
 * @uses $wp_rewrite WP_Rewrite
 * @return string The URL to the author's page.
 */
function get_author_posts_url($author_id, $author_nicename = '') {
    global $wp_rewrite;
    $auth_ID = (int) $author_id;
    $link = $wp_rewrite->get_author_permastruct();
     
    if ( empty($link) ) {
        $file = home_url( '/' );
        $link = $file . '?author=' . $auth_ID;
    } else {
        if ( '' == $author_nicename ) {
            $user = get_userdata($author_id);
            if ( !empty($user->user_nicename) )
                $author_nicename = $user->user_nicename;
        }
        $link = str_replace('%author%', $author_nicename, $link);
        $link = home_url( user_trailingslashit( $link ) );
    }
     
    $link = apply_filters('author_link', $link, $author_id, $author_nicename);
     
    return $link;
}

那么只要重写下规则即可改变作者存档页面的链接,这里以作者ID为例:(将以下代码加入到functions.php文件)

add_filter( 'request', 'v7v3_author_link_request' );
function v7v3_author_link_request( $query_vars ) {
    if ( array_key_exists( 'author_name', $query_vars ) ) {
        global $wpdb;
        $author_id=$query_vars['author_name'];
        if ( $author_id ) {
            $query_vars['author'] = $author_id;
            unset( $query_vars['author_name'] );    
        }
    }
    return $query_vars;
}
add_filter( 'author_link', 'v7v3_author_link', 10, 2 );
function v7v3_author_link( $link, $author_id) {
    global $wp_rewrite;
    $author_id = (int) $author_id;
    $link = $wp_rewrite->get_author_permastruct();
     
    if ( empty($link) ) {
        $file = home_url( '/' );
        $link = $file . '?author=' . $author_id;
    } else {
        $link = str_replace('%author%', $author_id, $link);
        $link = home_url( user_trailingslashit( $link ) );
    }
     
    return $link;
}

再次访问

abc.com/?author=$id

则转跳到

abc.com/author/$id

这样一来就不会暴露网站用户以及管理员账号了。

wordpress网站终极防黑手册,全方位保护网站安全(一)

wordpress网站终极防黑手册,全方位保护网站安全(一)-wordpress教程-代码笔记 %

昨日小V与2zzt的大叔在群中闲聊时发现很多wordpress站长都很不注意网站的信息安全,各种漏洞、各种信息泄露。接下来小V就来教大家为自己的wordpress修复一些常见的bug,预防黑客。

首先是wordpress的全版本通杀爆绝对路径漏洞:

1、/wp-includes/registration-functions.php

2、/wp-includes/user.php

3、/wp-admin/admin-functions.php

4、/wp-admin/upgrade-functions.php

只要直接访问以上文件或者访问当前wordpress网站的主题目录下任意php文件都会爆出网站的绝对路径,就连wordpress官方的主题twentytwelve也不例外。

解决方法一、在以上文件的的头部 <?php 后加入:

error_reporting(0);

解决方法二、直接修改php.ini屏蔽php报错。(参考:wordpress防黑教程之预防全版本通杀爆绝对路径漏洞

保护wordpress后台不被直接访问,防止直接post登录wordpress后台。

早在v7v3刚上线的时候小v就写过一篇隐藏wordpress后台的文章《wordpress防黑教程之保护登录文件wp-login.php》此方法只是使用$_GET对wp-login.php做一个访问的障眼法而已。其实仔细分析下wordpress登录页面代码不难发现wordpress是以post的方式来提交登陆参数的,如下图:

wordpress网站终极防黑手册,全方位保护网站安全(一)-wordpress教程-代码笔记 %

也就是说我们可以不用访问wp-login.php文件,而是直接通过post递交参数给wp-login.php来直接登录网站后台,那么之前小V所提到的$_GET对wp-login.php做的访问限制就形同虚设,那么该如何来有效的防止wordpress的登录文件不被直接访问而且不能以常规的post方式来登录网站后台呢?

第一步:我们登录后台进入到常规选项:在WordPress地址(URL)这一栏加上/v7v3如下图:

wordpress网站终极防黑手册,全方位保护网站安全(一)-wordpress教程-代码笔记 %

第二步:我们在网站根目录下新建一个名为v7v3的目录,然后将除了index.php、robots.txt以及.htaccess之外的所有网站文件移至v7v3目录(登录变为v7v3.com/v7v3/wp-login.php)。

第三步:打开index.php并将

require('./wp-blog-header.php');

修改为:

require('./v7v3/wp-blog-header.php');

这样一来wordpress的后台地址以及登录post提交参数的地址都随着wordpress系统文件的移动而改变了,再配合小V写的$_GET访问限制方法就可以达到很好的防黑效果。

(PS:这只是前半篇文章,请大家期待后半篇文章!)《wordpress网站终极防黑手册,全方位保护网站安全(二)

wordpress运维技巧:文章部分内容登陆后可见

在网站运维中为了留住访客通常站长会采取诱导注册方法来留住访客,但是如何来诱导访客注册网站就是一个难题了,其实大家可以在网站发布一些比较优秀而且不常见的资源然后强制访客只有注册才能下载这些资源或者是注册后才能观看到完整的文章,这样一来网站的用户注册数量就会慢慢提高了,那么wordpress如何来隐藏文章的部分内容必须登陆后显示呢?下面小V就来教大家使用简码(短代码、Shortcodes)来隐藏文章的部分内容。

首先打开当前使用的主题的functions.php文件,并加入以下代码:

add_shortcode( 'vip', 'v7v3_vip_shortcode' );
function v7v3_vip_shortcode( $atts, $content = null ) {
         if ( is_user_logged_in() && !is_null( $content ) && !is_feed() )
                return $content;
        return '';
}

然后在后台发布文章时只需要在html模式下用[vip][/vip]包括住需要隐藏的内容即可,示例如下:

[vip]
这是被隐藏的内容
[/vip]

由于小V只是在本地测试时用了此方法v7v3.com并没有使用此功能,所以演示代码并没有隐藏内容。(PS:一定要在html编辑模式下用[vip][/vip]包括住需要隐藏的内容,可视化编辑模式是无效的。)

2013.10.18无法访问缘故,以及友链数据说明

昨天大概19点左右的样子v7v3.com突然无法访问,VPS也ping不通,小V立即联系主机商,客服人员告诉小V服务器节点故障正在维护,说实话小V开始以为这家IDC的服务器非常稳定,但是最近这一个月已经出现两次问题了,不过客服人员态度还算不错。母机恢复后v7v3.com依然是502状态,联系客服,客服说是php-fpm文件丢失,还说小V自己删除的,可是小V自从装好VPS环境后就从来没有动过系统文件,没办法自认倒霉自己维护,早上7点多起来维护,到了大概9:50左右VPS终于恢复了,还好有备份,文章只丢失了两篇算是不幸中的万幸了,友链和其他数据也有所丢失,如过发现贵站友链丢失了请联系小V重新补上。另外小V给大家道歉了,因为机房的不可抗拒因素导致v7v3两次都长达14小时无法访问。