<?php
///////////////////////////////////////////////////////////////////////////
// Автор: Григорий Земсков
// Email: audit@revisium.com, http://revisium.com/ai/, skype: greg_zemskov

// Запрещено использовать скрипт и базы сигнатур в коммерческих целях без приобретения лицензии.
// Запрещено использовать код скрипта  без согласования с автором скрипта.

// Получено свидетельство о государственной регистрации ПЭВМ в РосПатенте 
// url: http://revisium.com/ai/i/mini_aibolit.jpg
///////////////////////////////////////////////////////////////////////////

define('PASS', 'сюда_вписать_пароль'); // пароль для запуска. This is pass for launching.


define('REPORT_MASK_PHPSIGN', 1);
define('REPORT_MASK_SPAMLINKS', 2);
define('REPORT_MASK_DOORWAYS', 4);
define('REPORT_MASK_SUSP', 8);
define('REPORT_MASK_CANDI', 16);
define('REPORT_MASK_WRIT', 32);
define('REPORT_MASK_FULL', REPORT_MASK_PHPSIGN | REPORT_MASK_SPAMLINKS | REPORT_MASK_DOORWAYS | REPORT_MASK_SUSP | REPORT_MASK_CANDI | REPORT_MASK_WRIT);


$defaults = array(
	'path' => dirname(__FILE__),
	'scan_all_files' => 0, // полное сканирование файлов (не только .js, .php, .html, .htaccess)
	'scan_delay' => 1, // задержка в миллисекундах при сканировании файлов для снижения нагрузки на файловую систему
	'max_size_to_scan' => '5M',
	'site_url' => '', // адрес вашего сайта
	'no_rw_dir' => 0,
	'report_mask' =>  REPORT_MASK_FULL // все в отчет
);


define('DEBUG_MODE', 0);

define('DIR_SEPARATOR', '/');

if ((isset($_SERVER['OS']) && stripos('Win', $_SERVER['OS']) !== false)/* && stripos('CygWin', $_SERVER['OS']) === false)*/) {
   define('DIR_SEPARATOR', '\\');
}

// завернутые сигнатуры, чтобы не ругались антивирусы на PC и на хостинге
$g_DBShe = unserialize(base64_decode(" "));
$g_FlexDBShe = unserialize(base64_decode(" "));
$g_ExceptFlex = unserialize(base64_decode("YToxMzp7aTowO3M6NjY6InJlcXVpcmVccypcKCpccypcJF9TRVJWRVJcW1xzKlsnIl17MCwxfURPQ1VNRU5UX1JPT1RbJyJdezAsMX1ccypcXSI7aToxO3M6NzE6InJlcXVpcmVfb25jZVxzKlwoKlxzKlwkX1NFUlZFUlxbXHMqWyciXXswLDF9RE9DVU1FTlRfUk9PVFsnIl17MCwxfVxzKlxdIjtpOjI7czo2NjoiaW5jbHVkZVxzKlwoKlxzKlwkX1NFUlZFUlxbXHMqWyciXXswLDF9RE9DVU1FTlRfUk9PVFsnIl17MCwxfVxzKlxdIjtpOjM7czo3MToiaW5jbHVkZV9vbmNlXHMqXCgqXHMqXCRfU0VSVkVSXFtccypbJyJdezAsMX1ET0NVTUVOVF9ST09UWyciXXswLDF9XHMqXF0iO2k6NDtzOjE3OiJcJHNtYXJ0eS0+X2V2YWxcKCI7aTo1O3M6MzA6InByZXBccytybVxzKy1yZlxzKyV7YnVpbGRyb290fSI7aTo2O3M6MTE6ImRvdWJsZXZhbFwoIjtpOjc7czoyMjoiVE9ETzpccytybVxzKy1yZlxzK3RoZSI7aTo4O3M6Mjc6Imtyc29ydFwoXCR3cHNtaWxpZXN0cmFuc1wpOyI7aTo5O3M6ODI6ImRvY3VtZW50XC53cml0ZVwodW5lc2NhcGVcKCIlM0NzY3JpcHQgc3JjPSciIFwrIGdhSnNIb3N0IFwrICJnb29nbGUtYW5hbHl0aWNzXC5jb20iO2k6MTA7czo2OiJcLmV4ZWMiO2k6MTE7czo4OiJleGVjXChcKSI7aToxMjtzOjI0OiJcJHgxID0gXCR0aGlzLT53IC0gXCR4MTsiO30="));
$g_SusDB = unserialize(base64_decode(" "));
$g_SusDBPrio = unserialize(base64_decode("YToxMTQ6e2k6MDtpOjA7aToxO2k6MDtpOjI7aTowO2k6MztpOjA7aTo0O2k6MTtpOjU7aToxO2k6NjtpOjA7aTo3O2k6MDtpOjg7aTowO2k6OTtpOjA7aToxMDtpOjA7aToxMTtpOjA7aToxMjtpOjA7aToxMztpOjA7aToxNDtpOjA7aToxNTtpOjA7aToxNjtpOjA7aToxNztpOjA7aToxODtpOjA7aToxOTtpOjA7aToyMDtpOjA7aToyMTtpOjA7aToyMjtpOjA7aToyMztpOjA7aToyNDtpOjA7aToyNTtpOjE7aToyNjtpOjE7aToyNztpOjA7aToyODtpOjA7aToyOTtpOjA7aTozMDtpOjA7aTozMTtpOjA7aTozMjtpOjA7aTozMztpOjA7aTozNDtpOjA7aTozNTtpOjA7aTozNjtpOjA7aTozNztpOjA7aTozODtpOjA7aTozOTtpOjA7aTo0MDtpOjA7aTo0MTtpOjA7aTo0MjtpOjA7aTo0MztpOjA7aTo0NDtpOjA7aTo0NTtpOjA7aTo0NjtpOjA7aTo0NztpOjA7aTo0ODtpOjA7aTo0OTtpOjA7aTo1MDtpOjA7aTo1MTtpOjA7aTo1MjtpOjA7aTo1MztpOjE7aTo1NDtpOjA7aTo1NTtpOjA7aTo1NjtpOjI7aTo1NztpOjE7aTo1ODtpOjA7aTo1OTtpOjA7aTo2MDtpOjA7aTo2MTtpOjI7aTo2MjtpOjI7aTo2MztpOjA7aTo2NDtpOjA7aTo2NTtpOjA7aTo2NjtpOjI7aTo2NztpOjE7aTo2ODtpOjA7aTo2OTtpOjA7aTo3MDtpOjE7aTo3MTtpOjA7aTo3MjtpOjE7aTo3MztpOjE7aTo3NDtpOjE7aTo3NTtpOjM7aTo3NjtpOjI7aTo3NztpOjA7aTo3ODtpOjI7aTo3OTtpOjA7aTo4MDtpOjA7aTo4MTtpOjI7aTo4MjtpOjA7aTo4MztpOjA7aTo4NDtpOjA7aTo4NTtpOjE7aTo4NjtpOjE7aTo4NztpOjE7aTo4ODtpOjE7aTo4OTtpOjA7aTo5MDtpOjI7aTo5MTtpOjI7aTo5MjtpOjI7aTo5MztpOjI7aTo5NDtpOjI7aTo5NTtpOjE7aTo5NjtpOjE7aTo5NztpOjM7aTo5ODtpOjM7aTo5OTtpOjE7aToxMDA7aTozO2k6MTAxO2k6MztpOjEwMjtpOjI7aToxMDM7aTowO2k6MTA0O2k6MztpOjEwNTtpOjE7aToxMDY7aToxO2k6MTA3O2k6MztpOjEwODtpOjM7aToxMDk7aTozO2k6MTEwO2k6MTtpOjExMTtpOjE7aToxMTI7aToxO2k6MTEzO2k6NDt9"));
$g_AdwareSig = unserialize(base64_decode("YToxNDp7aTowO3M6MTk6Il9fbGlua2ZlZWRfcm9ib3RzX18iO2k6MTtzOjEzOiJMSU5LRkVFRF9VU0VSIjtpOjI7czoxODoiX19zYXBlX2RlbGltaXRlcl9fIjtpOjM7czoyOToiZGlzcGVuc2VyXC5hcnRpY2xlc1wuc2FwZVwucnUiO2k6NDtzOjExOiJMRU5LX2NsaWVudCI7aTo1O3M6MTE6IlNBUEVfY2xpZW50IjtpOjY7czoxNzoiZGJcLnRydXN0bGlua1wucnUiO2k6NztzOjE2OiJ0bF9saW5rc19kYl9maWxlIjtpOjg7czoxNToiVHJ1c3RsaW5rQ2xpZW50IjtpOjk7czoxMzoiLT5ccypTTENsaWVudCI7aToxMDtzOjE2NjoiaXNzZXRccypcKCpccypcJF9TRVJWRVJccypcW1xzKlsnIl17MCwxfUhUVFBfVVNFUl9BR0VOVFsnIl17MCwxfVxzKlxdXHMqXClccyomJlxzKlwoKlxzKlwkX1NFUlZFUlxzKlxbXHMqWyciXXswLDF9SFRUUF9VU0VSX0FHRU5UWyciXXswLDF9XF1ccyo9PVxzKlsnIl17MCwxfUxNUF9Sb2JvdCI7aToxMTtzOjQzOiJcJGxpbmtzLT5ccypyZXR1cm5fbGlua3NccypcKCpccypcJGxpYl9wYXRoIjtpOjEyO3M6NDQ6IlwkbGlua3NfY2xhc3Nccyo9XHMqbmV3XHMrR2V0X2xpbmtzXHMqXCgqXHMqIjtpOjEzO3M6NTI6IlsnIl17MCwxfVxzKixccypbJyJdezAsMX1cLlsnIl17MCwxfVxzKlwpKlxzKjtccypcPz4iO30="));
$g_JSVirSig = unserialize(base64_decode("YTo1Nzp7aTowO3M6NDE6ImY9J2YnXCsncidcKydvJ1wrJ20nXCsnQ2gnXCsnYXJDJ1wrJ29kZSc7IjtpOjE7czoyMjoiXC5wcm90b3R5cGVcLmF9Y2F0Y2hcKCI7aToyO3M6Mzc6InRyeXtCb29sZWFuXChcKVwucHJvdG90eXBlXC5xfWNhdGNoXCgiO2k6MztzOjM0OiJpZlwoUmVmXC5pbmRleE9mXCgnXC5nb29nbGVcLidcKSE9IjtpOjQ7czo4NjoiaW5kZXhPZlx8aWZcfHJjXHxsZW5ndGhcfG1zblx8eWFob29cfHJlZmVycmVyXHxhbHRhdmlzdGFcfG9nb1x8YmlcfGhwXHx2YXJcfGFvbFx8cXVlcnkiO2k6NTtzOjU0OiJBcnJheVwucHJvdG90eXBlXC5zbGljZVwuY2FsbFwoYXJndW1lbnRzXClcLmpvaW5cKCIiXCkiO2k6NjtzOjgyOiJxPWRvY3VtZW50XC5jcmVhdGVFbGVtZW50XCgiZCJcKyJpIlwrInYiXCk7cVwuYXBwZW5kQ2hpbGRcKHFcKyIiXCk7fWNhdGNoXChxd1wpe2g9IjtpOjc7czo3OToiXCt6ejtzcz1cW1xdO2Y9J2ZyJ1wrJ29tJ1wrJ0NoJztmXCs9J2FyQyc7ZlwrPSdvZGUnO3c9dGhpcztlPXdcW2ZcWyJzdWJzdHIiXF1cKCI7aTo4O3M6MTE1OiJzNVwocTVcKXtyZXR1cm4gXCtcK3E1O31mdW5jdGlvbiB5Zlwoc2Ysd2VcKXtyZXR1cm4gc2ZcLnN1YnN0clwod2UsMVwpO31mdW5jdGlvbiB5MVwod2JcKXtpZlwod2I9PTE2OFwpd2I9MTAyNTtlbHNlIjtpOjk7czo2NDoiaWZcKG5hdmlnYXRvclwudXNlckFnZW50XC5tYXRjaFwoL1woYW5kcm9pZFx8bWlkcFx8ajJtZVx8c3ltYmlhbiI7aToxMDtzOjEwNjoiZG9jdW1lbnRcLndyaXRlXCgnPHNjcmlwdCBsYW5ndWFnZT0iSmF2YVNjcmlwdCIgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9IidcK2RvbWFpblwrJyI+PC9zY3InXCsnaXB0PidcKSI7aToxMTtzOjMxOiJodHRwOi8vcGhzcFwucnUvXy9nb1wucGhwXD9zaWQ9IjtpOjEyO3M6MTc6IjwvaHRtbD5ccyo8c2NyaXB0IjtpOjEzO3M6MTc6IjwvaHRtbD5ccyo8aWZyYW1lIjtpOjE0O3M6NjY6Ij1uYXZpZ2F0b3JcW2FwcFZlcnNpb25fdmFyXF1cLmluZGV4T2ZcKCJNU0lFIlwpIT0tMVw/JzxpZnJhbWUgbmFtZSI7aToxNTtzOjc6IlxceDY1QXQiO2k6MTY7czo5OiJcXHg2MXJDb2QiO2k6MTc7czoyMjoiImZyIlwrIm9tQyJcKyJoYXJDb2RlIiI7aToxODtzOjExOiI9ImV2IlwrImFsIiI7aToxOTtzOjc4OiJcW1woXChlXClcPyJzIjoiIlwpXCsicCJcKyJsaXQiXF1cKCJhXCQiXFtcKFwoZVwpXD8ic3UiOiIiXClcKyJic3RyIlxdXCgxXClcKTsiO2k6MjA7czozOToiZj0nZnInXCsnb20nXCsnQ2gnO2ZcKz0nYXJDJztmXCs9J29kZSc7IjtpOjIxO3M6MjA6ImZcKz1cKGhcKVw/J29kZSc6IiI7IjtpOjIyO3M6NDE6ImY9J2YnXCsncidcKydvJ1wrJ20nXCsnQ2gnXCsnYXJDJ1wrJ29kZSc7IjtpOjIzO3M6NTA6ImY9J2Zyb21DaCc7ZlwrPSdhckMnO2ZcKz0ncWdvZGUnXFsic3Vic3RyIlxdXCgyXCk7IjtpOjI0O3M6MTY6InZhclxzK2Rpdl9jb2xvcnMiO2k6MjU7czo5OiJ2YXJccytfMHgiO2k6MjY7czoyMDoiQ29yZUxpYnJhcmllc0hhbmRsZXIiO2k6Mjc7czo3OiJwaW5nbm93IjtpOjI4O3M6ODoic2VyY2hib3QiO2k6Mjk7czoxMDoia20wYWU5Z3I2bSI7aTozMDtzOjY6ImMzMjg0ZCI7aTozMTtzOjIyOiJpZlxzKlwoXHMqXGQrXHMqXClccyp7IjtpOjMyO3M6ODoiXFx4NjhhckMiO2k6MzM7czo4OiJcXHg2ZENoYSI7aTozNDtzOjc6IlxceDZmZGUiO2k6MzU7czo3OiJcXHg2ZmRlIjtpOjM2O3M6ODoiXFx4NDNvZGUiO2k6Mzc7czo3OiJcXHg3Mm9tIjtpOjM4O3M6NzoiXFx4NDNoYSI7aTozOTtzOjc6IlxceDcyQ28iO2k6NDA7czo4OiJcXHg0M29kZSI7aTo0MTtzOjEwOiJcLmR5bmRuc1wuIjtpOjQyO3M6OToiXC5keW5kbnMtIjtpOjQzO3M6Nzk6In1ccyplbHNlXHMqe1xzKmRvY3VtZW50XC53cml0ZVxzKlwoXHMqWyciXXswLDF9XC5bJyJdezAsMX1cKVxzKn1ccyp9XHMqUlwoXHMqXCkiO2k6NDQ7czo0NToiZG9jdW1lbnRcLndyaXRlXCh1bmVzY2FwZVwoJyUzQ2RpdiUyMGlkJTNEJTIyIjtpOjQ1O3M6MTg6IlwuYml0Y29pbnBsdXNcLmNvbSI7aTo0NjtzOjQxOiJcLnNwbGl0XCgiJiYiXCk7aD0yO3M9IiI7aWZcKG1cKWZvclwoaT0wOyI7aTo0NztzOjQ4OiJkb2N1bWVudFwud3JpdGVccypcKFxzKnVuZXNjYXBlXHMqXChbJyJdezAsMX0lM2MiO2k6NDg7czo0MToiPGlmcmFtZVxzK3NyYz0iaHR0cDovL2RlbHV4ZXNjbGlja3NcLnByby8iO2k6NDk7czo0NToiM0Jmb3JcfGZyb21DaGFyQ29kZVx8MkMyN1x8M0RcfDJDODhcfHVuZXNjYXBlIjtpOjUwO3M6NTg6Ijtccypkb2N1bWVudFwud3JpdGVcKFsnIl17MCwxfTxpZnJhbWVccypzcmM9Imh0dHA6Ly95YVwucnUiO2k6NTE7czoxMTA6IndcLmRvY3VtZW50XC5ib2R5XC5hcHBlbmRDaGlsZFwoc2NyaXB0XCk7XHMqY2xlYXJJbnRlcnZhbFwoaVwpO1xzKn1ccyp9XHMqLFxzKlxkK1xzKlwpXHMqO1xzKn1ccypcKVwoXHMqd2luZG93IjtpOjUyO3M6MTEwOiJpZlwoIWdcKFwpJiZ3aW5kb3dcLm5hdmlnYXRvclwuY29va2llRW5hYmxlZFwpe2RvY3VtZW50XC5jb29raWU9IjE9MTtleHBpcmVzPSJcK2VcLnRvR01UU3RyaW5nXChcKVwrIjtwYXRoPS8iOyI7aTo1MztzOjcwOiJubl9wYXJhbV9wcmVsb2FkZXJfY29udGFpbmVyXHw1MDAxXHxoaWRkZW5cfGlubmVySFRNTFx8aW5qZWN0XHx2aXNpYmxlIjtpOjU0O3M6MzE6IjwhLS0gW2EtekEtWjAtOV9dKz9cfFx8c3RhdCAtLT4iO2k6NTU7czo4NToiJnBhcmFtZXRlcj1cJGtleXdvcmQmc2U9XCRzZSZ1cj0xJkhUVFBfUkVGRVJFUj0nXCtlbmNvZGVVUklDb21wb25lbnRcKGRvY3VtZW50XC5VUkxcKSI7aTo1NjtzOjY4OiJuYXZpZ2F0b3JcLnVzZXJBZ2VudFwuaW5kZXhPZlwoWyciXXswLDF9ZHJvaWRbJyJdezAsMX1cKVxzKiE9XHMqLTFcKSI7fQ=="));

$g_UnsafeFilesArray = array('t\d*\.php', 'a{1,}\.php', 'z\d*\.php', '123\.php', 'test\d*.php', 'asd\.php', 'info\.php', 'CHANGELOG\.php', 
                           'COPYRIGHT\.php', 'CREDITS\.php', 'INSTALL\.php', 'LICENSE\.php', 'LICENSES\.php', 'backup.+?\.zip', 
                           'backup.+?\.tar\.gz', 'backup.+?\.tgz', 
                           'phpinfo\.php', 'changelog\.txt', 'readme\.txt', 'INSTALLATION\.php', 'dump\.php', 'changelog\.log');

$g_UnsafeDirArray = array('install', 'backup', 'webalizer', 'awstats');

////////////////////////////////////////////////////////////////////////////
if (!isCli() && !isset($_SERVER['HTTP_USER_AGENT'])) {
  print "#################################################\n";
  print "# Error: cannot run on php-cgi. Need php as cli #\n";
  print "#                                               #\n";
  print "# See FAQ: http://revisium.com/ai/faq.php       #\n";
  print "#################################################\n";
  exit;
}

define('AI_VERSION', '20130201');

define('INFO_M', base64_decode('PGZvbnQgY29sb3I9I0UwNjA2MD7QotC+0LvRjNC60L4g0LTQu9GPINC90LXQutC+0LzQvNC10YDRh9C10YHQutC+0LPQviDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjRjyE8L2ZvbnQ+PC9oNT4='));


////////////////////////////////////////////////////////////////////////////

$l_Res = '';

$g_Structure = array();
$g_Counter = 0;

$g_NotRead = array();
$g_FileInfo = array();
$g_Iframer = array();
$g_PHPCodeInside = array();
$g_CriticalJS = array();
$g_UnixExec = array();
$g_SkippedFolders = array();
$g_UnsafeFilesFound = array();
$g_CMS = array();
$g_SymLinks = array();
$g_HiddenFiles = array();

$g_TotalFolder = 0;
$g_TotalFiles = 0;

$g_FoundTotalDirs = 0;
$g_FoundTotalFiles = 0;

if (!isCli()) {
   $defaults['site_url'] = 'http://' . $_SERVER['HTTP_HOST'] . '/'; 
}

define('CRC32_LIMIT', pow(2, 31) - 1);
define('CRC32_DIFF', CRC32_LIMIT * 2 -2);

error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);

set_time_limit(0);
ini_set('max_execution_time', '90000');
ini_set('memory_limit','256M');

if (!function_exists('stripos')) {
	function stripos($par_Str, $par_Entry, $Offset = 0) {
		return strpos(strtolower($par_Str), strtolower($par_Entry), $Offset);
	}
}

/**
 * Print file
*/
function printFile() {
	$l_FileName = $_GET['fn'];
	$l_CRC = isset($_GET['c']) ? (int)$_GET['c'] : 0;
	$l_Content = implode('', file($l_FileName));
	$l_FileCRC = realCRC($l_Content);
	if ($l_FileCRC != $l_CRC) {
		print 'Доступ запрещен.';
		exit;
	}
	
	print '<pre>' . htmlspecialchars($l_Content) . '</pre>';
}

/**
 *
 */
function realCRC($str_in, $full = false)
{
        $in = crc32( $full ? normal($str_in) : $str_in );
        return ($in > CRC32_LIMIT) ? ($in - CRC32_DIFF) : $in;
}


/**
 * Determine php script is called from the command line interface
 * @return bool
 */
function isCli()
{
	return php_sapi_name() == 'cli';
}

/*
 *
 */
function shanonEntropy($par_Str)
{
    $dic = array();

    $len = strlen($par_Str);
    for ($i = 0; $i < $len; $i++) {
        $dic[$par_Str[$i]]++;
    } 

    $result = 0.0;
    $frequency = 0.0;
    foreach ($dic as $item)
    {
        $frequency = (float)$item / (float)$len;
        $result -= $frequency * (log($frequency) / log(2));
    }

    return $result;
}

 function generatePassword ($length = 9)
  {

    // start with a blank password
    $password = "";

    // define possible characters - any character in this string can be
    // picked for use in the password, so if you want to put vowels back in
    // or add special characters such as exclamation marks, this is where
    // you should do it
    $possible = "2346789bcdfghjkmnpqrtvwxyzBCDFGHJKLMNPQRTVWXYZ";

    // we refer to the length of $possible a few times, so let's grab it now
    $maxlength = strlen($possible);
  
    // check for length overflow and truncate if necessary
    if ($length > $maxlength) {
      $length = $maxlength;
    }
	
    // set up a counter for how many characters are in the password so far
    $i = 0; 
    
    // add random characters to $password until $length is reached
    while ($i < $length) { 

      // pick a random character from the possible ones
      $char = substr($possible, mt_rand(0, $maxlength-1), 1);
        
      // have we already used this character in $password?
      if (!strstr($password, $char)) { 
        // no, so it's OK to add it onto the end of whatever we've already got...
        $password .= $char;
        // ... and increase the counter by one
        $i++;
      }

    }

    // done!
    return $password;

  }

/**
 * Print to console
 * @param mixed $text
 * @param bool $add_lb Add line break
 * @return void
 */
function stdOut($text, $add_lb = true)
{
	if (!isCli())
		return;
		
	if (is_bool($text))
	{
		$text = $text ? 'true' : 'false';
	}
	else if (is_null($text))
	{
		$text = 'null';
	}
	if (!is_scalar($text))
	{
		$text = print_r($text, true);
	}

	@fwrite(STDOUT, $text . ($add_lb ? "\n" : ''));
}

/**
 * Print progress
 * @param int $num Current file
 */
function printProgress($num, &$par_File)
{

	$total_files = $GLOBALS['g_FoundTotalFiles'];
	$elapsed_time = microtime(true) - START_TIME;
	$stat = '';
	if ($elapsed_time >= 1)
	{
		$elapsed_seconds = round($elapsed_time, 0);
		$fs = floor($num / $elapsed_seconds);
		$left_files = $total_files - $num;
		if ($fs > 0) {
		   $left_time = ceil($left_files / $fs);
		   $stat = '. [Avg: ' . $fs . ' files/s' . ($left_time > 0  ? ' Left: ' . seconds2Human($left_time) : '') . ']';
                }
	}

	$l_FN = substr($par_File, -60);

	$text = "Scanning file [$l_FN] $num of {$total_files}" . $stat;
	$text = str_pad($text, 150, ' ', STR_PAD_RIGHT);

	stdOut(str_repeat(chr(8), 160) . $text, false);
}

/**
 * Seconds to human readable
 * @param int $seconds
 * @return string
 */
function seconds2Human($seconds)
{
	$r = '';
	$_seconds = floor($seconds);
	$ms = $seconds - $_seconds;
	$seconds = $_seconds;
	if ($hours = floor($seconds / 3600))
	{
		$r .= $hours . (isCli() ? ' h ' : ' час ');
		$seconds = $seconds % 3600;
	}

	if ($minutes = floor($seconds / 60))
	{
		$r .= $minutes . (isCli() ? ' m ' : ' мин ');
		$seconds = $seconds % 60;
	}

	$r .= $seconds + ($ms > 0 ? round($ms, 5) : 0) . (isCli() ? ' s' : ' сек'); //' сек' - not good for shell

	return $r;
}

if (isCli())
{

	$cli_options = array(
		'm:' => 'memory:',
		's:' => 'size:',
		'a' => 'all',
		'd:' => 'delay:',
		'r:' => 'report:',
		'f' => 'fast',
		'p:' => 'path:',
		'h' => 'help'
	);

	$options = getopt(implode('', array_keys($cli_options)), array_values($cli_options));

	if (isset($options['h']) OR isset($options['help']))
	{
		$memory_limit = ini_get('memory_limit');
		echo <<<HELP
AI-Bolit - Script to search for shells and other malicious software.

Usage: php {$_SERVER['PHP_SELF']} [OPTIONS] [PATH]
Current default path is: {$defaults['path']}

Mandatory arguments to long options are mandatory for short options too.
  -p, --path=PATH      Directory path to scan, by default the file directory is used
                       Current path: {$defaults['path']}
  -m, --memory=SIZE    Maximum amount of memory a script may consume. Current value: $memory_limit
                       Can take shorthand byte values (1M, 1G...)
  -s, --size=SIZE      Scan files are smaller than SIZE. 0 - All files. Current value: {$defaults['max_size_to_scan']}
  -a, --all            Scan all files (by default scan. js,. php,. html,. htaccess)
  -d, --delay=INT      delay in milliseconds when scanning files to reduce load on the file system (Default: 1)
  -r, --report=PATH    Filename of report html, by default 'AI-BOLIT-REPORT-dd-mm-YYYY_hh-mm.html'  is used, relative to scan path
                       Enter your email address if you wish to report has been sent to the email.
                       You can also specify multiple email separated by commas.
      --help           display this help and exit

HELP;
		exit;
	}

	$l_FastCli = false;
	
	if (
		(isset($options['memory']) AND !empty($options['memory']) AND ($memory = $options['memory']))
		OR (isset($options['m']) AND !empty($options['m']) AND ($memory = $options['m']))
	)
	{
		$memory = getBytes($memory);
		if ($memory > 0)
		{
			$defaults['memory_limit'] = $memory;
		}
	}

	if (
		(isset($options['size']) AND !empty($options['size']) AND ($size = $options['size']) !== false)
		OR (isset($options['s']) AND !empty($options['s']) AND ($size = $options['s']) !== false)
	)
	{
		$size = getBytes($size);
		$defaults['max_size_to_scan'] = $size > 0 ? $size : 0;
	}

	if (isset($options['f'])) 
	 {
	   $l_FastCli = true;
	 }
		
	if (
		(isset($options['delay']) AND !empty($options['delay']) AND ($delay = $options['delay']) !== false)
		OR (isset($options['d']) AND !empty($options['d']) AND ($delay = $options['d']) !== false)
	)
	{
		$delay = (int) $delay;
		if (!($delay < 0))
		{
			$defaults['scan_delay'] = $delay;
		}
	}

	if (isset($options['all']) OR isset($options['a']))
	{
		$defaults['scan_all_files'] = 1;
	}

	if (
		(isset($options['report']) AND ($report = $options['report']) !== false)
		OR (isset($options['r']) AND ($report = $options['r']) !== false)
	)
	{
		define('REPORT', $report);
	}

	defined('REPORT') OR define('REPORT', 'AI-BOLIT-REPORT-' . date('d-m-Y_H-i') . '-' . rand(1, 999999) . '.html');

	$last_arg = max(1, sizeof($_SERVER['argv']) - 1);
	if (isset($_SERVER['argv'][$last_arg]))
	{
		$path = $_SERVER['argv'][$last_arg];
		if (
			substr($path, 0, 1) != '-'
			AND (substr($_SERVER['argv'][$last_arg - 1], 0, 1) != '-' OR array_key_exists(substr($_SERVER['argv'][$last_arg - 1], -1), $cli_options)))
		{
			$defaults['path'] = $path;
		}
	}
}

// Init
define('MAX_ALLOWED_PHP_HTML_IN_DIR', 100);
define('BASE64_LENGTH', 100);
define('MAX_PREVIEW_LEN', 80);
define('MAX_EXT_LINKS', 1001);

// принудильно запускаем полное сканирование при запуске из командной строки
if (isCli() || isset($_GET['full'])) {
  $defaults['scan_all_files'] = 1;
}

if ($l_FastCli) {
  $defaults['scan_all_files'] = 0; 
}

define('SCAN_ALL_FILES', (bool) $defaults['scan_all_files']);
define('SCAN_DELAY', (int) $defaults['scan_delay']);
define('MAX_SIZE_TO_SCAN', getBytes($defaults['max_size_to_scan']));

if ($defaults['memory_limit'] AND ($defaults['memory_limit'] = getBytes($defaults['memory_limit'])) > 0)
	ini_set('memory_limit', $defaults['memory_limit']);

define('START_TIME', microtime(true));

define('ROOT_PATH', realpath($defaults['path']));

if (!ROOT_PATH)
{
        if (isCli())  {
		die(stdOut("Directory '{$defaults['path']}' not found!"));
	}
}
elseif(!is_readable(ROOT_PATH))
{
        if (isCli())  {
		die(stdOut("Cannot read directory '" . ROOT_PATH . "'!"));
	}
}

define('CURRENT_DIR', getcwd());
chdir(ROOT_PATH);

// Проверяем отчет
if (isCli() AND REPORT !== '' AND !getEmails(REPORT))
{
	$report = str_replace('\\', '/', REPORT);
	$abs = strpos($report, '/') === 0 ? DIR_SEPARATOR : '';
	$report = array_values(array_filter(explode('/', $report)));
	$report_file = array_pop($report);
	$report_path = realpath($abs . implode(DIR_SEPARATOR, $report));

	define('REPORT_FILE', $report_file);
	define('REPORT_PATH', $report_path);

	if (REPORT_FILE AND REPORT_PATH AND is_file(REPORT_PATH . DIR_SEPARATOR . REPORT_FILE))
	{
		@unlink(REPORT_PATH . DIR_SEPARATOR . REPORT_FILE);
	}
}


if (function_exists('phpinfo')) {
   ob_start();
   phpinfo();
   $l_PhpInfo = ob_get_contents();
   ob_end_clean();

   $l_PhpInfo = str_replace('border: 1px', '', $l_PhpInfo);
   preg_match('|<body>(.*)</body>|smi', $l_PhpInfo, $l_PhpInfoBody);
}

$l_Result =<<<MAIN_PAGE

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
<META NAME="ROBOTS" CONTENT="NOINDEX,NOFOLLOW">
<style type="text/css">
 body {
   font-family: Georgia;
   color: #303030;
   background: #FFFFF0;
   font-size: 12px;
   margin: 20px;
   padding: 0;
 }

 h3 {
   font-size: 27px;
   margin: 0 0;
 }

 .sec {
  font-size: 25px;
  margin-bottom: 10px;
 }


 .warn {
   color: #FF4C00;
   margin: 0 0 20px 0;
 }

 .warn .it {
   color: #FF4C00;
 }

 .warn2 {
   color: #42ADFF;
   margin: 0 0 20px 0;
 }

 .warn2 .it {
   color: #42ADFF;
 }

 .ok {
   color: #007F0E;
   margin: 0 0 20px 0;
 }

 .vir {
    color: #A00000;
    margin: 0 0 20px 0;
  }

 .vir .it {
    color: #A00000;
 }

 .disclaimer {
   font-size: 11px;
   font-family: Arial;
   color: #505050;
   margin: 10px 0 10px 0;
 }

 .thanx {
  border: 1px solid #F0F0F0;
   padding: 20px 20px 10px 20px;
  font-size: 12px;
  font-family: Arial;
  background: #FBFFBA;
 }

 .footer {
  margin: 40px 0 0 0;
 }

 .rep {
   margin: 10px 0 20px 0;
   font-size: 11px;
   font-family: Arial;
 }

 .php_ok
 {
  color: #007F0E; 
 }

 .php_bad
 {
  color: #A00000; 
 }

 .notice
 {
  border: 1px solid cornflowerblue;
  padding: 10px;
  font-size: 12px;
  font-family: Arial;
  background: #E8F8F8;
 }

 .offer {
  -webkit-border-radius: 6px;
   -moz-border-radius: 6px;
   border-radius: 6px;

   position: absolute;
   width: 350px;
   right: 100px;
   top: 85px;
   background: #E06060;
   color: white;
   font-size: 11px;
   font-family: Arial;
   padding: 20px 20px 10px 20px;

 }

  .offer2 {
  -webkit-border-radius: 6px;
   -moz-border-radius: 6px;
   border-radius: 6px;

   position: absolute;
   width: 350px;
   right: 100px;
   top: 100px;
   background: #30A030;
   color: white;
   font-size: 11px;
   font-family: Arial;
   padding: 20px 20px 10px 20px;

 }

 
 .offer A, .offer2 A {
   color: yellow;
 }

 .update {
   color: red;
   font-size: 12px;
   font-family: Arial;
   margin: 0 0 20px 0;
 }

 .tbg0 {
 }

 .tbg1 {
   background: #F0F0F0;
 }

 .it {
    font-size: 12px;
    font-family: Arial;
 }

 .ctd {
    font-size: 12px;
    font-family: Arial;
    color: #909090;
 }

 .flist {
   margin: 10px 0 30px 0;
 }

 .tbgh {
   background: #E0E0E0;
 }

 TH {
   text-align: left;
   font-size: 12px;
   font-family: Arial;
   color: #909090;
 }

 .details {
  font-size: 9px;
  font-family: Arial;
  color: #303030;
 }

 .marker
 {
    color: #FF0000;
    font-size: 16px;
    font-weight: 700;
 }

</style>

<script language="javascript">
  function addToIgnore(par_Lnk, par_FN, par_CRC) {
	var o = document.getElementById('igid');
	var ta = document.forms.ignore.list;
	
	ta.value = ta.value + par_FN + String.fromCharCode(09) + par_CRC + String.fromCharCode(10);
	
	par_Lnk.innerHTML = 'Добавлено'; 
	o.style.display = 'block';
  }
</script>

</head>
<body>
<noindex>
MAIN_PAGE;

////////////////////////////////////////////////////////////////////////////

$l_Result .= '<h3>AI-Болит v.' . AI_VERSION . ' &mdash; удаленькая искалка вредоносного ПО на хостинге.</h3><h5>Григорий Земсков, 2012, <a target=_blank href="http://revisium.com/ai/">Страница проекта на revisium.com.</a>  ' . INFO_M . '</h5>';

$l_CreationTime = filemtime(__FILE__);
if (time() - $l_CreationTime > 86400 * 7) {
  $l_Result .= '<div class="update">Проверьте обновление на сайте <a href="http://revisium.com/ai/">http://revisium.com/ai/</a>. Возможно, ваша версия скрипта уже устарела.</div>';
}

$l_Result .= '<div class="update" style="margin: 20px 0 20px 0; padding: 20px; width: 500px; border: 1px solid #400000"><b>ВНИМАНИЕ! Не оставляйте файл ai-bolit.php или файл отчета на сервере, и не давайте прямых ссылок с других сайтов на файл отчета или скрипта. Отчет содержит важную информацию о вашем сайте или сервере, сохраните его в надежном месте от посторонних глаз!</b></div>';

define('QCR_INDEX_FILENAME', 'fn');
define('QCR_INDEX_TYPE', 'type');
define('QCR_INDEX_WRITABLE', 'wr');
define('QCR_SVALUE_FILE', '1');
define('QCR_SVALUE_FOLDER', '0');

/**
 * Extract emails from the string
 * @param string $email
 * @return array of strings with emails or false on error
 */
function getEmails($email)
{
	$email = preg_split('#[,\s;]#', $email, -1, PREG_SPLIT_NO_EMPTY);
	$r = array();
	for ($i = 0, $size = sizeof($email); $i < $size; $i++)
	{
	        if (function_exists('filter_var')) {
   		   if (filter_var($email[$i], FILTER_VALIDATE_EMAIL))
   		   {
   		   	$r[] = $email[$i];
    		   }
                } else {
                   // for PHP4
                   if (strpos($email[$i], '@') !== false) {
   		   	$r[] = $email[$i];
                   }
                }
	}
	return empty($r) ? false : $r;
}

/**
 * Get bytes from shorthand byte values (1M, 1G...)
 * @param int|string $val
 * @return int
 */
function getBytes($val)
{
	$val = trim($val);
	$last = strtolower($val{strlen($val) - 1});
	switch($last) {
		case 't':
			$val *= 1024;
		case 'g':
			$val *= 1024;
		case 'm':
			$val *= 1024;
		case 'k':
			$val *= 1024;
	}
	return intval($val);
}

/**
 * Format bytes to human readable
 * @param int $bites
 * @return string
 */
function bytes2Human($bites)
{
	if ($bites < 1024)
	{
		return $bites . ' b';
	}
	elseif (($kb = $bites / 1024) < 1024)
	{
		return number_format($kb, 2) . ' Kb';
	}
	elseif (($mb = $kb / 1024) < 1024)
	{
		return number_format($mb, 2) . ' Mb';
	}
	elseif (($gb = $mb / 1024) < 1024)
	{
		return number_format($gb, 2) . ' Gb';
	}
	else
	{
		return number_format($gb / 1024, 2) . 'Tb';
	}
}

///////////////////////////////////////////////////////////////////////////
function needIgnore($par_FN, $par_CRC) {
  global $g_IgnoreList;
  
  for ($i = 0; $i < count($g_IgnoreList); $i++) {
     if (strpos($par_FN, $g_IgnoreList[$i][0]) !== false) {
		if ($par_CRC == $g_IgnoreList[$i][1]) {
			return true;
		}
	 }
  }
  
  return false;
}

///////////////////////////////////////////////////////////////////////////
function printList($par_List, $par_Details = null, $par_NeedIgnore = false) {
  global $g_Structure;
  
  $l_Result = '';
  $l_Result .= "<div class=\"flist\"><table cellspacing=1 cellpadding=4 border=0>";

  $l_Result .= "<tr class=\"tbgh" . ( $i % 2 ). "\">";
  $l_Result .= "<th>Путь</th>";
  $l_Result .= "<th>Дата создания</th>";
  $l_Result .= "<th>Дата модификации</th>";
  $l_Result .= "<th width=90>Размер</th>";
  $l_Result .= "<th width=90>CRC32</th>";
  
  $l_Result .= "</tr>";

  for ($i = 0; $i < count($par_List); $i++) {
    $l_Pos = $par_List[$i];
        if ($par_NeedIgnore) {
         	if (needIgnore($g_Structure['n'][$par_List[$i]], $g_Structure['crc'][$l_Pos])) {
         		continue;
         	}
        }
  
     $l_Creat = $g_Structure['c'][$l_Pos] > 0 ? date("d/m/Y H:i:s", $g_Structure['c'][$l_Pos]) : '-';
     $l_Modif = $g_Structure['m'][$l_Pos] > 0 ? date("d/m/Y H:i:s", $g_Structure['m'][$l_Pos]) : '-';
     $l_Size = $g_Structure['s'][$l_Pos] > 0 ? bytes2Human($g_Structure['s'][$l_Pos]) : '-';

     if ($par_Details != null) {
        $l_WithMarket = preg_replace('|@AI_MARKER@|smi', '<span class="marker">|</span>', $par_Details[$i]);
        $l_Body = '<div class="details">' . $l_WithMarket . '</div>';
     } else {
        $l_Body = '';
     }

     $l_Result .= '<tr class="tbg' . ( $i % 2 ). '">';
	 
	 if (is_file($g_Structure['n'][$l_Pos])) {
		$l_Result .= '<td><div class="it"><a  class="it" target="_blank" href="'. $defaults['site_url'] . 'ai-bolit.php?fn=' .
	              $g_Structure['n'][$l_Pos] . '&ph=' . realCRC(PASS) . '&c=' . $g_Structure['crc'][$l_Pos] . '">' . $g_Structure['n'][$l_Pos] . '</a></div>' . $l_Body . '</td>';
	 } else {
		$l_Result .= '<td><div class="it">' . $g_Structure['n'][$par_List[$i]] . '</div></td>';
	 }
	 
     $l_Result .= '<td><div class="ctd">' . $l_Creat . '</div></td>';
     $l_Result .= '<td><div class="ctd">' . $l_Modif . '</div></td>';
     $l_Result .= '<td><div class="ctd">' . $l_Size . '</div></td>';
     $l_Result .= '<td><div class="ctd"><a href="#" onclick="addToIgnore(this, \'' . $g_Structure['n'][$l_Pos] . '\',\'' . $g_Structure['crc'][$l_Pos] . '\');return false;">' . $g_Structure['crc'][$l_Pos] . '</a></div></td>';
     $l_Result .= '</tr>';

  }

  $l_Result .= "</table></div>";

  return $l_Result;
}

///////////////////////////////////////////////////////////////////////////
function extractValue(&$par_Str, $par_Name) {
  if (preg_match('|<tr><td class="e">\s*'.$par_Name.'\s*</td><td class="v">(.+?)</td>|sm', $par_Str, $l_Result)) {
     return str_replace('no value', '', strip_tags($l_Result[1]));
  }
}

///////////////////////////////////////////////////////////////////////////
function QCR_ExtractInfo($par_Str) {
   $l_PhpInfoSystem = extractValue($par_Str, 'System');
   $l_PhpPHPAPI = extractValue($par_Str, 'Server API');
   $l_AllowUrlFOpen = extractValue($par_Str, 'allow_url_fopen');
   $l_AllowUrlInclude = extractValue($par_Str, 'allow_url_include');
   $l_DisabledFunction = extractValue($par_Str, 'disable_functions');
   $l_DisplayErrors = extractValue($par_Str, 'display_errors');
   $l_ErrorReporting = extractValue($par_Str, 'error_reporting');
   $l_ExposePHP = extractValue($par_Str, 'expose_php');
   $l_LogErrors = extractValue($par_Str, 'log_errors');
   $l_MQGPC = extractValue($par_Str, 'magic_quotes_gpc');
   $l_MQRT = extractValue($par_Str, 'magic_quotes_runtime');
   $l_OpenBaseDir = extractValue($par_Str, 'open_basedir');
   $l_RegisterGlobals = extractValue($par_Str, 'register_globals');
   $l_SafeMode = extractValue($par_Str, 'safe_mode');


   $l_DisabledFunction = ($l_DisabledFunction == '' ? '-?-' : $l_DisabledFunction);
   $l_OpenBaseDir = ($l_OpenBaseDir == '' ? '-?-' : $l_OpenBaseDir);

   $l_Result = '<div class="sec">Конфигурация PHP: ' . phpversion() . '</div>';
   $l_Result .= 'System Version: <span class="php_ok">' . $l_PhpInfoSystem . '</span><br/>';
   $l_Result .= 'PHP API: <span class="php_ok">' . $l_PhpPHPAPI. '</span><br/>';
   $l_Result .= 'allow_url_fopen: <span class="php_' . ($l_AllowUrlFOpen == 'On' ? 'bad' : 'ok') . '">' . $l_AllowUrlFOpen. '</span><br/>';
   $l_Result .= 'allow_url_include: <span class="php_' . ($l_AllowUrlInclude == 'On' ? 'bad' : 'ok') . '">' . $l_AllowUrlInclude. '</span><br/>';
   $l_Result .= 'disable_functions: <span class="php_' . ($l_DisabledFunction == '-?-' ? 'bad' : 'ok') . '">' . $l_DisabledFunction. '</span><br/>';
   $l_Result .= 'display_errors: <span class="php_' . ($l_DisplayErrors == 'On' ? 'ok' : 'bad') . '">' . $l_DisplayErrors. '</span><br/>';
   $l_Result .= 'error_reporting: <span class="php_ok">' . $l_ErrorReporting. '</span><br/>';
   $l_Result .= 'expose_php: <span class="php_' . ($l_ExposePHP == 'On' ? 'bad' : 'ok') . '">' . $l_ExposePHP. '</span><br/>';
   $l_Result .= 'log_errors: <span class="php_' . ($l_LogErrors == 'On' ? 'ok' : 'bad') . '">' . $l_LogErrors . '</span><br/>';
   $l_Result .= 'magic_quotes_gpc: <span class="php_' . ($l_MQGPC == 'On' ? 'ok' : 'bad') . '">' . $l_MQGPC. '</span><br/>';
   $l_Result .= 'magic_quotes_runtime: <span class="php_' . ($l_MQRT == 'On' ? 'bad' : 'ok') . '">' . $l_MQRT. '</span><br/>';
   $l_Result .= 'register_globals: <span class="php_' . ($l_RegisterGlobals == 'On' ? 'bad' : 'ok') . '">' . $l_RegisterGlobals . '</span><br/>';
   $l_Result .= 'open_basedir: <span class="php_' . ($l_OpenBaseDir == '-?-' ? 'bad' : 'ok') . '">' . $l_OpenBaseDir . '</span><br/>';
   
   if (phpversion() < '5.3.0') {
      $l_Result .= 'safe_mode (PHP < 5.3.0): <span class="php_' . ($l_SafeMode == 'On' ? 'ok' : 'bad') . '">' . $l_SafeMode. '</span><br/>';
   }

   return $l_Result . '<p>';
}

///////////////////////////////////////////////////////////////////////////
function QCR_Debug($par_Str) {
  if (!DEBUG_MODE) {
     return;
  }

  $l_MemInfo = ' ';  
  if (function_exists('memory_get_usage')) {
     $l_MemInfo .= ' curmem=' .  bytes2Human(memory_get_usage());
  }

  if (function_exists('memory_get_peak_usage')) {
     $l_MemInfo .= ' maxmem=' .  bytes2Human(memory_get_peak_usage());
  }

  stdOut(date('H:i:s') . ': ' . $par_Str . $l_MemInfo);
}


///////////////////////////////////////////////////////////////////////////
function QCR_ScanDirectories($l_RootDir)
{
	global $g_Structure, $g_Counter, $g_Doorway, $g_FoundTotalFiles, $g_FoundTotalDirs, 
			$defaults, $g_SkippedFolders, $g_UrlIgnoreList, $g_DirIgnoreList, $g_UnsafeFilesArray, $g_UnsafeDirArray, 
                        $g_UnsafeFilesFound, $g_SymLinks, $g_HiddenFiles;

	$l_DirCounter = 0;
	$l_DoorwayFilesCounter = 0;
	$l_SourceDirIndex = $g_Counter - 1;

	QCR_Debug('Scan ' . $l_RootDir);

        $l_QuotedSeparator = quotemeta(DIR_SEPARATOR); 
        $l_NeedCheckCandi = ($defaults['report_mask'] & REPORT_MASK_CANDI) == REPORT_MASK_CANDI;

	if ($l_DIRH = @opendir($l_RootDir))
	{
		while ($l_FileName = readdir($l_DIRH))
		{
			if ($l_FileName == '.' || $l_FileName == '..') continue;

                        if (is_link($l_FileName)) 
                        {
                            $g_SymLinks[] = $l_FileName;
                            continue;
                        }

			$l_FileName = $l_RootDir . DIR_SEPARATOR . $l_FileName;

			$l_Ext = substr($l_FileName, strrpos($l_FileName, '.') + 1);

			$l_IsDir = is_dir($l_FileName);

			// какие файлы точно нужно сканировать
			$l_NeedToScan = SCAN_ALL_FILES || (in_array($l_Ext, array(
				'js', 'php', 'php3', 'phtml', 'shtml', 'khtml',
				'php4', 'php5', 'tpl', 'inc', 'htaccess', 'html', 'htm'
			)));

			if (strpos(basename($l_FileName), '.') === 0) {
                            $g_HiddenFiles[] = $l_FileName;
                        }

			if ($l_IsDir)
			{
				// директория в игноре?
				$l_Skip = false;
				for ($dr = 0; $dr < count($g_DirIgnoreList); $dr++) {
					if (($g_DirIgnoreList[$dr] != '') &&
						preg_match('#' . $g_DirIgnoreList[$dr] . '#', $l_FileName, $l_Found)) {
						$l_Skip = true;
					}
				}
			
				// если в игноре, пропускаем ее
				if ($l_Skip) {
					$g_SkippedFolders[] = $l_FileName;
					continue;
				}
				
				$g_Structure['d'][$g_Counter] = $l_IsDir;
				$g_Structure['n'][$g_Counter] = $l_FileName;

				$l_DirCounter++;


                                if ($l_NeedCheckCandi) {
         				for ($j = 0; $j < count($g_UnsafeDirArray); $j++) {
         				    if (preg_match('|' . $l_QuotedSeparator . $g_UnsafeDirArray[$j] . '$|i', $l_FileName, $l_Found)) {
                                                $g_UnsafeFilesFound[] = $g_Counter;
                                                break;
                                             }
         				}
     				}

				if ($l_DirCounter > MAX_ALLOWED_PHP_HTML_IN_DIR)
				{
					$g_Doorway[] = $l_SourceDirIndex;
					$l_DirCounter = -655360;
				}

				$g_Counter++;
				$g_FoundTotalDirs++;

				QCR_ScanDirectories($l_FileName);

			} else
			{
				if ($l_NeedToScan)
				{
					$g_FoundTotalFiles++;
					if (in_array($l_Ext, array(
						'php', 'php3',
						'php4', 'php5', 'html', 'htm', 'phtml', 'shtml', 'khtml'
					))
					)
					{
						$l_DoorwayFilesCounter++;
						
						if ($l_DoorwayFilesCounter > MAX_ALLOWED_PHP_HTML_IN_DIR)
						{
							$g_Doorway[] = $l_SourceDirIndex;
							$l_DoorwayFilesCounter = -655360;
						}
					}


					$l_Stat = stat($l_FileName);

					$g_Structure['d'][$g_Counter] = $l_IsDir;
					$g_Structure['n'][$g_Counter] = $l_FileName;
					$g_Structure['s'][$g_Counter] = $l_Stat['size'];
					$g_Structure['c'][$g_Counter] = $l_Stat['ctime'];
					$g_Structure['m'][$g_Counter] = $l_Stat['mtime'];

                                        if ($l_NeedCheckCandi) {
          					for ($j = 0; $j < count($g_UnsafeFilesArray); $j++) {
         					    if (preg_match('|' . $l_QuotedSeparator . $g_UnsafeFilesArray[$j] . '|i', $l_FileName, $l_Found)) {
                                                        $g_UnsafeFilesFound[] = $g_Counter;
                                                        break;
                                                     }
         					}
         				}

					$g_Counter++;
				}
			}
		}

		closedir($l_DIRH);
	}

	return $g_Structure;
}

///////////////////////////////////////////////////////////////////////////
function getFragment($par_Content, $par_Pos) {
  $l_MaxChars = MAX_PREVIEW_LEN;
  $l_MaxLen = strlen($par_Content);
  $l_RightPos = min($par_Pos + $l_MaxChars, $l_MaxLen); 
  $l_MinPos = max(0, $par_Pos - $l_MaxChars);

  $l_Res = substr($par_Content, $l_MinPos, $par_Pos - $l_MinPos) . 
           '@AI_MARKER@' . 
           substr($par_Content, $par_Pos, $l_RightPos - $par_Pos - 1);

  return htmlspecialchars($l_Res);
}

///////////////////////////////////////////////////////////////////////////
function escapedHexToHex($escaped)
{ $GLOBALS['g_EncObfu']++; return chr(hexdec($escaped[1])); }
function escapedOctDec($escaped)
{ $GLOBALS['g_EncObfu']++; return chr(octdec($escaped[1])); }
function escapedDec($escaped)
{ $GLOBALS['g_EncObfu']++; return chr($escaped[1]); }

function UnwrapObfu($par_Content) {
  $GLOBALS['g_EncObfu'] = 0;

  $par_Content = preg_replace_callback('/\\\\x([a-fA-F0-9]{2})/i','escapedHexToHex', $par_Content);
  $par_Content = preg_replace_callback('/\\\\([0-9]{3})/i','escapedOctDec', $par_Content);
  $par_Content = preg_replace_callback('/\\\\d([0-9]{1,3})/i','escapedDec', $par_Content);

  return $par_Content;
}

///////////////////////////////////////////////////////////////////////////
function QCR_SearchPHP($src)
{
  if (preg_match("/(<\?php[\w\s]{5,})/smi", $src, $l_Found, PREG_OFFSET_CAPTURE)) {
	  return $l_Found[0][1];
  }

  if (preg_match("/(<%[\w\s]{10,})/smi", $src, $l_Found, PREG_OFFSET_CAPTURE)) {
	  return $l_Found[0][1];
  }
  if (preg_match("/(<script[^>]*language\s*=\s*)('|\"|)php('|\"|)([^>]*>)/i", $src, $l_Found, PREG_OFFSET_CAPTURE)) {
    return $l_Found[0][1];
  }

  return false;
}


///////////////////////////////////////////////////////////////////////////
function knowUrl($par_URL) {
  global $g_UrlIgnoreList;

  for ($jk = 0; $jk < count($g_UrlIgnoreList); $jk++) {
     if  ((stripos($par_URL, $g_UrlIgnoreList[$jk]) !== false)) {
     	return true;
     }
  }

  return false;
}


///////////////////////////////////////////////////////////////////////////
function QCR_GoScan($par_Offset)
{
	global $g_IframerFragment, $g_Iframer, $g_SuspDir, $g_Redirect, $g_Doorway, $g_EmptyLink, $g_Structure, $g_Counter, 
		   $g_WritableDirectories, $g_CriticalPHP, $g_TotalFolder, $g_TotalFiles, $g_WarningPHP, $g_AdwareList,
		   $g_CriticalPHP, $g_CriticalJS, $g_UrlIgnoreList, $g_CriticalJSFragment, $g_PHPCodeInside, $g_PHPCodeInsideFragment, 
		   $g_NotRead, $g_WarningPHPFragment, $g_BigFiles, $g_RedirectPHPFragment, $g_EmptyLinkSrc, $g_CriticalPHPFragment, 
           $g_Base64Fragment, $g_UnixExec, $g_IframerFragment, $g_CMS, $defaults, $g_AdwareListFragment, $g_KnownList;

	static $_files_and_ignored = 0;

        QCR_Debug('QCR_GoScan ' . $par_Offset);

	for ($i = $par_Offset; $i < $g_Counter; $i++)
	{
		$l_Filename = $g_Structure['n'][$i];

 	        QCR_Debug('Check ' . $l_Filename);

		if ($g_Structure['d'][$i])
		{
			// FOLDER
			$g_TotalFolder++;

			if (is_writable($l_Filename))
			{
				$g_WritableDirectories[] = $i;
			}
		}
		else
		{

			// FILE
			if (MAX_SIZE_TO_SCAN > 0 AND $g_Structure['s'][$i] > MAX_SIZE_TO_SCAN)
			{
				$g_BigFiles[] = $i;
			}
			else
			{
				$g_TotalFiles++;

                $l_Content = @implode('', file($l_Filename));
                if (($l_Content == '') && ($g_Structure['s'][$i] > 0)) {
                   $g_NotRead[] = $i;
                }

				$g_Structure['crc'][$i] = realCRC($l_Content);

                                // detect version CMS
				if (strpos($l_Filename, DIR_SEPARATOR . 'engine' . DIR_SEPARATOR . 'data' . DIR_SEPARATOR . 'config.php') !== false) {
				   if (preg_match('|\'version_id\'\s*=>\s*"(.+?)"|smi', $l_Content, $l_Ver)) {
					$g_CMS[] = 'DLE v' . $l_Ver[1];
				   }
                                } else
				if (strpos($l_Filename, DIR_SEPARATOR . 'wp-includes' . DIR_SEPARATOR . 'version.php') !== false) {
				   if (preg_match('|\$wp_version\s*=\s*\'(.+?)\'|smi', $l_Content, $l_Ver)) {
					$g_CMS[] = 'Wordpress v' . $l_Ver[1];
				   }
                                } else
				if (strpos($l_Filename, 'install' . DIR_SEPARATOR . 'consts.php') !== false) {
				   if (preg_match('|STRING_VERSION\',\s*\'(.+?)\'|smi', $l_Content, $l_Ver)) {
					$g_CMS[] = 'ShopScript Premium v' . $l_Ver[1];
				   }
                                } else
				if (strpos($l_Filename, 'bitrix' . DIR_SEPARATOR . 'modules' . DIR_SEPARATOR . 'main' . DIR_SEPARATOR . 'classes' . DIR_SEPARATOR . 'general' . DIR_SEPARATOR . 'version.php') !== false) {
				   if (preg_match('|define\("SM_VERSION","(.+?)"\)|smi', $l_Content, $l_Ver)) {
					$g_CMS[] = 'Bitrix v' . $l_Ver[1];
				   }
                                }

                                $l_KnownCRC = $g_Structure['crc'][$i] + realCRC(basename($l_Filename));
                                if (in_array($l_KnownCRC, $g_KnownList)) {
	        		   printProgress(++$_files_and_ignored, $l_Filename);
                                   continue;
                                }

				$l_Unwrapped = UnwrapObfu($l_Content);

				// ignore itself
				if (strpos($l_Content, 'LJHJLKJHLKJHJKLKJHJKLKJFGF') !== false) {
					continue;
				}

				// warnings
				$l_Pos = '';
				if (WarningPHP($l_Filename, $l_Unwrapped, $l_Pos))
				{       $l_Prio = 1;
				        if (strpos($l_Filename, '.php') !== false) {
				       	   $l_Prio = 0;
					}

					$g_WarningPHP[$l_Prio][] = $i;
					$g_WarningPHPFragment[$l_Prio][] = getFragment($l_Content, $l_Pos);
				}

				// adware
				if (Adware($l_Filename, $l_Unwrapped, $l_Pos))
				{
					$g_AdwareList[] = $i;
					$g_AdwareListFragment[] = getFragment($l_Content, $l_Pos);
				}

				// critical
				if (CriticalPHP($l_Filename, $i, $l_Unwrapped, $l_Pos))
				{
					$g_CriticalPHP[] = $i;
					$g_CriticalPHPFragment[] = getFragment($l_Content, $l_Pos);
				}

				// critical JS
				$l_Pos = CriticalJS($l_Filename, $i, $l_Content);
				if ($l_Pos !== false)
				{
					$g_CriticalJS[] = $i;
					$g_CriticalJSFragment[] = getFragment($l_Content, $l_Pos);
				}

				if
				(stripos($l_Filename, 'index.php') ||
					stripos($l_Filename, 'index.htm') ||
					SCAN_ALL_FILES
				)
				{
					// check iframes
					if (preg_match_all('|<iframe.+?src.+?>|smi', $l_Unwrapped, $l_Found, PREG_SET_ORDER)) 
					{
						for ($kk = 0; $kk < count($l_Found); $kk++) {
						        $l_Pos = stripos($l_Found[$kk][0], 'http://');
							if  (($l_Pos !== false) && (!knowUrl($l_Found[$kk][0]))) {
         							$g_Iframer[] = $i;
         							$g_IframerFragment[] = getFragment($l_Found[$kk][0], $l_Pos);
							}
						}
					}

					// check empty links
					if (preg_match_all('|<a[^>]+href([^>]+?)>(.*?)</a>|smi', $l_Unwrapped, $l_Found, PREG_SET_ORDER))
					{
						for ($kk = 0; $kk < count($l_Found); $kk++) {
							if  ((stripos($l_Found[$kk][1], 'http://') !== false) &&
                                                            (trim(strip_tags($l_Found[$kk][2])) == '')) {

								$l_NeedToAdd = true;

							    if  ((stripos($l_Found[$kk][1], $default['site_url']) !== false)
                                                                 || knowUrl($l_Found[$kk][1])) {
										$l_NeedToAdd = false;
								}
								
								if ($l_NeedToAdd && (count($g_EmptyLink) < MAX_EXT_LINKS)) {
									$g_EmptyLink[] = $i;
									$g_EmptyLinkSrc[$i][] = substr($l_Found[$kk][0], 0, MAX_PREVIEW_LEN);
								}
							}
						}
					}
				}

				// check for PHP code inside any type of file
				if ((stripos($l_Filename, '.php') === false) && 
				    (stripos($l_Filename, '.phtml') === false))
				{
					$l_Pos = QCR_SearchPHP($l_Content);
					if ($l_Pos !== false)
					{
						$g_PHPCodeInside[] = $i;
						$g_PHPCodeInsideFragment[] = getFragment($l_Unwrapped, $l_Pos);
					}
				}

				// articles
				if (stripos($l_Filename, 'article_index'))
				{
					$g_AdwareSig[] = $i;
				}

				// unix executables
				if (strpos($l_Content, chr(127) . 'ELF') !== false) 
				{
                    $g_UnixExec[] = $i;
                }
				
				// htaccess
				if (stripos($l_Filename, '.htaccess'))
				{
				
				if (stripos($l_Content, 'index.php?name=$1') !== false ||
						stripos($l_Content, 'index.php?m=1') !== false
					)
					{
						$g_SuspDir[] = $i;
					}

					$l_Pos = stripos($l_Content, '^(%2d|-)[^=]+$');
					if ($l_Pos !== false)
					{
						$g_Redirect[] = $i;
                        $g_RedirectPHPFragment[] = getFragment($l_Content, $l_Pos);
					}

					$l_Pos = stripos($l_Content, '%{HTTP_USER_AGENT}');
					if ($l_Pos !== false)
					{
						$g_Redirect[] = $i;
                        $g_RedirectPHPFragment[] = getFragment($l_Content, $l_Pos);
					}


					if (
						preg_match_all('|(RewriteCond\s+%\{HTTP_HOST\}/%1 \!\^\[w\.\]\*\(\[\^/\]\+\)/\\\1\$\s+\[NC\])|smi', $l_Content, $l_Found, PREG_OFFSET_CAPTURE)
					   )
					{
						$g_Redirect[] = $i;
                        			$g_RedirectPHPFragment[] = getFragment($l_Content, $l_Found[0][1]);
					}
//

					$l_HTAContent = preg_replace('|^\s*#.+$|m', '', $l_Content);

					if (
						preg_match_all("|RewriteRule\s+.+?\s+http://(.+?)/.+\s+\[.*R=\d+.*\]|smi", $l_HTAContent, $l_Found, PREG_SET_ORDER)
					)
					{
						$l_Host = str_replace('www.', '', $_SERVER['HTTP_HOST']);
						for ($j = 0; $j < sizeof($l_Found); $j++)
						{
							$l_Found[$j][1] = str_replace('www.', '', $l_Found[$j][1]);
							if ($l_Found[$j][1] != $l_Host)
							{
								$g_Redirect[] = $i;
								break;
							}
						}
					}

					unset($l_HTAContent);
					
					$l_Pos = stripos($l_Content, 'auto_prepend_file');
					if ($l_Pos !== false) {
						$g_Redirect[] = $i;
						$g_RedirectPHPFragment[] = getFragment($l_Content, $l_Pos);
					}
					$l_Pos = stripos($l_Content, 'auto_append_file');
					if ($l_Pos !== false) {
						$g_Redirect[] = $i;
						$g_RedirectPHPFragment[] = getFragment($l_Content, $l_Pos);
					}

					if (preg_match("|RewriteRule\s+\^\(\.\*\)\$\s+-\s+\[\s*F\s*,\s*L\s*\]|smi", $l_Content, $l_Found)) {
						$g_Redirect[] = $i;
					}
				}
			}
			
			unset($l_Unwrapped);
			unset($l_Content);
			
			printProgress(++$_files_and_ignored, $l_Filename);
		} // end of if (file)

		usleep(SCAN_DELAY * 1000);

	} // end of for

}

///////////////////////////////////////////////////////////////////////////
function WarningPHP($l_FN, $l_Content, &$l_Pos)
{
  global $g_SusDB;

  $l_Res = false;


  foreach ($g_SusDB as $l_Item) {
    if (preg_match('#(' . $l_Item . ')#smi', $l_Content, $l_Found, PREG_OFFSET_CAPTURE)) {
       if (!CheckException($l_Content, $l_Found)) {
           $l_Pos = $l_Found[0][1];
//print  "\nSusDB $l_FN =" . $l_Item." l_Pos=" . $l_Pos . "\n";
           return true;
       }
    }
  }

  return $l_Res;
}

///////////////////////////////////////////////////////////////////////////
function Adware($l_FN, $l_Content, &$l_Pos)
{
  global $g_AdwareSig;

  $l_Res = false;

  foreach ($g_AdwareSig as $l_Item) {
    if (preg_match('#(' . $l_Item . ')#smi', $l_Content, $l_Found, PREG_OFFSET_CAPTURE)) {
       if (!CheckException($l_Content, $l_Found)) {
           $l_Pos = $l_Found[0][1];
//print  "\ng_AdwareSig $l_FN =" . $l_Item." l_Pos=" . $l_Pos . "\n";
           return true;
       }
    }
  }

  return $l_Res;
}

///////////////////////////////////////////////////////////////////////////
function CheckException(&$l_Content, &$l_Found) {
  global $g_ExceptFlex, $g_FlexDBShe, $g_DBShe, $g_Base64, $g_Base64Fragment;

   $l_FoundStrPlus = substr($l_Content, max($l_Found[0][1] - 10, 0), 70);

//print "Matched in " . $l_FN. "\n\n";
//print "==========> " . $l_Found[0][0]. "\r\n";

   foreach ($g_ExceptFlex as $l_ExceptItem) {
//print "\r\n" . $l_FoundStrPlus . " vs " . $l_ExceptItem."\r\n";

      if (preg_match('#(' . $l_ExceptItem . ')#smi', $l_FoundStrPlus, $l_Detected)) {
         $l_Exception = true;
//print "\r\n" . "****** EXCEPTION *************" . "\r\n";
         return true;
      }
   }

   return false;
}

///////////////////////////////////////////////////////////////////////////
function CriticalJS($l_FN, $l_Index, $l_Content)
{
  global $g_JSVirSig;

  $l_Res = false;

  foreach ($g_JSVirSig as $l_Item) {
    if (preg_match('#(' . $l_Item . ')#smi', $l_Content, $l_Found, PREG_OFFSET_CAPTURE)) {
       if (!CheckException($l_Content, $l_Found)) {
           $l_Pos = $l_Found[0][1];
//print "CriticalJS " . $l_FN . ' ' . $l_Item . ' l_Pos=' . $l_Pos . "\n";
           return $l_Pos;
       }
    }
  }

  return $l_Res;
}


///////////////////////////////////////////////////////////////////////////
function CriticalPHP($l_FN, $l_Index, $l_Content, &$l_Pos)
{
  global $g_ExceptFlex, $g_FlexDBShe, $g_DBShe, $g_Base64, $g_Base64Fragment;

  // LJHJLKJHLKJHJKLKJHJKLKJFGF

#var_dump($g_ExceptFlex);

  foreach ($g_FlexDBShe as $l_Item) {
    if (preg_match('#(' . $l_Item . ')#smi', $l_Content, $l_Found, PREG_OFFSET_CAPTURE)) {
//print "\r\nSIGNATURE: " . $l_Item . ''."\n\n";
//print "\r\nIN:" . $l_Found[0][0]. ']'."\n\n";
       if (!CheckException($l_Content, $l_Found)) {
//print "\r\n****** VIR *************\r\n";
           $l_Pos = $l_Found[0][1];
           return true;
       }
//unlink($l_FN);
    }
  }

  foreach ($g_DBShe as $l_Item) {
    $l_Pos = stripos($l_Content, $l_Item);
    if ($l_Pos !== false) {
//unlink($l_FN);
       return true;
    }
  }

  if (preg_match('#((include|require|require_once|include_once)\s*\(*\s*[\"\']http://.+?[\"\'])#smi', $l_Content, $l_Found)) {
     $g_Base64[] = $l_Index;
     $g_Base64Fragment[] = substr($l_Found[1], 0, MAX_PREVIEW_LEN);
  }

  // detect base64 suspicious
  if (preg_match('|([A-Za-z0-9+/]{' . BASE64_LENGTH . ',})|smi', $l_Content, $l_Found)) {
	        $l_ArrIgnore = array('doubl' => 5, 'must-r' => 6, 'retri' => 5);
                $l_StartOffset = 0;
                while (true) {
        		if (($l_Pos = stripos($l_Content, 'eval', $l_StartOffset)) !== false) {
        		        $l_Eval = true;

        		        foreach ($l_ArrIgnore as $l_Ignore => $l_Len) {
        		           $l_Start = max(0, $l_Pos - $l_Len);
        			   if (substr($l_Content, $l_Start, strlen($l_Ignore)) == $l_Ignore) {
                                      $l_Eval = false;
                                   }
                                }
        			
        			$l_NextLetter = ord($l_Content[$l_Pos + 4]);
        			if ($l_NextLetter >= 65 && $l_NextLetter <= 122) {
                                   $l_Eval = false;
                                }


        			if ($l_Eval) {
        			        if (!in_array($l_Index, $g_Base64)) {
        				   $g_Base64[] = $l_Index;
        				   $g_Base64Fragment[] = getFragment($l_Content, $l_Pos);
                                        }
        				break;
        			} 

				$l_StartOffset = $l_Pos + 1;
        		} else {
                            break;
                        }    
                } 

                if (preg_match('#(sort|array_map|create_function|base64_decode|gzip_decode|gzip_inflate|preg_replace_callback)\s*\(#smi', 
                      $l_Content, $l_Found, PREG_OFFSET_CAPTURE)) {
                      if ((!CheckException($l_Content, $l_Found)) && (!in_array($l_Index, $g_Base64))) {
			   $g_Base64[] = $l_Index;
			   $g_Base64Fragment[] = getFragment($l_Content, $l_Found[1][1]);
                        }
		}

  }
		
  

  if (preg_match('|eval\s*\(.+?\(.+?\(\s*implode|smi', $l_Content, $l_Found)) {
     $g_Base64[] = $l_Index;
     $g_Base64Fragment[] = getFragment($l_Content, $l_Pos);
  }

  // count number of base64_decode entries
  $l_Count = substr_count($l_Content, 'base64_decode');
  if ($l_Count > 10) {
     $g_Base64[] = $l_Index;
     $g_Base64Fragment[] = getFragment($l_Content, stripos($l_Content, 'base64_decode'));
  }

  return false;
}

///////////////////////////////////////////////////////////////////////////
if (!isCli()) {
   header('Content-type: text/html; charset=utf-8');
}

if (!isCli()) {

  $l_PassOK = false;
  if (strlen(PASS) > 8) {
     $l_PassOK = true;   
  } 

  if ($l_PassOK && preg_match('|[0-9]|', PASS, $l_Found) && preg_match('|[A-Z]|', PASS, $l_Found) && preg_match('|[a-z]|', PASS, $l_Found) ) {
     $l_PassOK = true;   
  }
  
  if (!$l_PassOK) {  
    print "Вы установили слабый пароль на скрипт AI-BOLIT. Укажите пароль не менее 8 символов, содержащий латинские буквы в верхнем и нижнем регистре, а также цифры. Например, такой <b>" . generatePassword() . "</b>";
    exit;
  }

  if (isset($_GET['fn']) && ($_GET['ph'] == crc32(PASS))) {
     printFile();
     exit;
  }

  if ($_GET['p'] != PASS) {
    print "Запустите скрипт с паролем, который установлен в переменной PASS (в начале файла). <br/>Например, так http://ваш_сайт_и_путь_до_скрипта/ai-bolit.php?p=<b>" .  generatePassword() . "</b>";
    exit;
  }
}

if (!is_readable(ROOT_PATH)) {
  print "Текущая директория не доступна для чтения скрипту. Пожалуйста, укажите права на доступ <b>rwxr-xr-x</b> или с помощью командной строки <b>chmod +r имя_директории</b>";
  exit;
}

if (isCli()) {
	if (defined('REPORT_PATH') AND REPORT_PATH)
	{
		if (!is_writable(REPORT_PATH))
		{
			die("\nCannot write report. Report dir " . REPORT_PATH . " is not writable.");
		}

		else if (!REPORT_FILE)
		{
			die("\nCannot write report. Report filename is empty.");
		}

		else if (($file = REPORT_PATH . DIR_SEPARATOR . REPORT_FILE) AND is_file($file) AND !is_writable($file))
		{
			die("\nCannot write report. Report file '$file' exists but is not writable.");
		}
	}
}


$g_IgnoreList = array();
$g_DirIgnoreList = array();
$g_UrlIgnoreList = array();
$g_KnownList = array();

$l_IgnoreFilename = '.aignore';
$l_DirIgnoreFilename = '.adirignore';
$l_UrlIgnoreFilename = '.aurlignore';
$l_KnownFilename = '.aknown';

if (file_exists($l_IgnoreFilename)) {
    $l_IgnoreListRaw = file($l_IgnoreFilename);
    for ($i = 0; $i < count($l_IgnoreListRaw); $i++) 
    {
    	$g_IgnoreList[] = explode("\t", trim($l_IgnoreListRaw[$i]));
    }
    unset($l_IgnoreListRaw);
}

if (file_exists($l_DirIgnoreFilename)) {
    $g_DirIgnoreList = file($l_DirIgnoreFilename);
	
	for ($i = 0; $i < count($g_DirIgnoreList); $i++) {
		$g_DirIgnoreList[$i] = trim($g_DirIgnoreList[$i]);
	}
}

if (file_exists($l_UrlIgnoreFilename)) {
    $g_UrlIgnoreList = file($l_UrlIgnoreFilename);
	
	for ($i = 0; $i < count($g_UrlIgnoreList); $i++) {
		$g_UrlIgnoreList[$i] = trim($g_UrlIgnoreList[$i]);
	}
}


if ($l_DIRH = @opendir('.'))
{
	while ($l_FileName = readdir($l_DIRH))
	{
		if ($l_FileName == '.' || $l_FileName == '..') continue;
		   if (strpos($l_FileName, $l_KnownFilename) !== false) {
                       $g_KnownListTmp = file($l_FileName);
                     	for ($i = 0; $i < count($g_KnownListTmp); $i++) {
                     		$g_KnownListTmp[$i] = trim($g_KnownListTmp[$i]);
                     	}

                        $g_KnownList = array_merge($g_KnownListTmp, $g_KnownList);
                   }
	}
}

closedir($l_DIRH);

stdOut("Loaded " . count($g_KnownList) . ' known files');

stdOut("Start scanning '" . ROOT_PATH . "'.");

QCR_Debug();

QCR_ScanDirectories(ROOT_PATH);

$g_FoundTotalFiles = count($g_Structure['n']);

QCR_Debug();

stdOut("Founded $g_FoundTotalFiles files in $g_FoundTotalDirs directories.");

$g_FoundTotalFiles = count($g_Structure['n']);
QCR_GoScan(0);

QCR_Debug();

////////////////////////////////////////////////////////////////////////////

$l_Result .= "<div class=\"sec\"><b>Отчет по " . (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : realpath('.')) . "</b></div>";

$time_tacked = seconds2Human(microtime(true) - START_TIME);

$l_Result .= "<div class=\"rep\">Известно ". (count($g_DBShe) + count($g_FlexDBShe)) ." шелл-сигнатур, а также " . (count($g_SusDB) + count($g_AdwareSig ) + count($g_JSVirSig)). " других вредоносных фрагментов. Затрачено времени: <b>$time_tacked</b
>.<br/>Сканирование начато: " . date('d-m-Y в H:i:s', floor(START_TIME)) . ". Сканирование завершено: " . date('d-m-Y в H:i:s') . ".</div> ";

$l_Result .= "<div class=\"rep\">Всего проверено $g_TotalFolder директорий и $g_TotalFiles файлов.</div>";

if (!$defaults['scan_all_files']) {
	$l_Result .= '<div class="rep" style="color: #0000A0">Внимание, скрипт выполнил быструю проверку сайта. Проверяются только наиболее критические файлы, но часть вредоносных скриптов может быть не обнаружена. Пожалуйста, запустите скрипт из командной строки для выполнения полного тестирования. Подробнее смотрите в <a href="http://revisium.com/ai/faq.php">FAQ вопрос №10</a>.</div>';
}

$l_Result .= "<div class=\"sec\">Критические замечания</div>";

$l_ShowOffer = false;

stdOut("\nBuilding report\n");

stdOut("Building list of shells " . count($g_CriticalPHP));

if (count($g_CriticalPHP) > 0) {
  $l_Result .= "<div class=\"vir\"><b>Найдены сигнатуры шелл-скрипта. Подозрение на вредоносный скрипт:</b>";
  $l_Result .= printList($g_CriticalPHP, $g_CriticalPHPFragment, true);
  $l_Result .= "</div>";

  $l_ShowOffer = true;
} else {
  $l_Result .= '<div class="ok"><b>Шелл-скрипты не найдены.</b></div>';
}

stdOut("Building list of js " . count($g_CriticalJS));

if (count($g_CriticalJS) > 0) {
  $l_Result .= "<div class=\"vir\"><b>Найдены сигнатуры javascript вирусов:</b>";
  $l_Result .= printList($g_CriticalJS, $g_CriticalJSFragment, true);
  $l_Result .= "</div>";

  $l_ShowOffer = true;
}

stdOut("Building list of unix executables " . count($g_UnixExec));

if (count($g_UnixExec) > 0) {
  $l_Result .= "<div class=\"vir\"><b>Найдены сигнатуры исполняемых файлов unix. Они могут быть вредоносными файлами:</b>";
  $l_Result .= printList($g_UnixExec, '', true);
  $l_Result .= "</div>";

  $l_ShowOffer = true;
}

stdOut("Building list of base64s " . count($g_Base64));

if (count($g_Base64) > 0) {
  $l_ShowOffer = true;

  $l_Result .= "<div class=\"vir\"><b>Найдены длинные зашифрованные последовательности в PHP или подключение внешних файлов. Подозрение на вредоносный скрипт:</b>";
  $l_Result .= printList($g_Base64, $g_Base64Fragment, true);
  $l_Result .= "</div>";

}

stdOut("Building list of iframes " . count($g_Iframer));

if (count($g_Iframer) > 0) {
  $l_ShowOffer = true;

  $l_Result .= "<div class=\"vir\"><b>Подозрение на вредоносный скрипт:</b>";
  $l_Result .= printList($g_Iframer, $g_IframerFragment, true);
  $l_Result .= "</div>";

}


stdOut("Building list of symlinks " . count($g_SymLinks));

if (count($g_SymLinks) > 0) {

  $l_Result .= "<div class=\"warn\"><b>Список файловых ссылок (symlinks):</b><br>";
  $l_Result .= implode("<br>", $g_SymLinks);
  $l_Result .= "</div>";

}

stdOut("Building list of hidden files " . count($g_HiddenFiles));

if (count($g_HiddenFiles) > 0) {

  $l_Result .= "<div class=\"warn\"><b>Список скрытых файлов:</b><br>";
  $l_Result .= implode("<br>", $g_HiddenFiles);
  $l_Result .= "</div>";

}


stdOut("Building list of susp dirs " . count($g_SuspDir));

if (count($g_SuspDir) > 0) {

  $l_Result .= "<div class=\"vir\"><b>Скорее всего этот файл лежит в каталоге с дорвеем:</b><br>";
  $l_Result .= printList($g_SuspDir);
  $l_Result .= "</div>";

} else {

  $l_Result .= '<div class="ok"><b>Не найдено директорий c дорвеями</b></div>';

}
 

stdOut("Building list of redirects " . count($g_Redirect));

$l_Result .= "<div class=\"sec\">Предупреждения</div>";

if (count($g_Redirect) > 0) {

  $l_ShowOffer = true;
  $l_Result .= "<div class=\"warn\"><b>Опасный код в .htaccess (редирект на внешний сервер, подмена расширений или автовнедрение кода):</b>";
  $l_Result .= printList($g_Redirect, $g_RedirectPHPFragment, true);
  $l_Result .= "</div>";

}

stdOut("Building list of php inj " . count($g_PHPCodeInside));

if ((count($g_PHPCodeInside) > 0) && (($defaults['report_mask'] & REPORT_MASK_PHPSIGN) == REPORT_MASK_PHPSIGN)) {

  $l_ShowOffer = true;
  $l_Result .= "<div class=\"warn\"><b>В не .php файле содержится стартовая сигнатура PHP кода. Возможно, там вредоносный код:</b>";
  $l_Result .= printList($g_PHPCodeInside, $g_PHPCodeInsideFragment, true);
  $l_Result .= "</div>";

}

stdOut("Building list of adware " . count($g_AdwareList));

if (count($g_AdwareList) > 0) {
  $l_ShowOffer = true;

  $l_Result .= "<div class=\"warn\"><b>В этих файлах размещен код по продаже ссылок. Убедитесь, что размещали его вы:</b>";
  $l_Result .= printList($g_AdwareList, $g_AdwareListFragment, true);
  $l_Result .= "</div>";

}

stdOut("Building list of unread files " . count($g_NotRead));

if (count($g_NotRead) > 0) {

  $l_ShowOffer = true;
  $l_Result .= "<div class=\"warn\"><b>Непроверенные файлы - ошибка чтения:</b>";
  $l_Result .= printList($g_NotRead);
  $l_Result .= "</div>";

}
stdOut("Building list of empty links " . count($g_EmptyLink));
if ((count($g_EmptyLink) > 0) && (($defaults['report_mask'] & REPORT_MASK_SPAMLINKS) == REPORT_MASK_SPAMLINKS)) {
  $l_ShowOffer = true;
  $l_Result .= "<div class=\"warn\"><b>В этих файлах размещены невидимые ссылки. Подозрение на ссылочный спам:</b>";
  $l_Result .= printList($g_EmptyLink, '', true);

  $l_Result .= 'Список невидимых ссылок:<br/>';
  
  if (count($g_EmptyLink) == MAX_EXT_LINKS) {
      $l_Result .= '(Отображены только первые ' . MAX_EXT_LINKS . ')<br/>';
    }
   
  for ($i = 0; $i < count($g_EmptyLink); $i++) {
	$l_Idx = $g_EmptyLink[$i];
    for ($j = 0; $j < count($g_EmptyLinkSrc[$l_Idx]); $j++) {
      $l_Result .= '<span class="details">' . $g_Structure['n'][$g_EmptyLink[$i]] . ' &rarr; ' . htmlspecialchars($g_EmptyLinkSrc[$l_Idx][$j]) . '</span><br/>';
	}
  }

  $l_Result .= "</div>";

}

stdOut("Building list of doorways " . count($g_Doorway));

if ((count($g_Doorway) > 0) && (($defaults['report_mask'] & REPORT_MASK_DOORWAYS) == REPORT_MASK_DOORWAYS)) {
  $l_ShowOffer = true;

  $l_Result .= "<div class=\"warn\"><b>Найдены директории, в которых подозрительно много файлов .php или .html. Подозрение на дорвей:</b>";
  $l_Result .= printList($g_Doorway);
  $l_Result .= "</div>";

}

stdOut("Building list of php warnings " . (count($g_WarningPHP[0]) + count($g_WarningPHP[1])));

if (($defaults['report_mask'] & REPORT_MASK_SUSP) == REPORT_MASK_SUSP) {
   if ((count($g_WarningPHP[0]) + count($g_WarningPHP[1])) > 0) {
     $l_ShowOffer = true;

     $l_Result .= "<div class=\"warn\"><b>Скрипт использует код, который часто используются во вредоносных скриптах:</b>";

     for ($i = 0; $i < count($g_WarningPHP); $i++) {
         if (count($g_WarningPHP[$i]) > 0) $l_Result .= printList($g_WarningPHP[$i], $g_WarningPHPFragment[$i], true);
     }
     $l_Result .= "</div>";

   } 
}

stdOut("Building list of skipped dirs " . count($g_SkippedFolders));
if (count($g_SkippedFolders) > 0) {
     $l_Result .= "<div class=\"warn2\"><b>Директории из файла .adirignore были пропущены при сканировании:</b><br/>";
     $l_Result .= implode("<br>", $g_SkippedFolders);
     $l_Result .= "</div>";
 }

 stdOut("Building list of writeable dirs " . count($g_WritableDirectories));

if (count($g_CMS) > 0) {
     $l_Result .= "<div class=\"warn2\"><b>Версии найденных CMS:</b><br/>";
     $l_Result .= implode("<br>", $g_CMS);
     $l_Result .= "</div>";
}

if (!isCli()) {
   $l_Result .= QCR_ExtractInfo($l_PhpInfoBody[1]);
}

$max_size_to_scan = getBytes(MAX_SIZE_TO_SCAN);
$max_size_to_scan = $max_size_to_scan > 0 ? $max_size_to_scan : getBytes('1m');

stdOut("Building list of bigfiles " . count($g_BigFiles));

if (count($g_BigFiles) > 0) {

  $l_Result .= "<div class=\"warn2\"><b>Большие файлы (больше чем " . bytes2Human($max_size_to_scan) . "! Пропущено:</b>";
  $l_Result .= printList($g_BigFiles);
  $l_Result .= "</div>";

} else {
  if (SCAN_ALL_FILES) {
	$l_Result .= '<div class="ok"><b>Не найдено файлов больше чем ' . bytes2Human($max_size_to_scan) . '</b></div>';
  }
}

stdOut("Building list of sensitive files " . count($g_UnsafeFilesFound) . "\n");

if ((count($g_UnsafeFilesFound) > 0) && (($defaults['report_mask'] & REPORT_MASK_CANDI) == REPORT_MASK_CANDI)) {
  $l_Result .= "<div class=\"warn2\"><b>Временные файлы или файлы(каталоги)-кандидаты на удаление по ряду причин:</b>";
  $l_Result .= printList($g_UnsafeFilesFound);
  $l_Result .= "</div>";
}

if (!$defaults['no_rw_dir']) {
   if ((($defaults['report_mask'] & REPORT_MASK_WRIT) == REPORT_MASK_WRIT)) {
      if ((count($g_WritableDirectories) > 0)) {

        $l_Result .= "<div class=\"warn2\"><b>Потенциально небезопасно! Директории, доступные скрипту на запись:</b>";
        $l_Result .= printList($g_WritableDirectories);
        $l_Result .= "</div>";

      } else {

        $l_Result .= '<div class="ok"><b>Не найдено директорий, доступных на запись скриптом</b></div>';

      }
   }
}

if (function_exists('memory_get_peak_usage')) {
  $l_Result .= 'Использовано памяти при сканировании: ' . bytes2Human(memory_get_peak_usage()) . '<p>';
}

$l_Result .= '<div id="igid" style="display: none;"><div class="sec">Добавить в список игнорируемых</div>';
$l_Result .= '<form name="ignore"><textarea name="list" style="width: 600px; height: 400px;"></textarea></form>';
$l_Result .= '<div class="details">Скопируйте этот список и вставьте его в файл .aignore, чтобы исключить эти файлы из отчета.</div></div>';

if (!SCAN_ALL_FILES) {
  $l_Result .= '<div class="notice"><span class="vir">[!]</span> В скрипте отключено полное сканирование файлов, проверяются только .php, .html, .htaccess. Чтобы выполнить более тщательное сканирование, <br/>поменяйте значение настройки на <b>\'scan_all_files\' => 1</b> в самом верху скрипта. Скрипт в этом случае может работать очень долго. Рекомендуется отключить на хостинге лимит по времени выполнения, либо запускать скрипт из командной строки.</div>';
}

$l_Result .= '<div class="footer"><div class="disclaimer"><span class="vir">[!]</span> Отказ от гарантий: даже если скрипт не нашел вредоносных скриптов на сайте, автор не гарантирует их полное отсутствие, а также не несет ответственности за возможные последствия работы скрипта ai-bolit.php или неоправданные ожидания пользователей относительно функциональности и возможностей.</div>';
$l_Result .= '<div class="thanx">Замечания и предложения по работе скрипта присылайте на <a href="mailto:audit@revisium.com">audit@revisium.com</a>.<p>Также буду чрезвычайно благодарен за любые упоминания скрипта ai-bolit на вашем сайте, в блоге, среди друзей, знакомых и клиентов. Ссылочку можно поставить на <a href="http://revisium.com/ai/">http://revisium.com/ai/</a>. <p>Если будут вопросы - пишите <a href="mailto:audit@revisium.com">audit@revisium.com</a>. Кстати, еще я написал <a href="http://sale.qpl.ru/">скрипт доски объявлений</a> и собрал точную <a href="http://gzq.ru/">базу IP</a> по городам России.</div>';
$l_Result .= '</div>';

$l_OfferVK = '<p>Если у вас есть эккаунт ВКонтакте, приглашаю в <a href="http://vk.com/siteprotect" target=_blank>группу "Безопасность Веб-сайтов"</a>: там я делюсь опытом защиты веб-сайтов и поиска вредоносных скриптов.</p>' ;
              
if ($l_ShowOffer) {
  $l_Result .= '<div class="offer" id="ofr">' .
        '<span style="font-size: 15px;"><a href="http://www.revisium.com/ru/order/" target="_blank">Лечение сайта от вирусов. Защита от взлома. Гарантия.</a></span><br/>' .
        '<p>Быстро и качественно вылечу ваш сайт от вирусов, удалю вредоносный код с сайта, проведу мероприятия по защите сайта от взлома, выполню проверку сервера на "рутования", пентест сайтов. <a href="http://www.revisium.com/ru/order/">Пишите</a>.</p>' .
        '<a href="http://www.revisium.com/ru/order/" target="_blank">www.revisium.com &rarr;</a><p>' .
        '<p>Также приглашаю в <a href="http://vk.com/siteprotect" style="color: white" target="_blank">группу ВКонтакте: "Безопасность Веб-сайтов"</a>' .
        '<p><a href="#" onclick="document.getElementById(\'ofr\').style.display=\'none\'" style="color: #303030">[x] закрыть сообщение</a></p>' .
        '</div>';
} else {
  $l_Result .= '<div class="offer2" id="ofr2">' . $l_OfferVK .
        '<p><a href="#" onclick="document.getElementById(\'ofr2\').style.display=\'none\'" style="color: #303030">[x] закрыть сообщение</a></p>' .
        '</div>';
}
////////////////////////////////////////////////////////////////////////////

if (!isCli())
{
	echo $l_Result;
	exit;
}

if (!defined('REPORT') OR REPORT === '')
{
	die('Report not written.');
}
 
$emails = getEmails(REPORT);

if (!$emails) {
	if ($l_FH = fopen($file, "w")) {
	   fputs($l_FH, $l_Result);
	   fclose($l_FH);
	   stdOut("\nReport written to '$file'.");
	} else {
		stdOut("\nCannot create '$file'.");
	}
}	else	{
		$headers = array(
			'MIME-Version: 1.0',
			'Content-type: text/html; charset=UTF-8',
			'From: ' . ($defaults['email_from'] ? $defaults['email_from'] : 'AI-Bolit@myhost')
		);

		for ($i = 0, $size = sizeof($emails); $i < $size; $i++)
		{
			mail($emails[$i], 'AI-Bolit Report ' . date("d/m/Y H:i", time()), $l_Result, implode("\r\n", $headers));
		}

		stdOut("\nReport sended to " . implode(', ', $emails));
}


$time_taken = microtime(true) - START_TIME;
$time_taken = number_format($time_taken, 5);

stdOut("Scanning complete! Time taken: " . seconds2Human($time_taken));

stdOut("\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
stdOut("Attention! DO NOT LEAVE either ai-bolit.php or AI-BOLIT-REPORT-<xxxx>-<yy>.html \nfile on server. COPY it locally then REMOVE from server. ");
stdOut("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");

QCR_Debug();

?>
