if(@txpinterface == 'admin') {
global $smd_akey_event, $smd_akey_styles;
$smd_akey_event = 'smd_akey';
$smd_akey_styles = array(
'list' =>
'.smd_hidden { display:none; }',
);
add_privs($smd_akey_event, '1');
add_privs('plugin_prefs.smd_access_keys', '1');
register_tab('extensions', $smd_akey_event, smd_akey_gTxt('smd_akey_tab_name'));
register_callback('smd_akey_dispatcher', $smd_akey_event);
register_callback('smd_akey_welcome', 'plugin_lifecycle.smd_access_keys');
register_callback('smd_akey_prefs', 'plugin_prefs.smd_access_keys');
}
global $smd_akey_prefs;
$smd_akey_prefs = array(
'smd_akey_file_download_expires' => array(
'html' => 'text_input',
'type' => PREF_HIDDEN,
'position' => 10,
'default' => '3600',
),
'smd_akey_salt_length' => array(
'html' => 'text_input',
'type' => PREF_HIDDEN,
'position' => 20,
'default' => '8',
),
'smd_akey_log_ip' => array(
'html' => 'yesnoradio',
'type' => PREF_HIDDEN,
'position' => 30,
'default' => '0',
),
);
if (!defined('SMD_AKEYS')) define("SMD_AKEYS", 'smd_akeys');
register_callback('smd_access_protect_download', 'file_download');
// ********************
// ADMIN SIDE INTERFACE
// ********************
// Jump off point for event/steps
function smd_akey_dispatcher($evt, $stp) {
if(!$stp or !in_array($stp, array(
'smd_akey_table_install',
'smd_akey_table_remove',
'smd_akey_create',
'smd_akey_prefs',
'smd_akey_prefsave',
'smd_akey_multi_edit',
'smd_akey_change_pageby',
))) {
smd_akey('');
} else $stp();
}
// Bootstrap when installed/deleted
function smd_akey_welcome($evt, $stp) {
$msg = '';
switch ($stp) {
case 'installed':
smd_akey_table_install(0);
$msg = 'Restrict your TXP world :-)';
break;
case 'deleted':
smd_akey_table_remove(0);
break;
}
return $msg;
}
// Main admin interface
function smd_akey($msg='') {
global $smd_akey_event, $smd_akey_list_pageby, $smd_akey_styles, $logging, $smd_akey_prefs;
pagetop(smd_akey_gTxt('smd_akey_tab_name'), $msg);
if (smd_akey_table_exist(1)) {
extract(gpsa(array('page', 'sort', 'dir', 'crit', 'search_method')));
if ($sort === '') $sort = get_pref('smd_akey_sort_column', 'time');
if ($dir === '') $dir = get_pref('smd_akey_sort_dir', 'desc');
$dir = ($dir == 'asc') ? 'asc' : 'desc';
switch ($sort) {
case 'page':
$sort_sql = 'page '.$dir.', time desc';
break;
case 'triggah':
$sort_sql = 'triggah '.$dir.', time desc';
break;
case 'maximum':
$sort_sql = 'maximum '.$dir.', time desc';
break;
case 'accesses':
$sort_sql = 'accesses '.$dir.', time desc';
break;
case 'ip':
$sort_sql = 'ip '.$dir.', time desc';
break;
default:
$sort = 'time';
$sort_sql = 'time '.$dir;
break;
}
set_pref('smd_akey_sort_column', $sort, 'smd_akey', PREF_HIDDEN, '', 0, PREF_PRIVATE);
set_pref('smd_akey_sort_dir', $dir, 'smd_akey', PREF_HIDDEN, '', 0, PREF_PRIVATE);
$switch_dir = ($dir == 'desc') ? 'asc' : 'desc';
$criteria = 1;
if ($search_method and $crit) {
$crit_escaped = doSlash(str_replace(array('\\','%','_','\''), array('\\\\','\\%','\\_', '\\\''), $crit));
$critsql = array(
'page' => "page like '%$crit_escaped%'",
'triggah' => "triggah like '%$crit_escaped%'",
'maximum' => "maximum = '$crit_escaped'",
'accesses' => "accesses = '$crit_escaped'",
'ip' => "ip like '%$crit_escaped%'",
);
if (array_key_exists($search_method, $critsql)) {
$criteria = $critsql[$search_method];
$limit = 500;
} else {
$search_method = '';
$crit = '';
}
} else {
$search_method = '';
$crit = '';
}
$total = safe_count(SMD_AKEYS, "$criteria");
echo '
';
if ($total < 1) {
if ($criteria != 1) {
echo n.smd_akey_search_form($crit, $search_method).
n.graf(gTxt('no_results_found'), ' class="indicator"').'
';
}
}
$limit = max($smd_akey_list_pageby, 15);
list($page, $offset, $numPages) = pager($total, $limit, $page);
echo n.smd_akey_search_form($crit, $search_method).'';
// Retrieve the secret keyring table entries
$secring = safe_rows('*', SMD_AKEYS, "$criteria order by $sort_sql limit $offset, $limit");
// Set up the buttons and column info
$newbtn = ''.smd_akey_gTxt('smd_akey_btn_new').'';
$prefbtn = ''.smd_akey_gTxt('smd_akey_btn_pref').'';
$showip = get_pref('smd_akey_log_ip', $smd_akey_prefs['smd_akey_log_ip']['default'], 1);
echo <<
function smd_akey_togglenew() {
box = jQuery("#smd_akey_create");
if (box.css("display") == "none") {
box.show();
} else {
box.hide();
}
jQuery("input.smd_focus").focus();
return false;
}
jQuery(function() {
jQuery("#smd_akey_add").click(function () {
jQuery("#smd_akey_step").val('smd_akey_create');
jQuery("#smd_akey_form").removeAttr('onsubmit').submit();
});
});
EOC;
// Inject styles
echo '';
// Access key list
echo n.'';
echo '
';
echo '
'.
n.nav_form($smd_akey_event, $page, $numPages, $sort, $dir, $crit, $search_method, $total, $limit).
n.pageby_form($smd_akey_event, $smd_akey_list_pageby).
n.'
'.n.'
';
} else {
// Table not installed
$btnInstall = '';
$btnStyle = ' style="border:0;height:25px"';
echo startTable('list');
echo tr(tda(strong(smd_akey_gTxt('smd_akey_prefs_some_tbl')).br.br
.smd_akey_gTxt('smd_akey_prefs_some_explain').br.br
.smd_akey_gTxt('smd_akey_prefs_some_opts'), ' colspan="2"')
);
echo tr(tda($btnInstall, $btnStyle));
echo endTable();
}
}
// Change and store qty-per-page value
function smd_akey_change_pageby() {
event_change_pageby('smd_akey');
smd_akey();
}
// The search dropdown list
function smd_akey_search_form($crit, $method) {
global $smd_akey_event, $smd_akey_prefs;
$doip = get_pref('smd_akey_log_ip', $smd_akey_prefs['smd_akey_log_ip']['default'], 1);
$methods = array(
'page' => smd_akey_gTxt('smd_akey_page'),
'triggah' => smd_akey_gTxt('smd_akey_trigger'),
'maximum' => smd_akey_gTxt('smd_akey_max'),
'accesses' => smd_akey_gTxt('smd_akey_accesses'),
);
if ($doip) {
$methods['ip'] = gTxt('IP');
}
return search_form($smd_akey_event, '', $crit, $methods, $method, 'page');
}
// Create a key from the admin side's 'New key' button
function smd_akey_create() {
extract(gpsa(array('smd_akey_newpage', 'smd_akey_triggah', 'smd_akey_time', 'smd_akey_maximum')));
if ($smd_akey_newpage) {
// Just call the public tag with the relevant options
$key = smd_access_key(
array(
'url' => $smd_akey_newpage,
'trigger' => $smd_akey_triggah,
'start' => $smd_akey_time,
'max' => $smd_akey_maximum,
)
);
$msg = smd_akey_gTxt('smd_akey_generated', array('{key}' => $key));
} else {
$msg = array(smd_akey_gTxt('smd_akey_need_page'), E_ERROR);
}
smd_akey($msg);
}
// Handle submission of the multi-edit dropdown options
function smd_akey_multi_edit() {
$selected = gps('selected');
$operation = gps('smd_akey_multi_edit');
$del = 0;
$msg = '';
switch ($operation) {
case 'smd_akey_delete':
if ($selected) {
foreach ($selected as $sel) {
$parts = explode('|', $sel);
$ret = safe_delete(SMD_AKEYS, "page = '" . $parts[0] . "' AND t_hex = '" . $parts[1] . "'");
$del = ($ret) ? $del+1 : $del;
}
$msg = smd_akey_gTxt('smd_akey_deleted', array('{deleted}' => $del));
}
break;
}
smd_akey($msg);
}
// Display the prefs
function smd_akey_prefs() {
global $smd_akey_event, $smd_akey_prefs;
pagetop(smd_akey_gTxt('smd_akey_pref_legend'));
$out = array();
$out[] = '';
echo join(n, $out);
}
// Save the prefs
function smd_akey_prefsave() {
global $smd_akey_event, $smd_akey_prefs;
foreach ($smd_akey_prefs as $idx => $prefobj) {
$val = ps($idx);
set_pref($idx, $val, $smd_akey_event, $prefobj['type'], $prefobj['html'], $prefobj['position']);
}
$msg = smd_akey_gTxt('smd_akey_prefs_saved');
smd_akey($msg);
}
// Add akey table if not already installed
function smd_akey_table_install($showpane='1') {
$GLOBALS['txp_err_count'] = 0;
$ret = '';
$sql = array();
// Use 'triggah' and 'maximum' because 'trigger' and 'max' are reserved words.
$sql[] = "CREATE TABLE IF NOT EXISTS `".PFX.SMD_AKEYS."` (
`page` varchar(255) NOT NULL default '',
`t_hex` varchar(12) NOT NULL default '',
`time` int(14) NOT NULL default 0,
`secret` varchar(255) NOT NULL default '',
`triggah` varchar(255) NULL default '',
`maximum` int(11) NULL default 0,
`accesses` int(11) NULL default 0,
`ip` text NOT NULL default '',
PRIMARY KEY (`page`,`t_hex`)
) ENGINE=MyISAM";
if(gps('debug')) {
dmp($sql);
}
foreach ($sql as $qry) {
$ret = safe_query($qry);
if ($ret===false) {
$GLOBALS['txp_err_count']++;
echo "".$GLOBALS['txp_err_count'].". ".mysql_error()."
\n";
echo "\n";
}
}
// Be kind to beta testers and update table
$flds = getThings('describe `'.PFX.SMD_AKEYS.'`');
if (!in_array('ip',$flds)) {
safe_alter(SMD_AKEYS, "add `ip` text NOT NULL default '' after `accesses`");
}
// Spit out results
if ($GLOBALS['txp_err_count'] == 0) {
if ($showpane) {
$msg = smd_akey_gTxt('smd_akey_tbl_installed');
smd_akey($msg);
}
} else {
if ($showpane) {
$msg = smd_akey_gTxt('smd_akey_tbl_not_installed');
smd_akey($msg);
}
}
}
// ------------------------
// Drop table if in database
function smd_akey_table_remove() {
$ret = '';
$sql = array();
$GLOBALS['txp_err_count'] = 0;
if (smd_akey_table_exist()) {
$sql[] = "DROP TABLE IF EXISTS " .PFX.SMD_AKEYS. "; ";
if(gps('debug')) {
dmp($sql);
}
foreach ($sql as $qry) {
$ret = safe_query($qry);
if ($ret===false) {
$GLOBALS['txp_err_count']++;
echo "".$GLOBALS['txp_err_count'].". ".mysql_error()."
\n";
echo "\n";
}
}
}
if ($GLOBALS['txp_err_count'] == 0) {
$msg = smd_akey_gTxt('smd_akey_tbl_removed');
} else {
$msg = smd_akey_gTxt('smd_akey_tbl_not_removed');
smd_akey($msg);
}
}
// ------------------------
function smd_akey_table_exist($all='') {
if ($all) {
$tbls = array(SMD_AKEYS => 8);
$out = count($tbls);
foreach ($tbls as $tbl => $cols) {
if (gps('debug')) {
echo "++ TABLE ".$tbl." HAS ".count(@safe_show('columns', $tbl))." COLUMNS; REQUIRES ".$cols." ++".br;
}
if (count(@safe_show('columns', $tbl)) == $cols) {
$out--;
}
}
return ($out===0) ? 1 : 0;
} else {
if (gps('debug')) {
echo "++ TABLE ".SMD_AKEYS." HAS ".count(@safe_show('columns', SMD_AKEYS))." COLUMNS;";
}
return(@safe_show('columns', SMD_AKEYS));
}
}
//**********************
// PUBLIC SIDE INTERFACE
//**********************
function smd_access_key($atts, $thing=NULL) {
global $smd_akey_prefs;
extract(lAtts(array(
'secret' => '',
'url' => '',
'site_name' => '1',
'start' => '',
'trigger' => 'smd_akey',
'max' => '',
'extra' => '',
),$atts));
if (smd_akey_table_exist(1)) {
$trigger = trim($trigger);
$trigger = ($trigger == 'file_download') ? '' : $trigger;
$smd_akey_salt_length = get_pref('smd_akey_salt_length', $smd_akey_prefs['smd_akey_salt_length']['default']);
// Without a URL, assume current page
$page = rtrim( (($url) ? $url : serverSet('REQUEST_URI')), '/');
if ($site_name) {
$page = (strpos($page, 'http') === 0) ? $page : rtrim(hu, '/') . $page;
}
if (!$secret) {
$secret = uniqid('', true);
}
$salt = substr(md5(uniqid(rand(), true)), 0, $smd_akey_salt_length);
$plen = strlen($page) % 32; // Because 32 is the size of an md5 string and we don't want to fall off the end
// Generate a timestamp. The clock starts ticking from this moment
$ts = ($start) ? safe_strtotime($start) : time();
$ts = ($ts === false) ? time() : $ts;
$t_hex = dechex($ts);
// Update/insert the remaining data
$exists = safe_field('page', SMD_AKEYS, "page='".doSlash($page)."' AND t_hex='".doSlash($t_hex)."'");
$maxinfo = '';
if ($max) {
$maxinfo = ", maximum = '".doSlash($max)."', accesses = '0'";
}
if ($exists) {
safe_update(SMD_AKEYS, "triggah='".doSlash($trigger)."', time='".doSlash($ts)."', secret='".doSlash($secret)."'" . $maxinfo, "page='".doSlash($page)."' AND t_hex='".doSlash($t_hex)."'");
} else {
safe_insert(SMD_AKEYS, "page='".doSlash($page)."', t_hex='".doSlash($t_hex)."', triggah='".doSlash($trigger)."', secret='".doSlash($secret)."', time='".doSlash($ts)."'" . $maxinfo);
}
// Tack on max if applicable
$max = ($max) ? '.'.$max : '';
// And any extra
$extratok = ($extra) ? '/'.$extra : '';
// Create the raw token...
$token = md5($salt.$secret.$page.$trigger.$t_hex.$max.$extra);
// ... and insert the salt partway through
$salty_token = substr($token, 0, $plen) . $salt . substr($token, $plen);
return $page . (($trigger) ? '/' . $trigger : '') . '/' . $salty_token . '/' . $t_hex . $max . $extratok;
} else {
trigger_error(smd_akey_gTxt('smd_akey_tbl_not_installed'), E_USER_NOTICE);
}
}
// Protect a page for a given time limit from the moment the
// access token has been generated. Embed this tag at the top
// of the page you want to protect or wrap it around part of a
// page you wish to protect. The unique URL to the resource
// is generated by
function smd_access_protect($atts, $thing=NULL) {
global $smd_access_error, $smd_access_errcode, $smd_akey_info, $smd_akey_prefs, $permlink_mode;
extract(lAtts(array(
'trigger' => 'smd_akey',
'trigger_mode' => 'exact', // exact, begins, ends, contains
'site_name' => '1',
'force' => '0',
'expires' => '3600', // in seconds
),$atts));
if (smd_akey_table_exist(1)) {
$url = serverSet('REQUEST_URI');
$url = (($site_name && (strpos($url, hu) === false)) ? rtrim(hu, '/') : '') . $url;
$parts = explode('/', $url);
// Look for one of the triggers in the URL and bomb out if we find it
$triggers = do_list($trigger);
$trigger = $triggers[0]; // Initialise to the first value in case no others are found
$trigoff = false;
foreach ($triggers as $trig) {
switch ($trigger_mode) {
case 'exact':
$trigoff = array_search($trig, $parts);
$realTrig = $trig;
break;
case 'begins':
$count = 0;
foreach ($parts as $part) {
if (strpos($part, $trig) === 0) {
$trigoff = $count;
$realTrig = $part;
break;
}
$count++;
}
break;
case 'ends':
$count = 0;
foreach ($parts as $part) {
$re = '/.+'.preg_quote($trig).'$/i';
if (preg_match($re, $part) === 1) {
$trigoff = $count;
$realTrig = $part;
break;
}
$count++;
}
break;
case 'contains':
$count = 0;
foreach ($parts as $part) {
$re = '/.*'.preg_quote($trig).'.*$/i';
if (preg_match($re, $part) === 1) {
$trigoff = $count;
$realTrig = $part;
break;
}
$count++;
}
break;
}
if ($trigoff !== false) {
// Found it so set the trigger to be the current item and jump out
$trigoff = ($trigger == 'file_download') ? $trigoff + 2 : $trigoff;
$trigger = $realTrig;
break;
}
}
$ret = false;
$smd_access_error = $smd_access_errcode = '';
$smd_akey_salt_length = get_pref('smd_akey_salt_length', $smd_akey_prefs['smd_akey_salt_length']['default']);
$doip = get_pref('smd_akey_log_ip', $smd_akey_prefs['smd_akey_log_ip']['default']);
if ($trigoff !== false) {
$tokidx = $trigoff + 1;
$timeidx = $trigoff + 2;
$extraidx = $trigoff + 3;
// OK, on a trigger page, so read the token from the URL
$tok = (isset($parts[$tokidx]) && strlen($parts[$tokidx]) == intval(32 + $smd_akey_salt_length)) ? $parts[$tokidx] : 0;