diff -r 000000000000 -r df77b4db90d7 plugins/Linkchomper.php --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/Linkchomper.php Fri Oct 17 22:04:53 2008 -0400 @@ -0,0 +1,1040 @@ +sql_query('CREATE TABLE '.table_prefix.'linkchomper( + link_id mediumint(8) NOT NULL auto_increment, + link_name varchar(255) NOT NULL, + link_href text NOT NULL, + link_inner_html text NOT NULL, + link_before_html text NOT NULL, + link_after_html text NOT NULL, + link_flags tinyint(1) NOT NULL DEFAULT 0, + link_clicks bigint(15) NOT NULL DEFAULT 0, + link_order mediumint(8) NOT NULL DEFAULT 0, + PRIMARY KEY ( link_id ) + );'); + if ( !$q ) + { + // Prevent Linkchomper from loading again + $plugin_key = 'plugin_' . basename(__FILE__); + setConfig($plugin_key, '0'); + $db->_die('The error occurred during an attempt to create the table for Linkchomper. For your site\'s protection, Linkchomper has disabled itself. It can be re-enabled in the administration panel.'); + } + setConfig('linkchomper_version', '0.1b1'); +} + +// Hook into the template compiler + +$plugins->attachHook('links_widget', 'linkchomper_generate_html($ob);'); + +// Add our link tracking page + +$plugins->attachHook('base_classes_initted', ' + global $paths; + $paths->add_page(Array( + \'name\'=>\'LinkChomper click tracker\', + \'urlname\'=>\'LCClick\', + \'namespace\'=>\'Special\', + \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\', + )); + $paths->add_page(Array( + \'name\'=>\'Administration\', + \'urlname\'=>\'Linkchomper\', + \'namespace\'=>\'Admin\', + \'special\'=>0,\'visible\'=>0,\'comments_on\'=>0,\'protected\'=>1,\'delvotes\'=>0,\'delvote_ips\'=>\'\', + )); + $paths->addAdminNode(\'Plugin configuration\', \'Linkchomper manager\', \'Linkchomper\'); + '); + + +// Function to generate HTML for the sidebar widget + +function linkchomper_generate_html(&$links_array) +{ + global $db, $session, $paths, $template, $plugins; // Common objects + + $q = $db->sql_query('SELECT link_id, link_name, link_href, link_inner_html, link_before_html, link_after_html, link_flags FROM '.table_prefix.'linkchomper ORDER BY link_order ASC;'); + if ( !$q ) + $db->_die(); + + if ( $row = $db->fetchrow() ) + { + do { + + // Get flags + $flags =& $row['link_flags']; + + // Is this link disabled? If so, skip the whole painful process + if ( $flags & LC_LINK_DISABLED ) + continue; + + // First check to see if the inner_html is an image URL. If so, generate a nice img tag for the inner HTML. + if ( $flags & LC_LINK_INNER_IMAGE ) + { + $row['link_inner_html'] = '' . htmlspecialchars($row['link_name']) . ''; + } + + // If it's raw HTML, just send it through + if ( $flags & LC_LINK_RAW ) + { + $links_array[] = $row['link_before_html'] . $row['link_inner_html'] . $row['link_after_html']; + } + // If we're supposed to track clicks, send a deceptive anchor + else if ( $flags & LC_LINK_TRACK_CLICKS ) + { + $url = makeUrlNS('Special', 'LCClick/' . $row['link_id'], false, true); + // Escape target URL for Javascript-safety + $real_url = htmlspecialchars(str_replace(array('\\', '\'', '"'), array('\\\\', '\\\'', '\\"'), $row['link_href'])); + $link = $row['link_before_html'] . '' . $row['link_inner_html'] . '' . $row['link_after_html']; + $links_array[] = $link; + } + // None of those? OK just send a normal link + else + { + $url = htmlspecialchars($row['link_href']); + $link = $row['link_before_html'] . '' . $row['link_inner_html'] . '' . $row['link_after_html']; + $links_array[] = $link; + } + + } while ( $row = $db->fetchrow() ); + } + + $db->free_result(); + +} + +// Special page handler for click tracker + +function page_Special_LCClick() +{ + global $db, $session, $paths, $template, $plugins; // Common objects + + $link_id = ( $xx = $paths->getParam(0) ) ? intval($xx) : false; + + if ( !$link_id ) + die_friendly('Nice try', '

Hacking attempt

'); + + $q = $db->sql_query('SELECT link_href,link_flags FROM '.table_prefix.'linkchomper WHERE link_id=' . $link_id . ';'); + + if ( !$q ) + $db->_die(); + + $row = $db->fetchrow(); + $db->free_result(); + + if ( ! ( $row['link_flags'] & LC_LINK_TRACK_CLICKS ) ) + { + die_friendly('Nice try', '

This ain\'t no tracker link...

'); + } + + $q = $db->sql_query('UPDATE '.table_prefix.'linkchomper SET link_clicks=link_clicks+1 WHERE link_id=' . $link_id . ';'); + + if ( !$q ) + $db->_die(); + + redirect($row['link_href'], 'Redirecting', 'Thanks for clicking the link, you are now being transferred to the destination.', 0); + +} + +function linkchomper_admin_redirect_home($message = 'Your changes have been saved, and you will now be transferred back to the administration panel.') +{ + global $db, $session, $paths, $template, $plugins; // Common objects + $url = makeUrlComplete('Special', 'Administration', 'module=' . $paths->nslist['Admin'] . 'Linkchomper'); + redirect($url, 'Linkchomper changes saved', $message, 2); +} + +function page_Admin_Linkchomper() +{ + + //@ini_set('display_errors', 'On') or die('Can\'t set display_errors'); + //error_reporting(E_ALL); + + global $db, $session, $paths, $template, $plugins; // Common objects + if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN ) + { + echo '

Error: Not authenticated

It looks like your administration session is invalid or you are not authorized to access this administration page. Please re-authenticate to continue.

'; + return; + } + + if ( isset($_POST['action']) ) + { + if ( isset($_POST['action']['move_up']) || isset($_POST['action']['move_down']) ) + { + $direction = ( isset($_POST['action']['move_up']) ) ? 'up' : 'down'; + $ordering = ( isset($_POST['action']['move_up']) ) ? 'ASC' : 'DESC'; + + // Move an item up in the list + // First step: Get IDs of the item to move and the item above it + $id = array_keys($_POST['action']['move_' . $direction]); + $id = intval( $id[0] ); + if ( !$id ) + { + echo 'Hacking attempt'; + return false; + } + + $q = $db->sql_query('SELECT link_id, link_name, link_order FROM '.table_prefix.'linkchomper ORDER BY link_order ' . $ordering . ';'); + + if ( !$q ) + $db->_die(); + + $last_id = false; + $this_id = false; + + $last_order = false; + $this_order = false; + + $id_to = false; + $id_from = false; + + $order_to = false; + $order_from = false; + + while ( $row = $db->fetchrow() ) + { + $this_id = $row['link_id']; + $this_order = $row['link_order']; + if ( $this_id == $id && $last_id === false ) + { + linkchomper_admin_redirect_home('This item is already at the top or bottom of the list.'); + } + else if ( $this_id == $id ) + { + $id_from = $last_id; + $id_to = $this_id; + $order_from = $this_order; + $order_to = $last_order; + break; + } + $last_id = $this_id; + $last_order = $this_order; + } + + unset($this_id, $this_order, $last_id, $last_order); + + if ( $last_order === false || $this_order === false ) + { + linkchomper_admin_redirect_home('Sanity check failed.'); + } + + $sql1 = 'UPDATE '.table_prefix.'linkchomper SET link_order=' . $order_to . ' WHERE link_id=' . $id_to . ';'; + $sql2 = 'UPDATE '.table_prefix.'linkchomper SET link_order=' . $order_from . ' WHERE link_id=' . $id_from . ';'; + + if ( !$db->sql_query($sql1) ) + { + $db->_die(); + } + + if ( !$db->sql_query($sql2) ) + { + $db->_die(); + } + + linkchomper_admin_redirect_home('The item "' . $row['link_name'] . '" has been moved ' . $direction . '.'); + + } + else if ( isset($_POST['action']['delete']) ) + { + // Delete a link + $id = array_keys($_POST['action']['delete']); + $id = intval( $id[0] ); + if ( !$id ) + { + echo 'Hacking attempt'; + return false; + } + $q = $db->sql_query('DELETE FROM '.table_prefix."linkchomper WHERE link_id=$id;"); + if ( !$q ) + $db->_die(); + + linkchomper_admin_redirect_home('The selected link has been deleted.'); + } + + linkchomper_admin_redirect_home('Invalid or no action defined'); + } + + else if ( isset($_POST['stage2']) ) + { + $_GET['module'] = $paths->page; + $_POST['stage2_real'] = $_POST['stage2']; + unset($_POST['stage2']); + page_Special_Administration(); + return true; + } + + else if ( isset($_POST['stage2_real']) ) + { + /* + + TODO: + The idea here is to build a template-based unified edit form that will be used both for creating and editing links. Make it have + intelligent auto-hiding/auto-(un)checking elements and make it use the standard flags field. + + */ + // allow breaking out + switch(true){case true: + $stage2 =& $_POST['stage2_real']; + $err_and_revert = array( + 'error' => false + ); + if ( isset($stage2['delete']) ) + { + $id = array_keys($stage2['delete']); + $id = intval( $id[0] ); + if ( !$id ) + { + echo 'Hacking attempt'; + return false; + } + echo '
'; + echo '
+ '; + echo ' + + + + + + '; + + echo '
Confirm deletion
+ Are you sure you want to permanently delete this link? +
+ + +
+
'; + echo '
'; + } + else if ( isset($stage2['create_new']) ) + { + $editor = new LinkchomperFormGenerator(); + $editor->echo_html(); + } + else if ( isset($stage2['edit']) ) + { + $id = array_keys($stage2['edit']); + $id = intval( $id[0] ); + if ( !$id ) + { + echo 'Hacking attempt'; + return false; + } + $q = $db->sql_query('SELECT * FROM '.table_prefix."linkchomper WHERE link_id=$id;"); + if ( !$q ) + $db->_die(); + if ( $db->numrows() < 1 ) + { + echo "Can't find link: $id"; + $db->free_result(); + } + else + { + $row = $db->fetchrow(); + $db->free_result(); + $editor = new LinkchomperFormGenerator(); + $editor->track_clicks = ( $row['link_flags'] & LC_LINK_TRACK_CLICKS ); + $editor->raw_html = ( $row['link_flags'] & LC_LINK_RAW ); + $editor->link_flag_image = ( $row['link_flags'] & LC_LINK_INNER_IMAGE ); + $editor->link_disabled = ( $row['link_flags'] & LC_LINK_DISABLED ); + $editor->link_target = $row['link_href']; + $editor->link_name = $row['link_name']; + $editor->mode = LC_EDIT; + $editor->inner_html = $row['link_inner_html']; + $editor->before_html = $row['link_before_html']; + $editor->after_html = $row['link_after_html']; + $editor->link_id = $row['link_id']; + $editor->echo_html(); + } + } + else if ( isset($stage2['create_new_finish']) ) + { + $flags = 0; + + // Validation + $errors = array(); + + $link_name = trim($_POST['link_name']); + if ( empty($link_name) ) + $errors[] = 'Please enter a name for your link.'; + + if ( isset($_POST['raw_html']) && isset($_POST['track_clicks']) ) + $errors[] = 'Raw blocks cannot be used with clicktracking.'; + + $link_target = trim($_POST['link_target']); + if ( empty($link_target) && !isset($_POST['raw_html']) ) + $errors[] = 'Please enter a target for your link.'; + + if ( $_POST['link_flag_img'] == '1' ) + { + $inner_html = trim($_POST['link_img_path']); + if ( empty($inner_html) ) + $errors[] = 'Please enter a path or URL to an image file.'; + } + else + { + $inner_html = trim($_POST['link_inner_html']); + if ( empty($inner_html) ) + $errors[] = 'Please enter some content to go inside your link.'; + } + + if ( count($errors) > 0 ) + { + $err_and_revert['error'] = true; + $err_and_revert['message'] = implode("
\n ", $errors); + } + else + { + if ( isset($_POST['link_disabled']) ) + $flags = $flags | LC_LINK_DISABLED; + if ( $_POST['link_flag_img'] == '1' ) + $flags = $flags | LC_LINK_INNER_IMAGE; + if ( isset($_POST['raw_html']) ) + $flags = $flags | LC_LINK_RAW; + if ( isset($_POST['track_clicks']) ) + $flags = $flags | LC_LINK_TRACK_CLICKS; + + $before_html = strval(trim($_POST['link_before_html'])); + $after_html = strval(trim($_POST['link_after_html'])); + + if ( !$session->get_permissions('php_in_pages') ) + { + // Not allowed to embed PHP and Javascript + $before_html = sanitize_html($before_html); + $after_html = sanitize_html($after_html); + $inner_html = sanitize_html($inner_html); + } + + $sanitized = array( + 'link_name' => $db->escape($link_name), + 'link_target' => $db->escape($link_target), + 'link_inner_html' => $db->escape($inner_html), + 'link_before_html' => $db->escape($before_html), + 'link_after_html' => $db->escape($after_html) + ); + + $sql = "INSERT INTO ".table_prefix."linkchomper(link_name, link_href, link_inner_html, link_before_html, link_after_html, link_flags, link_order) VALUES('{$sanitized['link_name']}','{$sanitized['link_target']}','{$sanitized['link_inner_html']}','{$sanitized['link_before_html']}','{$sanitized['link_after_html']}', $flags, ".LC_ADMIN_ORDER_LAST.");"; + if ( !$db->sql_query($sql) ) + $db->_die(); + + echo '
Link created.
'; + break; + } + } + else if ( isset($stage2['edit_finish']) ) + { + $flags = 0; + + // Validation + $errors = array(); + + $link_name = trim($_POST['link_name']); + if ( empty($link_name) ) + $errors[] = 'Please enter a name for your link.'; + + if ( isset($_POST['raw_html']) && isset($_POST['track_clicks']) ) + $errors[] = 'Raw blocks cannot be used with clicktracking.'; + + $link_target = trim($_POST['link_target']); + if ( empty($link_target) && !isset($_POST['raw_html']) ) + $errors[] = 'Please enter a target for your link.'; + + if ( $_POST['link_flag_img'] == '1' ) + { + $inner_html = trim($_POST['link_img_path']); + if ( empty($inner_html) ) + $errors[] = 'Please enter a path or URL to an image file.'; + } + else + { + $inner_html = trim($_POST['link_inner_html']); + if ( empty($inner_html) ) + $errors[] = 'Please enter some content to go inside your link.'; + } + + $link_id = intval($_POST['link_id']); + if ( $link_id < 1 ) + $errors[] = 'Unable to obtain link ID'; + + if ( count($errors) > 0 ) + { + $err_and_revert['error'] = true; + $err_and_revert['message'] = implode("
\n ", $errors); + } + else + { + if ( isset($_POST['link_disabled']) ) + $flags = $flags | LC_LINK_DISABLED; + if ( $_POST['link_flag_img'] == '1' ) + $flags = $flags | LC_LINK_INNER_IMAGE; + if ( isset($_POST['raw_html']) ) + $flags = $flags | LC_LINK_RAW; + if ( isset($_POST['track_clicks']) ) + $flags = $flags | LC_LINK_TRACK_CLICKS; + + $before_html = strval(trim($_POST['link_before_html'])); + $after_html = strval(trim($_POST['link_after_html'])); + + if ( !$session->get_permissions('php_in_pages') ) + { + // Not allowed to embed PHP and Javascript + $before_html = sanitize_html($before_html); + $after_html = sanitize_html($after_html); + $inner_html = sanitize_html($inner_html); + } + + $sanitized = array( + 'link_name' => $db->escape($link_name), + 'link_target' => $db->escape($link_target), + 'link_inner_html' => $db->escape($inner_html), + 'link_before_html' => $db->escape($before_html), + 'link_after_html' => $db->escape($after_html) + ); + + $sql = "UPDATE ".table_prefix."linkchomper SET link_name='{$sanitized['link_name']}',link_href='{$sanitized['link_target']}',link_inner_html='{$sanitized['link_inner_html']}',link_before_html='{$sanitized['link_before_html']}',link_after_html='{$sanitized['link_after_html']}',link_flags=$flags WHERE link_id=$link_id;"; + if ( !$db->sql_query($sql) ) + $db->_die(); + + echo '
Your changes have been saved.
'; + break; + } + } + else if ( isset($stage2['cancel']) ) + { + break; + } + else + { + echo 'Undefined Superform handler:
' . htmlspecialchars(print_r($stage2, true)) . '
'; + } + if ( $err_and_revert['error'] ) + { + $editor = new LinkchomperFormGenerator(); + $editor->error = $err_and_revert['message']; + $editor->track_clicks = ( isset($_POST['track_clicks']) && !isset($_POST['raw_html']) ); + $editor->raw_html = ( isset($_POST['raw_html']) && !isset($_POST['track_clicks']) ); + $editor->link_flag_image = ( $_POST['link_flag_img'] == '1' ); + $editor->link_disabled = ( isset($_POST['link_disabeld']) ); + $editor->link_target = $_POST['link_target']; + $editor->link_name = $_POST['link_name']; + $editor->mode = ( isset($stage2['create_new_finish']) ) ? LC_CREATE : LC_EDIT; + $editor->inner_html = $_POST['link_inner_html']; + $editor->before_html = $_POST['link_before_html']; + $editor->after_html = $_POST['link_after_html']; + $editor->link_id = ( isset($stage2['create_new_finish']) ) ? -1 : intval($_POST['link_id']); + $editor->echo_html(); + } + return true; + } + } + + echo <<Linkchomper link manager +

Linkchomper is a plugin that allows you to add custom content to the "Links" block on your sidebar. You can add tracking links, raw HTML, or just normal links.

+EOF; + + echo '
'; + echo '
+ + + + + + + '; + + $q = $db->sql_query('SELECT link_id, link_name, link_href, link_flags, link_clicks, link_order FROM '.table_prefix.'linkchomper ORDER BY link_order ASC;'); + + if ( !$q ) + $db->_die(); + + $num_rows = $db->numrows(); + $i = 0; + + if ( $row = $db->fetchrow() ) + { + do { + echo ''; + echo ''; + echo ''; + echo ''; + // Admin actions + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + $i++; + } while ( $row = $db->fetchrow() ); + } + else + { + echo ' + + '; + } + + echo ' + + '; + + echo '
Link nameLink targetClicksAdmin
' . htmlspecialchars($row['link_name']) . '' . ( ( $row['link_flags'] & LC_LINK_RAW ) ? '<Raw HTML block>' : '' . htmlspecialchars($row['link_href']) . '' ) . '' . ( ( $row['link_flags'] & LC_LINK_TRACK_CLICKS ) ? $row['link_clicks'] : '' ) . '
+ You haven\'t created any links yet. +
+ +
'; + echo '
'; + + // */ + +} + +// Hopefully no one will ever get 4 billion links in their sidebar. +define('LC_ADMIN_ORDER_LAST', ( pow(2, 33)-3 )); + +/** + * Class to generate edit forms for Linkchomper links. + * @package Enano + * @subpackage Linkchomper + * @license GNU General Public License + */ + +class LinkchomperFormGenerator +{ + + /** + * What this editor instance does, create or edit. Should be LC_EDIT or LC_CREATE. + * @var int + */ + + var $mode = LC_CREATE; + + /** + * The name of the link. + * @var string + */ + + var $link_name = ''; + + /** + * Link ID - only used when editing + * @var int + */ + + var $link_id = -1; + + /** + * Flag for raw HTML switch + * @var bool + */ + + var $raw_html = false; + + /** + * Flag for inner HTML field is an image URL + * @var bool + */ + + var $image_url = false; + + /** + * Flag to determine if clicks will be tracked + * @var bool + */ + + var $track_clicks = false; + + /** + * "Appear after" (link order) + * @var int The link ID to appear after + */ + + var $appear_after = LC_ADMIN_ORDER_LAST; + + /** + * Link target. + * @var string + */ + + var $link_target = 'http://www.example.com/'; + + /** + * If the image flag is on, this should be set to true. Should only be used while editing. + * @var bool + */ + + var $link_flag_image = false; + + /** + * Set to true if the link is disabled (hidden) + * @var bool + */ + + var $link_disabled = false; + + /** + * The inner HTML (or image URL) + * @var string + */ + + var $inner_html = ''; + + /** + * HTML shown before the link + * @var string + */ + + var $before_html = ''; + + /** + * HTML shown after the link + * @var string + */ + + var $after_html = ''; + + /** + * Unique identifier used for Javascript bits + * @var string + * @access private + */ + + var $uuid = ''; + + /** + * Error message to show at the top of the form. Default is false for no error. + * @var string + */ + + var $error = ''; + + /** + * Constructor. + */ + + function __construct() + { + $uuid = md5( mt_rand() . microtime() . @file_get_contents('/proc/uptime') /* That last one's just for fun ;-) */ ); + if ( file_exists('/dev/urandom') ) + { + $f = @fopen('/dev/urandom', 'r'); + if ( $f ) + { + $random = fread($f, 16); + $random = hexencode($random, '', ''); + fclose($f); + $uuid = $random; + } + } + $this->uuid = $uuid; + } + + /** + * PHP 4 constructor + */ + + function LinkchomperFormGenerator() + { + $this->__construct(); + } + + /** + * Generates the ready to use HTML. + * @return string + */ + + function get_html() + { + global $db, $session, $paths, $template, $plugins; // Common objects + + if ( !empty($template->theme) && file_exists(ENANO_ROOT . '/themes/' . $template->theme . '/linkchomper_editor.tpl') ) + { + $parser = $template->makeParser('linkchomper_editor.tpl'); + } + else + { + $tpl_code = << + + +
+ The following error occurred while creating the linksaving your changes:
+ {ERROR_MESSAGE} +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Create new link + + + Editing link: {LINK_NAME} + +
+
+ This is only used "internally" for your convenience - the user never sees this value. +
+ +
+ Link options: + +

+

+

+
+ Link target:
+ This should be in the format of http://url. +
+ +
+ Content inside link:
+ You may use HTML here. +
+ Use inside link: +
+ Path to image, relative or absolute:
+
+
+  +
+
+ {TEXTAREA_HTML_INNER} +
+
+ Text before link:
+ You may use HTML here. +
+ {TEXTAREA_HTML_BEFORE} +
+ Text after link:
+ You may use HTML here. +
+ {TEXTAREA_HTML_AFTER} +
+ + + + + + + +
+
+ + + +
+ +EOF; + $parser = $template->makeParserText($tpl_code); + } + + $form_action = makeUrlNS('Admin', 'Linkchomper'); + + $sanitized = array( + 'name' => &$this->link_name, + 'target' => &$this->link_target, + 'inner' => &$this->inner_html, + 'before' => &$this->before_html, + 'after' => &$this->after_html + ); + + foreach ( $sanitized as $id => $item ) + { + unset($sanitized[$id]); + $sanitized[$id] = htmlspecialchars($item); + } + + $textarea_html_inner = $template->tinymce_textarea('link_inner_html', $sanitized['inner'], 10, 60); + $textarea_html_before = $template->tinymce_textarea('link_before_html', $sanitized['before'], 10, 60); + $textarea_html_after = $template->tinymce_textarea('link_after_html', $sanitized['after'], 10, 60); + + if ( $this->mode == LC_EDIT ) + { + $parser->assign_vars(array( + 'LINK_ID' => $this->link_id + )); + } + + $parser->assign_vars(array( + 'UUID' => $this->uuid, + 'FORM_ACTION' => $form_action, + 'LINK_NAME' => $sanitized['name'], + 'LINK_TARGET' => $sanitized['target'], + 'HTML_INNER' => $sanitized['inner'], + 'HTML_BEFORE' => $sanitized['before'], + 'HTML_AFTER' => $sanitized['after'], + 'TEXTAREA_HTML_INNER' => $textarea_html_inner, + 'TEXTAREA_HTML_BEFORE' => $textarea_html_before, + 'TEXTAREA_HTML_AFTER' => $textarea_html_after, + 'ERROR_MESSAGE' => strval($this->error) + )); + $parser->assign_bool(array( + 'raw_html' => $this->raw_html, + 'track_clicks' => $this->track_clicks, + 'mode_is_create' => ( $this->mode == LC_CREATE ), + 'mode_is_edit' => ( $this->mode == LC_EDIT ), + 'show_error' => ( !empty($this->error) ), + 'link_flag_image' => $this->link_flag_image, + 'link_disabled' => $this->link_disabled + )); + + $html = $parser->run(); + + return $html; + + } + + /** + * For convenience. Echoes out HTML. + */ + + function echo_html() + { + echo $this->get_html(); + } + +} + +?>