as_admintool: WEB Administrator tool class

Module as_admintool written primarily for people (like me) who often execute administering tasks through a WEB-interface: run SQL queries, 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.)
As a result, as_admintool was implemented as an empty container, and all 'real' jobs reside in plugin modules. A few ready-to-use plugins included in distributive.
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.

All plugin modules in distributive use AJAX calls, so the main screen is drawn only once, then built-in javascript functions sends data 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).

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

Distributive contents

Installing as_admintool on Your site

  1. 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.
  2. Do the same with as_propsheet class module, because it's used by as_admintool. Current version of as_propsheet can be downloaded from phpclasses.org or from author's site
  3. Create/open Your PHP script, that will draw 'admin tools' screen.
    Place "require_once('as_admintool.php');" somewhere in the beginning of file. Do it with all plugin modules you're going to use.
  4. 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.

Preparing CSS styles to draw admin pages

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.

Creating admininstrator's screen with as_admintool

Make a decision what plugin modules You'll need in Your administering tasks, and include them by require_once() or include_once() functions after the line require_once('as_admintool.php') Listing 1: header part

require_once('as_admintool.php');
require_once('as_admintool_sqlqry.php'); // SQL queries plugin
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).

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

Listing 2: create CAsAdminTool object, add pages and draw it.

$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();

Now, we have a good looking HTML page with all our tools. But who will do the job when our user press 'Execute' button' ?
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 BEFORE 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 CAsAdminTool::PerformAction() call in the right place. Next listing is a full code example (we assume there is a special session variable containing user access level):

Listing 3: full code example

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 <HTML><BODY>
and all CSS styles or css file reference...

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

Global variables in as_admintool

There are few global vars that help you fine tune as_admintool behaviour.

Methods in as_admintool

Here is a full method definition in CAsAdminTool.

constructor: CAsAdminTool($width='920',$height='600')
$width - width of the property sheet containing all admin pages; 920 by default
$height - height, 600 by default.

Sample: $obj = new CAsAdminTool(800,400);
AddPage($pagetype, $pagetitle, $userparam1='', $userparam2='',$userparam3='') Register new page that will be drawn.
$pagetype - string ID of one of registered types
$pagetitle - string will be a title in the tab for this page.
$userparam1,2,3 - 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.

Sample: $obj->AddPage('sqlqry', 'Sql query - page 1','','mydatabase');
SetJsPath($strk) Sets path to the module as_jsfunclib.js, used by javascript functions inside plugins

Sample: $obj->SetJsPath('../scripts/');
Draw($initpage=false) This is a final method that draws the whole HTML code for Your administrator pages. Parameter $initpage can set initially active page number.

Sample: $obj->Draw(2);
PerformAction() Special 'static' function that handles all requests from client. It analizes POST or GET passed parameter adm_action_type, 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).

Sample: CAsAdminTool::PerformAction();

Plugin modules included in distributive

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.

Plugin: as_admintool_sqlqry.php - Executing SQL queries

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 "&P1", "&P2" and so on. (Note: 'P' must be Capital!) Before executing every &P{nn} in SQL query will be replaced with respective parameter value.

To add SQL query page to Your admin screen, You must add a line in your code (after including 'as_admin_tool.php'):

require_once('as_admintool_sqlqry.php');
This inclusion registers a new page type 'sqlqry', so now You can add as many SQL pages as You want by calling AddPage() :
$adminobj-gt;AddPage('sqlqry','Sql Queries, Page NN');

Using "as_admintool_sqlqry" details AddPage() for sqlqry type has a following 'user parameters':

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).


Predefined Queries
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.

You can prepare an array variable containing predefined queries, in the next form : each row of this array is an array('query label', 'SQL query text' [,parameter_1_prompt [,...])
If you have that variable, use it as a parameter when calling AddPage:

$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->AddPage('sqlqry', 'My queries',$myqueries);
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...])
If You want som of Your SQL queries to be multi-line, just insert "{CRLF}" as a line delimiter.
It is posible to run more than one query per call - queries must be delimited with a line containing single "/" char. All parameter values will be used in ALL queries in that case. So If You want "predefined" multi-query call, insert "{CRLF}/{CRLF} between queries
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
Example: Two-queries in one call|SELECT SYSDATE(){CRLF}/{CRLF}SELECT * FROM mytable
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.
Make a file with this list (let's call it 'qry-list1.txt') and perform a call :

$adminobj-gt;AddPage('sqlqry','My queries','qry-list1.txt');

In this case You'll see a select box with two items:



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 <optgroup label="..."> is generated between <option ...> select tags.

Constants in as_admintool_sqlqry

ASADM_SQLQUERY holds a unique id for plugin's type, so it's better write everywhere AddPage(ASADM_SQLQUERY,...).

ASADM_MAXRECORDS 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.

$as_adm_qryaccess - this variable relates to current user access level. Yo can set it to the one of three values, before calling CAsAdminTool::Draw() method:

ASADM_QRYPARAM 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.

User defined "HREF" columns

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).
User column definition Syntax :

#HREF ^ {column_number} ^ HTML-code_with_{ID}
As You see, every column definition must begin with "#HREF" string (user column flag), followed by field number and HTML code, delimited with "^" char.
column_number is zero-based query column number, a field value in this column will be used as ID in Your html code.
HTML-code - 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.

Example

We have a query, returning employee list, with employee ID in first column: SELECT emp_id, emp_name ... FROM employees ... And we want to have a column with <A HREF> tag, that opens full info page about employee, say "fullinfo.php?emp_id=NNN".
For this case we construct a query definition:

Query title|SELECT emp_id, emp_name ... FROM employees|#HREF^0^<A HREF='fullinfo.php?emp_id={ID}'>open info</a>
Note that as column numbers are zero-based, our (first) column has a number 0.
Like other query definition blocks, user column definition must be delimited with standard '|' char (if you use a text file as a query container).
If You define query array in PHP, just add array elements with "#HREF" blocks:
$myqueries[] = array('Find person',"SELECT * from employees where name like '&P1%'",'person name',"#HREF^0^....");

Plugin: as_admintool_backup.php - making database backups

This plugins makes a backup copy of selected (al all) tables in your database. Plugin unique ID is 'backup', it has a constant ASADM_BACKUP for this string.
Adding backup functions to Your admin page:
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
Like in other plugins, the second parameter is a label for the tab.

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.

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.

The optional 5-th parameter is a database name, needed if You want to select another database.

// 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

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

Global variables and constants in as_admintool_backup:

ASADM_BACKUP_GZIP - 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.

$as_admt_bckpfolder - default folder for backup files. Default: 'backup/'

$as_admt_bcktemplate is a template for created backup file name. It can contain 'date elements' strings, that will be replaced with current date:
YYYYyear (4 digits)
YYyear (2 digits)
MMmonth (2 digits with leading zero)
DDday (2 digits)
HHHours
MIMinutes
SSSeconds

Default template value is 'backup-YYYY-MM-DD-HHMI'. File extension '.xml' is added by program, so don't include it into template. If user has entered his own file name before starting backup, that name will override default template.

Plugin: as_admintool_restore.php - restoring data from backup files

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

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':

require_once('as_admintool_restore.php');
...

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

Using "as_admintool_restore" plugin

Like a previous plugin, as_admintool_backup, this module has a variable 'default' backup folder, it's the same var:
$as_admt_bckpfolder

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 ($backupfolder in example above).
Any file in 'backup' folder, with extension '.xml' or '.gz' will be treated as 'backup-file' and placed into 'backup files' select box.

as_admintool_filemgr - file manager plugin

This module designed primarily to update program modules on the server, in situations when You (an Administrator) have only HTTP access to Your site.
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).

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

Using "as_admintool_filemgr" plugin

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:

$folders = array( array('scripts/', 'My scripts folder'),
                  array('config/',  'Config files'),
                  'img/');
$adminoj-gt;AddPage(ASADM_FILEMGR,'Ôàéë-ìåíåäæåð', $folders);
...
There are two constants in plugin:

Writing plugin modules for as_admintool

Plugin module for as_admintool must conform a few rules.
  1. It must contain somewhere in the beginning of file a 'registering' code like this:
    CAsAdminTool::RegisterPlugin('mytype_id','DrawHtml_func','ajax_func','nonajax_func');
    'mytype_id' must be a string that will be a plugin ID and must be unique.
    DrawHtml_func 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 :
    1. $pginfo[0] - pageid (current page number) ,
    2. $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.
    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.
    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 as_admintool_sqlqry.php for example how to use it. Check out as_admintool_stub.php example plugin for details.
    Remember: You'll have some forms in Your page, <div>'s for drawing result, so don't forget to use passed pageid 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.
    DrawHtml_func should draw valid form, beginning with <FORM ...> and ending with "</FORM>. 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 !)
    There must be one mandatory parameter in parameter string, passed to the server:
    adm_action_type, in this parameter You pass your plugin type id string, so as_admintool can recognise it and pass execution to the right handler function.
    For example, if Your plugin has a type id 'mytask', just add "&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 pageid in all html elements id's, that intended to be dinamically changed, and use pageid as a parameter in all javascript calls (instead of that, You can deside to draw multiple similar javascript functions - one for every page)
  2. ajax_func is a name of Your PHP function that performs client request and returns result in AJAX manner. ajax_func 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 - as_admintool will do it for You before sending reply to the client.
  3. nonajax_func is needed only in cases when AJAX model is not suitable for Your needs.
    For example, uploading files is an easy task through a standard <FORM method=POST...> 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 nonajax_func parameter, when registering Your plugin. This approach used in as_admintool_filemgr module.

Some javascript functionality has moved to a separate module, as_jsfunclib.js, 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.
For example, to create XMLHttpRequest object, well known function NewXMLHttpRequest() is used.

To make a parameter string containing all fields in HTML form, I use ComputeParamString(frmname, skipempty, fldlist), where frmname is passed form name, skipempty 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.

Plugin: as_admintool_slqimport.php - import sql data from plain text files

With this plugin administrator can insert data into database from txt,csv files with fields delimited by one of standard chars : TAB (chr(9)), ";", and "|". Supported delimiters list can be easely modified in the source code.

When adding "import data" page to Your admin tool screen, You have to pass "base" folder, that contains text data files - only this folder will be searched for source text files. Supported source file extensions are "txt", "csv" and "tdf" - the rest of a folder contents is ignored. (Of course, this extensions list can be changed in the source code).

Using sqlimport plugin Example

require_once('as_admintool.php');
require_once('as_admintool_slqimport.php');

$tables = array('employees','departments','salaries'); # only these tables can be imported from txt files
$adminobj = new CAsAdminTool(800,620);
$adminobj->AddPage(ASADM_SQLIMPORT,'Data importing', 'data-files/',$tables);
$adminobj->Draw();

AddPage parameters fro sqlimport plugin As You could see in example, AddPage can pass two parameters: first is as tring containing folder (path) to the source text files. This parameter is optional, if ofitted, files will be searched in current folder.
Second optional parameter can be a string with comma delimited tables list, or an array - in both cases passed table names will be used to fill select box, that sets table to import to. If You omit this parameter, all tables in the current databases will be shown.

How it works

On the "import" page You have to choose on of available tables in select box N1, and one of source files in select box N2 (this list can be instantly refreshed by pressing "refresh files" button, without reloading the whole page). When choice done, press "Select fields for columns..." button. On this action, selected text file is parsed on server, delimiter chat is autodetected (by maximal "splitting result" of it's lines). Then the HTML code for choosing a field for each text filke "data column" is computed and sent to the client. This code is a grid, that shows first 20 parsed lines from text file, and select boxes for each data column, where You will choose data table field for every of them (if no field selected, this column of data will be ignored)

Importing can be done with or without cleaning (truncating) of a target table. (Use a respective checkbox for this option )

Conclusion

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 !

Bug reports will be appreciated too !

Version History

14.04.2008 as_admintool_slqimport plugin added
11.12.2007 as_admintool_sqlqry plugin update

1.000.003 (2007-03-06 ... 2007-05-07)

1.0.001 (2007-03-03)


© Alexander Selifonov, 2007as-works.narod.ru