if(@txpinterface == 'admin') {
global $smd_macro_event, $smd_macro_styles;
$smd_macro_event = 'smd_macro';
add_privs($smd_macro_event,'1,2');
register_tab('content', $smd_macro_event, smd_macro_gTxt('smd_macro_tab_name'));
register_callback('smd_macro_dispatcher', 'smd_macro');
register_callback('smd_macro_upload_form', $smd_macro_event.'_ui', 'upload_form');
register_callback('smd_macro_welcome', 'plugin_lifecycle.smd_macro');
}
if (!defined('SMD_MACRO')) {
define("SMD_MACRO", 'smd_macro');
}
// Bootstrap the function insertion
register_callback('smd_macro_boot', 'pretext');
// ********************
// ADMIN SIDE INTERFACE
// ********************
// ------------------------
function smd_macro_dispatcher($evt, $stp) {
if(!$stp or !in_array($stp, array(
'smd_macro_table_install',
'smd_macro_table_remove',
'smd_macro_prefsave',
'smd_macro_save',
'smd_macro_delete',
))) {
smd_macro('');
} else $stp();
}
// ------------------------
function smd_macro_welcome($evt, $stp) {
$msg = '';
switch ($stp) {
case 'installed':
smd_macro_table_install(0);
$msg = 'Go go gadget macro!';
break;
case 'deleted':
smd_macro_table_remove(0);
break;
}
return $msg;
}
// ------------------------
function smd_macro($msg='') {
global $smd_macro_event;
$export_list = gps('smd_macro_export');
$max_file_size = get_pref('smd_macro_import_filesize', 15 * 1024);
if (gps('step') == 'smd_macro_export' && $export_list) {
// Generate an associative array that is translated to an ini file
$out = array();
$rows = safe_rows('*', SMD_MACRO, "macro_name IN ('".join("','", doSlash($export_list))."')");
foreach ($rows as $row) {
$atts = unserialize($row['attributes']);
$outatts = array();
foreach ($atts as $att => $vals) {
$outatts[] = join('|', array($att, $vals['default'], $vals['rep']));
}
$out[$row['macro_name']] = array(
'description' => $row['description'],
'attributes' => $outatts,
'definition' => $row['definition'],
);
}
$content = smd_macro_create_ini($out, array('definition' => 'base64_encode'));
header("Content-Type: text/plain");
header("Content-Disposition: attachment; filename=\"smd_macros.ini\"");
header("Content-Length: " . strlen($content));
header("Content-Transfer-Encoding: binary");
header("Cache-Control: no-cache, must-revalidate, max-age=60");
header("Expires: Sat, 01 Jan 2000 12:00:00 GMT");
print($content);
exit;
} else if (gps('step') == 'smd_macro_import') {
$overwrite = gps('smd_macro_import_overwrite');
$file = @get_uploaded_file($_FILES['thefile']['tmp_name'], get_pref('tempdir').DS.basename($_FILES['thefile']['tmp_name']));
if ($file === false) {
$msg = array(smd_macro_gTxt('smd_macro_cannot_import'), E_WARNING);
} else {
$size = filesize($file);
if ($max_file_size < $size) {
$msg = array(smd_macro_gTxt('smd_macro_file_size'), E_WARNING);
} else {
$ini = @parse_ini_file($file, true);
if ($ini) {
$done = array('ok' => array(), 'nok' => array(), 'skip' => array());
foreach ($ini as $key => $val) {
$atts = array();
$def = $desc = '';
if (isset($val['attributes'])) {
foreach ($val['attributes'] as $attlist) {
list($nam, $dflt, $rep) = explode('|', $attlist);
$atts[sanitizeForUrl($nam)] = array(
'default' => $dflt,
'rep' => $rep
);
}
}
if (isset($val['description'])) {
$desc = $val['description'];
}
if (isset($val['definition'])) {
$def = base64_decode($val['definition']);
}
$result = (string)smd_macro_save_direct($key, $desc, $atts, $def, $overwrite);
switch ($result) {
case 'SMD_MACRO_BAD_NAME':
case 'SMD_MACRO_CLASH':
$done['nok'][] = $key;
break;
case 'SMD_MACRO_SKIP':
$done['skip'][] = $key;
break;
default:
$done['ok'][] = $key;
break;
}
}
$msg = (($done['ok']) ? smd_macro_gTxt('smd_macro_imported') . join(', ', $done['ok']).br : '')
. (($done['skip']) ? smd_macro_gTxt('smd_macro_skipped') . join(', ', $done['skip']).br : '')
. (($done['nok']) ? smd_macro_gTxt('smd_macro_not_imported') . join(', ', $done['nok']) : '');
} else {
$msg = array(smd_macro_gTxt('smd_macro_invalid_ini'), E_WARNING);
}
}
unlink($file);
}
} else if (gps('step') == 'smd_macro_clone') {
$source = safe_row('*', SMD_MACRO, "macro_name='".doSlash(gps('smd_macro_name'))."'");
$name = gps('smd_macro_new_name');
$desc = $source['description'];
$def = $source['definition'];
$atts = $source['attributes'];
$result = (string)smd_macro_save_direct($name, $desc, $atts, $def, false);
switch($result) {
case 'SMD_MACRO_BAD_NAME':
$msg = array(smd_macro_gTxt('smd_macro_invalid'), E_WARNING);
break;
case 'SMD_MACRO_CLASH':
case 'SMD_MACRO_SKIP':
$msg = array(smd_macro_gTxt('smd_macro_exists'), E_WARNING);
break;
default:
$msg = smd_macro_gTxt('smd_macro_created');
$_POST['smd_macro_name'] = $name; // Inject the new macro into the post stream so it's selected by default
break;
}
}
pagetop(smd_macro_gTxt('smd_macro_tab_name'), $msg);
if (smd_macro_table_exist(1)) {
$macros = safe_rows('*', SMD_MACRO, '1=1 ORDER BY macro_name');
$macro_name = $macro_new_name = gps('smd_macro_name');
$macro_description = $macro_def = $macro_code = '';
$macro_atts = array();
// Build the select list if possible
$macrolist = array();
foreach ($macros as $idx => $macro) {
$macrolist[$macro['macro_name']] = $macro['macro_name'];
if ($macro['macro_name'] == $macro_name) {
$macro_new_name = $macro['macro_name'];
$macro_description = $macro['description'];
$macro_atts = $macro['attributes'] ? unserialize($macro['attributes']) : array();
$macro_def = $macro['definition'];
}
}
$macroSelector = ($macrolist) ? selectInput('smd_macro_name', $macrolist, $macro_name, true, 1) : '';
$multi_macsel = '';
if ($macrolist) {
$multi_macsel = '';
}
$editcell = ($macrolist) ? ''.sp.$macroSelector : '';
// Edit form
echo '
';
// Import / export form
echo startTable('smd_macro_impexp', '', '', '', '800');
echo tr(
tda(
''.smd_macro_gTxt('smd_macro_import').''
.(($multi_macsel)
? ' / ' . ''.smd_macro_gTxt('smd_macro_export').''
. (($macro_name) ? ' / ' . ''.smd_macro_gTxt('smd_macro_clone').'' : '')
: '')
.''
. upload_form(smd_macro_gTxt('smd_macro_upload'), '', 'smd_macro_import', $smd_macro_event, '')
. '
'
. (($multi_macsel)
? ''
. ''
: ''
)
, ' class="noline" style="text-align: right; vertical-align: middle;"'
)
);
echo endTable();
echo '';
echo <<
jQuery(function() {
jQuery('#smd_macro_att_add').click(function(ev) {
var obj = jQuery('#smd_macro_attlist tbody');
var elems = jQuery('.smd_macro_att');
// Add the row, empty it and focus. Can't do this in any fewer jQuery() calls for some reason
obj.append(obj.children().eq(0).clone());
obj.children().last().find('input:text').val('');
obj.children().last().find('input:text').first().focus();
ev.preventDefault();
});
// Import link
jQuery('#smd_macro_import').click(function(ev) {
jQuery('#smd_macro_export_holder').hide('normal');
jQuery('#smd_macro_clone_holder').hide('normal');
jQuery('#smd_macro_import_holder').toggle('normal');
});
// Export link
jQuery('#smd_macro_export').click(function(ev) {
jQuery('#smd_macro_import_holder').hide('normal');
jQuery('#smd_macro_clone_holder').hide('normal');
jQuery('#smd_macro_export_holder').toggle('normal');
});
// Clone link
jQuery('#smd_macro_clone').click(function(ev) {
jQuery('#smd_macro_import_holder').hide('normal');
jQuery('#smd_macro_export_holder').hide('normal');
jQuery('#smd_macro_clone_holder').toggle('normal').find("input[name='smd_macro_new_name']").focus();
});
});
function smd_macro_export_close() {
jQuery("#smd_macro_export").click();
}
EOJS;
} else {
// Table not installed
$btnInstall = '';
$btnStyle = ' style="border:0;height:25px"';
echo startTable('list');
echo tr(tda(strong(smd_macro_gTxt('smd_macro_prefs_some_tbl')).br.br
.smd_macro_gTxt('smd_macro_prefs_some_explain').br.br
.smd_macro_gTxt('smd_macro_prefs_some_opts'), ' colspan="2"')
);
echo tr(tda($btnInstall, $btnStyle));
echo endTable();
}
}
// ------------------------
// Add an overwrite checkbox to the upload form
function smd_macro_upload_form($evt, $stp, $data, $args) {
$ret = str_replace(
''
, checkbox('smd_macro_import_overwrite', '1', 0) . smd_macro_gTxt('smd_macro_overwrite') . ''
, $data
);
return $ret;
}
// ------------------------
function smd_macro_save_direct($name='', $desc='', $atts=array(), $def='', $overwrite = false) {
global $smd_macro_event;
$smd_macro_new_name = sanitizeForUrl($name);
$smd_macro_description = doSlash($desc);
$smd_macro_definition = $def;
$ret = '';
if (smd_macro_valid($smd_macro_new_name)) {
$code = doSlash(smd_macro_build($smd_macro_new_name, $atts, $smd_macro_definition));
$smd_macro_definition = doSlash($smd_macro_definition);
$smd_macro_atts = is_array($atts) ? serialize($atts) : $atts;
if (smd_macro_table_exist()) {
// Check if this macro name clashes with a built-in PHP/TXP function
$exists = smd_macro_exists($smd_macro_new_name, false);
if ($exists === false) {
$indb = safe_field('macro_name', SMD_MACRO, "macro_name='$smd_macro_new_name'");
if ($indb) {
if ($overwrite) {
// Update
$ret = safe_update(SMD_MACRO, "macro_name='$smd_macro_new_name', description='$smd_macro_description', attributes='$smd_macro_atts', definition='$smd_macro_definition', code='$code'", "macro_name='$smd_macro_new_name'");
} else {
$ret = 'SMD_MACRO_SKIP';
}
} else {
// Insert
$ret = safe_insert(SMD_MACRO, "macro_name='$smd_macro_new_name', description='$smd_macro_description', attributes='$smd_macro_atts', definition='$smd_macro_definition', code='$code'");
}
} else {
$ret = 'SMD_MACRO_CLASH';
}
}
} else {
$ret = 'SMD_MACRO_BAD_NAME';
}
// $ret may be empty only if macro table not installed
return $ret;
}
// ------------------------
function smd_macro_save() {
global $smd_macro_event;
extract(doSlash(gpsa(array(
'smd_macro_name',
'smd_macro_new_name',
'smd_macro_description',
))));
$msg = '';
$smd_macro_new_name = sanitizeForUrl($smd_macro_new_name);
if (smd_macro_valid($smd_macro_new_name)) {
$att_name = gps('smd_macro_attname');
$att_dflt = gps('smd_macro_attdflt');
$att_rep = gps('smd_macro_attrep');
// Don't doSlash() this yet
$smd_macro_definition = gps('smd_macro_definition');
$atts = array();
foreach($att_name as $idx => $att) {
if ($att == '') continue;
$atts[sanitizeForUrl($att)] = array(
'default' => $att_dflt[$idx],
'rep' => $att_rep[$idx]
);
}
$code = doSlash(smd_macro_build($smd_macro_new_name, $atts, $smd_macro_definition));
$smd_macro_definition = doSlash($smd_macro_definition);
$smd_macro_atts = serialize($atts);
if (smd_macro_table_exist()) {
$exists = ($smd_macro_name != $smd_macro_new_name) && smd_macro_exists($smd_macro_new_name);
if ($exists === false) {
// Inject the new name so it's selected in the dropdown if renamed
$_POST['smd_macro_name'] = $smd_macro_new_name;
if ($smd_macro_name == '') {
// Insert
$ret = safe_insert(SMD_MACRO, "macro_name='$smd_macro_new_name', description='$smd_macro_description', attributes='$smd_macro_atts', definition='$smd_macro_definition', code='$code'");
$msg = smd_macro_gTxt('smd_macro_created');
} else {
// Update
$ret = safe_update(SMD_MACRO, "macro_name='$smd_macro_new_name', description='$smd_macro_description', attributes='$smd_macro_atts', definition='$smd_macro_definition', code='$code'", "macro_name='$smd_macro_name'");
$msg = smd_macro_gTxt('smd_macro_saved');
}
} else {
$msg = array(smd_macro_gTxt('smd_macro_exists'), E_WARNING);
}
}
} else {
$msg = array(smd_macro_gTxt('smd_macro_invalid'), E_WARNING);
}
smd_macro($msg);
}
// ------------------------
function smd_macro_delete() {
global $smd_macro_event;
$macro_name = doSlash(gps('smd_macro_name'));
$ret = safe_delete(SMD_MACRO, "macro_name='$macro_name'");
$msg = smd_macro_gTxt('smd_macro_deleted');
$_GET['smd_macro_name'] = '';
smd_macro($msg);
}
// ------------------------
// Check the macro doesn't exist and also that it doesn't clash with an internal PHP/TXP function
function smd_macro_exists($macro, $check_db = true) {
$ret = ($check_db) ? safe_field('macro_name', SMD_MACRO, "macro_name='$macro'") : false;
if ($ret === false) {
$fns = get_defined_functions();
foreach ($fns as $flist) {
if ($ret === false) {
$ret = in_array($macro, $flist);
}
}
}
return $ret;
}
// ------------------------
// Check the macro name is a valid PHP function name
function smd_macro_valid($macro) {
return is_callable($macro, true) && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $macro);
}
// ------------------------
function smd_macro_build($macro, $args, $def) {
$arglist = $reps = array();
$lAtts = '';
// Validate macro name and bail if it'd cause problems
// Build arg list and replacements array.
// Replacements are prefixed with the name of the macro for clash minimisation
$args = is_array($args) ? $args : unserialize($args);
foreach ($args as $arg => $vals) {
$arglist[] = "'$arg' => '".$vals['default']."'";
$rep = empty($vals['rep']) ? $arg : $vals['rep'];
$reps[] = '"{' . $rep . '}" => "$'.$macro.'_'.$arg.'"';
}
$arg_string = join(','.n, $arglist);
$rep_string = join(','.n, $reps);
$def = doSlash($def);
// Only create lAtts if there's at least one attribute defined
if ($arg_string) {
$lAtts = << 'base64_encode')
function smd_macro_create_ini($arr, $special=array()) {
$content = '';
foreach ($arr as $key => $elem) {
$content .= "[".$key."]\n";
foreach ($elem as $subkey => $subelem) {
$subelem = (array_key_exists($subkey, $special)) ? doArray($subelem, $special[$subkey]) : $subelem;
if(is_array($subelem)) {
$num = count($subelem);
for($idx = 0; $idx < $num; $idx++) {
$content .= $subkey . "[] = \"" . $subelem[$idx] . "\"\n";
}
} else if($subelem == "") {
$content .= $subkey . " = \n";
} else {
$content .= $subkey . " = \"" . $subelem . "\"\n";
}
}
}
return $content;
}
// ------------------------
// Add macro table if not already installed
function smd_macro_table_install($showpane='1') {
$GLOBALS['txp_err_count'] = 0;
$ret = '';
$sql = array();
$sql[] = "CREATE TABLE IF NOT EXISTS `".PFX.SMD_MACRO."` (
`macro_name` varchar(32) NOT NULL default '',
`description` varchar(255) NULL default '',
`attributes` text NULL default '',
`definition` mediumtext NULL default '',
`code` mediumtext NULL default '',
PRIMARY KEY (`macro_name`)
) 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";
}
}
$flds = getThings('describe `'.PFX.SMD_MACRO.'`');
if (!in_array('definition',$flds)) {
safe_alter(SMD_MACRO, "add `definition` mediumtext NULL default '' after `attributes`");
}
// Spit out results
if ($GLOBALS['txp_err_count'] == 0) {
if ($showpane) {
$msg = smd_macro_gTxt('smd_macro_tbl_installed');
smd_macro($msg);
}
} else {
if ($showpane) {
$msg = smd_macro_gTxt('smd_macro_tbl_not_installed');
smd_macro($msg);
}
}
}
// ------------------------
// Drop table if in database
function smd_macro_table_remove() {
$ret = '';
$sql = array();
$GLOBALS['txp_err_count'] = 0;
if (smd_macro_table_exist()) {
$sql[] = "DROP TABLE IF EXISTS " .PFX.SMD_MACRO. "; ";
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_macro_gTxt('smd_macro_tbl_removed');
} else {
$msg = smd_macro_gTxt('smd_macro_tbl_not_removed');
smd_macro($msg);
}
}
// ------------------------
function smd_macro_table_exist($all='') {
if ($all) {
$tbls = array(SMD_MACRO => 5);
$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_MACRO." HAS ".count(@safe_show('columns', SMD_MACRO))." COLUMNS;";
}
return(@safe_show('columns', SMD_MACRO));
}
}
// *********************
// PUBLIC SIDE INTERFACE
// *********************
// ------------------------
// Extracts all prebuilt macros (essentially, new tags) and injects them into the global scope so they can be called
function smd_macro_boot() {
$full_macros = array();
$rs = safe_rows('*', SMD_MACRO, '1=1');
foreach ($rs as $row) {
$full_macros[] = str_replace('\r\n','
',$row['code']); // yukky newline workaround
}
$macros = join(n, $full_macros);
// Inject the virtual tags into the global scope
eval($macros);
}
/**
* smd_macro_gTxt Convert strings for i18n purposes
*
* @param string $what [+] [private] [static] Name of the item from the array to retrieve
* @param array $atts [+] (Default: Array) Array of 'search' => 'replacements' to make
*/
function smd_macro_gTxt($what, $atts = array()) {
$lang = array(
'smd_macro_attributes' => 'Attributes',
'smd_macro_choose' => 'Select macro to edit:',
'smd_macro_att_clone' => '[+]',
'smd_macro_att_clone_help' => 'Add an attribute',
'smd_macro_cannot_import' => 'Unable to import macro. Please check folder permissions/settings on your host',
'smd_macro_clone' => 'Clone',
'smd_macro_created' => 'Macro created',
'smd_macro_deleted' => 'Macro deleted',
'smd_macro_exists' => 'Macro name already exists or clashes',
'smd_macro_export' => 'Export',
'smd_macro_file_size' => 'Macro file too large',
'smd_macro_import' => 'Import',
'smd_macro_imported' => 'Imported: ',
'smd_macro_invalid' => 'Macro name not valid',
'smd_macro_invalid_ini' => 'Macro file not in expected format',
'smd_macro_not_imported' => 'Not imported: ',
'smd_macro_overwrite' => 'Force overwrite',
'smd_macro_prefs_some_explain' => 'This is either a new installation or a different version'.br.'of the plugin to one you had before.',
'smd_macro_prefs_some_opts' => 'Click "Install table" to add or update the table'.br.'leaving all existing data untouched.',
'smd_macro_prefs_some_tbl' => 'Not all table info available.',
'smd_macro_repname' => 'Replacement name',
'smd_macro_saved' => 'Macro saved',
'smd_macro_skipped' => 'Skipped: ',
'smd_macro_tab_name' => 'Macros',
'smd_macro_tag_definition' => 'Macro definition',
'smd_macro_tbl_install_lbl' => 'Install table',
'smd_macro_tbl_installed' => 'Table installed',
'smd_macro_tbl_not_installed' => 'Table not installed',
'smd_macro_tbl_removed' => 'Table removed',
'smd_macro_tbl_not_removed' => 'Table not removed',
'smd_macro_upload' => 'Macro file',
);
return strtr($lang[$what], $atts);
}