WordPress 4.2
版本之后,查看网页源代码你会发现WordPress
会自动在加载一段用于支持emjo
表情的脚本(JS+CSS
)。对于大部分人来说,这个是十分鸡肋的功能,反而影响加载速度,仔细观察一下就会发现,这部分功能引入了非常多的脚本以及代码,实际上绝大部分人从来不使用这部分功能,另外这部分加载脚本在Internet Explorer 11
+ HTTPS
的时候,会出现警告访问不安全的内容,原因就在于emjo
加载脚本在HTTPS
的情况下依旧会使用HTTP
去请求数据。
分类: WordPress
使用PHP语言开发的博客平台,支持在PHP和MySQL的服务器上架设自己的博客
WordPress 4.7.5改善Twenty Fifteen主题在Internet Explorer 11上的兼容显示问题
WordPress 4.7.5
使用Twenty Fifteen
主题的时候,在Internet Explorer 11
上存在兼容问题,页面的左边的侧边栏经常会不绘制,出现空白,这个问题是由于Internet Explorer 11
使用的Trident
引擎导致的,我们可以通过强制Internet Explorer 11
使用Internet Explorer 9
引擎来改善问题,注意: 是改善,暂时还没办法彻底解决。
继续阅读WordPress 4.7.5改善Twenty Fifteen主题在Internet Explorer 11上的兼容显示问题
Ubuntu 14.04服务器利用Apache 2.4的.htaccess文件阻止对wp-config.php.bak的访问
最近在分析请求链接的时候发现有对wp-config.php.bak
的下载请求,被吓了一跳。在WordPress
的某些升级操作中,会特意备份wp-config.php
方便出现问题后的回退。如果有人恶意下载这个文件,会导致数据库密码以及配置信息的泄漏,后果影响很大。
对于使用Apache 2.4
的服务器来说,比较简单,只要在.htaccess
中,使用如下配置即可:
1 2 3 4 5 6 |
#reject all .bak,.old file download because wordpress upgrade may rename #wp-config.php to wp-config.php.bak <FilesMatch (.*)\.(bak|old)> Order allow,deny deny from all </FilesMatch> |
如何正确隐藏WordPress的版本号?
默认情况下,当你使用WordPress
来搭建网站的时候,WordPress
会在你的网站上留下个标记:这就是WordPress
的版本号。在某些时候,这个标记也会成为网站的安全漏洞。
打开你的WordPress
网站,在浏览中的空白地方点击右键,选择查看源代码,通常你会找到有这样一行代码:
1 |
<meta name="generator" content="WordPress 4.4.1" /> |
这是WordPress
自动生成的代码,向外界宣告你所使用的WordPress
版本。如果你的网站一直使用的是最新版WordPress
,那你基本无需担心因为泄露版本号而导致的安全问题。但是,由于某些特殊的原因,如果你使用的是旧版本的软件,那么暴露WordPress
版本号可能会成为你网站的安全漏洞。
因此,在这种情况下,你应该隐藏网站所使用的WordPress
版本号。
在你的网站中,有四个地方容易暴露WordPress
的版本号:
- 网站源码页头部分的
meta
标签里: - 脚本和样式表文件中:
- 网站
RSS feeds
中: - 网站根目录下的
readme.html
文件中。
网络中各种隐藏WordPress
版本号的技巧很多,功能最为完整且简洁的代码,应当是属于下面这段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php /* 在 js 文件和 css 文件中隐藏 WordPress 版本号 * @return {string} $src * @filter script_loader_src * @filter style_loader_src */ function wpchina_remove_wp_version_strings( $src ) { global $wp_version; parse_str(parse_url($src, PHP_URL_QUERY), $query); if ( !empty($query['ver']) && $query['ver'] === $wp_version ) { $src = remove_query_arg('ver', $src); } return $src; } add_filter( 'script_loader_src', 'wpchina_remove_wp_version_strings' ); add_filter( 'style_loader_src', 'wpchina_remove_wp_version_strings' ); /* 在 generator meta 标签中隐藏 WordPress版本号 */ function wpchina_remove_version() { return ''; } add_filter('the_generator', 'wpchina_remove_version'); ?> |
这段代码可以移除前面3个地方中所包含的WP
版本号。记得要把这段代码放在你所用主题(或子主题)的funcitons.php
模板文件中。
修改完成后,如果是使用PHP-FPM
来进行处理的服务器,需要重启PHP-FPM
服务否则代码可能不能及时生效:
1 |
$ sudo service php5-fpm restart |
对于上面第4点提到的,位于WordPress
根目录下的readme.html
文件,你直接删除该文件就可以了。这份文件是关于WordPress
的简单介绍和安装说明,安装好账户就没有什么用途了。
如果使用的是Apache
服务器,也可以简单的在根目录下面建立.htaccess
文件,里面增加如下内容:
1 2 3 4 5 |
# 禁止 readme.html 的访问,这个文件会暴露版本号信息 <Files readme.html> order deny,allow deny from all </Files> |
当然,以上这些做法,隐藏了WordPress
的版本号,并不能真正解决网站中所存在的安全漏洞。确保网站安全的第一要素,还是要及时更新WordPress
核心软件,所使用的主题、插件;使用健壮的用户名和密码;不要使用来历不明的盗版主题和插件等。
引用链接
WordPress首页显示摘要(手工设置)
用WordPress
比较长的时间了,一直是在首页显示文章全文的,但是最近由于摘抄的某些文章中的图片非常多,导致每次加载首页会下载非常多的图片资源,整个页面加载速度都被拖慢了,于是想只在首页显示摘要,而不是全文显示。
网上搜索了一下,发现WordPress
早就有这个功能了,如下图:
如果想手工编辑Html
的话,只要简单的加入
1 |
<!--more--> |
标签就可以达到相同的效果了。
WordPress 4.7.x版本禁用 REST API
最近WordPress
频繁爆出漏洞,尤其是REST API
部分,简直是漏洞百出,但是,从4.7.0版本开始,这部分功能被深度整合进入了核心模块,没办法彻底屏蔽REST API
,只有通过rest_authentication_errors
这个接口来限制非登陆用户,具体代码如下
1 2 3 4 5 6 7 8 |
<?php add_filter('rest_authentication_errors','disable_rest_api'); function disable_rest_api(){ if(!is_user_logged_in()){ return new WP_Error('Error!', __('Unauthorized access is denied!','rest-api-error'), array('status' => rest_authorization_required_code())); } } ?> |
此部分的代码需要被添加到当前主题的functions.php
中的最后即可。
增加完成后,重启Apache2
服务器,然后再访问https://www.mobibrw.com/wp-json/ 就可以看到错误信息了。
参考链接
解决从WordPress 4.7.1升级到WordPress 4.7.2失败后再次更新提示"另一更新正在进行"
从WordPress 4.7.1升级到WordPress 4.7.2,中途失败了,结果再次更新的时候,提示“另一更新正在进行”,如下图所示:
这是由于在升级WordPress
时,WordPress
会在数据库wp_options
表中增加core_updater.lock
记录。如中途打断WordPress
升级,这个记录会留在数据库中。当下次升级时,WordPress
检测到此记录的存在就会返回”另一更新正在进行”。可通过终端登录数据库删除这条记录来处理.
1 2 3 4 5 6 7 8 9 |
$ mysql -u root -p $ mysql> use wordpress; $ mysql> select * from wp_options where option_name='core_updater.lock'; $ mysql> delete from wp_options where option_name='core_updater.lock'; $ mysql> exit; |
如上操作之后,再次重新升级,就可以解决问题了。
参考链接
从零创建WordPress自定义插件
序曲
使用WordPress
统计插件WP Statistics
之后,经常会出现某个IP的访问突然出现比较多的情况,那么这个时候就需要了解这个IP访问的是哪个页面,是否发生了访问攻击。但是遗憾的是,WP Statistics
并没有根据IP地址查询访问记录的功能,因此,我们就自己写一个查询插件好了。
创建插件的文件和文件夹
WordPress
插件存储在wp-content/plugins/
文件夹中,而我们的新建文件也要存放在这个文件夹中。一般情况下,如果所制作的插件非常简单,可直接把所有代码放在一个PHP
文件中,然后把其放在wp-content/plugins/
文件夹中。但是,我们这里要制作的插件要使用两个文件(一个是主要的插件文件,另一个为执行管理页面的文件),因此,我们需要把新创建的文件另放在一个文件夹中,我们这里把这个文件夹命名为wp-statistics-visitor-query
。
创建插件的功能文件
我们就要创建插件主要文件了,我们把其命名为wp-statistics-visitor-query.php
。当然,你也可把其命名为其它名称,这并不重要。
然后再文件的头部增加插件的描述信息,如果不增加描述信息,WordPress
是找不到这个插件的。增加的内容如下:
1 2 3 4 5 6 7 8 9 10 |
<?php /* Plugin Name: WP Statistics Visitors Query Plugin URI: http://www.mobibrw.com Description: Plugin for query WP Statistics Visitors Author: LongSky Version: 1.0 Author URI: http://www.mobibrw.com */ ?> |
这样操作完成后,就可以在插件管理界面中找到名字为"WP Statistics Visitors Query
"的插件了。
使用行为钩子(Action Hook)
虽然插件现在已在管理面板显示,但是由于它只含有header
信息,因此它并没有其它功用。现在,我们就来增加它的功能吧。
WordPress
允许用户把插件代码放在模板的任意位置,包括页面的空间位置及页面创建过程中的逻辑位置。在此,我们将进一步了解后者,逻辑位置——即行为钩子。
行为钩子
我们可把行为钩子视为回调函数。WordPress
执行某项操作时,如,显示页脚,它就会让插件来执行自己的代码并且要在确切的时间运行。
为了方便大家理解,我们以my_plugin
这个普通插件为例,当系统显示页脚时,这个插件就会执行mp_footer()
函数。因此,显示页脚时,使用名为add_action()
这个特殊的函数,我们就会告知WordPress
调用mp_footer()
函数:
add_action()
函数把行为钩子名称作为其第一个参数,同时把必须执行的函数名称作为其第二个参数。我们将把此函数调用添加到插件的主要文件(即包括header
信息的文件),通常把它放在需要执行的函数代码正下方(本例中即放在mp_footer()
下)。可在WordPress Codex
查看所有可用的行为钩子 。
创建插件管理页面
我们要先创建新菜单条目并把其放置在设置菜单中。
WordPress
提供了新建菜单可调用的钩子(即admin_menu
),因此,这也是我们创建菜单条目的最佳地点。
既然已确认需使用的行为钩子,我们接着就要定义行为钩子运行时要调用的函数了,我们把其称为visitors_query_admin_actions()
。代码显示如下:
1 2 3 4 5 |
<?php function visitors_query_admin_actions() { } add_action('admin_menu', 'visitors_query_admin_actions'); ?> |
正如您所看到的,我们已创建了visitors_query_admin_actions()
函数,并用add_action()
函数让其与admin_menu
行为钩子结合。接下来,我们就要给visitors_query_admin_actions()
函数添加一些代码以创建真正的菜单条目了。
和WordPress
其它许多操作类似,添加新菜单条目也非常简单,只需调用一个函数就可完成!把新菜单条目添加到设置菜单需要使用add_options_page()
函数,然后把以下代码添加到visitors_query_admin_actions()
函数中。
1 2 3 4 5 6 7 8 9 |
<?php function ip_admin() { } function visitors_query_admin_actions() { add_options_page("Query Visitor From IP", "Query Visitor From IP", 1, "Query Visitor From IP", "ip_admin"); } add_action('admin_menu', 'visitors_query_admin_actions'); ?> |
此时刷新管理页面,设置页面下就已包括新建菜单条目了。
WordPress
中的每个菜单都使用不同的函数来添加其子菜单条目。例如,如果要给工具添加子菜单条目,我们就应该使用add_management_page()
函数,而非设置页面使用的add_options_page()
。更多信息,请查看WordPress Codex
中的添加管理菜单。
重新回到新添加的代码,或许您已注意到了最后一个参数。它即是请求新增菜单条目时,系统将调用的函数,我们也将使用它来创建插件的管理页面。
我们最好把此页面功能放在单独的文件中,并给其命名为query_visitor_import_admin.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<?php function ip_admin() { include('query_visitor_import_admin.php'); } // 只有管理员才能使用这个功能,基本安全防护 function is_administrator() { if( current_user_can( 'manage_options' ) ) { return True; } return False; // 非管理员 } function visitors_query_admin_actions() { if(is_administrator()) { add_options_page("Query Visitor From IP", "Query Visitor From IP", 1, "Query Visitor From IP", "ip_admin"); } } add_action('admin_menu', 'visitors_query_admin_actions'); ?> |
此时点击设置菜单下的链接,系统将显示空白页面,这是因为query_visitor_import_admin.php
文件现在没有任何内容。
接下来我们配置页面中的内容,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
<?php function ip_query($ipaddress) { $q = "select referred from wp_statistics_visitor where ip='$ipaddress';"; global $wpdb; $rows = $wpdb->get_results($q,ARRAY_N); $i=0; while ($i< count($rows)){ $row = $rows[$i]; /*echo var_dump($row[0]);*/ echo "<br/>"; echo $row[0]; $i++; } } ?> <div class="wrap"> <form name="visitors_query_form" method="post" action="<?php echo str_replace( '%7E', '~', $_SERVER['REQUEST_URI']); ?>"> <p><?php _e("IP Address: " ); ?><input type="text" name="visitors_ip" value="" size="20"><?php _e(" ex: 192.168.1.1" ); ?></p> <hr /> <p class="submit"> <input type="submit" name="Submit" value="Query" /> </p> </form> <hr /> <p> <?php $ipaddress = $_POST['visitors_ip']; _e("Query $ipaddress :"); ?> </p> <hr /> <div> <?php $ipaddress = $_POST['visitors_ip']; if(is_administrator()) { ip_query($ipaddress); } else { echo "only administrator can use this function"; } ?> </div> </div> |
如此调整之后,需要禁用一下插件,然后再启用,否则可能不会生效。
代码详解
熟悉HTML和PHP的人都会理解以上代码,但我们这里仍将简单解释一下。
- 我们首先用
wrap
类创建一个div
,它是一个标准的WordPress
类,使新建页面能够和WordPress
管理版块的其它页面风格一致。 - 表单将使用
POST
方法回发数据。这意味着表单数据将由同一页面接收,这样以来,我们就可添加数据库更新代码到同一文件。 - 查询数据库的时候使用
WordPress
自带的全局数据库对象$wpdb
来访问数据库。 - 为了安全,我们只允许管理员权限的人员调用我们的插件功能。
参考链接
Ubuntu 14.04系统WordPress 4.5升级到PHP7之后执行插件升级报错“无法定位WordPress内容目录(wp-content)”
Ubuntu 14.04
系统上WordPress 4.5
升级到PHP7
之后执行插件升级报错,
1 |
无法定位WordPress内容目录(wp-content) |
如下图所示:
这个是由于PHP
升级之后,有些函数的支持出现了变化,导致调用失败。
目前已知的修复方法是修改wp-admin/includes/class-wp-filesystem-ssh2.php
中的如下的几个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
/** * @access public * * @param string $file * @return bool */ public function exists($file) { return file_exists( $this->sftp_path( $file ) ); } /** * @access public * * @param string $file * @return bool */ public function is_file($file) { return is_file( $this->sftp_path( $file ) ); } /** * @access public * * @param string $path * @return bool */ public function is_dir($path) { return is_dir( $this->sftp_path( $path ) ); } /** * @access public * * @param string $file * @return bool */ public function is_readable($file) { return is_readable( $this->sftp_path( $file ) ); } /** * @access public * * @param string $file * @return int */ public function atime($file) { return fileatime( $this->sftp_path( $file ) ); } /** * @access public * * @param string $file * @return int */ public function mtime($file) { return filemtime( $this->sftp_path( $file ) ); } /** * @access public * * @param string $file * @return int */ public function size($file) { return filesize( $this->sftp_path( $file ) ); } |
修改为:
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 |
/** * @access public * * @param string $file * @return bool */ public function exists($file) { //return file_exists( $this->sftp_path( $file ) ); if(version_compare(PHP_VERSION,'7.0.0','ge')){ $stat = @ssh2_sftp_stat( $this->sftp_link, $file ); if ( false === $stat ) { return false; } return (true); }else{ return file_exists( $this->sftp_path( $file ) ); } } /** * @access public * * @param string $file * @return bool */ public function is_file($file) { //return is_file( $this->sftp_path( $file ) ); if(version_compare(PHP_VERSION,'7.0.0','ge')){ $stat = @ssh2_sftp_stat( $this->sftp_link, $file ); if( false === $stat ){ return false; } $mode = $stat['mode']; $type = $mode & 0xf000; return ($type == 0x8000); }else{ return is_file( $this->sftp_path( $file ) ); } } /** * @access public * * @param string $path * @return bool */ public function is_dir($path) { //return is_dir( $this->sftp_path( $path ) ); if(version_compare(PHP_VERSION,'7.0.0','ge')){ $stat = @ssh2_sftp_stat( $this->sftp_link, $path ); if ( false === $stat ) { return false; } $mode = $stat['mode']; $type = $mode & 0xf000; return ($type == 0x4000); }else{ return is_dir( $this->sftp_path( $path ) ); } } /** * @access public * * @param string $file * @return bool */ public function is_readable($file) { //return is_readable( $this->sftp_path( $file ) ); if(version_compare(PHP_VERSION,'7.0.0','ge')){ $stat = @ssh2_sftp_stat( $this->sftp_link, $file ); if ( false === $stat ) { return false; } $mode = $stat['mode']; return ($mode & 0x0004); }else{ return is_readable( $this->sftp_path( $file ) ); } } /** * @access public * * @param string $file * @return int */ public function atime($file) { //return fileatime( $this->sftp_path( $file ) ); if(version_compare(PHP_VERSION,'7.0.0','ge')){ $stat = @ssh2_sftp_stat( $this->sftp_link, $file ); if ( false === $stat ) { return false; } return $stat['atime']; }else{ return fileatime( $this->sftp_path( $file ) ); } } /** * @access public * * @param string $file * @return int */ public function mtime($file) { //return filemtime( $this->sftp_path( $file ) ); if(version_compare(PHP_VERSION,'7.0.0','ge')){ $stat = @ssh2_sftp_stat( $this->sftp_link, $file ); if ( false === $stat ) { return false; } return $stat['mtime']; }else{ return filemtime( $this->sftp_path( $file ) ); } } /** * @access public * * @param string $file * @return int */ public function size($file) { //return filesize( $this->sftp_path( $file ) ); if(version_compare(PHP_VERSION,'7.0.0','ge')){ $stat = @ssh2_sftp_stat( $this->sftp_link, $file ); if ( false === $stat ) { return false; } return $stat['size']; }else{ return filesize( $this->sftp_path( $file ) ); } } |
参考链接
WORDPRESS 4.5 后台/登录页面强制HTTPS
这段时间貌似服务器经常被人攻击,由于服务器已经支持HTTPS登陆,而全站SSL加密又不是那么迫切,遂考虑后台SSL加密,强制HTTPS。
设置方法如下:
修改wp-config.php
在
1 |
require_once(ABSPATH . 'wp-settings.php'); |
之前(貌似放在后面也可以),加
1 |
define('FORCE_SSL_ADMIN', true); |
就能使得后台强制加密了;
而加入一行
1 |
define('FORCE_SSL_LOGIN', true); |
就可以使登录页面强制加密了。