An Installation System for Wikka Actions




There are a certain number of patterns popping out of the action development routine -- sometimes there is MySQL, sometimes there is CSS, sometimes there are changes to the configuration file, and there is always PHP code.

It would be nice if we could define all of these things in a single wiki page and then use it as a type of "installation file." That is what this action does.

To start off, we're going to need to make some serious changes to the show handler, the Run() and Action() methods in wikka.php, wikka.config.php, and the header action.

Let's start with the show handler... (handler/page/show.php)

<?php

$edit = (!$user || ($user["doubleclickedit"] == 'Y')) && ($this->GetMethod() == "show") ? ' ondblclick="document.location=\'' . $this->href('edit') . '\';"' : '';
$body = "<div class=\"page\" $edit>";

if (!$this->HasAccess("read"))
{
    $body .= "<p><em>You aren't allowed to read this page.</em></p></div>";
}
else
{
    if (!$this->page)
    {
        $body .= "<p>This page doesn't exist yet. Maybe you want to <a href=\"".$this->Href("edit")."\">create</a> it?</p></div>";
    }
    else
    {
        if ($this->page["latest"] == "N")
        {
            $body .= "<div class=\"revisioninfo\">This is an old revision of <a href=\"".$this->Href()."\">".$this->GetPageTag()."</a> from ".$this->page["time"].".</div>";
        }

        if (preg_match_all('/\{\{(.*)\}\}/U', $this->page['body'], $matches))
        {
            foreach ($matches[1] as $match)
            {
                if ($space = strpos($match, ' ')) $match = substr($match, 0, $space);
                $lc_action = strtolower($match);
                if (!isset($this->config['css_files'][$lc_action]) && isset($this->config["{$lc_action}_version"]))
                {
                    $css_file = $this->config['installer_base_dir'] . "/actioncss/$lc_action.css";
                    if (file_exists($css_file))
                    $this->config['css_files'][$lc_action] .= $css_file;
                }
            }
        }

        $body .= $this->Format($this->page['body'], 'wakka');

        // if this is an old revision, display some buttons
        if ($this->page["latest"] == "N" && $this->HasAccess("write"))
        {
            // dotmg modifications : contact m.randimbisoa@dotmg.net
            // #dotmg [1 line modified, 2 lines added, 7 lines indented]: added if encapsulation : in case where some pages were brutally deleted from database
            if ($latest = $this->LoadPage($this->tag))
            {
                $body .= '<br />';
                $body .= $this->FormOpen('edit');
                $body .= '<input type="hidden" name="previous" value="' . $latest['id'] . '" />';
                $body .= '<input type="hidden" name="body" value="' . $this->htmlspecialchars_ent($this->page['body']) . '" />';
                $body .= '<input type="submit" value="Re-edit this old revision" />';
                $body .= $this->FormClose();
            }
        }
        $body .= '</div>';
        if ($this->GetConfigValue('hide_comments') != 1)
        {
            // load comments for this page
            $comments = $this->LoadComments($this->tag);

            // store comments display in session
            $tag = $this->GetPageTag();
            if (!isset($_SESSION["show_comments"][$tag]))
                $_SESSION["show_comments"][$tag] = ($this->UserWantsComments() ? "1" : "0");
            if (isset($_REQUEST["show_comments"])){ 
                switch($_REQUEST["show_comments"])
                {
                case "0":
                    $_SESSION["show_comments"][$tag] = 0;
                    break;
                case "1":
                    $_SESSION["show_comments"][$tag] = 1;
                    break;
                }
            }
            // display comments!
            if ($_SESSION["show_comments"][$tag])
            {
                // display comments header
                $body .= '<div class="commentsheader">';
                $body .= '<span id="comments">&nbsp;</span>Comments [<a href="' . $this->Href("", "", "show_comments=0") . '">Hide comments/form</a>]';
                $body .= '</div>';

                // display comments themselves
                if ($comments)
                {
                    $current_user = $this->GetUserName();
                    foreach ($comments as $comment)
                    {
                        $body .= "<div class=\"comment\"> \n";
                        $body .= "<span id=\"comment_" . $comment['id'] . '"></span>' . $comment["comment"] . "\n";
                        $body .= "\t<div class=\"commentinfo\">\n-- " . $this->Format($comment["user"]) . ' (' . $comment['time'] . ")\n";
                        $current_user = $this->GetUserName();
                        if ($this->UserIsOwner() || $current_user == $comment["user"] || ($this->config['anony_delete_own_comments'] && $current_user == $comment["user"]) )
                        {
                            $body .= $this->FormOpen('delcomment');
                            $body .= '<input type="hidden" name="comment_id" value="' . $comment['id'] . '" />';
                            $body .= '<input type="submit" value="Delete Comment" accesskey="d" />';
                            $body .= $this->FormClose();
                        }
                        $body .= "\n\t</div>\n";
                        $body .= "</div>\n";
                    }
                }
                // display comment form
                $body .= "<div class=\"commentform\">\n";
                if ($this->HasAccess('comment'))
                {
                    $body .= $this->FormOpen("addcomment");
                    $body .= '<label for="commentbox">Add a comment to this page:<br />';
                    $body .= '<textarea id="commentbox" name="body" rows="6" cols="78"></textarea><br />';
                    $body .= '<input type="submit" value="Add Comment" accesskey="s" />';
                    $body .= '</label>';
                    $body .= $this->FormClose();
                }
                $body .= "</div>\n";
            }
            else
            {
                $body .= '<div class="commentsheader">';
                switch (count($comments))
                {
                case 0:
                    $body .= '<p>There are no comments on this page. ';
                    $showcomments_text = 'Add comment';
                    break;
                case 1:
                    $body .= '<p>There is one comment on this page. ';
                    $showcomments_text = 'Display comment';
                    break;
                default:
                    $body .= '<p>There are ' . count($comments) . ' comments on this page. ';
                    $showcomments_text = 'Display comments';
                }
                $body .= '[<a href="' . $this->Href('', '', 'show_comments=1#comments') . "\">$showcomments_text</a>]</p></div>";
            }
        }
    }
}

$page = $this->Header() . $body . $this->Footer();
echo $page;

?>


As you can see, the entire file has changed. Instead of directly printing everything to output, we're collecting it in a variable called $page. Also, we've moved the calls to Header() and Footer() out of the Run() method in wikka.php and put them at the bottom of this file. This will allow for actions to send headers to the browser directly, rather than requiring developers to define a separate "handler" file for such cases (please discuss: was this ever actually a requirement?). With this setup, actions will now be processed before anything is sent back to the browser.

The other notable change to the show handler is this snippet of code:

        if (preg_match_all('/\{\{(.*)\}\}/U', $this->page['body'], $matches))
        {
            foreach ($matches[1] as $match)
            {
                if ($space = strpos($match, ' ')) $match = substr($match, 0, $space);
                $lc_action = strtolower($match);
                if (!isset($this->config['css_files'][$lc_action]) && isset($this->config["{$lc_action}_version"]))
                {
                    $css_file = $this->config['installer_base_dir'] . "/actioncss/$lc_action.css";
                    if (file_exists($css_file))
                    $this->config['css_files'][$lc_action] .= $css_file;
                }
            }
        }


Here we look through the current page for any calls to actions that are installed on the system (through the InstallableActions interface). If we find any that included a CSS file as part of their installation package, we add the corresponding CSS file to an array.

Next we have to edit the header action to include these files in the output. Open up actions/header.php and locate the line that prints out the stylesheets...

    <link rel="stylesheet" type="text/css" href="css/<?php echo $this->GetConfigValue("stylesheet") ?>" />
    <?php
        if (is_array($this->config['css_files']))
        {
            foreach ($this->config['css_files'] as $css_file)
            {
                echo '<link rel="stylesheet" type="text/css" href="' . $css_file . "\" />\n";
            }
        }
    ?>


The php code should be inserted after the main wikka CSS stylesheet, as indicated above.

Now it's time to replace the Action() method in root/wikka.php:

    function Action($action, $forceLinkTracking = 0)
    {
        $action = trim($action);
        $vars=array();
        // only search for parameters if there is a space
        if (is_int(strpos($action, ' ')))
        {
            // treat everything after the first whitespace as parameter
            preg_match("/^([A-Za-z0-9]*)\s+(.*)$/", $action, $matches);
            // extract $action and $vars_temp ("raw" attributes)
            list(, $action, $vars_temp) = $matches;
            if ($action) {
                // match all attributes (key and value)
                preg_match_all("/([A-Za-z0-9]*)=\"(.*)\"/U", $vars_temp, $matches);

                // prepare an array for extract() to work with (in $this->IncludeBuffered())
                    if (is_array($matches)) {
                        for ($a = 0; $a < count($matches[0]); $a++) {
                            $vars[$matches[1][$a]] = $matches[2][$a];
                        }
                    }
                $vars["wikka_vars"] = trim($vars_temp); // <<< add the buffered parameter-string to the array
            } else {
                return "<span class='error'><em>Unknown action; the action name must not contain special characters.</em></span>"; // <<< the pattern ([A-Za-z0-9])\s+ didn't match!
            }
        }
        if (!preg_match("/^[a-zA-Z0-9]+$/", $action)) return "<span class='error'><em>Unknown action; the action name must not contain special characters.</em></span>";
        if (!$forceLinkTracking) $this->StopLinkTracking();
        $action_name = strtolower($action);
        $action_path = isset($this->config["{$action_name}_version"]) ? $this->config['installer_base_dir'] . '/actions/' : $this->config['action_path'];
        $result = $this->IncludeBuffered("$action_name.php", "<em>Unknown action \"$action\"</em>", $vars, $action_path);
        $this->StartLinkTracking();
        return $result;
    }


Only a few lines at the bottom have changed, but I included the whole thing so you don't have to scratch your head about where to insert the new code.

We'll do the same for the Run() method in the same file (root/wikka.php):

    function Run($tag, $method = "")
    {
        // do our stuff!
        if (!$this->method = trim($method)) $this->method = "show";
        if (!$this->tag = trim($tag)) $this->Redirect($this->Href("", $this->config["root_page"]));
        if ((!$this->GetUser() && isset($_COOKIE["wikka_user_name"])) && ($user = $this->LoadUser($_COOKIE["wikka_user_name"], $_COOKIE["wikka_pass"]))) $this->SetUser($user);
        $this->SetPage($this->LoadPage($tag, (isset($_REQUEST["time"]) ? $_REQUEST["time"] :'')));
   
        $this->LogReferrer();
        $this->ACLs = $this->LoadAllACLs($this->tag);
        $this->ReadInterWikiConfig();
        if(!($this->GetMicroTime()%3)) $this->Maintenance();

        if (preg_match('/\.(xml|mm)$/', $this->method))
        {
            header("Content-type: text/xml");
            print($this->Method($this->method));
        }
        // raw page handler
        elseif ($this->method == "raw")
        {
            header("Content-type: text/plain");
            print($this->Method($this->method));
        }
        elseif (preg_match('/\.(gif|jpg|png)$/', $this->method))
        {
            header('Location: images/' . $this->method);
        }
        elseif (preg_match('/\.css$/', $this->method))
        {
            header('Location: css/' . $this->method);
        }
        elseif ($this->method == 'show')
        {
            // show will handle the display of headers and footers from now on.
            print($this->Method('show'));
        }
        else
        {
            print($this->Header().$this->Method($this->method).$this->Footer());
        }
    }
}


A special case for the show handler has been added -- the elseif ($this->method == 'show') part. That's the only change.

Now we need to open up wikka.config.php and add the following lines to the bottom of the file:

// load actions defined by InstallableActions
// wikka.config.php settings will take precedence
include('uploads/action.config.php');
$wakkaConfig = array_merge($action_config, $wakkaConfig);


As you can see, the InstallableActions action has its own config file. Whether or not this is more secure is debatable, but at least it means the Installer isn't going to trash all of your settings when it tries to write a new config file.

Speaking of writing a new config file, maybe we should go ahead and do that. Save the following code as uploads/action.config.php:

<?php
$action_config = array (
  'installer_base_dir' => 'uploads'
);
?>


Also, create two directories in the uploads directory named "actions" and "actioncss"

Save the following in the wikka root directory as "util.php"...

<?php
function smart_title($wikka_body)
{
    return preg_match('/(=){2,5}([^=]*)(=){2,5}/', $wikka_body, $matches) ? $matches[2] : '';
}
function fetch_section($wikka_body, $section)
{
    return preg_match("/(=){2,5}$section(=){2,5}([^=]*)(\n\n)/ism", $wikka_body, $matches) ? $matches[3] : false;
}
function fetch_code_block($wikka_body, $language)
{
    return preg_match("/%REMOVE ME%\($language\)(.*)%REMOVE ME%/ismU", $wikka_body, $matches) ? $matches[1] : false;
}
if (!function_exists('file_put_contents'))
{
    function file_put_contents($filename, $data, $file_append = false)
    {
        $fp = fopen($filename, (!$file_append ? 'w+' : 'a+'));
        if(!$fp) return false;
        fputs($fp, $data);
        fclose($fp);
        return true;
    }
}
?>


Note: You'll have to find %REMOVE ME% and replace with %% in your text editor before the above code will work.

Save the following in the actions directory as installer.php:

<?php

if ($this->IsAdmin())
{

// where will this installer put the files?
$installer_base_dir =  $this->config['installer_base_dir'];
$table_pages = $this->config['table_prefix'] . 'pages';
       
include_once('util.php');

function parse_config_settings($config)
{
    if ($config)
    {
        $settings = split("\n", $config);
        foreach ($settings as $setting)
        {
            if ($setting = trim($setting))
            {
                list($key, $val) = split('=>', $setting);
                $config_vars[trim($key)] = trim(str_replace("'", '', $val));
            }
        }
        return $config_vars;
    }
    return false;
}

$sql = "SELECT tag, body FROM $table_pages WHERE MATCH (body) AGAINST ('InstallableAction') AND latest = 'Y' ORDER BY tag";
$result = mysql_query($sql);
if ($result && mysql_num_rows($result))
{
    while ($row = mysql_fetch_array($result))
    {
        $version_tag = strtolower($row['tag']) . '_version';
        $regex = "$version_tag.*'(.*)'";
        $current_version = preg_match("|$regex|U", $row['body'], $match) ? $match[1] : null;
        if (strstr($row['body'], '%REMOVE ME%(php)') && $current_version)
        {
            $currently_installing = isset($_REQUEST['installer_install']) && $_REQUEST['installer_install'] == $row['tag'];
            $installable_actions[$row['tag']] = $row['body'];
            $action = '<a href="' . $this->Href('', $row['tag']) . "\">$row[tag]</a>";
            $installed_version =  isset($this->config[$version_tag]) && !$currently_installing ? $this->config[$version_tag] : '--';
            if (!$summary = smart_title($row['body'])) $summary = 'None';
            $mysql = strstr($row['body'], '%REMOVE ME%(mysql)') ? 'Yes' : 'No';
            $css = strstr($row['body'], '%REMOVE ME%(css)') ? 'Yes' : 'No';
            if ($installed_version == '--' || $installed_version != $current_version)
            {
                $install_link = '<a href="' . $this->Href('','', "installer_install=$row[tag]") . '">Install</a>';
            }
            else
            {
                $install_link = '<span style="color:#393">Install</span>';
            }
            $remove_link = ($installed_version != '--') ? '<a href="' . $this->Href('','', "installer_remove=$row[tag]") . '">Remove</a>' : '';
            $actions = $remove_link ? "$install_link&nbsp;&nbsp;$remove_link" : $install_link;
            $color = (++$i % 2 != 0) ? 'bgcolor="#f6f6f6"' : '';
            if ($installed_version != '--') $color = 'bgcolor="#ccffcc"';
            $rows .= "<tr $color><td style=\"text-align:left\" valign=\"top\">$action</td>
                          <td style=\"text-align:left\">$summary</td>
                          <td valign=\"top\" align=\"center\">$installed_version</td>
                          <td valign=\"top\" align=\"center\">$current_version</td>
                          <td valign=\"top\" align=\"center\">$mysql</td>
                          <td valign=\"top\" align=\"center\">$css</td>
                          <td valign=\"top\">$actions</td></tr>"
;
        }
    }
}

if (isset($_REQUEST['installer_install']))
{
    $install_action = $_REQUEST['installer_install'];
    if (isset($installable_actions[$install_action]))
    {
        $action_body =& $installable_actions[$install_action];
        $hidden_tag_field = "<input type=\"hidden\" name=\"installer_install\" value=\"$install_action\" />";
        $next_step = isset($_REQUEST['next_step']) ? $_REQUEST['next_step'] : 'readme';
        echo $this->FormOpen();
        echo "<h2>Installing $install_action...</h2><br />";
        $buttons['continue'] = '<input type="submit" value="Continue" />';
        $buttons['cancel'] = '<input type="submit" value="Cancel" />';
        switch ($next_step)
        {
            case 'readme':
                if ($readme = fetch_code_block($action_body, 'readme'))
                {
                    echo '<input type="hidden" name="next_step" value="mysql" />';
                    echo '<h3>The Read Me</h3>';
                    echo $this->Format($readme);
                    break;
                }
            case 'mysql':
                if ($mysql = fetch_code_block($action_body, 'mysql'))
                {
                    $mysql = preg_match('/# INSTALL STEP(.*)# INSTALL STEP/ism', $mysql, $matches) ? $matches[1] : '';
                    $queries = split('# INSTALL STEP', str_replace('prefix_', $this->config['table_prefix'], $mysql));
                    if (!isset($_REQUEST['run']))
                    {
                        echo '<h3>The Data Model</h3><br />';
                        echo '<input type="hidden" name="next_step" value="mysql" />';
                        echo '<input type="hidden" name="run" value="1" />';
                        echo $this->Format("If you click continue, the following queries will be run...\n\n%REMOVE ME%" . join('', $queries) . '%REMOVE ME%');
                    }
                    else
                    {
                        echo '<h3>Running The Queries...</h3><br />';
                        echo '<input type="hidden" name="next_step" value="css" />';
                        foreach ($queries as $sql)
                        {
                            $sql = trim($sql);
                            $result = mysql_query(trim($sql));
                            $report .= "$sql -- " . ($result ? 'OK!' : 'FAILED: ' . mysql_error()) . "\n\n";
                        }
                        echo $this->Format("%REMOVE ME%\n$report\n%REMOVE ME%");
                    }
                    break;
                }
            case 'css':
                if ($css = fetch_code_block($action_body, 'css'))
                {
                    echo '<h3>The CSS Styles</h3><br />';
                    $css_filename = $installer_base_dir . '/actioncss/' . strtolower($install_action) . '.css';
                    if (!isset($_REQUEST['run']))
                    {
                        echo '<input type="hidden" name="next_step" value="css" />';
                        echo '<input type="hidden" name="run" value="1" />';
                        echo $this->Format("If you continue, the Installer will write the following CSS code to \"$css_filename\"\n\n%REMOVE ME%$css%REMOVE ME%");
                    }
                    else
                    {
                        echo '<input type="hidden" name="next_step" value="php" />';
                        $save_css = file_put_contents($css_filename, $css) ? 'OK!' : 'FAILED!';
                        echo $this->Format("Saving CSS code... **$save_css**");
                    }
                    break;
                }
            case 'php':
                if ($php = fetch_code_block($action_body, 'php'))
                {
                    echo '<h3>The PHP Code</h3><br />';
                    echo '<input type="hidden" name="next_step" value="php" />';
                    $config = preg_match('/(.*)<\?php/sm', $php, $match) ? $match[1] : false;
                    if (preg_match('/<\?php(.*)\?>/sm', $php, $match))
                    {
                        $code = "<?php$match[1]?>";
                        $action_filename = $installer_base_dir . '/actions/' . strtolower($install_action) . '.php';
                        $config_vars = parse_config_settings($config);
                        global $action_config;
                        if (!isset($_REQUEST['run']))
                        {
                            echo '<input type="hidden" name="run" value="1" />';
                            if ($config)
                            {
                                foreach ($config_vars as $key => $val)
                                {
                                    $overwrite_warning = isset($action_config[$key]) ? "-- WARNING: will overwrite current value of '$action_config[$key]'" : '';
                                    $config_msg .= "$key => '$val' $overwrite_warning\n";
                                }
                                $config_msg = "===Config Settings===\n\n%REMOVE ME%$config_msg%REMOVE ME%\n";
                            }
                            $file_warning = file_exists($action_filename) ? "WARNING: will overwrite current file '$action_filename'" : '';
                            echo $this->Format("$config_msg===Action Code===\n\n%REMOVE ME%$file_warning\n$code%REMOVE ME%\nContinue install?");
                        }
                        else
                        {
                            echo '<input type="hidden" name="next_step" value="finish" />';
                            if ($config)
                            {
                                $action_config = array_merge($action_config, $config_vars);
                                $save_config = file_put_contents($installer_base_dir . '/action.config.php', "<?php\n\$action_config = " . var_export($action_config, true) . ";\n?>") ? 'OK!' : 'FAILED!';
                                $config_msg = "Saving config settings... **$save_config**\n";
                            }
                            $save_code = file_put_contents($action_filename, $code) ? 'OK!' : 'FAILED!';
                            echo $this->Format("{$config_msg}Saving PHP code... **$save_code**");
                        }
                    }
                    else
                    {
                        echo '<p class="error">Fatal Error: The Installer couldn\'t find any PHP code in the Installable Action!</p> ';
                    }
                }
                break;
            case 'finish':
                echo '<h3>Installation Completed!</h3><br />';
                echo '<p>Here\'s to hoping the new action works!</p>';
                $buttons['continue'] = '<input type="submit" value="Finish" />';
                unset($buttons['cancel']);
                $hidden_tag_field = '';
        }
        $buttons = join(' ', $buttons);
        echo $hidden_tag_field;
        echo '<div style="margin:15px 0px 15px 0px;">' . $buttons . '</div>';
        echo '</form>';
    }
}

if (isset($_REQUEST['installer_remove']))
{
    $remove_action = $_REQUEST['installer_remove'];
    if (isset($installable_actions[$remove_action]))
    {
        $action_body =& $installable_actions[$remove_action];
        $hidden_tag_field = "<input type=\"hidden\" name=\"installer_remove\" value=\"$remove_action\" />";
        $next_step = isset($_REQUEST['next_step']) ? $_REQUEST['next_step'] : 'confirm';
        echo $this->FormOpen();
        echo "<h2>Removing $remove_action...</h2><br />";
        $buttons['continue'] = '<input type="submit" value="Continue" />';
        $buttons['cancel'] = '<input type="submit" value="Cancel" />';
        if ($mysql = fetch_code_block($action_body, 'mysql'))
        {
            $mysql = preg_match('/# REMOVAL STEP(.*)# REMOVAL STEP/ism', $mysql, $matches) ? $matches[1] : '';
            $queries = split('# REMOVAL STEP', str_replace('prefix_', $this->config['table_prefix'], $mysql));
        }
        $lc_action = strtolower($remove_action);
        $php_file = $installer_base_dir . "/actions/$lc_action.php";
        $css_file = $installer_base_dir . "/actioncss/$lc_action.css";
        $config = preg_match('/(.*)<\?php/sm', fetch_code_block($action_body, 'php'), $match) ? $match[1] : false;
        $config_vars = parse_config_settings($config);
        switch ($next_step)
        {
            case 'confirm':
                echo '<input type="hidden" name="next_step" value="run" />';
                $mysql = isset($queries) ? "\nThe following queries will be run:\n\n%REMOVE ME%" . join('', $queries) . '%REMOVE ME%' : '';
                if ($config_vars)
                {
                    foreach ($config_vars as $key => $val) $settings[] = "$key => '$val'";
                    $settings = "\nThe following config settings will be removed:\n\n%REMOVE ME%" . join("\n", $settings) . "%REMOVE ME%";
                }
                $php_file = file_exists($php_file) ? "\n$php_file" : '';
                $css_file = file_exists($css_file) ? "\n$css_file" : '';
                echo $this->Format("====Warning====\n$mysql$settings\nThe following files will be removed:\n\n%REMOVE ME%$php_file$css_file%REMOVE ME%");
                break;
            case 'run':
                if ($queries)
                {
                    $mysql = '';
                    foreach ($queries as $sql)
                    {
                        $sql = trim($sql);
                        $result = mysql_query(trim($sql));
                        $mysql .= "$sql -- " . ($result ? 'OK!' : 'FAILED: ' . mysql_error()) . "\n\n";
                    }
                    $mysql = "\nRunning queries:\n\n%REMOVE ME%$mysql%REMOVE ME%";
                }
                if ($config_vars)
                {
                    global $action_config;
                    foreach (array_keys($config_vars) as $key) unset($action_config[$key]);
                    $settings = file_put_contents($installer_base_dir . '/action.config.php', "<?php\n\$action_config = " . var_export($action_config, true) . ";\n?>") ? 'OK!' : 'FAILED!';
                    $settings = "\nWriting new config file... **$settings**\n";
                }
                $php_file = file_exists($php_file) && @unlink($php_file) ? "$php_file\n" : false;
                $css_file = file_exists($css_file) && @unlink($css_file) ? "$css_file\n" : false;
                $files = ($php_file || $css_file) ? "Removing files:\n\n%REMOVE ME%$php_file$css_file%REMOVE ME%" : '';
                echo $this->Format("====Removal Complete!====\n$mysql$settings\n$files");
                $buttons['continue'] = '<input type="submit" value="Finish" />';
                unset($buttons['cancel']);
                $hidden_tag_field = '';
        }
        $buttons = join(' ', $buttons);
        echo $hidden_tag_field;
        echo '<div style="margin:15px 0px 15px 0px;">' . $buttons . '</div>';
        echo '</form>';
    }
}

if ($rows)
{
    echo '<table width="700" cellpadding="5" id="installable_actions">';
    echo '<tr><th>Action</th><th>Summary</th><th align="center">Installed&nbsp;Version</th><th align="center">Current&nbsp;Version</th><th align="center">MySQL</th><th align="center">CSS</th><th>Actions</th></tr>';
    echo $rows;
    echo '</table>';
}
else
{
    echo '<p>There are no installable actions on this system.</p>';
}

}} // end IsAdmin() check

?>


Note: You'll have to find %REMOVE ME% and replace with %% in your text editor before the above code will work.

Now create a page like "ActionInstaller" and call the action from within it like so -- {{installer}}.

If you don't have any InstallableActions in your wiki, you'll need to find some! If you'd just like to test the system, copy the InstallableActionTemplate to your wiki and load your installer page. It should look something like...

The Screenshots


image

image

image

image

image

image

image

image

image

image

The removal process is similar (one of them "exercise for the reader" dealies).

Authors


DennyShimkoski


CategoryUserContributions
There are 7 comments on this page. [Show comments]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki