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 '
'; echo startTable('smd_macro_select', '', '', '', '800'); echo tr( tda($editcell . eInput($smd_macro_event), ' class="noline" style="text-align: right; vertical-align: middle;"') ); echo endTable(); 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) ? '
' . $multi_macsel . br . fInput('submit', 'smd_macro_export_go', gTxt('go'), '', '', 'smd_macro_export_close();') . eInput($smd_macro_event) . sInput('smd_macro_export') . '
' . '
' . hInput('smd_macro_name', $macro_name) . fInput('text', 'smd_macro_new_name', '') . fInput('submit', 'smd_macro_clone_go', gTxt('go')) . eInput($smd_macro_event) . sInput('smd_macro_clone') . '
' : '' ) , ' class="noline" style="text-align: right; vertical-align: middle;"' ) ); echo endTable(); echo '
'; echo startTable('edit'); echo tr( fLabelCell('name', '', 'smd_macro_new_name') .td( fInput('text', 'smd_macro_new_name', $macro_new_name).fInput('hidden', 'smd_macro_name', $macro_name) .(($macro_name == '') ? '' : sp.'[x]') ) ); echo tr( fLabelCell('description', '', 'smd_macro_description') .td( fInput('text', 'smd_macro_description', $macro_description, '', '', '', '66') ) ); $attlist = array(''); $macro_atts = empty($macro_atts) ? array('' => array('default' => '', 'rep' => '')) : $macro_atts; foreach ($macro_atts as $attname => $att) { $attlist[] = '' .'' .'' .'' .''; } $attlist[] = '
'.gTxt('name').''.gTxt('default').''.smd_macro_gTxt('smd_macro_repname').'
'.fInput('text', 'smd_macro_attname[]', $attname). ''.fInput('text', 'smd_macro_attdflt[]', $att['default']). ''.fInput('text', 'smd_macro_attrep[]', $att['rep']). '
'; $atts = join(n, $attlist); echo tr( tda(''.sp.''.smd_macro_gTxt('smd_macro_att_clone').'', ' class="noline" style="text-align: right; vertical-align: top;"') .tda($atts, ' id="smd_macro_att"') ); echo tr( tda('', ' class="noline" style="text-align: right; vertical-align: top;"') .tda( text_area('smd_macro_definition', 250, 700, $macro_def) ) ); echo tr(td(' ').eInput($smd_macro_event).sInput('smd_macro_save').td(fInput('submit', 'save', gTxt('save'), 'smallerbox', '', ''))); 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 = '
'.fInput('submit', 'submit', smd_macro_gTxt('smd_macro_tbl_install_lbl'), 'smallerbox').'
'; $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); }