
ewiki internals and extension howto
===================================

This part of the [README] series describes a bit of the internals of
the ewiki script and its plugin system. It lists variables, coding
guidelines and a few recommendations.
These informations are useful if you'd like to change some of the
hardcoded behaviour, fix annoying bugs you've found or to write your
own extensions. You do not need to read this, if you just want to
setup and use a Wiki.


README.programming
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
        1 ewiki_ functions()
        2 $GLOBALS pollution ($ewiki_ variables)
        3 internal coding explained
      3.1 how ewiki operates
      3.2 used variables
        4 Extension HowTo
      4.1 the PlugInterface
      4.2 plugin tasks
    4.2.1 mpi plugins
    4.2.2 authentication/permission plugins
      4.3 writing your own plugin
      4.4 format_* / rendering plugins
    4.4.1 ewiki_format() internals
    4.4.2 the format_ plugin hooks
    4.4.3 $iii[] and $ooo[] block flags
    4.4.4 your own block markup plugin
      4.5 xpi plugin system
        5 mysql database structure
        6 Just using the wiki source transformation




  -------------------------------------------------------------------- 1 --





ewiki_ functions()
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
Some of the core functions of ewiki.php can be used separate from the
others and some of them were designed to be replaced by different
implementations.
Btw, all the functions, constants and variables start with "ewiki_"
to make it easier to mix it into other projects (reduces function name
conflicts and similar problems, that usually arise if you join two
or more scripts into one program).


   ewiki_page($id)
   ---------------
       This is the main function which fetches the selected WikiPage
       (or the one given with $id) via ewiki_database to transform
       with ewiki_format().
       If the requested page does not exist it returns the edit
       screen.
       It also includes some virtual pages (InfoAboutThisPage,
       NewestPages, SearchPage, ReferencesToThisPage, ...).


   ewiki_page_...()
   ----------------
       These functions were separated out from the main ewiki_page()
       to make it more readable.
       Most of them contain code to generate the few special/internal
       WikiPages (Search, Newest, Info, and the Edit <FORM>, ...)


   ewiki_control_links($id, $data)
   -------------------------------
       Prints the line with the EditThisPage and PageInfo, ... links.


   ewiki_format($wiki_source, $params)
   ----------------------------------------------------------
       This returns the formatted (HTML) output for the given WikiSource
       (with all the WikiMarkup in it).

       The second param is an array with various config overrides. An entry
       of "scan_links"=>1 for example tells ewiki_format to lookup the
       referenced WikiPages in the database (see ewiki_scan_wikiwords) for
       filling up $ewiki_links. Another $params entry is "html"=>0, which
       controls interpetation of the <html>...</html> page content blocks.


   ewiki_render_wiki_links(&$o)
   ----------------------------
       Transforms WikiLinks and square brackets in a page into html links.


   ewiki_scan_wikiwords(&$wiki_source, &$ewiki_links)
   --------------------------------------------------
       work with regex on the wiki source text, to find valid WikiWords,
       the $ewiki_links will be filled with informations if the found page
       names exist in the DB.


   ewiki_link_regex_callback()
   ---------------------------
       Called from ewiki_format(). To separate the ewiki_format() from
       the database this function will utilize the global $ewiki_links
       (generated on demand by ewiki_format) to output either a normal
       link or a question-mark after the WikiPageName to signal a
       non-existent page.


   ewiki_script()
   --------------
       Builds the complete URL needed to access the given resource. This
       function replaces/enhances the static EWIKI_SCRIPT constant and
       unifies the generated URLs (less bugs). It also helps around
       various design flaws (like nice looking URL strings), that made
       some parts of ewiki a bit weird and unreliable in the past. Btw,
       now the base URL is stored in $ewiki_config["script"].


   ewiki_script_binary()
   ---------------------
       Is just a ewiki_script() wrapper, but can additionally distinguish
       between binary download and upload URLs, which could be utilized by
       (database external) plain file storages (see plugins/binary_store).
     

   ewiki_binary()
   --------------
       Gets called automatically for requests with the ?binary= trailer
       which is used to reference cached and uploaded images (or not
       yet cached ones).       


   ewiki_author()
   --------------
       returns a string with REMOTE_ADDR and the $ewiki_author or a default
       string incorporated


   ewiki_auth()
   ------------
       Is a simple interface to a probably large collection of plugins,
       which should to actual user and permission management. Support for
       this in the core is however still sporadic.


   ewiki_auth_user()
   -----------------
       Queries all registered user databases, and is usually itself called
       from within an auth_method/auth_query plugin.


   ewiki_t()
   ---------
     Fetches a text string from the $ewiki_t[] array and additionally adds
     some text pieces into it (given as second param). It can retrieve
     translations for registered abbreviations, or searches for complete
     text fragment replacements. It also understands _{...} to recursively
     translate a text snippet inside of larger text blocks.
     This is probably a bit slower and less readable than the previous usage
     of EWIKI_T_ constants, but it saves some memory and allows to extend
     translations or additional text constants (of plugins) a lot more
     easier (previously one had to edit inside a function, which is almost
     impossible to do from outside / per configuration).


   ewiki_make_title()
   ------------------
     Returns a string enclosing (the generated) page title (as link) into
     the html title markup "<h2>". The $class parameter actually tells from
     which plugin sort it was called, and this decides if a link will be
     generated or the title will be unclickable plain text (the setting in
     $ewiki_config["print_title"] is used to determine that). $go_action tells
     which action to link the title to.


   ewiki_chunked_page(...)
   -----------------------
     Is a helper function to split large results into multiple click-through
     pages, and is used by info/ and some search functions/plugins. It only
     produces the click-through links for inclusion on other dynamic pages,
     allows overlapping of page chunk ranges.

     
   ewiki_in_array($value, &$array, $dn=0)
   --------------------------------------
     Case-insensitive variant of PHPs` in_array(), returns the $value if
     found. The $array will be all-lowercased afterwards (except when $dn
     was set).


   ewiki_array($array, $index=false, $am=1)
   ----------------------------------------
     Returns input-array lowercased (indices), or just the entry for the
     $index if searched for. The $am decides if multiple entries should be
     merged together (uppercase+lowercase merging produces overlaps).


   ewiki_db
   --------
       This static class provides the interface to the database backends.
       It abstracts the database as a simple flat store for named entries
       (file or page names). Therefore it is that easy to switch from a
       SQL backend to a flat file based data store.
       Actually, this rude form of "database abstraction" has the drawback,
       that it knows only little about the data it maintains. But this also
       allows to internally extend the used structures if necessary.

       You call the individual functions like " ewiki_db::GET() ",
       the atomic features are:

       ::GET($id)
           Fetches the latest version of the "$id" page from the database.

       ::GET($id, $version)
           Retrieves a given version instead. Counting starts at 1.

       ::WRITE($data)
           Saves the contents of the given data array in the database,
           does _never_ overwrite an existing entry (you must keep track
           of the {version} yourself) unless a second paremeter (1) was
           given.

       ::GETALL($fieldnames, $mask, $filter)
           Fetches an array of all existing pages in the database, but
           returns it as ewiki_dbquery_result object, which will throw
           the requested columns on ->get(), where the entries 'id',
           'version' and 'flags' are always present.

       ::FIND($list_of_pagenames)
           Searches the database for the queried page names, returns an
           array which associates the boolean value (if pages found) with
           their names

       ::SEARCH($field, $content, $caseinsensitive, $regex, $mask, $filter)
           Returns only those pages, where the database COLUMN has a content
           that matches the requested value; the list of pages is returned
           as ewiki_dbquery_result object, where you can access the
           individual entries using the ->get() call, which will return the
           columns 'id', 'version', 'flags' and the scanned COLUMN of course
           unless you ->get("_ALL=1").

       The following three actions are not required for correct operation,
       but provide additional functionality for some plugins or tools.

       ::HIT($id)
           Increases the hit counter of the given wiki page by 1,
           what is not implemented in db_flat_file.

       ::DELETE($id, $version)
           Removes the specified page (only the given version) from the
           database; implemented in all database plugins but should be used
           from within the tools/ only.

       ::INIT()
           For SQL database backends this creates the required tables.

       There are also a few virtual functions, that only provide utility
       code or make use of the atomic funtions itself:

       ::APPEND($id, $text)
           Adds the given $text at the bottom of the named page.

       ::UPDATE(&$data)
           Refreshes all the meta data fields in the given page hash, but of
           the {version} field. This is usefully be called before any ::WRITE
           call.

       ::CREATE($id, $flags, $author)
           Returns a fresh page $data hash.

       Other functions are usually used internally only, as for example the
       ->ALLFILES() command in dbff or dba/dbm plugins.


   ewiki_dbquery_result
   --------------------
       Has the member variables $keys and $entries, where the latter
       contains an array of page names that where triggered by your GETALL
       or SEARCH request, and the $keys array contains the column names that
       each subsequent "$result->get()" will return.

       get()
           Returns the database entry array (see GET above), but only the
           fields the database query should return (at minimum these are
           'id', 'version' and 'flags' and the searched column for SEARCH).

       get("_ALL=1")
           Instead returns the complete entry.

       get(0, $mask)
           The second parameter is for filtering out content:
           0x0001  strips out _HIDDEN pages from the result set
           0x0002  removes any _DISABLED pages
           0x0020  performs the _PROTECTED_MODE_HIDING checks

       get(0, $mask, $type)
           if the $type parameter is supplied, then the results are filtered
           by the given page type (_DB_F_TYPE mask)

       count()
           Returns the number of found database entries.

       add($row)
           [internal]  This is used by the ewiki_database() core functions
           to initialize the $result object with the found entries.


  -------------------------------------------------------------------- 2 --



$GLOBALS pollution ($ewiki_ variables)
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
At least the ewiki_page() function produces variables in the
global namespace. Of course they also were named to not interfere
with anything from yoursite.php:

 $ewiki_id	- Contains the current page name, after ewiki_page()
                  was called.

 $ewiki_action  - Contains the $action/ForTheCurrentPage.

 $ewiki_title   - Will be set after the first call to ewiki_page(),
                  it is most useful to be printed inside the <TITLE>
                  tags inside <HEAD>. So if you want to use it you
                  should call ewiki_page() very early, but save its
                  output into a variable for later use. This way
                  you can make the current wiki pages` title available
                  (the _title may be different from the pages _id).

 $ewiki_data    - Contains the page data hash as retrieved from the
                  database, but that {content} has been removed.

 $ewiki_errmsg  - Sometimes used to pass error notices back (ewiki_auth
                  does so for example).

 $ewiki_links   - Is an array produced by ewiki_format() that associates
                  all found WikiPageNames with a value of 0 or 1,
                  depending on if the referred page exists in the
                  database.

 $ewiki_author  - The content of this variable is saved in the author
                  field of newly created wiki pages (it will be filled
                  with IP:PORT if not set from outside). This is only an
                  informational setting, and does not directly correspond
                  to the _PROTECTED_MODE.
                  You should set it, whenever yoursite.php notes a logged in
                  user (so his login gets saved in the wiki pages 'author'
                  column). But you should REALLY NOT SPAM IT with your own
                  name or ad words.

 $ewiki_auth_user  - Is set by ewiki_auth_user() whenever it successfully
                  authenticates a user in _PROTECTED_MODE. This variable
                  is then used as reliable state setting, which affects
                  permission granting. 

 $ewiki_ring    - Holds the permission level ('ring') of the currently
                  authenticated user (or else will be unset). This value
                  tells only about the user, many plugin functions have
                  built-in requirements which will be compared against
                  this value (no value or zero means full permissions).
                  While this is the built-in way to grant permissions
                  and often also suits the needs to do it, the _auth()
                  plugin interface allows to work at a much finer degree
                  of access granting.
                  values: 0=administrator, 1=moderator, 2=editor, 3=guest
                  See also plugins/auth/README.auth for more informations.

 $ewiki_plugins - Is an array which connects task names (say "database"
                  or "image_resize" for example) to function names.
                  You can utilize this if you decide to extend ewiki.
                  There is an own chapter on this.

 $ewiki_config  - Imports some configuration settings from older constants,
                  and introduces newer ones, which can then be overridden at
                  runtime. Also holds some work and markup transform data.

 $ewiki_t       - Text definitions and translations for all possible
                  messages.




  -------------------------------------------------------------------- 3 --




internal coding explained
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
This section is to explain some of the coding style of ewiki, and how some
things work. While many parts of ewiki carry good source code comments, it
is always difficult to quickly understand larger scripts like ewiki.php by
just reading through it.



         how ewiki operates
         ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
         ewiki_page()
           - decodes the $id and $action from the GET or POST parameters
           - tries to load the page from ewiki_database()
           - if this failed then it calls the database init function
           - calls some init plugins, calls the _auth() interface
           - chains to ["page"] plugins which activate for registered $id's
           - alternatively calls a plugin that was registered for $action
           - the default however is to render the current page via _page_view()
           - adds a page title
           - sends the generated output (view page or plugin output) back to
             caller (for output into yoursite.php)

         ewiki_page_view()
           - feeds the current page $data's ["content"] into ewiki_format()
           - also decodes paramters (html allowed)
           - returns the gererated html back

         ewiki_format()
           - beatifies the source code (unifies to plain UNIX newlines)
           - calls init plugins (wiki source mangling)
           - splits source into blocks, calls block plugins
           - then goes through each line of the wiki source to generate html
           - there is line-start, in-line and complete-markup
           - afterwards everything went from source into the $ooo-output var
           - first calls the link_pre_scan_regex (which searches for
             wikiwords and stores that information into $ewiki_links)
           - then calls the wiki-link transformation regex function
           - then calls post plugins and returns generated <html>

         ewiki_render_wiki_links()
           - searches for all (pre-fetched) $ewiki_links via ewiki_db::FIND()
           - transforms the wikiwords into html-links
           - with the regex and callback func: returns output back to
           - ewiki_format()

         ewiki_link_regex_callback()
           - transform the wiki source snippet returned from the
             preg_replace() call into a html link string
           - (complicated)

         ewiki_$page_plugin_*()
           - page plugins return html output, which usually is hardcoded as
             strings into them
           - provide some interactivity
          
         ewiki_$action_plugins_*()
           - activate on pages with special registered $action's
           - provide some interactivity (for page editing for example)



         used variables
         ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
         Variables in ewiki often have similar names, and are also
         regularily passed by reference from one function to another (so it
         is in fact the same variable).

         $id         - Is often the name of the current page (which is to be shown
                       returned as output. The content of this variable is
                       also available via the global $ewiki_id [[for plugins
                       that do not have the common ($id,$data,$action)
                       interface parameters]].

         $data       - Contains the entry fetched with the initial
                       ewiki_database() call. This is an array of the form:
                       array(
                          "id" => "CurrentPageName",
                          "version" => 1,               # 1 is the lowest possible
                          "flags" => 1,
                          "created" => 1002056301,
                          "lastmodified" => 1002171711,
                          "hits" => 235,
                          "author" => "localhost (127.0.0.1:4981),
                          "meta" => array("Http-Header"=>"X", "setting"=>"val"),
                          "content" => "wiki source...",
                       )

         $action     - The $action with wich the current page was requested
                       (most often "view", but everybody also knows "edit").

         $uu         - Short for "unused". Is used as temporary variable, especially
                       with preg_match() and string functions.

         $result     - Used for database queries SEARCH and GETALL.

         $row        - Holds temporarily fetched entries from the databases
                       (like $data), if page lists are to be generated.



  -------------------------------------------------------------------- 4 --




Extension HowTo
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
Best way to extend ewiki is to read the man page on vi or emacs ;-> However
the tool that made this all possible was joe.



the PlugInterface
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
The $ewiki_plugins array holds an array of "task names" connected to
function names (that of course should do something senseful). As an
example:

  $ewiki_plugins["image_resize"][0] = "ewiki_binary_image_resize_gd";

connects the task name "image_resize" to function already inside ewiki.php,
and the task "image_resize" will be called for every uploaded or to be
cached image. The function name here does not say anything about the
parameters the function will be called with later. You have to look up
the original function implementation in ewiki.php to see which parameters
will be passed; so you could write your own task plugin.

The [0] in the example above shows that this is the very first registered
function for the task "image_resize", there could be others as well. So
if you write a plugin you should take care to add your function name using
$ewiki_plugins["task"][] = "my_func" so you won't overwrite a previous
function name ''registration''.
There are of course tasks like ["database"] where only one of the plugin
functions will be called, in this case you should of course overwrite [0].

Two special case "tasks" are ["page"] and ["action"], because they aren't
counted with numerical indices, but instead carry WikiPageNames or
other idf strings as array/hash index.



plugin tasks
ŻŻŻŻŻŻŻŻŻŻŻŻ
Here's a short summary of current PlugInterface "tasks" and (recommended)
function interface definitions (the "= function (..." lines). A plugin hook
with [] means there can be multiple, and each one would be tried.

basic
-----

  ["page"][$PageName]   - called for requests to page "$PageName"
                          (like "SearchPage", "NewestPages")
                        = function ( $id, $data, $action )

  ["action"][$ACTION]   - called for requests with url "?id=$ACTION/pagename"
                          (core actions are "edit", "links", "info", "view")
                        = function ( $id, &$data, $action )

  ["handler"][]         - called from ewiki_page() on start-up, if it returns
                          a string the page was handled and no further
                          processing takes place, the plugins output is used
                        = function ( $id, &$data, $action )

rendering
---------

  ["render"][0]         - alias for ewiki_format() - our "WikiKernel"

  ["format_source"][]   - called inside the format function for the wiki
                          source, implement this or the following ones to
                          use complex wiki markup
                        = function ( &$wiki_source )

  ["format_line"][]     - generic call from inside wiki format engine
                          for every line, you may need to use static
                          vars inside your plugin function
                        = function ( &$o, &$line, &$post )

  ["format_tbl"][0]     - called to handle "wiki|table|markup"
                          (the first and last | are already stripped)
                        = function ( &$o, &$line, &$post, $tbl_open=0 )

  ["format_final"][]    - call after wiki source was transformed into html
                          (WikiPageLinks were already interpolated too)
                        = function ( &$html )

  ["format_block"][]    - called, with the page fragment extracted using
                          the string patterns of the according
                          $ewiki_config["format_block"] entry
                        = function (&$currbuf, &$in, &$iii, &$s, $btype);

  ["format_para"][]     - called, if the $para (text enclosed in <p></p>)
                          is to be written into the output stream $ooo[$in][0]
                        = function (&$para, &$ooo, &$s);

  ["link_url"][]        - called to transform wiki source references
                        = function ( $href, $title )

  ["link_final"][]      - called from ewiki_link_regex_callback to transform
                          the final <a href>
                        = function ( &$str,, $type, $href, $title )

special tasks
-------------

  ["database"][0]       - only [0] will be called in favour of the ewiki.php
                          internal ewiki_database_mysql()
                        = function ( $action, $args=array() )

  ["image_resize"][]    - all [] registered functions will be invoked
                        = function ( &$content, &$mime, $return=0 )

  ["mime_magic"][0]	- hooks before save_binary/image to fetch the
			  correct mime type for non-image files; nowadays
                          just an always-available get_content_type()
			= function ( &$content )

  ["binary_get"][0]     - the binary_repository handles large/binary content
                          (to separate it out of the standard sql-database),
                          usually just sending it to stdout
			= function ( $id, $meta )

page lists
----------

  ["list_pages"][0]     - <li>st generating callback function
                        = function ( $lines )

  ["list_dict"][0]	- special variant of the above one (called just for /
                          from within PageIndex and WordIndex listings)
			= ???

  ["list_transform"][]  - works on the given list of links (text transformations)
                        = function ( &$lines )

  ["make_title"][0]     - allows to chain a replacement function for
                          ewiki_make_title()
                        = function ($title, $class, $action, $go_action, $may_split)

  ["title_transform"]   - changing the currently linked title (called from
                          within _make_title)
                        = function ($id, &$title, &$go_action)

page transform / additions
--------------------------

  ["view_append"][]	- output will be printed below a rendered page
			= function ( $id, $data, $action )

  ["view_final"][]	- can rework the full html of the rendered page
			= function ( &$html, $id, $data, $action )

  ["view_append"][]     - add <html> code at the end of the currently
                          viewed page
                        = function ($id, $data, $action)

  ["view_final"][]      - filter hook for final processing of "view/"ed pages
                        = function ($o, $id, $data, $action)

  ["page_final"][]      - filter hook for final processing of any
                          shown page (any action: edit/, view/, info/, ...)
                        = function ($o, $id, $data, $action)

edit/ hooks
-----------

  ["edit_preview"][]    - called if edit pages [preview] button pressed
                        = function ( $data )

  ["edit_form_final"][] - add <html>/<form>s to the edit/ page
                        = function (&$o, $id, &$data, $action)

  ["edit_form_append"][] - insert other <input> fields between <textarea>
                          and <submit> button on the edit/ page
                        = function ($id, &$data, $action)

  ["edit_hook"][]	- chains into before the edit box is printed
                          (to allow security checks, pre-edit-tweaking, ...)
                          any output terminates the current edit/ attemp
			= function (&$id, &$data, &$hidden_postdata)

  ["edit_save"][]       - immediately called before saving the currently
                          "edit/"ed page into the database, allows last
                          transformations or rejection (unsetting $data)
                        = function (&$data, &$old_data)

  ["edit_patch"][0]     - special hook for the patchsaving plugin
                        = function ($id, &$data)

bloat extensions 
----------------

  ["auth_*"][]		- plugin tasks used with ewiki_auth()
			= see the plugins/auth/README.auth

  ["mpi"][...]          - markup plugins, see next paragraph

  ["init"][]		- run once, when the main script is included()

  ["page_init"][...]    - init functions, called when ewiki_page()
                          is called the very first time

aliases and variants
--------------------

  ["action_always"][$ACTION]   - are called with precedence over ["page"]
                                 plugins (for example "links" which also
                                 works for registered page plugins)

  ["action_binary"][$ACTION]   - action/admin plugins which do not care, if
                                 the current page actually is binary data


Some other entries have been re-extracted into $ewiki_config, because they
were falsely in $ewiki_plugins. See the paragraph at the start of the README
on the $ewiki_config array.

This list will probably not stay up-to-date, so please grep the ewiki.php
script for all occurrences of 'ewiki_plugins["', and you can of course
invent some new and tell the author how it helped you to implement something
very different.



        mpi plugins
        ŻŻŻŻŻŻŻŻŻŻŻ
        Plugins of the class "mpi" extend the wiki markup with html like
        calls to dynamic content generating functions.  They were taken from
        the ewiki adaption of Hans B Pufal and are very similar to the
        plugins found in PhpWiki.

        In order to use them you must first load their generic PlugInterface
        file using include("plugins/mpi.php");
        As an exception to all other ewiki plugins, the mpi plugins are then
        loaded only as needed (the mpi interface takes care). You could
        however still load all the "mpi_*.php" scripts yourself beforehand.

        You can then call those plugins from the wiki markup with:

            <?plugin Calendar ?>

        There are many different plugins available (not all included with
        this ewiki distribution), and the allowed arguments differ widely
        (must all be noted inside the < > and are written in arg=value style
        separated by semicolon):

        <?plugin Insert WikiPageName ?>
                          # this includes the referenced WikiPage in a box
                          # into the current one, Note the ! to prevent that
                          # WikiWord from getting rendered (before mpi sees
                          # it)

        <?plugin BackLinks page="ForGivenPageName" ?>

        <?plugin SparseTable columns="c1,c2,c3"

           c1="column 1"
           c2="column 2"
           c3="column 3"

           c1="#1"
           c2="2.0"

           c1="#2"
           c3="3.0"

           c2="2.5"
           c3="--"
        ?>

        See the distributed page "MpiPlugins" for a complete list.

        The API is very simple, so one could easily write a custom
        code block extension. (The mpi_backlinks plugin makes a nicely
        short example.)



        authentication/permission plugins
        ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
        The paragraph and descriptions about the _auth interfaces have gone
        into plugins/auth/README.auth



writing your own plugin
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
Using the list of current plugin tasks, you could (hopefully) write your own
extension with ease. It is probably most simple to write a dynamic ["page"]
plugin, so we start with this as example. All you need is a function
definition like:

   function my_page_plugin($id, $data, $action) {
      return("This is the returned page <b>content</b>.");
   }

And then just register it as ["page"] plugin, using your defined function
name (yes, this does NOT need to start with the usual "ewiki_" prefix!). You
also need to tell ewiki about the WikiPageName under which your plugin
should be made available:

   $ewiki_plugins["page"]["MyPagePlugin"] = "my_page_plugin";

That's it. But of course your function should do something more useful, than
just returning a hardcoded html string - even if this all, what's necessary
here. The parameters to your ["page"] plugin function you'll often just want
to ignore, and implement your plugin functionality (hard disk formation e.g.)
independently from such things.

It is likewise easy to write an ["action"] plugin; but this type of plugin
should then process some parts of the $data entry and work for nearly any
page (extracting contents or presenting the current page differently). So
this kind of plugin could be used to initialize a download for the current
page or to allow to email it to someone else (beware of the spammers!).



format_* / rendering plugins
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
It is rather simple to add WikiMarkup using the $ewiki_config["wm_..."]
settings, but for some tasks you need stronger weapons like rendering
and markup plugins.

The ewiki_format() function (often blatantly referred to as "rendering
kernel") recently got rather complicated to add support for the 'block'
plugins. Therefore we'll first need to discuss the variables structures
and names used inside of it:



        ewiki_format() internals
        ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
        When the function receives the input string (WikiSource), it first
        escapes all html tags using &amp; &lt; &gt; to replace the & < >
        chars (because HTML is not allowed within Wiki, initially).

        Then it runs optional ["format_source"] plugins on the whole wiki
        page (still one source string).
        Afterwards ewiki_format() starts to split that wikisource into
        fragments meant to get handled by ["format_block"] plugins AND/OR
        the Wiki -> HTML transformation code inside of it. It creates an
        array called $iii[] from it - each fragment being an array on its
        own:
           $iii[0] = array(
              0 => "WikiSource ...",
              1 => 0x0FFF,
              2 => "core",
           );
        Initially we here just have one fragment [0] - and often this
        remains the only one (if no block plugin activates for the current
        WikiPage). The 0=> entry contains the body (wiki source) of a
        fragment, while at the 1=> index you'll find the block flags and 2=>
        is just the name of the block plugin to handle that fragment.

        If there is some block code, like <htm>...</htm> or <pre>...</pre>
        in the WikiPage, you'll end up with a larger $iii[] input array:
           $iii[0] = array("WikiSource...",0xFFFF,"core"),
           $iii[1] = array("<b>....",0x0002,"html"),
           $iii[2] = array("text",0x0FFF,""),
        
        Besides the $iii[] input array, we'll also have an array containing
        rendering status variables called $s[]. The most important entry
        there is $s["in"], which is the index into the currently accessed
        $iii[] wiki page source or block fragment.
        And ewiki_format() then uses various alias variable names for
        entries of the status var $s[] array - for example $in and $s["in"]
        are the same index number.

        After ewiki_format() separated the input source into the block
        fragments of $iii[], it will then run the actual ["fragment_block"]
        plugins on it. These can then apply regexs on them, or strip the
        fragments completely out of $iii[] or transform then into regular
        wiki source.

        Then the large wiki transform loop comes into action, but only
        for $iii[] fragments, whose flags (in the $iii[...][1] number)
        have the bit 0x0001 set. Other blocks/fragments of $iii[] remain
        untouched.
        While transforming the $iii[] arrays WikiSource a new fragments
        array will be created, called $ooo[] - the output array, which has
        exactly the same layout. And every $iii[$in] directly maps to the
        $ooo[$in] - same index number! But the later then already contains
        <html> instead of wiki source.

        Inside of the transformation loop, two other plugin types are
        activated (besides applying the $ewiki_config["wm_..."] ruleset):
        the ["format_line"] and ["format_para"] plugin groups.

        After all $iii[] blocks have been transformed into $ooo[], a second
        loop will check the flags (this time $ooo[...][1]) for the bit 0x0002
        which tells, if WikiWords should be transformed into html <a href=>
        links.

        After link conversion (on the selected fragments), all blocks (the
        content entries $ooo[...][0] of course) of $ooo[] are merged together
        into one <html> string. After the ["format_final"] plugins run over
        this, ewiki_format() returns the resulting <html> page.



        the format_ plugin hooks
        ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
        As denoted above, the ["format_source"] and ["format_final"] plugin
        hooks are the simplest to work with, as both only get one parameter
        (passed by reference) containing either the full WikiPage source
        text or the already fully rendered <html> output.

        The ["format_line"] and ["format_tbl"] hooks are also rather simple,
        lookup their interface to know which variables you could modify.

        The ["format_para"] and ["format_block"] plugins both recieve
        either the $iii[] or $ooo[] and status $s[] array variables (plus
        a few aliases and shortcomings). This makes these hooks look a
        bit more complicated, but allows great flexibility - a "_block"
        plugin could for example merge its $iii[] fragment with another
        one, or replace itself with nothing.

        To write a markup plugin, you should lookup the actual interface in
        the 'ewiki.php' script or in this README. And don't forget that most
        parameters are meant to be passed by reference to be useful!



        $iii[] and $ooo[] block flags
        ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
        The $iii[...][1] and $ooo[...][1] hold the flags (as defined by
        $ewiki_config["format_block"][...][2]) for each fragment of the
        WikiPage. The "core" blocks (plain WikiSource) always have the
        default 0x137F assigned.

        currently used bit values are:
          0x0001 - render WikiMarkup (inline / text style)
          0x0002 - render WikiLinks
          0x0004 - international character &#htmlentities; allowed
          0x0008 - enable BlockMarkup (lists, tables, headlines, ...)
    *NEW* 0x0400 - decode < > htmlentities again before calling block plugin
          0x1000 - fragment further (other block plugins can split it)

        pseudo-values (OR checks / behaviour):
          0x0010 - consider to be inline block between WikiSourceBlocks
                   (prevents paragraph breaks between plugin and wiki block)
          0x0022 - scan for WikiWords in this paragraph



        your own block markup plugin
        ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
        Of course a _block plugin is a bit more complicated than a action
        or page plugin, but generally you only need this small stub:

          $ewiki_plugins["format_block"]["your"] = "your_block_func";
          $ewiki_config["format_block"]["your"] = array(
             "&lt;your&gt;",
             "&lt;/your&gt;",
             false,   // no special filter rule/flag
             0x0014   // see above, often also just 0x0000
          );
          function your_block_func(&$str, &$in, &$iii, &$s, $btype) {
             ...
          }

        Where you would just rework the conents of "$str", which will be
        the text part in between the <your> and </your> tags as defined
        by the $ewiki_config[] block plugin settings. The other variables
        in that API aren't normally important.

        You only must take care, that "<", ">" and "&" are still encoded
        in htmlentities() at this stage.



xpi plugin system
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
A newer extension of ewiki (namely plugins/feature/xpi) allows to store
addon functions in the database (the code is saved as _BINARY db entry
where usually page text was stored). The "PlugInstall" page allows to load
the extension code from (even remotely located) .xpi files into the
database, from where it can be used later.
In order to use once installed xpi code, only the "feature/xpi0.php"
plugin was needed.

Through the design of the xpi feature extension nearly all plugins could
be converted and installed in the .xpi format. Though this doesn't make
sense for database backends, and converting all to-date plugins is silly.
So this feature is further merely used for fun and mini-extensions.

You could easily write your own .xpi plugins using the description in the
"tools/mkxpi" script. First you need to create a .src file with the plugin
code as usual (write it like an ordinary plugin script, except for page
plugins), and a few meta: informations on top of that file. Then the mkxpi
tool converts this in the binary .xpi format for distribution and
installation.
Typically this would look like:

  id: UniqueExtensionName
  type: actionlink_and_textdata
  license: Free to use
  author: PutYourNameHere
  description: adds the search/ action to the control-links line
  icon: data:image/png;base64,iVBORw0KGgoAAAANS...
  code: <?php
     // just look'n'feel settings, no real plugin code here...
     $ewiki_config["action_links"]["view"]["search"] = "SEARCH_ACTION";
     $ewiki_t["en"]["SEARCH_ACTION"] = "search in other pages";
     $ewiki_t["de"]["SEARCH_ACTION"] = "woanders suchen";
  ?>

Most of the fields are optional (author, license, description and of course
icon) but senseful. The type: is required, but only a value of "page" has
a special meaning here (otherwise is merely descriptive). The id: gives that
plugin an internal identifier which will later be used for storing the
extension with a database-wide unique name; for "page" type plugins it of
course would be the name under which it was installed.

The code: contains the usual plugin registration and function definition
code. But for "page" xpi plugins it may not have a function body, but lots
of 'echo' calls to output the dynamic pages contents when called (no return
allowed in this incarnation of page plugins). After this no other fields
should appear.

Future .xpi versions may allow to embed other files for instant installation
(maybe image files for storage in database). But until now onle the code:
entry carries data which will be installed as database page. All the other
meta entries (id, type, author, ...) will however be stored in the xpi
registry database entry, which is also used to control the enable/disable
flag for each of it (only page plugins cannot be disabled).

To share your own extensions simply send them to one of the core project
developers (Andy or Mario) or just leave a link on the "XpiPlugins" page:
http://erfurtwiki.sourceforge.net/?XpiPlugins

because that way users will immediately see it when remotely installing
.xpi plugins from that default xpi plugin repository. It may be an
security risk for users if they install code from unchecked sources, but
the complete URL is always displayed right before storing the external
code into the database.

The most interesting part of the .xpi system (PlugInstall page) is the
possibility to later disable or remove extensions easily. You only need
to setup the administrator password to install and control click-and-run
extensions without hacking the 'config.php'.



   ------------------------------------------------------------------ 5 ---



mysql database structure
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
The MySQL database table structure is (to a certain degree) compatible
with that of the well known ğPHPWikiĞ v1.2.x (you only need to change
EWIKI_DB_TABLE_NAME to "wiki" to use it). This is the MySQL statement
which creates our database table (you can find it at the bottom of the
"ewiki.php" script):
    CREATE TABLE ewiki (
        pagename VARCHAR(160) NOT NULL,
        version INTEGER UNSIGNED NOT NULL DEFAULT 0,
        flags INTEGER UNSIGNED DEFAULT 0,
        content MEDIUMTEXT,
        author VARCHAR(100) DEFAULT 'ewiki',
        created INTEGER UNSIGNED DEFAULT 0,
        lastmodified INTEGER UNSIGNED DEFAULT 0,
        refs MEDIUMTEXT,
        meta MEDIUMTEXT,
        hits INTEGER UNSIGNED DEFAULT 0,
        PRIMARY KEY id (pagename, version)
    )

I didn't like the column name {pagename} but as I've seen this was
the only difference I renamed it, therefore now the ewiki_database()
function translates it from "pagename" to "id" and vice versa most of
the time - else this would be really slim and nice code :)

The columns {version} holds the different saved page versions. Other
Wikis require a secondary "backup" or "history" table for old versions,
but as I couldn't imagine what this is for, there is just one table
in ewiki; and it seems this is really enough. The first {version} of
a wiki page is always numbered 1. An existing page {version} will
never get overwritten => very secure MySQL usage.

For what's in the {flags}, see the README section about constants. The
{content} of course holds the wiki pages source. The {created} and
{lastmodified} should be clear too.

{refs} contain a "\n" separated list of referenced WikiPages. The
code to generate that list is rather unclean, so it often contains
GhostPages. However this does not hurt ewiki and the few functions
that utilize {refs}, so there is currently no need to slow it down
by fixing this.

{meta} can hold additional informations, which allows to extend ewiki
without requiring to ALTER and convert the ewiki database table. It
currently holds some mime headers for binary content and some other
useful informations for images and uploaded files.

{hits} should have gone into {meta} really. But having it separate
allows us to use the very fast mysql UPDATE function.

Note, that the ewiki database table can hold other things than wiki
pages - binary content (images) for example, depending on the setting
of the {flags} field.

And last comment about this, the one-table-concept also made it really easy
to implement the flat file based "database backend".



   ------------------------------------------------------------------ 6 ---



Just using the wiki source transformation
ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ
The ewiki_format function was designed to be used independently from the
ewiki database.

  ewiki_format($wiki_source, 0);

It just needs the "wiki_source" as argument and generates a nicely
formatted page from it. All you need to take care about is the
$ewiki_links variable.
Set the $ewiki_links=true ("true" and not "1" or anything else) to
enforce ewiki_format() to treat all references as existing.

To separate the ewiki_format() function out of recent ewiki versions,
you'll also need ewiki_script(), ewiki_link_regex_callback(), ... and
a lot of constants to take with. It is often much easier to just
include("ewiki.php") for using ewiki_format(). You then should however
take care, that the _binary part doesn't get activated by accident. To
prevent this, just put following before the include() statement:

  unset($_REQUEST["binary"]);
  include("ewiki.php");

If you need it more quickly, or don't want to load the whole ewiki.php
file, then just try the fragments/wiki_format.inc, which is a stripped
down version of an older rendering core function (no WikiLinks, no binary
stuff). Contributed by Frank Luithle.



