All pastes #570345 Raw Edit

Miscellany

public text v1 · immutable
·published 2007-06-16 17:30 UTC
rendered paste body
<?php
/***************************************************************************
 * File: admin_logs_system.php
 * CCIP Version: 0.4.0
 * copyright: (C) 2002 - 2005 The CodeCrush Brothers
 * Author: kris@codecrush.com
 * begin: Monday, May 6, 2002
 * Note: CodeCrush Log System - based on CodeCrush IP Log mod
 ***************************************************************************
/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

define('IN_PHPBB', 1);

if( !empty($setmodules) )
{
	$file = basename(__FILE__);
	$module['Logs']['Admin_Log'] = $file . '?db=4';
	$module['Logs']['Moderator_log'] = $file . '?db=5';
	$module['Logs']['Visits_log'] = $file . '?db=1';
	$module['Logs']['Warning_log'] = $file . '?db=2';
	$module['Logs']['Error_log'] = $file . '?db=3';
	return;
}

//
// Load default header
//
$phpbb_root_path = "../";
require($phpbb_root_path . 'extension.inc');
require('pagestart.' . $phpEx);
include($phpbb_root_path . 'includes/functions_admin.'.$phpEx);
//include_once($phpbb_root_path . 'includes/functions_log.'.$phpEx);
include($phpbb_root_path . 'language/lang_' . $board_config['default_lang'] . '/lang_logs.' . $phpEx);

if( $userdata['user_level'] != ADMIN )
{
	Header("Location: " . $phpbb_root_path . "login.php");
	exit;  /* Make sure that code below does not get executed when we redirect. */
}



//
// Load Logs configuration
//
$log_config = get_log_config(CCLOG_CONFIG, 0); // returns array: name->value


// Variables
$ip_list = array(); // some other mods aparently use this var! make sure we initiate it! (thanx to Marie)
$mode = '';
$user_batch = '';
$ip_batch = '';
$log_db = 1;
$per_page = $log_config['per_page'];
$start = 0; //default - start is a record value - we need to convert jump_page to record later on
$jump_page = 1; // default to first page


if( isset($HTTP_GET_VARS['mode']) || isset($HTTP_POST_VARS['mode']) )
{
	$mode = ($HTTP_GET_VARS['mode']) ? htmlspecialchars($HTTP_GET_VARS['mode']) : htmlspecialchars($HTTP_POST_VARS['mode']);
}

$params = array('mode' => 'mode', 'sort_key' => 'sk', 'sort_order' => 'sd', 'user_batch' => 'ub', 'ip_batch' => 'ipb');
while( list($var, $param) = @each($params) )
{
	if ( !empty($HTTP_POST_VARS[$param]) || !empty($HTTP_GET_VARS[$param]) )
    {
		$$var = ( !empty($HTTP_POST_VARS[$param]) ) ? htmlspecialchars($HTTP_POST_VARS[$param]) : htmlspecialchars($HTTP_GET_VARS[$param]);
    }
    else
    {
		$$var = '';
    }
}

$params = array('log_db' => 'db', 'per_page' => 'pp', 'dayspan' => 'st', 'jump_page' => 'jump_page');
while( list($var, $param) = @each($params) )
{
	if ( !empty($HTTP_POST_VARS[$param]) || !empty($HTTP_GET_VARS[$param]) )
    {
		$$var = ( !empty($HTTP_POST_VARS[$param]) ) ? intval($HTTP_POST_VARS[$param]) : intval($HTTP_GET_VARS[$param]);
    }
    else
    {
		$$var = 0;
    }
}

$use_timespan = (!empty($HTTP_POST_VARS['use_timespan'])) ? 'checked=checked' : '';

// some defaults
$sort_key = ($sort_key == '') ? 't' : $sort_key;
$sort_order = ($sort_order == '') ? 'd' : $sort_order;
$jump_page = ($jump_page == 0) ? 1 : $jump_page;

//dump_ary($HTTP_POST_VARS);

// Remember which log/db-table we're viewing
$template->assign_vars(array(
	'U_LOG_DB' => $log_db,
	'U_SEARCH_USER' => $phpbb_root_path . 'cc_select.' . $phpEx . '?sid=' .
	$userdata['session_id'] . '&mode=ccip&db=' . $log_db,
	'U_SEARCH_IP' => $phpbb_root_path . 'cc_select.' . $phpEx . '?sid=' .
    $userdata['session_id'] . '&mode=ccip2&db=' . $log_db,
	'S_LOG_ACTION' => append_sid("admin_logs_system.$phpEx")
));

// We need the numeric log_db value for URLs etc
$log_db_num = $log_db;

// Which DB-table/log is this?
switch($log_db) {
	case 1:
		$log_db = CCLOG_VISIT;
		$lang_log_title = $lang['Log_Title1'];
		$lang_log_text = $lang['Log_Text1'];
		break;
	case 2:
		$log_db = CCLOG_WARNING;
		$lang_log_title = $lang['Log_Title2'];
		$lang_log_text = $lang['Log_Text2'];
		break;
	case 3:
		$log_db = CCLOG_ERROR;
		$lang_log_title = $lang['Log_Title3'];
		$lang_log_text = $lang['Log_Text3'];
		break;
	case 4:
		$log_db = CCLOG_ADMIN;
		$lang_log_title = $lang['Log_Title4'];
		$lang_log_text = $lang['Log_Text4'];
		break;
	case 5:
		$log_db = CCLOG_MOD;
		$lang_log_title = $lang['Log_Title5'];
		$lang_log_text = $lang['Log_Text5'];
		break;
	default:
		$log_db = CCLOG_VISIT;
		$lang_log_title = $lang['Log_Title1'];
		$lang_log_text = $lang['Log_Text1'];
}


$ip_pattern = "/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/";
$ip_pattern_match = "/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/";
$ip_pattern_replace = "/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/";


//
// Check if user did or did not confirm
//
if ( isset($HTTP_POST_VARS['cancel']) )
{
	$mode = 'gen';
}

//
// (Semi-)Auto Pruning - v.0.3.1 -
//
$cc_pruned_rows = 0;
if( ($log_config['auto_prune'] == 1) )
{
	// "automagicly" delete records from the db older than $log_config['auto_prune_age'] days.
	$cc_xdays_ago = date("YmdHis",
						 mktime(0,0,0,date("m"),date("d")-$log_config['auto_prune_age'],date("Y")));
	//printf("TS xdays: %s<br>", $cc_xdays_ago);
	$sql = "DELETE FROM $log_db WHERE logged < $cc_xdays_ago";
	if ( !$db->sql_query($sql) )
	{
    	message_die(GENERAL_ERROR, 'Could not prune entries', '', __LINE__, __FILE__, $sql);
    }
	$cc_pruned_rows = $db->sql_affectedrows();
}



if($mode == 'delete') {

	//
	// Admin check
	//
	if($log_config['cc_log_admins'] != '')
	{
		$cc_log_admins = array();
		$cc_log_admins = explode(",", $log_config['cc_log_admins']);
		if(!in_array($userdata['session_user_id'], $cc_log_admins)) {
			message_die(GENERAL_ERROR, 'Not allowed to administer logs', '', __LINE__, __FILE__, $userdata['username']);
			exit;
		}
		unset($cc_log_admins);
	}

	$confirm = ( $HTTP_POST_VARS['confirm'] ) ? TRUE : 0;
    $delete = ( isset($HTTP_POST_VARS['delete']) ) ? TRUE : FALSE;

    if ( $confirm )
	{
    	if ( empty($HTTP_POST_VARS['entry_id_list']) )
		{
			message_die(GENERAL_MESSAGE, $lang['None_selected']);
		}
		$entries = $HTTP_POST_VARS['entry_id_list'];

		$entry_id_sql = '';
		for($i = 0; $i < count($entries); $i++)
		{
			$entry_id_sql .= ( ( $entry_id_sql != '' ) ? ', ' : '' ) . intval($entries[$i]);
		}

        $sql = "DELETE FROM $log_db
				WHERE log_id IN ($entry_id_sql)";
		if ( !$db->sql_query($sql) )
		{
			message_die(GENERAL_ERROR, 'Could not delete entries', '', __LINE__, __FILE__, $sql);
		}

		$redirect_page = "admin_logs_system.{$phpEx}?db={$log_db_num}&sid=" . $userdata['session_id'];
		$l_redirect = sprintf($lang['Click_return_ip'], '<a href="' . $redirect_page . '">', '</a>');

		$template->assign_vars(array(
			'META' => '<meta http-equiv="refresh" content="3;url=' . $redirect_page . '">')
		);

		message_die(GENERAL_MESSAGE, $lang['Entries_Removed'] . '<br /><br />' . $l_redirect);

    }
	else
	{
		// Not confirmed, show confirmation message
		if ( empty($HTTP_POST_VARS['entry_id_list']) )
		{
			message_die(GENERAL_MESSAGE, $lang['None_selected']);
		}

		$hidden_fields = '<input type="hidden" name="sid" value="' . $userdata['session_id'] . '" /><input type="hidden" name="mode" value="' . $mode . '" /><input type="hidden" name="db" value="' . $log_db_num . '" />';

		if ( isset($HTTP_POST_VARS['entry_id_list']) )
		{
			$entries = $HTTP_POST_VARS['entry_id_list'];
			for($i = 0; $i < count($entries); $i++)
			{
				$hidden_fields .= '<input type="hidden" name="entry_id_list[]" value="' . intval($entries[$i]) . '" />';
			}
		}

		//
		// Set template files
		//
		$template->set_filenames(array(
			'body' => 'admin/adm_confirm_body.tpl'
        ));

		$template->assign_vars(array(
			'MESSAGE_TITLE' => $lang['Confirm'],
			'MESSAGE_TEXT' => $lang['Confirm_delete_entries'],
			'L_NO' => $lang['No'],
			'S_CONFIRM_ACTION' => append_sid("admin_logs_system.$phpEx"),
			'S_HIDDEN_FIELDS' => $hidden_fields)
		);
	}
}
else //if( $mode == 'gen' || $mode == 'simple')
{
    //
    // 0.3.0 - batch jobs
    //
	$user_batch_ary   = array();
    $ip_batch_ary   = array();
    $sql_user = '';
    $sql_span_start = '';
    $sql_span_end = '';

    if(!empty($user_batch))
    {
        // Clean up the batch and prepare a string for url pagination
        $user_batch_ary = explode(";", $user_batch);

		foreach($user_batch_ary as $key => $value)
        {
        	//strip leading whitespace (incase someone types like: dar; kris; someone..)
            $value = ltrim($value);
            if(!empty($value))
            {
                // add wildcards
				$sql_user .= ( ( empty($sql_user) ) ? '' : ' OR ' ) . "username LIKE '" . preg_replace('/\*/', '%', $value) ."'";
            }
		}
    }
    if(!empty($ip_batch))
    {
        //$word2 = preg_replace("$ip_pattern", "$1 <br>", $word);
        preg_match_all($ip_pattern, $ip_batch, $matches);
        $ip_batch_ary = $matches[0];
        unset($matches);

        // Include C- and B- net matches?
        if( isset($HTTP_POST_VARS['ip_cnet']) || isset($HTTP_GET_VARS['ip_cnet']) || isset($HTTP_POST_VARS['ip_bnet']) || isset($HTTP_GET_VARS['ip_bnet']) )
        {
        	foreach($ip_batch_ary as $i => $value)
        	{
        		// If we include B-net matches then there's no need to test for full-IP or C-net matches
				if(isset($HTTP_POST_VARS['ip_bnet']) || isset($HTTP_GET_VARS['ip_bnet']))
				{
					// remember setting - B-net matching implies C-net matching
					$template->assign_vars(array(
						'S_IP_BNET' => 'checked="checked"',
						'S_IP_CNET' => 'checked="checked"'
					));
					$ip_batch_ary[$i] = preg_replace($ip_pattern_match, "$1.$2.%.%", $value);
				} else {
					// remember setting
					$template->assign_var('S_IP_CNET', 'checked="checked"'); // assign 1 var
					$ip_batch_ary[$i] = preg_replace($ip_pattern_match, "$1.$2.$3.%", $value);
				}
			}
        }
	}

	//
	// Olympus style Select-boxes
	//
	$s_limit_days = $s_sort_key = $s_sort_order = $s_ip_per_page = '';

	$limit_days = array(0 => $lang['ALL_ENTRIES'], 1 => $lang['1_DAY'], 7 => $lang['7_DAYS'], 14 => $lang['2_WEEKS'], 30 => $lang['1_MONTH'], 90 => $lang['3_MONTHS'], 180 => $lang['6_MONTHS'], 365 => $lang['1_YEAR']);
    $sort_by_text = array('u' => $lang['SORT_USERNAME'], 't' => $lang['SORT_DATE'], 'i' => $lang['SORT_IP'], 'o' => $lang['SORT_ACTION']);
    $sort_by_sql = array('u' => 'username', 't' => 'logged', 'i' => 'user_ip', 'o' => 'log_code');

	$s_limit_days = n7_gen_select_box($limit_days, 'st', $dayspan);
	$s_sort_key = n7_gen_select_box($sort_by_text, 'sk', $sort_key);
	$s_sort_order = n7_gen_select_box(array('a' => $lang['Ascending'], 'd' => $lang['Descending']), 'sd', $sort_order);

   	//
   	// Build the per-page select-box
   	//
   	$s_ip_per_page = n7_gen_select_box(array($log_config['per_page'] => $log_config['per_page'], 50 => 50, 100 => 100, 200 => 200, 400 => 400), 'pp', $per_page);
   	// override config per_page
   	$log_config['per_page'] = ($per_page > 0) ? $per_page : $log_config['per_page'];


   	//
   	// Get/Set the datespan (taken from admin_ip_stats)
   	//
   	$sql_start = "SELECT logged FROM $log_db ORDER BY log_id ASC LIMIT 1";
   	$sql_end = "SELECT logged FROM $log_db ORDER BY log_id DESC LIMIT 1";
   	$sql_span_start = $sql_span_end = '';

   	//
   	// Get the log start date
   	//
   	if ( !($result = $db->sql_query($sql_start)) )
   	{
		message_die(GENERAL_ERROR, 'Could not get the start date', '', __LINE__, __FILE__, $sql_start);
   	}
   	$first_row = $db->sql_fetchrow($result); //get first row
   	$start_date = $first_row['logged']; // some db configurations don't populate the numerical array
	$db->sql_freeresult($result);

   	//
   	// Get the log end date
   	//
   	if ( !($result = $db->sql_query($sql_end)) )
   	{
    	message_die(GENERAL_ERROR, 'Could not get the end date', '', __LINE__, __FILE__, $sql_end);
   	}
   	$first_row = $db->sql_fetchrow($result); //get first row
	$end_date = $first_row['logged']; // see start_date comment
   	$db->sql_freeresult($result);

	if($use_timespan)
	{
    	if( isset($HTTP_GET_VARS['span_start']) || isset($HTTP_POST_VARS['span_start']) )
      	{
        	$sql_span_start = ($HTTP_GET_VARS['span_start']) ? intval(preg_replace('/\//', '', $HTTP_GET_VARS['span_start'])) : intval(preg_replace('/\//', '', $HTTP_POST_VARS['span_start']));
      	} else {
        	$sql_span_start = substr($start_date, 0, 8);
      	}
      	if( isset($HTTP_GET_VARS['span_end']) || isset($HTTP_POST_VARS['span_end']) )
      	{
        	$sql_span_end = ($HTTP_GET_VARS['span_end']) ? intval(preg_replace('/\//', '', $HTTP_GET_VARS['span_end'])) : intval(preg_replace('/\//', '', $HTTP_POST_VARS['span_end']));
      	} else {
        	$sql_span_end = substr($end_date, 0, 8);
      	}
      	$sql_span_start .= '000000';
      	$sql_span_end .= '235959';
	}
	elseif($dayspan > 0)
	{
		// Use dayspan
		// end is today
		$sql_span_end = date("YmdHis");
		// start is x days ago
		$sql_span_start = date("YmdHis", mktime(0, 0, 0, date("m"), date("d")-$dayspan, date("Y")));
	}

    //
    // Prepare sql
    //
    $sql_ipdec = '';
	$ip_debug_listing = ''; // mainly for debugging
    if(!empty($ip_batch_ary))
    {
		//foreach($ip_batch_ary as $ip => $iphex)
		foreach($ip_batch_ary as $i => $ip)
        {
			// listings mainly for debugging
			$ip_debug_listing .= ( ( !empty($ip_debug_listing) ) ? '; ' : '' ) . $ip;

            $sql_ipdec .= ( (empty($sql_ipdec)) ? '':' OR ' ) . "user_ip LIKE '" . $ip . "' OR env_x_forwarded_for LIKE '%" . $ip . "%'";
        }
        // unfortunately the IN () clause doesn't understand wildcards (%) - going back to LIKE
		// 'user_ip IN (' . $sql_iphex . ') OR proxy_ip IN (' . $sql_ipdec . ')';
    }



    // the main call - users with newer mysql servers could benefit by using SELECT SQL_BUFFER_RESULT * FROM cc_ip_log
    $sql = "SELECT * FROM $log_db";
    $sql_span = (empty($sql_span_start) || empty($sql_span_end)) ? '' : " WHERE logged >= $sql_span_start AND logged <= $sql_span_end";
    //$sql_db = " WHERE logged >= $sql_span_start AND logged <= $sql_span_end";

	$sql_ipuser = '';
	if(!empty($sql_ipdec)) {
		$sql_ipuser = $sql_ipdec;
	}
	if(!empty($sql_user)) {
    	$sql_ipuser .= ( ( $sql_ipuser != '' ) ? ' OR ' : ' ' ) . $sql_user;
    }

    if($sql_ipuser != '') {
    	$sql .= ($sql_span != '') ? $sql_span . ' AND ' . $sql_ipuser : ' WHERE ' . $sql_ipuser;
    } else {
    	$sql .= $sql_span;
    }

    // TODO: add Sorting - sort_key, sort_order
    if(!empty($sort_key)) {
		$sql .= " ORDER BY " . $sort_by_sql[$sort_key];
		$sql .= ($sort_order == 'd') ? ' DESC' : ' ASC';
    }



    // selecting "logged" so we can get the date-range - deprecated - already gotten date-range
    //$sql_records = "SELECT logged FROM $cc_db_name" . $sql . ' ORDER BY log_nr ASC';
	$sql_records = "SELECT count(log_id) as record_count FROM $log_db"; // should be faster

   	//
	// Get the number of records
	//
	if ( !($result = $db->sql_query($sql_records)) )
	{
		message_die(GENERAL_ERROR, 'Could not get the number of records', '', __LINE__, __FILE__, $sql_records);
	}
	$row = $db->sql_fetchrow($result);
   	$record_count = $row['record_count'];
	//$record_count = $db->sql_numrows($result);
	$db->sql_freeresult($result);

   	//
   	// Consider jump_page
   	//
  	$total_pages = ceil($record_count/$log_config['per_page']);
	// printf("JUMP: %s<br>", $jump_page);
  	if ( isset($HTTP_POST_VARS['next']) ) {
		$jump_page = intval($HTTP_POST_VARS['current_page']); // first override jump_page field
  		$jump_page++;
  	} elseif ( isset($HTTP_POST_VARS['previous']) ) {
		$jump_page = intval($HTTP_POST_VARS['current_page']); // first override jump_page field
  	   	$jump_page--;
  	}
	// printf("JUMP: %s<br>", $jump_page);
  	if ( $jump_page > 1 ) {
  	   	$start = ($jump_page - 1) * $log_config['per_page'];
  	}
  	$on_page = floor($start / $log_config['per_page']) + 1;

	//
	//	Hide / show the prev/next buttons
	//
	if( $on_page > 1 )
	{
		$template->assign_block_vars('previous_btn', array());
	}
	if( $total_pages > $on_page )
	{
		$template->assign_block_vars('next_btn', array());
	}


    //
    // LIMIT the result based on $start and $log_config['per_page']
    //
	$sql .= " LIMIT $start, " . $log_config['per_page'];

	//printf("SQL: %s<br />", $sql);


	//
	// Start page proper
	//
	$template->set_filenames(array(
		'body' => 'admin/logs_body.tpl')
    );


	//
	// Execute the main SQL call - populate ip_rows()
	//
	$ip_rows = array();
	$error_log = array();
	$error_id_str = '';
	$error_count = 0;
	if( !$result = $db->sql_query($sql) )
	{
		message_die(GENERAL_ERROR, "Couldn't get IP Log information", "", __LINE__, __FILE__, $sql);
	}
	$ip_count = $db->sql_numrows($result);
	//$ip_rows = $db->sql_fetchrowset($result);
	while ( $row = $db->sql_fetchrow($result) )
	{
		$ip_rows[] = $row;
		if($row['error_log'] > 0){
			$error_id_str .= ( ( $error_id_str != '' ) ? ', ' : '' ) . $row['error_log'];
			$error_count++;
		}
	}
	$db->sql_freeresult($result);

	// Fetch error details
	if(!empty($error_id_str))
	{
		$sql = "SELECT * FROM " . CCLOG_ERROR . " WHERE log_id IN ({$error_id_str}) LIMIT {$error_count}";
		if( !$result = $db->sql_query($sql) )
		{
			message_die(GENERAL_ERROR, "Couldn't get IP Log Error information", "", __LINE__, __FILE__, $sql);
		}
		while ( $row = $db->sql_fetchrow($result) )
		{
			$error_log[$row['log_id']] = $row;
		}
		$db->sql_freeresult($result);
	}



	$template->assign_vars(array(
		'S_IP_PER_PAGE' => $s_ip_per_page,
		'S_SELECT_DAYS' => $s_limit_days,
		'L_DISPLAY_FROM_DAYS' => $lang['Display_from_days'],
		'S_SELECT_SORT' => $s_sort_key,
		'L_SORT_BY' => $lang['Sort_by'],
		'S_SELECT_ORDER' => $s_sort_order,
		'S_IP_USER_BATCH' => $user_batch,
		'S_IP_IP_BATCH' => $ip_batch,
		'L_PROBE_PROXY' => $lang['CCIP_probe'],
      	'LOOKUP_URL' => $log_config['ip_lookup_url'],
      	'S_IP_SPAN_START' => preg_replace('/(\d{4})(\d{2})(\d{2})/', "\\1/\\2/\\3", substr($sql_span_start, 0, 8)),
      	'S_IP_SPAN_END' => preg_replace('/(\d{4})(\d{2})(\d{2})/', "\\1/\\2/\\3", substr($sql_span_end, 0, 8))
	));




	//
	// Main Output Loop
	//
	for($i=0; $i < $ip_count; $i++)
	{
		$row = $ip_rows[$i];
    	$log_id = $ip_rows[$i]['log_id'];

		// Request method
		switch($row['req_method'])
		{
			case 'u':
				$row['req_method'] = 'PUT';
				break;
			case 'p':
				$row['req_method'] = 'POST';
				break;
			case 'g':
				$row['req_method'] = 'GET';
				break;
			case 'h':
				$row['req_method'] = 'HEAD';
				break;
			default:

		}


		$ip_date = create_date($log_config['log_dateformat'], n7_bigint_to_timestamp($ip_rows[$i]['logged']), $board_config['board_timezone']);
        $ip_full_date = create_date('H:i:s', n7_bigint_to_timestamp($ip_rows[$i]['logged']), $board_config['board_timezone']);

        $ip_ip = ($ip_rows[$i]['user_ip']) ? $ip_rows[$i]['user_ip'] : ''; // this is the one to ban
        $bb_ip = ($ip_rows[$i]['bb_ip']) ? $ip_rows[$i]['bb_ip'] : '';

		$ip_browser = $ip_rows[$i]['env_agent'];
		$ip_user_link = (intval($ip_rows[$i]['user_id']) > 0) ? '<a href="' . append_sid("admin_users.$phpEx?u=" .
            intval($ip_rows[$i]['user_id']) . "&mode=edit")  . '">' . $ip_rows[$i]['username'] . '</a>' : $ip_rows[$i]['username'];

		// replace referer urls with links
		$ip_referer_link = ereg_replace("[[:alpha:]]+://[^<>[:space:]]+[[:alnum:]/]", "<a href=\"\\0\">\\0</a>", $ip_rows[$i]['env_referer']);

		// New
		// Determine proxy usage: env_x_forwarded_for, env_remote_ip,	env_via, env_proxy_connection
		$proxy_lnk = '-';
		$ip_proxy_str = '';
		$ip_proxies = '';
		$ip_proxy_ary = array();
		if( !empty($ip_rows[$i]['env_x_forwarded_for']) || !empty($ip_rows[$i]['env_via']) || !empty($ip_rows[$i]['env_proxy_connection']) ) {
			$proxy_lnk = sprintf('<a href="javascript:handleClick(\'px%s\');">%s</a>', $log_id, $lang['Yes']);

			// proxy ip handling changed v.0.3.0 - the db field is now a text/blob that may contain several IPs
			// extract IPs and create ip lookup links
			/*
			$ip_pattern = "/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/";
			$ip_pattern_match = "/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/";
			$ip_pattern_replace = "/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/";
			* */
			//$replacement = '<a href="' . $log_config['ip_lookup_url'] . '$1" target="_phpbbwhois">$1</a>';
			//$ip_rows[$i]['env_x_forwarded_for'] = preg_replace($ip_pattern_replace, $replacement, $ip_rows[$i]['env_x_forwarded_for']);
		}

		// TODO: determine bots??

		// Country Flag
		$country_flag = '';
		$row['ip_country'] = strtolower($row['ip_country']);
		if( $row['ip_country'] != '' && file_exists($phpbb_root_path . 'images/flags/' . $row['ip_country'] . '.gif') ) {
			// Check if image exists
			$country_flag = sprintf('<img src="%s" alt="%s" title="%s" />', $phpbb_root_path . 'images/flags/' . $row['ip_country'] . '.gif', $row['ip_country'], $row['ip_country']);
		}

		// Page
		if( !empty($ip_rows[$i]['page_name']) ) {
			$page_name = ( ( $ip_rows[$i]['page_dir'] != '' ) ? $ip_rows[$i]['page_dir'].'/' : '' ) . $ip_rows[$i]['page_name'];
		}

		// error
		$error_msg = ($ip_rows[$i]['error_log']) ? sprintf('<a href="javascript:handleClick(\'er%s\');">%s</a>', $log_id, $ip_rows[$i]['error_log']) : '-';

		// Log code msg
		//if(isset($cc_lang[$row['log_code']])){
			//eval("\$row['log_msg'] = \$cc_lang[\$row['log_code']];");
			// continue
			$row['page'] = $phpbb_root_path . $page_name;
			//eval('$row["log_msg"] = sprintf("<a href=\"%s\">%s</a>", \$row[\'page\'], \$row[\'page_name\']);');
			switch($row['log_code'])
			{
				case 'CODE_PAGEREQ':
					$row['log_msg_short'] = sprintf('(%s) <a href="%s">%s</a> ', $row['req_method'], $row['page'], $page_name);
					$row['log_msg'] = $row['req_method'] . ' -&gt; ' . $page_name;
					break;
				default:
					$row['log_msg'] = htmlspecialchars($row['log_msg']);
					$row['log_msg_short'] = htmlspecialchars(substr($row['log_msg'],0,20));
			}
		//}


		$row_color = ( !($i % 2) ) ? $theme['td_color1'] : $theme['td_color2'];
		$row_class = ( !($i % 2) ) ? $theme['td_class1'] : $theme['td_class2'];

      $template->assign_block_vars("ip", array(
         'ROW_COLOR' => "#" . $row_color,
         'ROW_CLASS' => $row_class,
         'LOG_ID' => $log_id,
         'DATE' => $ip_date,
         'UNAME' => $ip_user_link,
         'USERNAME' => $ip_rows[$i]['username'],
         'USER_IP' => $ip_ip,
         'LOG_ACTION' => $ip_rows[$i]['log_code'],
         //'LOG_MSG' => $ip_rows[$i]['log_msg'],
         'LOG_MSG' => $row['log_msg'],
         'LOG_MSG_SHORT' => $row['log_msg_short'],
		 		'COUNTRY' => $country_flag,
		 		'RESOLVED' => $row['ip_resolved'],
		 		'ERROR_LNK' => $error_msg,
		 		'ERROR' => $ip_rows[$i]['error_log'],
		 		'BROWSER' => $ip_browser,
		 		'REFERER' => $ip_referer_link,
		 		'PAGE' => $page_name,
		 		'PAGE_QSTR' => htmlspecialchars($ip_rows[$i]['page_query_str']),
		 		'PAGE_QSTR_SHORT' => htmlspecialchars(substr($ip_rows[$i]['page_query_str'],0,30)),
         'IP_PROXY_LNK' => $proxy_lnk,
         'X_FORW_FOR' => $ip_rows[$i]['env_x_forwarded_for'],
				'PROBE_PROXY_URL' => append_sid("admin_ip_proxy.$phpEx?ip=" . $ip_rows[$i]['user_ip'])
      ));

	if( !empty($ip_rows[$i]['env_x_forwarded_for']) || !empty($ip_rows[$i]['env_via']) || !empty($ip_rows[$i]['env_proxy_connection']) )
	{
		$replacement = '<a href="' . $log_config['ip_lookup_url'] . '$1" target="_phpbbwhois">$1</a> [<a href="javascript:banip(\'$1\');" title="' . $lang['Ban_IP'] . '">B</a>] [<a href="javascript:excip(\'$1\');" title="' . $lang['Exc_IP'] . '">E</a>]';

		$template->assign_block_vars("ip.proxy", array(
			'REMOTE_IP' => preg_replace($ip_pattern_replace, $replacement, $ip_rows[$i]['env_remote_ip']),
			'X_FORW_FOR' => preg_replace($ip_pattern_replace, $replacement, $ip_rows[$i]['env_x_forwarded_for']),
			'VIA' => preg_replace($ip_pattern_replace, $replacement, $ip_rows[$i]['env_via']),
			'PROXY_CONNECTION' => preg_replace($ip_pattern_replace, $replacement, $ip_rows[$i]['env_proxy_connection'])
		));
     }

	// error_log is empty or 0
	if($ip_rows[$i]['error_log'])
	{
      $template->assign_block_vars("ip.error", array(
		'ERROR_CODE' => $ip_rows[$i]['error_code'],
		'ERROR' => $error_log[$ip_rows[$i]['error_log']]['log_msg']
      ));
	}
	}

	// Pagination - as of 0.3.0 handled by forms
}


// Assign general language and template variables
$template->assign_vars(array(
	'L_LOG_TITLE' => $lang_log_title,
	'L_LOG_TEXT' => $lang_log_text,
	'L_LOG_USER' => $lang['User'],
	'L_LOG_ID' => $lang['ID'],
	'L_LOG_IP' => $lang['IP'],
	'L_LOG_TIME' => $lang['Time'],
	'L_LOG_ACTION' => $lang['Action'],
	'L_LOG_PROXY' => $lang['Proxy'],
	'L_LOG_COUNTRY' => $lang['Country'],
	'L_LOG_ERROR' => $lang['Error'],
	'L_LOG_BROWSER' => $lang['Browser'],
	'L_REFERER' => $lang['Referer'],
	'L_PAGE' => $lang['Page'],
	'L_DELETE' => $lang['Delete'],
	'L_LOG_BAN' => $lang['Ban'],
	'L_USERS' => $lang['Ban_Users'],
	'L_BAN_USER' => $lang['Ban_User'],
	'L_IPS' => $lang['Ban_IPs'],
	'L_BAN_IP' => $lang['Ban_IP'],
	'L_EXC_USER' => $lang['Exclude_User'],
	'L_EXC_IP' => $lang['Exclude_IP'],
	'L_EXC_BROWSER' => $lang['Exclude_Browser'],

	'L_IP_USER_BATCH' => $lang['CCIP_ip_user_batch'],
    'L_USER_BATCH' => $lang['CCIP_user_batch'],
    'L_IP_BATCH' => $lang['CCIP_ip_batch'],
    'L_IP_INCLUDE' => $lang['CCIP_include'],
    'L_IP_CNET' => $lang['CCIP_cnet'],
    'L_IP_BNET' => $lang['CCIP_bnet'],
    'L_USER_OR_IP' => $lang['CCIP_OR'],
    'L_MORE_OPTIONS' => $lang['More_Options'],

	'L_FIND_USERNAME' => $lang['Find_Users'],
	'L_FIND_IPS' => $lang['Find_IPs'],

	'L_IP_PREVIOUS' => $lang['CCIP_previous'],
	'L_IP_NEXT' => $lang['CCIP_next'],
	'L_SUBMIT' => $lang['Submit'],
	'L_RESET' => $lang['Reset'],
	'L_IP_PER_PAGE' => $lang['CCIP_per_page'],
    'L_PROXY' => $lang['Proxy'],
    'L_REMOTE_IP' => $lang['REMOTE_ADDR'],
    'L_VIA' => $lang['HTTP_VIA'],
    'L_X_FORW_FOR' => $lang['HTTP_X_FORWARDED_FOR'],
    'L_PROXY_CONNECTION' => $lang['HTTP_PROXY_CONNECTION'],
    'L_REFERER' => $lang['HTTP_REFERER'],

    'L_ERROR_CODE' => $lang['Error_code'],
    'L_ERROR' => $lang['Error'],
    'L_PAGE_QSTR' => $lang['Page_query_str'],

    'L_PROXY_WINDOW' => $lang['CCIP_probe_proxy'],

    'L_LOG_EXCLUDE' => $lang['IP_exc_title'],
    'L_EXCLUDE' => $lang['Exclude'],

    'L_IP_DATESPAN' => $lang['CCIP_datespan'],
    'L_IP_JUMP_PAGE' => $lang['CCIP_jump_page'],
	'L_IP_PAGE' => $lang['CCIP_page'],
	'L_IP_JUMP' => $lang['CCIP_jump'],
    'L_IP_TO' => $lang['CCIP_to'],
	'L_IP_PRUNE_ON' => ($log_config['cc_auto_prune'] == 1) ? $lang['CCIP_Prune_is_on'] : $lang['CCIP_Prune_is_off'],
	'U_IP_PRUNED' => sprintf($lang['CCIP_Pruned_rows'], $cc_pruned_rows),

	'L_IP_CURRENT_PAGE' => $lang['IP_current_page'],
	'S_IP_CURRENT_PAGE' => $on_page,
	'S_IP_ONPAGE' => '<b>'.$on_page . '</b>/' . $total_pages,
	'S_IP_JUMP_PAGE' => $on_page + 1,
	'S_IP_CONF_PER_PAGE' => $log_config['per_page'],
	'S_DAYSPAN' => $dayspan,
	'S_SORT_ORDER' => $sort_order,
	'S_SORT_KEY' => $sort_key,
	'S_TIMESPAN_CHK' => $use_timespan,
	'S_TIMESPAN_DISABLED' => ((empty($use_timespan)) ? 'disabled' : ''),
	'S_BAN_ACTION' => append_sid("admin_user_ban.$phpEx?submit=true"),
	'S_EXCLUDE_ACTION' => append_sid($phpbb_root_path . 'admin/admin_logs_exclude.' . $phpEx),
	'PHPBB_ROOT' => $phpbb_root_path
));


$template->pparse("body");

include('page_footer_admin.'.$phpEx);
?>