Skip to content

Instantly share code, notes, and snippets.

@tenman
Created August 29, 2013 02:37
Show Gist options
  • Save tenman/6373691 to your computer and use it in GitHub Desktop.
Save tenman/6373691 to your computer and use it in GitHub Desktop.
このファイルは、個別のテーマやプラグインファイルの簡単な検査と、それぞれのファイルで使用されているMD5_FILEの値を計算し配列として表示します。 表示された配列を、テーマやプラグインディレクトリに、check-same.phpという名前で表示すると、次回から現在のMD5_FILEと記録されたMD5_FILEと比較して、ファイルに変更があったかどうかを表示する事が出来ます。
<?php
/*
File Name: detect-bom.php
Description: WordPressのインストールディレクトリに配置する事で、テーマ、プラグインの簡易的な検査と、それぞれのテーマやテンプレートファイルで使われているファイルのMD5_FILEを、表示します。テーマやプラグインのルートディレクトリにcheck-same.phpとして表示された配列をphpとしてペーストしておくと、次回の検査で、check-same.php配置後に変更されたテーマやテンプレートの同一性をチェックする事ができます。
Author: Tenman
Author URI: http://www.tenman.info/
Version: 0.1
License: GNU General Public License v2.0
License URI: http://www.gnu.org/licenses/gpl-2.0.html
*/
//注意:このファイルは、WordPressにログインしないと表示できないようになっていますが、
//クッキー偽装されると、開くので、常にWEBサーバに置いておくのは、厳禁です
//WordPressにログインしているかどうか、簡易チェック。
check_auth();
//設定
//プラグインを調べたい時は、pluginsに、テーマの場合は、themesに変更してください
define( 'SCANED_DIR','themes' );
date_default_timezone_set('Asia/Tokyo');
//md5は、テーマ直下に check-same.phpを作成し、ペースト (<?php で囲んでください)
?>
<!DOCTYPE html>
<head>
<meta charset=utf-8>
<title><?php title();?></title>
<!--[if IE]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link rel="stylesheet" href="http://html5resetcss.googlecode.com/files/html5-reset-1.4.css" media="all">
<!--Include YUI Loader: -->
<script type="text/javascript" src="http://yui.yahooapis.com/2.8.0r4/build/yuiloader/yuiloader-min.js"></script>
<!--Use YUI Loader to bring in your other dependencies: -->
<script type="text/javascript">
// Instantiate and configure YUI Loader:
(function() {
var loader = new YAHOO.util.YUILoader({
base: "",
require: ["base","fonts","grids","reset"],
loadOptional: false,
combine: true,
filter: "MIN",
allowRollup: true,
onSuccess: function() {
}
});
loader.insert();
})();
</script>
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">google.load("jquery", "1.7");</script>
<script type="text/javascript">
jQuery(function() {
jQuery('*[class^="toggle"]').hide().css("width","100%");
jQuery('*[id^="toggle"]').css("cursor","pointer").click(function(){
var target ="."+jQuery(this).attr("id");
jQuery(target).toggle("slow");
});
});
</script>
<style type="text/css">
i{content:"\"/*"}
/* inline high pass filter
see http://tantek.com/CSS/Examples/inlinehpf.html
quote{
As a result of the inline high pass filter,
the rules after the filter will only be seen by the following:
* IE5/Mac or later
* IE6/Windows or later
* Netscape 6 or later
* Opera 5 or later
* or any other browser which can pass Section 7.1 of the CSS1 Test Suite.
}
*/
/*-----------------------------------------------------
Yahoo UI Library Font-size Adjustment
Copyright (c) 2006, Yahoo! Inc. All rights reserved.
http://developer.yahoo.com/yui/license.txt
http://developer.yahoo.com/yui/fonts/
10px = 77% 11px = 85% 12px = 93% 13px = 100%
14px = 108% 15px = 116% 16px = 123.1% 17px = 131%
18px = 138.5% 19px = 146.5% 20px = 153.9% 21px = 161.6%
22px = 167% 23px = 174% 24px = 182% 25px = 189%
26px = 197%
------------------------------------------------------*/
h1,h2,h3{font-family:times, Times New Roman, times-roman, georgia, serif;font-weight:bold;margin:1em 0 .5em 0;text-align:left;}h1{font-size:153.9%;}h2{font-size:138.5%;}h3{font-size:123.1%;}html{padding:0;} body{margin:0!important;background:#fff;}h1 {text-indent:1em;}header {padding:10px 0;}article,aside, dialog, figure, footer, header, hgroup, menu, nav, section {display:block;}html>body nav li a {width:auto;}nav {font-family:'Trebuchet MS','Lucida Grande',Verdana,Lucida,Geneva,Helvetica,Arial,sans-serif;margin-bottom:1em;padding:0 0 1em;width:12em;} nav ul li{ } nav li a {display:block;padding:5px 5px 5px .5em;text-decoration:none;width:100%;}nav ul {list-style:none;margin:0;padding:0;}span.location {color:green;}table {width:100%;}td {border:none;}td a {text-decoration:none;}.bar {padding:1em;height:3em; background: -moz-linear-gradient(top,rgba(0,0,200,1), rgba(0,0,51,1)); background: -webkit-gradient(linear, left top, left bottom, from(rgba(0,0,200,1)),to(rgba(0,0,51,1))); border-top:1px solid #fff; border-bottom:1px solid #fff; -moz-box-shadow: 0 3px 5px #999; -webkit-box-shadow: 0 3px 5px #999; color:#fff; background:rgb(0,0,51)\9; /*for IE hack*/ }.bar a{color:orange;}.vevent {border:1px solid #ccc;margin:1em;padding:1em; border-radius:1em 0px 1em 0px; -moz-border-radius: 1em 0px 1em 0px; -khtml-border-radius: 1em 0px 1em 0px; -webkit-border-radius: 1em 0px 1em 0px; background:rgba(200,200,255,0.3);}.vevent:before {content:"Schedule";display:block;font-weight:700;margin-bottom:1em;text-decoration:underline;}p.description{font-size:small;text-align:right;}h3 ~ p{ /*general sibling combinator*/background:#000;border:1px solid #ccc;color:#eee;padding:1em;} h3 + p{ /*Adjacent sibling combinator*/background:#efe;color:#333;border:1px solid #ccc;padding:1em;}nav ul > li{list-style-type:none;}nav li > ul li {border-bottom:1px solid #ccc;margin:0;}figure{ border:1px solid #ccc;padding:3px;text-align:center;vertical-align:top;display:inline-block; border-radius:3px; -moz-border-radius:3px; -khtml-border-radius:3px; -webkit-border-radius:3px; background:rgba(200,200,200,0.1); max-widht:100%;}figure img{display:block; /*for IE*/max-width:100%;}img{max-width:100%;height:auto;}.extra{ color:#333;}
</style>
<style type="text/css">
.selectbox{display:inline-block;}
.form,
.result-body{margin:10px 50px;}
.result-body{min-height:400px;}
.php-info table{max-width:80%;margin:0 10%;}
</style>
</head>
<body>
<header class="bar">
<h1><?php title();?></h1>
<p style="font-size:100%;">BOM チェックと テーマで使われているちょっと怪しいPHP関数をチェックします</p>
</header>
<div id="doc3" class="yui-t4">
<div id="yui-main">
<div class="yui-b" >
<article>
<div class="form">
<?php
/**
* form 表示
*
*
*
*/
echo themes_selector();
?>
</div>
<div class="result-body">
<?php if(isset($_POST) ){
/**
* POST を処理
*
*
*
*/
$result = '';
if(isset( $_POST['theme_name'] ) and !empty( $_POST['theme_name'] ) ){
$theme_dir_name = htmlspecialchars( $_POST['theme_name'] );
}else{
$theme_dir_name = 'twentyeleven';
}
$files = search_files( $theme_dir_name );
foreach( $files as $key=>$filename ){
$result .= list_loops($filename);
}
echo "<p>{$theme_dir_name}の{$key}件のファイルをチェックしました。それぞれの項目をクリックすると表示します</p>";
echo '<h2 id="toggle-result">結果</h2>';
echo '<div class="toggle-result">';
if( ! empty($result) ){
echo $result;
}else{
echo '<p>BOM付のファイルはありません。ファイル操作系のPHP関数も、このチェックでは、見つけられませんでした</p>';
}
?>
</div>
<h2 id="toggle-md5-list">MD5</h2>
<div class="toggle-md5-list">
<?php
$result = '';
foreach( $files as $key=>$filename ){
$result .= list_md5($filename);
}
printf('$raindrops_template_md5 = array(%1$s)', $result );
?>
</div>
<h2 id="toggle-modify-list">Modify check</h2>
<div class="toggle-modify-list">
<ul><?php
clearstatcache();
echo check_modify();
?>
</ul>
</div>
<h2 id="toggle-file-list">チェックしたファイル 一覧</h2>
<div class="toggle-file-list">
<pre>
<?php
var_export($files);
?>
</pre>
</div>
<h2 id="toggle-function-list">チェック済み非推奨関数一覧</h2>
<div class="toggle-function-list">
<?php $deprecated_functions = get_deprecated_functions();?>
<ol>
<?php
foreach($deprecated_functions as $deprecated){
echo '<li>'.$deprecated. '</li>';
}
?>
</ol>
</div>
<h2 id="toggle-phpinfo">PHP info</h2>
<div class="toggle-phpinfo">
<ol class="php-info">
<?php phpinfo();?>
</ol>
</div>
<?php
if( file_exists( 'wp-content'.DIRECTORY_SEPARATOR.'debug.log') and debug_check() == 'true' ){
?>
<h2 id="toggle-last-error">Last error</h2>
<div class="toggle-last-error">
<?php echo read_log();?>
<?php }//file_exists( 'wp-content... ?>
</div>
</div>
<?php }//isset($_POST)?>
</article>
</div>
</div>
<nav class="yui-b" id="toc"></nav>
<br style="clear:both;" />
</div>
<footer class="bar">
<address>
http://d.hatena.ne.jp/tenman/
</address>
</footer>
</body>
</html>
<?php
/**
*
*
*
*
*/
function debug_check(){
$configs = file('wp-config.php' );
foreach( $configs as $config ){
if( strpos( $config, 'WP_DEBUG' ) === false){
}else{
preg_match('!(true|false)!',$config,$regs);
return (bool) $regs[1];
}
}
return 'none';
}
/**
*
*
*
*
*/
function read_log( ){
$logs = file( 'wp-content'.DIRECTORY_SEPARATOR.'debug.log', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
echo '<p><strong>debug.log last message</strong></p>';
echo array_pop($logs);
echo '<p><strong>PHP error_get_last() message</strong></p>';
$error = error_get_last();
echo '<p>エラータイプ:'. $error['type'].'<br />';
echo 'エラーメッセージ:'.$error['message'].'<br />';
echo 'ファイル:'.$error['file'].'<br />';
echo '行:'.$error['line'].'</p>';
}
/**
*
*
*
*
*/
function search_files($theme_dir_name, $includes = false ){
define ('UTF8_BOM', chr(0xEF) . chr(0xBB) . chr(0xBF));
$files = array();
//wp-includesのファイルを検索
if( $includes == true ){
$dir_name = 'wp-includes';
if( file_exists( $dir_name ) ){
$child = scandir( $dir_name );
$files = get_file_list($dir_name);
}else{
echo "<p>{$dir_name}<br />ありません</p>";
}
}
//テーマ直下のファイルを検索
$theme_path = 'wp-content'. DIRECTORY_SEPARATOR.SCANED_DIR. DIRECTORY_SEPARATOR. $theme_dir_name;
if( file_exists($theme_path) ){
$theme_dir_child = scandir( $theme_path );
$theme_files = get_file_list($theme_path);
$files = array_merge($files, $theme_files);
}else{
echo '<p>wp-content'. DIRECTORY_SEPARATOR.SCANED_DIR. DIRECTORY_SEPARATOR. $theme_dir_name.'<br />ありません</p>';
}
//チェックするファイルに、wp-config.phpを追加
$files[] ='wp-config.php';
$files[] ='.htaccess';
return $files;
}
/**
*
*
*
*
*/
//bomのチェックと、テーマファイル終端のphp閉じタグの後ろの改行を検査
function detect_utf_encoding($filename) {
global $theme_dir_name;
$result = '';
$path_parts = pathinfo( $filename );
$text = file_get_contents($filename);
if(isset( $path_parts['extension'] ) and ($path_parts['extension'] == 'php' or $path_parts['extension'] == 'html') ){
$encode = mb_detect_encoding($text, "auto");
$first2 = substr($text, 0, 2);
$first3 = substr($text, 0, 3);
$first4 = substr($text, 0, 3);
if ($first3 == UTF8_BOM){
$result .= '<p>'.$filename.'のエンコード '. $encode.' BOM( Byte Order Markを検出しました。修正が必要です。)</p>';
}elseif( $encode == 'UTF-8' or $encode == 'ASCII' ) {
//return '<p>'.basename($filename). '正常</p>';
}else{
$result .= '<p>'.$filename.'のエンコードがUTF-8ではありません '. $encode. '修正が必要です。</p>';
}
$regex = '!(\?>\n+$)!siu';
if( preg_match( $regex,$text) and preg_match("!$theme_dir_name!", $filename) ){
$result .= '<p>'.$filename.'<br />ファイル末尾の?>の後ろに改行あり</p>';
}
$regex = '!\sheader\(!';
if( preg_match( $regex,$text) and preg_match("!$theme_dir_name!", $filename) ){
$result .= '<p>'.$filename.'<br />header()関数を、使っています</p>';
}
/**
*
*
*
*
*/
$regex = '!(@?include\s*\([^\)]*\)|@?requre\s*\([^\)]*\)|[^(//.*?|/\*.*?)]file_get_contents\s*\([^\)]*\)|[^(//.*?|/\*.*?)]file_put_contents\s*\([^\)]*\)[^\)]*\)|base64_[^\(]+\([^\)]*\)|[^(//.*?|/\*.*?)]eval\s*\([^\)]*\)|wp_set_auth_cookie\s*\(|convert_uuencode\s*\([^\)]*\)|`user_pass`|`wp_users`|str_rot13\s*\([^\)]*\)|strrev\s*\(|<iframe[^>]+>|_(_|e)\([^(\,|\)]+\) )!';
if( preg_match( $regex,$text,$matches) and preg_match("!$theme_dir_name!", $filename) and ! preg_match("!functions.php!", $filename)){
$result .= '<p>'.$filename."<br />".htmlspecialchars($matches[0])."<br />テンプレートでは、通常使いません</p>";
}
/**
*
*
*
*
*/
$regex = '!([^(//.*?|/\*.*?)]file_get_contents\s*\([^\)]*\)|[^(//.*?|/\*.*?)]file_put_contents\s*\([^\)]*\)|@?copy\s*\([^\)]*\)|@?fgets\s*\([^\)]*\)|@?file\s*\([^\)]*\)|@?fopen\s*\([^\)]*\)|@?fputcsv\s*\([^\)]*\)|@?fwrite\s*\([^\)]*\)|@?mkdir\s*\([^\)]*\)|@?popen\s*\([^\)]*\)|@?tmpfile\s*\([^\)]*\)|base64_[^\(]+\([^\)]*\)|[^(//.*?|/\*.*?)]eval\s*\([^\)]*\)|wp_set_auth_cookie\s*\(|convert_uuencode\s*\(|`user_pass`|`wp_users`|str_rot13\s*\(|strrev\s*\(|<iframe[^>]+>|_(_|e)\([^(\,|\)]+\) )!';
if( preg_match( $regex,$text,$matches) and preg_match("!$theme_dir_name!", $filename) and preg_match('!functions\.php!', $filename)){
$result .= '<p>'.$filename."<br />".htmlspecialchars($matches[0])."<br />テンプレートでは、通常使いません</p>";
}
/**
*
*
*
*
*/
$functions = get_deprecated_functions();
foreach($functions as $name){
$function[] = '[^\_]'.trim($name).'\s*\([^\)]*\)|';
}
$functionlist = implode('', $function);
//追加
$functionlist = $functionlist.'get_template_part\s*\((.*)?/|bloginfo\s*\((.*)?(home|siteurl)[^)]+\)';
$functionlist = trim($functionlist,'|');
$regex = "!({$functionlist})!";
$regex = str_replace('($more_link_text=\'','',$regex);//引数内のカッコをとりきれないため置換 the_content_rss
if( preg_match( $regex,$text,$matches) and preg_match("!$theme_dir_name!", $filename) ){
$result .= '<p>'.$filename."<br />".htmlspecialchars($matches[0])."<br />非推奨関数が使われています。調べてください(代表的なものだけしかテストしていません。また、旧バージョンとの互換性のために、記述されている事もあります。)</p>";
}
}
/**
*
*
*
*
*/
$regex = '!(<\?php|header\s*\([^)]+\) )!';
if( preg_match( $regex,$text,$matches) and preg_match("!(\.jpe?g|\.gif|\.png|\.tif)!", $filename) ){
$result .= '<p>'.$filename."<br />{$matches[0]}<br />画像ファイルの中にスクリプトが含まれている可能性があります</p>";
}
/**
*
*
*
*
*/
$regex = '!(\n{20,})!';
if( preg_match( $regex,$text,$matches) ){
$result .= '<p>'.$filename."<br />{$matches[0]}<br />異常に長い空行が見つかりました。チェックが必要です。</p>";
}
return $result;
}
/**
*
*
*
*
*/
function get_file_list ( $path ){
// ディレクトリでなければ false を返す
if (!is_dir($path)) {
return false;
}
// 戻り値用の配列
$dir = array();
$file = scandir($path);
foreach($file as $key){
if ('.' == $key || '..' == $key) {
// 自分自身と上位階層のディレクトリを除外
continue;
}
$result = $path.'/'.$key;
if (is_dir($result)) {
// ディレクトリならば自分自身を呼び出し
get_file_list($result);
array_push($dir, get_file_list($result));
} elseif (is_file($result)) {
// ファイルならばパスを格納
array_push($dir, $result);
}
}
return $dir;
}
/**
*
*
*
*
*/
function list_loops($path){
$result = '';
if( ! is_array( $path ) ){
return detect_utf_encoding( $path );
}else{
foreach($path as $file){
$result .= list_loops($file);
}
return $result;
}
}
function list_md5($path){
$result = '';
if( ! is_array( $path ) ){
if( basename($path) !== 'wp-config.php' and basename($path) !== '.htaccess' ){
return detect_md5( $path );
}
}else{
foreach($path as $file){
$result .= list_md5($file);
}
return $result;
}
}
/**
*
*
*
*
*/
function themes_selector(){
if(defined('SCANED_DIR') and SCANED_DIR == 'themes' ){
if(isset( $_POST['theme_name'] ) and !empty( $_POST['theme_name'] ) ){
$theme_dir_name = htmlspecialchars( $_POST['theme_name'] );
}else{
$theme_dir_name = 'twentyeleven';
}
$legend = 'テーマの選択';
}elseif(defined('SCANED_DIR') and SCANED_DIR == 'plugins' ){
if(! isset( $_POST['theme_name'] ) and !empty( $_POST['theme_name'] ) ){
$theme_dir_name = htmlspecialchars( $_POST['theme_name'] );
}else{
$theme_dir_name = 'akismet';
}
$legend = 'プラグインの選択';
}
$theme_path = 'wp-content'. DIRECTORY_SEPARATOR.SCANED_DIR. DIRECTORY_SEPARATOR;
$form_html = '<form method="%1$s" action="%2$s"><fieldset name="%3$s"><legend>%4$s</legend>
<div class="%5$s">%6$s</div><div class="%5$s %7$s"><input type="submit" value="%8$s"></p></fieldset></form>';
$option_html = '<option value="%1$s" %2$s>%1$s</option>';
if( file_exists($theme_path) ){
$theme_dir_child = scandir( $theme_path );
$option = '';
foreach( $theme_dir_child as $dir ){
if( ! preg_match( '!\.{1,2}!', $dir ) ){
$dir = htmlspecialchars( $dir );
if( $theme_dir_name == $dir ){
$option .= sprintf( $option_html, $dir, 'selected="selected"');
}else{
$option .= sprintf( $option_html, $dir, '');
}
}
}
$option = '<select id="theme_name" name="theme_name">'.$option .'</select>';
}
return sprintf( $form_html,'POST','detect-bom.php','themes_selector',$legend,'selectbox',$option,'submit-button','Check');
}
/**
*
*
*
*
*/
function get_deprecated_functions(){
$function = array();
$deprecated = 'wp-includes'. DIRECTORY_SEPARATOR.'deprecated.php';
$content = file_get_contents($deprecated);
preg_match_all("/(function )(\S*)(\()/", $content, $matches);
foreach($matches[2] as $match) {
$function[] = trim($match);
}
$deprecated_ms = 'wp-includes'. DIRECTORY_SEPARATOR.'ms-deprecated.php';
$content = file_get_contents($deprecated_ms);
preg_match_all("/(function )(\S*)(\()/", $content, $matches);
foreach($matches[2] as $match) {
$function_ms[] = trim($match);
}
$function = array_merge($function,$function_ms);
natcasesort($function);
return $function;
}
/**
*
*
*
*
*/
function check_auth(){
$host = $_SERVER['HTTP_HOST'];
$dirname = dirname($_SERVER['PHP_SELF']);
$filename = basename($_SERVER['SCRIPT_FILENAME']);
$query_str = $_SERVER['QUERY_STRING'];
$wordpress_url = trim( "http://{$host}{$dirname}", '/' );
$md5 = md5( $wordpress_url );
if( ! array_key_exists('wordpress_logged_in_'.$md5,$_COOKIE ) ){
header( "location: $wordpress_url" );
exit;
}
}
function title($title = '' ){
If( defined('SCANED_DIR') and SCANED_DIR == 'themes' ){
if( empty( $add ) ){
$title = 'テーマ 面接君';
}
}elseif( defined('SCANED_DIR') and SCANED_DIR == 'plugins' ){
if( empty( $add ) ){
$title = 'プラグイン 面接君';
}
}
echo $title;
}
/**
*
*
*
*
*/
//bomのチェックと、テーマファイル終端のphp閉じタグの後ろの改行を検査
function detect_md5($filename) {
global $theme_dir_name;
$theme_path = 'wp-content'. DIRECTORY_SEPARATOR.SCANED_DIR. DIRECTORY_SEPARATOR. $theme_dir_name;
$result = '';
$path_parts = pathinfo( $filename );
$text = md5_file($filename);
$filename = str_replace( $theme_path .'/','',$filename );
//if( $text !== check ){
return "'{$filename}' => '{$text}' ,\n";
//}
/* if( $text !== $raindrops_md5[$filename] ){
return $text .'==='.$raindrops_md5[$text] .'<br />';
}*/
}
function check_modify() {
global $theme_dir_name;
$theme_path = 'wp-content'. DIRECTORY_SEPARATOR.SCANED_DIR. DIRECTORY_SEPARATOR. $theme_dir_name;
$result = '';
$modify_file = $theme_path.'/check-same.php';
if( file_exists( $modify_file ) ){
include( $modify_file );
foreach( $raindrops_template_md5 as $key=>$val){
if( $key !== 'check-same.php' ){
if( md5_file($theme_path .'/'.$key) == $val ){
$result .= "<li style=\"color:green\">{$key} is fine</li>";
}else{
$result .= "<li style=\"color:red;\">{$key} is modify</li>";
}
}
}
return $result;
}else{
return 'md5 file not exists';
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment