Location: PHPKode > projects > as_admintool > asadmintool/as_admintool.htm
<HTML>
<HEAD><TITLE>as_admintool: WEB Administrator tool class</TITLE>
<META http-equiv="Content-Type" Content="text/html; charset=windows-1251">
<STYLE TYPE="text/css">
<!--
  body     { font-family:arial,helvetica;font-size:12px; }
  pre { color:#0000FF; }
  td   { font-family:arial,helvetica;font-size:12px;}
  tr.head  { background-color: #D0D0FF; color:#000000; font-size:13px; font-weight:bold; }
  tr.odd   { background-color: #F0F0F8; color:#000000; }
  tr.even  { background-color: #E0E0F0; color:#000000; }
  h3       { background-color: #E0E0F0; color:#000000; font-size:16px; text-align: center; }
  h4       { background-color: #E0E0F0; color:#000000; font-size:14px; text-align: left; }
  h5       { background-color: #E0E0F0; color:#000000;
           text-align: left; margin-left: 50px; }
  pre      { font-family:arial,helvetica;font-size:12px; color:#000080; font-weight:bold;}
-->
</STYLE>

</head>
<BODY>
<H3>as_admintool: WEB Administrator tool class</H3>

<!--
<div align=right><a href="as_admintool.rus.htm">Russian version</a><br><br></div>
<p>
-->
<div align=center>
<img src="as_admintool-screenshot.gif">
</div>
<p>
Module as_admintool written primarily for people (like me) who often
execute administering tasks through a WEB-interface: 
run SQL queries, get SQL 'explain plan',
backup/restore data from/to SQL server, and so on.
First,I wanted to have a flexible solution, that allows to add functionality as easy as possible.
Second, I desided to make all requests in AJAX manner (no need to redraw a whole page, asynchronous calls etc.)

<br>
As a result, as_admintool was implemented as an empty container, and all 'real' jobs reside
in plugin modules. Four ready-to-use plugins included in distributive.
<br>
Anyone can develop and 'attach' his own plugin module, that can be far from 'administering' tasks
- it's a matter of Your needs and fantasy.

<p>
All plugin modules in distributive use AJAX calls, so the main screen is drawn only once,
then built-in javascript functions send all through a POST request to the server by XMLHttpRequest, receive result, and make
some dynamic changes depending on it (for example, draw returned HTML code containing execution result).

<p>
<b>Attention</b>: Javascript and DHTML widely used, so browser compatibility
should be tested before publishing production version of Your application.

<br>

<H4>Distributive contents</H4>
<ul>
 <li><b>as_admintool.php</b> - main module (wrapper and container for all admin plugins)
 </li>

 <li><b>as_admintool_sqlqry.php</b> - plugin module for executing SQL queries
 </li>

 <li><b>as_admintool_backup.php</b> - plugin module for making database/tables backups
 </li>

 <li><b>as_admintool_restore.php</b> - restore SQL data from backup files plugin
 </li>

 <li><b>as_admintool_filemgr.php</b> - file manager plugin
 </li>

 <li><b>as_admintool_stub.php</b> - self-documented 'empty' plugin that You can use as 'starting point'
 for writing Your own plugin modules.
 </li>
 
 <li><b>as_dbutils.php</b> - database access wrapper class, used in plugins that access SQL databases
 </li>
 <li><b>as_jsfunclib.js</b> - JavaScript module, used by all plugins (making AJAX calls)
 </li>

 <li><b>sample.php</b> - working sample that demonstrates as_admintool functionality
 </li>

 <li><b>styles.css</b> - cascade styles sheet file, used by sample.php
 </li>

 <li><b>as_admintool.htm</b> - instruction file You're reading now
 </li>
</ul>

<H4>Installing as_admintool on Your site</H4>

<ol>
  <li>Download distributive zip file and unzip it into temporary folder.
  If you will use admin tools in multiple pages, place as_admintool.php and other PHP-files from distributive
  into one of the folders listed in your PHP.ini "include_path" variable. Otherwise, just place it
  into the folder with your main PHP-script.
  </li>
  <li>Do the same with as_propsheet class module, because it's used by as_admintool. Current version of as_propsheet can be
   downloaded from <a href="phpclasses.ord">phpclasses.org</a> or from <a href="http://as-works.narod.ru/en/php/">author's site</a>
   </li>
  <li> Create/open Your PHP script, that will draw 'admin tools' screen.<br>
    Place "<b>require_once('as_admintool.php');</b>" somewhere in the beginning of file.
    Do it with all plugin modules you're going to use.
  </li>
  <li>Copy "as_jsfunclib.js" module into the 'current' folder of Your admin page, or into a special 'scripts'
  folder at Your wish - in that case You'll need to make a call of CAsAdminTool::SetJsPath() method, to show where is this file.
</ol>
<br>

<H4>Preparing CSS styles to draw admin pages</H4>

as_admintool uses as_propsheet class for drawing pages, so please read as_propsheet class instruction
to make HTML format looking good by CSS tuning.

<H4>Creating admininstrator's screen with as_admintool</H4>
<p>
Make a decision what plugin modules You'll need in Your administering tasks, and include them
by <b>require_once()</b> or <b>include_once()</b> functions after the line <b>require_once('as_admintool.php')</b>

<b>Listing 1: header part</b>
<pre>
require_once('as_admintool.php');
require_once('as_admintool_sqlqry.php'); // SQL queries plugin
</pre>

Now You can create a CAsAdminTool object and fill it with some pages.
You can add more than one page of any registered type, for example, make two independent pages for running SQL queries.
(As we'll see later, each query page can have it's own predefined queries list).

<p>
When all pages added, just call Draw() method.

<p><b>Listing 2: create CAsAdminTool object, add pages and draw it.</b>
<pre>
$adminobj = new CAsAdminTool(800,620); // desired width and height passed
$adminobj->AddPage(ADM_SQLQUERY,'SQL Queries page 1', 'predef-qry1.txt');
$adminobj->AddPage(ADM_SQLQUERY,'SQL Queries (page 2)', 'predef-qry2.txt');
$adminobj->Draw();
</pre>

<p>Now, we have a good looking HTML page with all our tools. But who will do the job when our user
press 'Execute' button' ?
<br>as_admintool designed in self-contained manner, so all plugin modules must send queries to the
same URL that draws admin screen. (We'll have a closer look at plugin design later).

To provide 'receiving' client request and executing a job, You should add 'executing' code somewhere
<b>BEFORE</b> any HTML drawing (including html 'Header' sends ! like cookies etc). 
Otherwise this HTML code will be AJAX-sent to the client before query result, what is wrong.

From the other hand, 'request handling' code must be inserted into Your page after all security checks,
to prevent unauthorized calls. So You have to put <b>CAsAdminTool::PerformAction()</b>
call in the right place.

Next listing is a full code example (we assume there is a special session variable containing user access level):

<p>
<b>Listing 3: full code example</b>
<pre>
require_once('as_admintool.php');
require_once('as_admintool_sqlqry.php'); // as_admintool: executing SQL queries plugin

// localize interface here or just change titles, if needed:
$as_iface['parameters'] ='Query parameters';
$as_iface['predef-qry'] ='predefined queries list...';
$as_iface['execqry'] ='Execute Qry';
$as_iface['explainqry'] ='Show execution plan';
$as_iface['qryresult'] ='Query result';
$as_iface['msg_waiting'] ='Waiting for server reply...';

// some CSS tuning
$as_cssclass['pagebody'] = 'frmtable';

if(!isset($_SESSION)) session_start();
$access = $_SESSION['access_level']; // Have You admin rights ?

ConnectDb(); // some function for connecting to your DB

$as_adm_qryaccess = 2; // sqlqry plugin can work in three access levels : 0-1-2

# Client request executing code: this is a mandatory line, 
# You add it before any HTML drawing code !
# You can check user access level before this, to avoid unauthorized calls
if(!empty($admt_call_handler))  CAsAdminTool::PerformAction(); 

HTML_Header(); // function that draws your html header block, at least &lt;HTML&gt;&lt;BODY&gt; 
and all CSS styles or css file reference...

if($access > 1 ) {
  $adminobj = new CAsAdminTool;
  $adminobj->SetJsPath('../scripts/'); // if as_jsfunclib.js file is not in cur.dir
  $adminobj->AddPage(ADM_SQLQUERY,'SQL Queries', 'predef-qry1.txt');
  $adminobj->AddPage(ADM_SQLQUERY,'SQL Queries (page 2)', 'predef-qry2.txt');
  $adminobj->Draw();
}
else echo "access denied !";
</pre>

<H4>Global variables in as_admintool</H4>

There are few global vars that help you fine tune as_admintool behaviour.
<ul>
  <li>
  <b>$as_admt_charset</b> - default charset used in Your site. It is used
  to make a right conversion between UTF-8 code returned by XMLHttpRequest object.
  If Your site's charset is not 'UTF-8', conversion is needed, so make sure Your ISP
  has installed support of <b>mb_convert_*</b> PHP functions !
  </li>
  <li><b>$admt_call_handler</b> is a 'flag' var that becomes true when POST or GET data have come from
  client and contain a field 'adm_action_type'. With this var Your code will know when to call 
  PerformAction():<br>
  <pre>
  if(!empty($admt_call_handler))  CAsAdminTool::PerformAction();
  </pre>
  </li>
</ul>  
  
<H4>Methods in as_admintool</H4>
<p>
Here is a full method definition in CAsAdminTool.<br><br>
<table border=0 bgcolor='#5050E0' width='100%' cellspacing=1>
<tr class='odd'>
 <td valign=top>constructor: <b>CAsAdminTool($width='920',$height='600')</b></td>
 <td>
  <br><b>$width</b> - width of the property sheet containing all admin pages; 920 by default
  <br><b>$height</b> - height, 600 by default.
  <br><br><b>Sample: $obj = new CAsAdminTool(800,400);</b>
</td></tr>
<tr class='even'>
 <td valign=top><b>AddPage($pagetype, $pagetitle, $userparam1='', $userparam2='',$userparam3='')</b></td>
  <td>Register new page that will be drawn.
  <br><b>$pagetype</b> - string ID of one of registered types
  <br><b>$pagetitle</b> - string will be a title in the tab for this page.
  <br><b>$userparam1,2,3</b> - optional parameters that will be passed to the 
  drawing page function, so every page of this type can have some differences.
  In a sample.php we use it to have different predefined query lists on "SQL query" pages, 
  and to work with different davabases on server.
  <br><br><b>Sample: $obj-&gt;AddPage('sqlqry', 'Sql query - page 1','','mydatabase');</b>
</td></tr>

<tr class='odd'>
 <td valign=top><b>SetJsPath($strk)</b></td>
 <td>Sets path to the module as_jsfunclib.js, used by javascript functions inside plugins
  <br><br><b>Sample: $obj-&gt;SetJsPath('../scripts/');</b>
</td></tr>

<tr class='even'>
 <td valign=top><b>Draw($initpage=false)</b>
 </td><td>This is a final method that draws the whole HTML code for Your
   administrator pages. Parameter <b>$initpage</b> can set initially active page number.
  <br><br><b>Sample: $obj-&gt;Draw(2);</b>
</td></tr>

<tr class='odd'>
 <td valign=top><b>PerformAction()</b></td>
 <td>Special 'static' function that handles all requests from client. It analizes POST or GET passed parameter <b>adm_action_type</b>,
  and depending on it's value calls respective plugin's handler function. As mentioned above, You have to place
  this function call in the right place (before any HTML output, but after security checks).
  <br><br><b>Sample: CAsAdminTool::PerformAction();</b>
  
</td></tr>


</table>

<p>

<H4>Plugin modules included in distributive</H4>
as_admintool comes with a few ready-to-use plugin modules, that can be used by programmer as starting point
or a glue for developing his own plugins. 
<!-- They have some comments for programmer, but I prefer
leaving short comments, because of "interpreter" nature of PHP (every comment will be parsed and dropped by PHP
hundreds times, wasting CPU resources)
-->

<H4>Plugin: as_admintool_sqlqry.php - Executing SQL queries</H4>

Running SQL queries and managing data was the first demand I started this project for.
Plugin as_admintool_sqlqry contains all in one: it draws client screen to write a query,
and a code for executing it, form a result as HTML table, pass it to the client, and draw on the client side.
Query screen contains a field for writing SQL query, select box for choosing one of 'predefined' queries,
and a parameter fields. When user wants to run a query multiple times with different parameter values,
hi/she can use in SQL query text special macros <b>"&amp;P1"</b>, <b>"&amp;P2"</b> and so on. (Note: 'P' must be Capital!)
Before executing every &amp;P{nn} in SQL query will be replaced with respective parameter value.

<p>To add SQL query page to Your admin screen, You must add a line in your code (after including 'as_admin_tool.php'):
<pre>
require_once('as_admintool_sqlqry.php');
</pre>

This inclusion registers a new page type 'sqlqry', so now You can add as many SQL pages as You want
by calling AddPage() :
<pre>
$adminobj->AddPage('sqlqry','Sql Queries, Page NN');
</pre>

<p><b>Using "as_admintool_sqlqry" details</b>
AddPage() for <b>sqlqry</b> type has a following 'user parameters':
<br><br>
User Parameter 1 is a var to pass pre-defined SQL queries, and second - for database name 
(if it's not a default database already connected earlier by Your code).

<p> 
<br><b>Predefined Queries</b>
<br>sqlqry page can have a pre-defined queries, that user won't have to write manually, he just select query name in select-box,
and SQL text is automatically placed into the text field.
<p>
You can prepare an array variable containing predefined queries, in the next form :
each row of this array is an <b>array('query label', 'SQL query text' [,parameter_1_prompt [,...])</b>
<br>
If you have that variable, use it as a parameter when calling AddPage:
<pre>
$myqueries = array();
$myqueries[] = array('Find dept',"SELECT * from depts where deptname like '&P1%'",'search for dept:');
$myqueries[] = array('Find person',"SELECT * from employees where name like '&P1%'",'person name');
$adminobj-&gt;AddPage('sqlqry', 'My queries',$myqueries);
</pre>

The second way: You can save predefined queries list is in a text file. 
One line in this file must contain all the same items for the query, delimited by '|': (label | SQL text [|parameter prompts...])

<pre>
Employees list in the dept|SELECT * from employees WHERE deptname LIKE '&P1%'|Department name
Get all goods for class and name|SELECT * from goods WHERE good_class='&P1' AND good_name='&P2'|class|good name
</pre>
As You can see, first field is a 'title' for a query, second is a query itself, and the rest are the prompts for all parameters,
if query contains them and you need to have user-friendly interface.

<br>Make a file with this list (let's call it 'qry-list1.txt') and perform a call :
<br><br>
<b>$adminobj->AddPage('sqlqry','My queries','qry-list1.txt');</b>
<br><br>
In this case You'll see a select box with two items: <br><br>
<select name=test01><option value=0>pre-defined queries...</option>
<option value=1>employees list in the dept</option>
<option value=2>get all goods for class and name</option>
</select>
<br><br>
By the way, if You want to have a groups of queries, You can use the syntax "group name|-" -
first item will be treated as group title, if second one contains only one char (any char, I used "-").
In this case tag &lt;optgroup label="..."&gt; is generated between &lt;option ...&gt; select tags.

<p><b>Constants in as_admintool_sqlqry</b>
<br><br>
<b>ASADM_SQLQUERY</b> holds a unique id for plugin's type, so it's better write everywhere AddPage(ASADM_SQLQUERY,...).
<br><br>
<b>ASADM_MAXRECORDS</b> is a maximum number or records, that can be returned from SQL query executing.
Default is 200. Even if query does not contain LIMIT N1,N2 option, output will be stopped after reaching ASADM_MAXRECORDS's item.
To turn limiting Off, just set it to 0.

<br><br>
<b>$as_adm_qryaccess</b>  - this variable relates to current user access level.
Yo can set it to the one of three values, before calling CAsAdminTool::Draw() method:
<ul>
 <li><b>zero (0)</b> value means minimal access level : at that level user only choose one of predefined sql queries from select box,
 he cannot edit query text, he doesn't even see it. This can be useful to prepare some "standard" search queries with
 parameters for "ordinary users". User can see only select box with pre-defined queries titles, and "parameters" fields.
 </li>

 <li><b>1</b> is a mid-level of access: User can edit query text, but all queries can only "read" data:
 all queries that don't begin with SELECT, DESC, SHOW, will be rejected. Besides, at this access level
 an additional button 'Explain Query' is drawn and "execution plan" for Your query can be shown by pressing it.
 In MySQL databases you'll receive a result of "EXPLAIN SELECT ..." query,
 just the same as You could see if have inserted "EXPLAIN" word before Your SQL query.
 </li>

 <li><b>2</b> - the highest access level, for administrators. Such a cool man can do anything, including data modification
 by INSERT,UPDATE, CREATE, DROP, TRUNCATE etc.
 </li>
</ul>

<p>
<b>ASADM_QRYPARAM</b> is a number of "parameter" fields on SQL Query form. Default is 4.
You can adjust this value. In a form all parameters are drawn by four items per row.

<A name="HREFCOLUMN" />
<p><b>User defined "HREF" columns</b>
<br><br>
What if You d'like to have some "A HREF" anchor tags in a query result, that open desired page, related to current record ?
For that case a special feature was added: user defined columns. 
All You need is to add one or more strings in Your query definition, after all parameters titles (or in mixed manner).
<br>
User column definition Syntax :
<pre>
#HREF ^ {column_number} ^ HTML-code_with_{ID}
</pre>
As You see, every column definition must begin with "#HREF" string (user column flag), followed by field number and HTML code,
delimited with "^" char.<br>
<b>column_number</b> is zero-based query column number, a field value in this column will be used as ID in Your html code.<br>
<b>HTML-code</b> - this is a HTML code that will be used as template for building result column's HTML.
The macro string {ID} must exist in this code, to be replaces with desired column's value, and one more rule:
this HTML code can contain single quotation char {'}, but NOT double quote {"}, because it is used to build Javascript code blocks,
and in case of {"} javascript error will raise.

<p><b>Example</b>
<br><br>
We have a query, returning employee list, with employee ID in first column: <b>SELECT emp_id, emp_name ... FROM employees ...</b>
And we want to have a column with &lt;A HREF&gt; tag, that opens full info page about employee, say "<b>fullinfo.php?emp_id=NNN</b>".
<br>
For this case we construct a query definition:
<pre>
Query title|SELECT emp_id, emp_name ... FROM employees|#HREF^0^&lt;A HREF='fullinfo.php?emp_id={ID}'&gt;open info&lt;/a&gt;
</pre>
Note that as column numbers are zero-based, our (first) column has a number 0.
<br>Like other query definition blocks, user column definition must be delimited with standard '|' char (if you use a text file as a query container).
<br>
If You define query array in PHP, just add array elements with "#HREF" blocks:
<pre>
$myqueries[] = array('Find person',"SELECT * from employees where name like '&P1%'",'person name',"#HREF^0^....");
</pre>

<br>
<H4>Plugin: as_admintool_backup.php - making database backups</H4>

This plugins makes a backup copy of selected (al all) tables in your database.
Plugin unique ID is 'backup', it has a constant <b>ASADM_BACKUP</b> for this string.

<br>Adding backup functions to Your admin page:

<pre>
require_once('as_admintool_backup.php'); // register plugin after as_admintool included line
...
$bckp_folder = 'mybackups/'; // I will save all backups in this folder.
$bckp_list = array('mytable1','mytable2');
$db_name = 'mydatabase';
$adminobj->AddPage(ASADM_BACKUP,'my backups', $bckp_list, $bckp_folder, $db_name);
...
$adminobj->Draw(); // draw admin screen
</pre>

Like in other plugins, the second parameter is a label for the tab.

<p>
The third parameter ($bckp_list) can be either an array variable with all table names You want to backup in one file,
or just a text file name (that file must contain table names, one per line).
If You want to backup ALL tables in database, just pass an empty string in this parameter.

<p>The optional fourth parameter is a folder where You want to save a backup file. If omitted, default folder is used.
Default folder is set in variable $as_admt_bckpfolder, so You can change it.

<p>The optional 5-th parameter is a database name, needed if You want to select another database.
<pre>
// pass an array with all table names:
$mytables = array('users','employees','depts','orderlist','clientlist');
$adminobj->AddPage(ASADM_BACKUP,'my backups', $mytables, $bckp_folder,'mydb'); // add a page with a backup FORM
</pre>

<br><i>Remember</i>: All database functionality moved in a wrapper module as_dbutils, that "knows" only MySQL databases
for this moment. So all 'database-oriented' plugins can work with MySQL only.

<p>Global variables and constants in as_admintool_backup:

<br><br>
<b>ASADM_BACKUP_GZIP</b> - defines saving mode for backup files, if non zero, backup file will be
saved in gzip format, extension '.gz' is added to the filename. Default : 1.

<br><br>
<b>$as_admt_bckpfolder</b> - default folder for backup files. Default: 'backup/'

<br><br>
<b>$as_admt_bcktemplate</b> is a template for created backup file name. It can contain 'date elements' strings,
that will be replaced with current date:
<table>
<tr class='even'><td>YYYY</td><td>year (4 digits)</td></tr>
<tr class='odd'><td>YY</td><td>year (2 digits)</td></tr>
<tr class='even'><td>MM</td><td>month (2 digits with leading zero)</td></tr>
<tr class='odd'><td>DD</td><td>day (2 digits)</td></tr>
<tr class='even'><td>HH</td><td>Hours</td></tr>
<tr class='odd'><td>MI</td><td>Minutes</td></tr>
<tr class='even'><td>SS</td><td>Seconds</td></tr>
</table>

<p>
Default template value is 'backup-YYYY-MM-DD-HHMI'.
File extension '.xml' is added by program, so don't include it into template.
<br>

<H4>Plugin: as_admintool_restore.php - restoring data from backup files</H4>

This plugin lets You choose one of the saved backup files and perform a restore operation into 
SQL database.

<p>To add 'Restore' page to Your "admin screen", You must add a line in your code (after including 'as_admin_tool.php') and 
  add a page with a type 'restore':
<pre>
require_once('as_admintool_restore.php');
...

$adminobj->AddPage('restore','Restore from backups',$backupfolder,$db_name);
...
$adminobj->Draw();
</pre>

<p><b>Using "as_admintool_restore" plugin</b>
<br><br>
Like a previous plugin, as_admintool_backup, this module has a variable 'default' backup folder, it's the same var:
<br>
<b>$as_admt_bckpfolder</b>
<br><br>You can have multiple 'restore' pages on Your "admin screen", and each of them can work with different backup folder 
and different database.
You have to pass this folder (and database name) in the 3-rd (and 4-rd) parameter of AddPage() method 
(<b>$backupfolder</b> in example above).

<br>Any file in 'backup' folder, with extension '.xml' or '.gz' will be treated as 'backup-file'
and placed into 'backup files' select box.


<H4>as_admintool_filemgr - file manager plugin</H4>

This module designed primarily to update program modules on the server, in situations 
when You (an Administrator) have only HTTP access to Your site.

<br> With this plugin Web-Administrator can manage files on the server through a WEB-interface.
This is the only plugin that does not fit fully in AJAX model, because it uploads files (it seems to
be difficult or even impossible to 'pack' the local file contents into AJAX query, 
because of browser's security limitations).

<p>You can 'protect' some file names from deleting or overwriting by filling a special array var:
<b>$asdt_fmgr_protect</b>.

<p><b>Using "as_admintool_filemgr" plugin</b>
<br><br>

Just add a line with require_once for this module, and Addpage() somewhere in Your code.
Prepare an array with all folders that You want to manage and pass it in the AddPage() function.
Every array item can be scalar var (in that case it's value will be a folder exact name. and a title shown in select box),
on two-dimensional array: the first element must be a existing folder name with ending slash ("scripts/"),
and second one - it's label shown in select box:

<pre>
$folders = array( array('scripts/', 'My scripts folder'),
                  array('config/',  'Config files'),
                  '../img/');
$adminoj->AddPage(ASADM_FILEMGR,'Ôàéë-ìåíåäæåð', $folders);
...
</pre>

There are two constants in plugin:
<br>
<ul>
  <li><b>ASADM_UPLOADSIZE</b>, maximal size for one uploaded file;</li>
  <li><b>ASADM_UPLOADFILES</b>, number of files that can be uploaded at once (respective number of &lt;INPUT type=FILE&gt;
    tags will be drawn on the file manager page</li>
</ul>

<br>
<H4>Writing plugin modules for as_admintool</H4>
Plugin module for as_admintool must conform a few rules.
<ol>
  <li> It must contain somewhere in the beginning of file a 'registering' code like this:
     <br><b>CAsAdminTool::RegisterPlugin('mytype_id','DrawHtml_func','ajax_func','nonajax_func')</b>;
 
  <br>'<b>mytype_id</b>' must be a string that will be a plugin ID and must be unique.
  <br> <b>DrawHtml_func</b> is a PHP function name; that function must be somewhere in your plugin file.
  This function will be called to draw every required page of this type. Function must have at least one parameter 
  ($pginfo in all pre-installed plugins) - as_admintool passes an array holding : 
  <ol><li> $pginfo[0] - pageid (current page number) ,</li>
    <li> $pginfo[1], $pginfo[2] - "master page" width and height (You could set them when use constructor CAsAdminTool(). 
    They must be used to limit the nested HTML blocks (tables, DIVs and so on) size. </li>
  </ol>
  Up to three additional parameters can be added, to pass user values,
  that could be passed by You through  CAsAdminTool::AddPage() method.
  If You want to pass more than three user parameters for drawing page, gather them into array variable.
  <br>You will need some javascript code to process actions on Your page, that code can be drawn only once , while echoing
  "first" page of current type. To do this You can use static variable inside a function, and set it from 0 to 1
  when javascript already drawn. Yo can check out <b>as_admintool_sqlqry.php</b> for example how to use it.
  Check out as_admintool_stub.php example plugin for details.
  <br>
  Remember: You'll have some forms in Your page, &lt;div&gt;'s for drawing result, so don't forget 
  to use passed <b>pageid</b> in their names, otherwise in case of multi-page sheet program won't know what page made 
  a call and where to draw the result.
  <br><b>DrawHtml_func</b> should draw valid form, beginning with &lt;FORM ...&gt; and ending with "&lt;/FORM&gt;.
  Besides, it must have at least one Javascript function, that performs AJAX communication: creates XMLHttpRequest object,
  uses it to send all data to server (as POST method !), reseive,parse and show result (and don't forget to delete an object
  when all done, to avoid memory leaks !)
  <br>There must be one mandatory parameter in parameter string, passed to the server:
  <br><b>adm_action_type</b>, in this parameter You pass your plugin type id string, so as_admintool can recognise it and
 pass execution to the right handler function.
  <br>For example, if Your plugin has a type id 'mytask', just add "&amp;adm_action_type=mytask" to the parameter string.
  In multi-page case, You should pass page_id as well, and make Your server handler function to send it back, so your javascript handler
  could understand what exactly page to refresh.

  To make Your plugin re-usable in one admin screen (i.e. draw multiple pages of this type), You have to use passed <b>pageid</b>
  in all html elements id's, that intended to be dinamically changed, and use <b>pageid</b> as a parameter in all javascript calls
  (instead of that, You can deside to draw multiple similar javascript functions - one for every page)
  </li>

  <li>
  <b>ajax_func</b> is a name of Your PHP function that performs client request and returns result in AJAX manner.
  <b>ajax_func</b> must have one parameter - as_admintool will pass all decoded POST data in this parameter 
  as associative array variable (like a $_POST[] var). Received data is already converted from UTF-8 if needed.
  This Function must return exact string that You want to pass to the client for parsing and showing result.
  Again, You don't need to convert this string to UTF-8 - <b>as_admintool</b> will do it for You before sending reply 
  to the client.
  </li>
  <li><b>nonajax_func</b> is needed only in cases when AJAX model is not suitable for Your needs.
    <br>For example, uploading files is an easy task through a standard &lt;FORM method=POST...&gt; request, but not through
    AJAX call. In that case You can write separated handler function for saving uploaded files, and pass it's name in 
    <b>nonajax_func</b> parameter, when registering Your plugin. This approach used in <b>as_admintool_filemgr</b> module.
  </li>
</ol>
  
<p>Some javascript functionality has moved to a separate module, <b>as_jsfunclib.js</b>, to make it reusable in many scripts.
This modile is not absolutely my invention, some functions were found in internet, adapted and gathered into one file.
<br>
For example, to create XMLHttpRequest object, well known function <b>NewXMLHttpRequest()</b> is used.

<br><br>
To make a parameter string containing all fields in HTML form, I use ComputeParamString(frmname, skipempty, fldlist),
where <b>frmname</b> is passed form name, <b>skipempty</b> is a parameter that orders to skip empty values,
and fldlist is optional array holding form field names - if You pass this array, only these fields will be collected,
the rest are skipped. Investigate included plugin modules and You'll find how these functions used.

<H4>Conclusion</H4>

I'd be happy to hear a fresh ideas about what features or new tasks could be added to administrator's pages.
If You have written Your own as_admintool plugin that can be interesting for other people, 
and You don't mind to share it, feel free to send it to me, and I'll include it to 
the main distributive. Or You can publish it by yourself, of course !

<br><br>Bug reports will be appreciated too !

<!--
<H4>ToDo list</H4>
<ul>Plugin module for configurable import data from txt/csv files to the SQL server
</ul>
-->

<H4>Version History</H4>

<b>1.000.003 (2007-03-06 ... 2007-05-07)</b>
<ul>
  <li>small improvements and bug fixes
  </li>
  <li>New feature in as_admintool_sqlqry.php plugin (<a href='#HREFCOLUMN'>user defined 'HREF' columns</a> in query result)
</ul>
<br>

<b>1.0.001 (2007-03-03)</b>
<ul>
  <li>First release
  </li>
</ul>
<br>

<hr>
<div align=center><font size=-2>&copy; Alexander Selifonov, 2007<a href="http://as-works.narod.ru" target="_blank">as-works.narod.ru</a>
</font></div>
</HTML></BODY>
Return current item: as_admintool