# mkInstaller - an installer builder for php projects

## To construct a web installer for your php scripts + db

by mm AT nisu.org
Version October 2015

If you write php scripts that need an installation, this script quickly builds an installer for you. The installer also can install mysql or postgressql databases.

### What it does?

• Your installer in 1 minute.
• Complete i18n.
• Allows to setup variable values up to 3 levels of evaluation.
• Allows to create mysql & postgresql databases and copy selected tables.
• Appareance is controlled by optionnal templates.
• The installer is a single php script.
• Indirect features:
• Backup of entiere sites (including databases).
• Upload of large mysql or postgresql dumps.
• See the examples.

### Why.

If someone write a php script and thinks to distribute it, probabily will need to do some extra work, as writting some instructions and some scripts to create databases.
If, unfortunatelly, some redesign is done, and environment change, or databases change, the instructions and database creations scripts need to be rewriten.
The aim of mkInstaller is to automatize this work.

### Howto and tutorial.

#### First steps.

Edit this simple script my.php:

 <?php  //!  $private='some secret'; //! // %en% Please enter the site dependent value$sitedep='depends on site';  echo $sitedep."\n";?>  The script contains two variable asignements that must change in other installation. To allow mkInstaller.php handle them, every assignement must be in a separate line, and the comment //! must be before the assignement. An optionnal comment can be placed between the two lines, with the form: // %lg%: message, as shown in my.php. Then create the installer: php mkInstaller.php -o out instdir/myinst.php my.php Note: If you do not have access to a command line, put mkInstaller.php in the web tree of your web server and load it with your browser. Then you can type in the command line options explained here. The directory instdir and the file _mkInstaller.php have been created. The installer is leaved in instdir, called myinst.php. You have leaved the installer in a different directory in order to you can test it; else it would overwrite original files on testing. Then open a web browser and access: http://yourserver/...../instdir/myinst.php An ugly installer is ready for you. By now, do not press the button "Do it". To improve the installer, edit the file _mkInstaller.php, you see something like:  //!$defvars=array (  'd206c1d1' =>   array (    'va' => 'private',    'df' => '""',    'ty' => 'text',    'st' => true,    'sz' => 2,    'lg' =>     array (      'en' => 'Type the value of variable <i>private</i>',    ),  ),  '68ec8746' =>   array (    'va' => 'sitedep',    'df' => '""',    'ty' => 'text',    'st' => true,    'sz' => 2,    'lg' =>     array (      'en' => 'Please enter the site dependent value',    ),  ),)$defbdds=array ()$myopt=array (  'big' => false,  'out' => 'instdir/myinst.php',)$svbufs=array ( 'my1.php' => array ( 'p' => true, ),)  It's a php array, when you edit be carefull. The 'df' item is the default value, that is evaled when running installer, so '""' becomes empty. Read here for more info. Observe that _mkInstaller.php contains a long comment acting as template for other features. Now, replace 'text' by 'password' for the 'ty' parameter of the variable private. Observe that a default message for the private var has been placed. Messages in source code have always precedence over those of _mkInstaller.php. Then, re-run: php mkInstaller.php Reload the installer myinst.php with your browser, you will see the new messages, and box for$private is of type 'password'.

If you are not interest in appearance, go to next section.

The installer is still ugly. You can edit a template file to improve the aspect. To see the default template, run:
php mkInstaller.php -inf instdir/myinst.php
that shows internal info from the installer file and the template.

Then, edit a web page and put {CONT} when you want the installer write its <iframe>. Name the page en-my.html, as is for english. The only requeriment is to define a CSS class called ifr for the <iframe>.
For example:

	<html>
<style>
.ifr {
width: 100%;
height: 100%;
border: none;
}
</style>
<h2 style="text-align: center">My installer.</h2>
{CONT}
Built by me
</body>
</html>
Then run:
php mkInstaller.php -o tpl en-my.html
and reload myinst.php. The page is very ugly, you can do a better page, sure.
mkInstaller.php has included en-my.html as an option, so you dont need specify it any more.
Then, you can build similar pages for other languages, and call them fr-my.html, es-my.html, etc., and re-run:
php mkInstaller.php
to rebuild the installer.

#### Test the installer. ^

Open the installer myinst.php with your browser, and enter then values
my secret
for private and
my site
for sitedep. Then press "Do it".
Then, observe that a new my.php file has been installed in instdir, containing the correct values. Also a file called _last_inst_mkI.......php has been created, to remenber installed values, in order to use as default values for a possible further installation.

#### Final steps. ^

Usually, after files are created, it is necessary some additional installation. You achieve it by adding a hand-made installation script using -f run. This file is parsed like any other, but after installation is done, the file is executed. The file is never created on target directory, is executed on the fly. For example, the file hello.php:
     <?php      //!      $sayhello=""; if ($sayhello)        mail("some@adress","Installation","Hello from ".            $_SERVER["HTTP_HOST"].$_SERVER["SCRIPT_NAME"]);    ?> 

If you include it with -f run hello.php, user wil be prompted (at installation time) for send hello.

#### Databases. ^

Create a test database (or use someone, we will only perform read operations):
	mysql -p -u root

create database mydb;
use mydb;
create table one (
name varchar(255) NOT NULL default ''
) type=MyISAM;
create table two (
value int(11) NOT NULL default '0'
) type=MyISAM;
insert into two (value) values (222);
quit

Edit file my.php:

 <?php  //!  $private='some secret'; //!$sitedep='depends on site';  echo $sitedep."\n"; //!$dbname='mydb';  //!  $dbhost='localhost'; //!$dbuser='root';  //!  $dbpwd='my current passwd';?>  Put correct values for$dbuser and $dbpwd, current valid user and passwd in your system. Now, run: php mkInstaller.php -d 'dbhost==dbuser==dbpwd==dbname' If you have especified wrong current values for$dbuser or $dbpwd, you will get an error. Else, observe that contents of all tables is copied. If you want to modify this, for example, edit _mkInstaller.php, and change$defbdds to (copy/paste):

 $defbdds=array ( 'mydbdef' => array ( 'comm' => 'a comment', 'ty' => 'mysql', 'vho' => 'dbhost', 'vus' => 'dbuser', 'vpw' => 'dbpwd', 'mydb' => array ( 'comm' => 'some comment', 'vdb' => 'dbname', 'tc' => array ( ), 'tp' => array ( 'two' => array ( ), ), ), ),)  Also, set ty to password for variable dbpwd. Again, run: php mkInstaller.php If every current value is correct, _mkInstaller.php has been updated. Edit it and you see that tc contain the current list of the tables of your database. Now you have your new installer ready, test it with your browser specifying a different database name. Verify that the database is created and that the table two has been copied. Usually, after databases are created, you need insert some dependent installation records, for example the name and password of the site administrator. Then you can proceed as explained before, for example, create a post-inst.php script like:  <?php // this values are irelevant as this file is not part of the project //!$admUs="";      //!      $admPwd=""; //!$dbHost="";      //!      $dbUs=""; //!$dbPas="";      //!      $dbDef=""; // insert into the database some necessary values, // as we need an initial admin for the app // connect cannot fail, as installation has been successful mysql_connect($dbHost,$dbUs,$dbPas);      mysql_select_db($dbDef); mysql_query("insert into users (user,pwd,isAdm)" "values ('$admUs',md5('$admPwd'),1)"); // get logged$_SESSION['user']=$admUs;$_SESSION['admin']=true;      // goes to main app page      loge('<script>setTimeout("parent.location=\"myapp.php\"",2000);</script>'.           '<a target=_"top" href=myapp.php>Initiate</a>',true);    ?> 

The function loge writes the message and scrolls the iframe.
If you have only a database, you can safely avoid the connection and database selection, as installer leaves it open. This simplifies the code of post-inst.php a little:      <?php      // this values are irelevant as this file is not part of the project      //!      $admUs=""; //!$admPwd="";      // insert into the database some necessary values,       // as we need an initial admin for the app      mysql_query("insert into users (user,pwd,isAdm)"                  "values ('$admUs',md5('$admPwd'),1)");      // get logged      $_SESSION['user']=$admUs;      $_SESSION['admin']=true; // goes to main app page loge('<script>setTimeout("parent.location=\"myapp.php\"",2000);</script>'. '<a target=_"top" href=myapp.php>Initiate</a>',true); ?>  As you are using sessions, you can force the installer to also use them: mkInstaller -o ses -f run post-inst.php Similar code has been used in this example. ### Installing mkInstaller. ^ In the previous examples, we have suppossed that the file mkInstaller.php is left in the current direcrtory in order to allow php (cli) to execute it doing: php mkInstaller.php To avoid having a copy of mkInstaller into every directory you need, you can proceed as follows: #### Windows 1. Leave the file mkInstaller.php in some directory. 2. Create ithe file mkInstaller.bat, for example on c:\windows, containing: @echo off\path\to\php \path\to\mkInstaller.php %* #### Linux 1. Leave the file mkInstaller.php in some directory, for example /usr/local/src. 2. Create in /usr/local/bin the file mkInstaller, containing: #!/bin/bashphp /usr/local/src/mkInstaller.php "$@"
3. Set permissions:
chmod a+x /usr/local/bin/mkInstaller
So, you can run
mkInstaller arguments...
from any directory

Now, here you are some features.
• The array 'sp' displays text in the appropiate language before the field.
• If default values specified with 'df' is an array, a <select> is dislayed instead an input box. The 'sz' attribute represents the size attribute.
This is usefull to set variables with boolean values, doing:
'df' => array( '"false"', '"true"' ), st=> false,
or better:
'df' => array( '"false"' => 'No', '"true"' => 'Yes'),
To force a multiple select, set the 'mp' attribute, resulting a PHP array with the selected values or NULL.

• Files specified with -f run and -f filter can access the values introduced by the at installation time, using some like $_REQUEST[v][varcode]. but, the$_REQUEST array is not avaiable if installed from command line. You can use, instead, the array $v, that needs evaluation. To discover varcodes, see the source file of form generated by the installer. If readonly access is needed (the usual), you can define the same install variables in this files, and, as they are parsed, you can access directly the variables. A complete example can be downloaded here (see, see). • The created installer can be invoqued from command line, in the form: php -q myinst.php option "var=value" Where options are any of the described here. For example: php -q myinst.php skdb \ "private='very private'" \ "sitedep=$_SERVER['HTTP_HOST']"
The values are copied literally, not evaluated. If you need evaluation (very bizarre), use:
php -q myinst.php eval skdb \
"private='\'very private\''" \
"sitedep=\'$_SERVER['LANG']\'" Here, the value assigned to$sitedep is the value obtained from $_SERVER['LANG'] at installation time. Warning: eval may cause reevaluation of default vaules ('df'); so, its a good idea to especify all the values, not using default ones. • If your project has a lot of files, or long ones, or big tables to be copied, do not use -o out, use -o big instead. So, all the data are stored in a separate file. The installer will take install data from it. For example, you do: php mkInstaller.php -o big instdir/myinst.php The file instdir/myinst.php_dat has been also created. Then: • you distribute the two files, or • use -o ext setting the datafile path to some URL in your server. Then, move instdir/myinst.php_dat to your web server to be downloaded with such URL. Then, you distribute a small file instdir/myinst.php, that will download big data file from the given URL. Here an example. • Only php files can be parsed automatically by the installer, if you need parse another file type, you can write your own mini-parser. For example, suposse you want to create an .htaccess depending on the installation, you can proceed as follows: 1. Create the file _ht-inst.php containing:  <?php //!$DirectoryIndex = "irelevant dummy value";  if ($DirectoryIndex) // stated at install time fwrite(fopen(".htaccess","w"),"DirectoryIndex$DirectoryIndex");?> 

2. State mkInstaller to run the file after installing:
php mkInstaller.php -f run _ht-inst.php
So, user will be prompted and .htaccess correctly created.

• Suposse you develop in one site and production is in another site (or simply, in another directory). Then, you prepare the installer on the development site and you install as usual (this is the porpouse of the installer). Then, you make some change in the development site, and you want to update the production site, you simply do, in the development site:
mkInstaller -U production_site:directory
This cause the creation of a installer (that is not stored) that is sent to the production site via ssh, and executed. On the production site, the installer takes the previous installation values. Observe that this will try to install again databases.

If you modify only a few files, is a better idea to use:

mkInstaller -u production_site:directory some_file.php someotherfile.php -- someimage.jpg ...

### Reference ^

#### Tailoring

You can set:
• The template (html) file for every supported languaje.
• The CSS file that controls the apareance of form. See any form to view the default CSS.
• The scripts to be run at initialization (-f load).
• The scripts to be run after the user fills the form, before installing (-f filter).
• The scripts to be run after installation (-f run).

#### Command line

Arguments with '-' (must be specified first):
• -c[onfig] file: Name of the definition file, defaults to _mkInstaller.php.
• -d[atabase] host[+port]==user==passw==database[+[table+...+table]][==type[==[+]file]]: Defines a database.
Two possibilities:
• No file or no '+' in file name.
By default, all tables are included and copied, you must edit configuration file to change this behaviour.
If host, port, user, passw or database begin with ':', they are taken as literal values, else they are taken as the names of (installable) variables. For example: -d :localhost==dbUser==dbPwd==:myDB will use localhost and myDB literally, and dbUser and dbPwd as variable names.
The type can be mysql or pgsql. if type is empty mysql4 is assumed, table structure is taken from mysql without considering constrains. If mysql5 is used, type must be set to mysql.
If file is specified, it is read to get table creation commands, else mysqldump or pgdump are used to get them. Note that mysqldump or pg_dump must be in current O.S. PATH to be executed.
In any case, table data are fetched with php commands.
Port specification in mysql can be done in the host attribute as is allowed by mysql_connect, but this is no related to mkInstaller.
If no tables are specified with the database, all the tables are copied with its rows. If only a '+' is present, tables will be taken without data and if some tables are specified, the rows of this tables will be copied. In any case, all the tables in the database are set for creation. Once the installer is built, editing arrays 'tc' and 'tp' in _mkInstaller,php, you can control better the database.
• File name is prefixed with '+'.
Database creation (table creation and insertions) are taken from file. The connection parameters are ignored, although a warning is issued of cannot connect to local data server. This connection parameters where needed when installer works.
In this case, 'tc' ab 'tp' are ignored.
• -f[ile] mode: Can be specified multiple times. If file is already defined, is ignored. The mode can be:
• copy file: Append the file to the list of files to be literally copied.
• parse file: Append the file to the list of files to be parsed and copied.
• norun file: This file is parsed to find variables, but is not included in the installer. Used to define extra variables, see examples.
• load file This file will be executed just before user prompt.
Appropiate to query the environment. It is not parsed to find variables. The files given with run, load and filter are used as normal scripts but they are not created at install time, only executed on the fly.
• filter file: This file will be executed before the installation, just after user send data using the html form.
Appropiate to validate user input, will be parsed.
• run file: Append the file to the list of files to be parsed and executed.
• exclude file: Excludes a file (even if specified after).
• exclude regex==: Excludes any file that match regex.
• tree level directory: Append (copy mode) all the subtree starting at directory with recursion level (0 = infinite).
• jump file label: This file will be run in an independent way, only if the built installer is called with ?jmp=label. This file is not parseable. Can be called in any circumstance, but cannot access to any installation variable.
If file has the form current_file==new_path, the new_path is included instead current_file, and soft links to files are de-referenced. For example: -f copy ../../some_file==some_file takes the original file but the built installer will install it in the current directory. The == form applies also to the tree mode. Obviously, in the exclude mode, == has a different meaning.
Also, if file has the form current_file++content_filter.php, the file content_filter.php is taken as a content filter for current_file. Should be valid php code that finds then complete file content in variable $inbuff and mush write the filtered content to variable$outbuff. It must return true if filter works, or false if fails (to leave original file unchanged, ignoring $outbuff). See an example. Also, if file has the form current_file%%variable/regexp/ the file will be installed only if variable matches the regexp during installation. Valid for parse, copy and tree. See an example.. The complete syntax is current_file++content_filter.php==new_path%%variable/regexp/. • -g [file]: Downloads file from repository, or list files available. • -i[nfo] [installer-file]: Extracts info from installer file. • -I[nfo] [installer-file]: Extracts complete info from installer file. • -n[ooption] option: removes option. • -o[ption] option: Sets an option, option can be: • big installer-file: Alternative for big projects. Is the file where the build installer is written. Also a file called installer-file_dat is created. • cip: If set, when reinstall, controls if installed from the same ip, to avoid data revelation from previous install. • chr charset: Uses this charset, i. e. ISO-8859-15. • css file: Loads form css from file. • cte: Continue building even if some errors occur (i.e. file not found). • drp: The built installer drop databases before create them. • ext path1[==path2]: With -o big, the installer will load data from path1, for example some URL. If path2 specified, it will be the local path for the data file (to be written) instead the default. • err error-handling: To change error_reporting(), if not specified is set to E_ALL ^ E_NOTICE. • fsm microseconds: Forces simulation mode, hardcoded in the installer. Introduces a delay between operations when performing the installation. The value of microseconds must be greater than zero. If it is zero, no simulation is performed. This can be usefull for testing porpouses or to give some nice appearance for programs that install "too quickly". Use it for demos in your sites, but if you distribute the installer, consider that the user can carefully remove the hardcoded option editing the installer. • idb: If set, database insertions and table creation errors are ignored. • ili text_file: If set, sets the license of the installer (different from the license of the installed appication). If not set, the installer license is the mkInstaller license. • inf: If set the installer accepts the parameter --info [r directory|J|I|i] intended to show info about itself, as mkInstaller do with parameters -r, -J, -I or -i. Example. • key file: load private key in PEM format from file to generate a digital signature, that is stored in a file with the same name that the built installer with .sig added. If big model is used, a signature file for data is also generated. See pwd option. To verify signatures, read here. • lic text_file: Set the license option. An checkbox will be included to request user accept license. The license is displayed in a textarea. The file name must follow the same convention that the template files, see the "tpl" option for info. This licenses correspond to application license, different from the installer license. • nam name: Name of the package to be displayed in header, only if default template are used. • nld: If set, do not load user input from previous install. • ngz: If gzinflate or base64_decode are not available in target server, use this option to generate an installer without compression. • nru: I set, user is allowed to avoid running '-x' scripts. • nsv: If set, form user input is not saved when install. • out installer-file: The file where the build installer is written. Cancels previous big option. • pwd env-var: If the key for digital signature needs a password, it is taken form the environment variable env-var. • ses: The built installer uses start_session(). • sim microseconds: An checkbox will be included to set installer in simulation mode (see fsm option). The microseconds value must be greater than zero. Warning: files set with -o load will be executed (to get total simulation, simu=microseconds must be passed in the URL). • ski: If set, the user is allowed to do not install databases. • smo value: Very bizarre: changes the behaviour of progress bar. Values are in range 0-1, 1 means that the percentage of completion is computed only from bytes transferred, and 0 only on operations performed. Default is 0.5, but you can set it to 0 when used with option 'fsm', or use a low value when file sizes are very different. • tpl template-file: Template file name must be as XX-filename, being XX the two letter of some language, i.e. en, es, fr, etc. mkIntaller will try to load all files according to ??-filename, for the languages defined for the variables described in the definition file. Use -o tpl '' to return to default template. The template files can include javascript and/or CSS, but inline or with absolute paths. mkInstaller will only parse images, that will be included in the installer, the rest of elements must be inline or point to external URLs. • ver URL: This URL is used to determine installer version. The build installer connects with it to get current version and warns user if a new version is available. This url is also used to handle the {VER} label in templates, but called with ?lang=lg, where lg is the language of the template. See the example. • -r[ecover] directory [installer-file]: Creates directory and tries to create inside it the source from which installer-file was created. The basic diferences are: the names of the autorun files, values asigned into vars on source code and database source (is always a file). • -s[ample]: Include samples as comments in the definition file. • -U[pdater] directory==arg==arg... Acts as an updater: an installer is built , then change to directrory, execute installer with the specified args, then delete the installer. If directory has the form host:directory, try to connect via ssh. The file _mkInstaller.php is used but not updated. • -u[pdater] directory==arg==arg... Like -U but no databases and no files are loaded from _mkInstaller.php. So, you need to pass them as arguments. It is intended to update individual files. • -v[ersion]: Do no test for a new fersion of mkIntaller, takes this version as good. The rest of arguments are taken as file names to be included, in the form: files to be parsed -- files to be copied. If any file is specified, the previous stored list is cleared, so to add files, use '-f'. #### mkInstaller web interface. ^ If you havent command line access to buid the installer, mkInstaller incorporates a (very) basic web interface. To use it, put mkInstaller.php in your server and load it with your browser. The first time, a password is required for further access. From this interface, you can execute mkInstaller, giving command the command line. The behaviour is the same as the command line interface, except minor convenient diferences. To do automated processes, some parameters can be added (see this example): • pass: The password. • cml: The command line, as usual, leave it empty to simple repeat previos execution. • xcml: Execute command line, used internally when accessing wuth a browser. • fout: Execute command line (to be used instead xcml), without any log information. Used to get the installer via web, see this example. #### Installation options ^. Set by the user when installing, using the browser, or directly via parameters on the built installer. • acli: The user accepts the license. • dmdb: Write database creating commands in a file instead of ejecuting them. • nrun: Do not run scripts. • simu: Only simulates, no autorun is done, no file is write, no database is handled. • skdb: The user wants to skip database handling (creation and copy). Also, at URL, some options can be specified: • data: URL for the datafile. • lang: The two letter language code. • nsav: Do not save and do not load values from previous install session. • scfn: Alternate file for internal data. And only for command line: • intc: Ineractive mode, prompts the variables with empty value. #### Templates. ^ Inside a template you must define {CONT} where you want the installer write its work (a <iframe> tags). If you want to use te same template for several packages, use {NAME} for the name of package, that can be set using the -o nam command line option. If file contains CSS or javascript must be inline or referenced in absolute URLS. The file can contain images, they are included automatically. Also, the file can contain two javascript funciones: • mkProgress(progress) will be invoqued continously with a value between 0 and 100, intended to buid a progress bar. • chStep(step) will be invoqued with values 1 (at start), 2 (when installations begins) and 3 (at the end). Also, the template can contain {IVER}, wich is substituted by the mkInstaller version, {LOGO}, substituted by the URL of the mkInstaller logo (for example <img src="{LOGO}">), and {VER}, substituted by the project version in the language of the template, if the version is set with option ver. See the example. #### Database definition. ^ Databases can be defined using command line or manually editing the config file. A database set is defined by a server and a collection of database names. The server type ('ty') can be mysql or pgsql. If the server has no connection defined, every database must have a file associated with them. • If a file is defined ('fi'), it is loaded and parsed. Example: $defbdds=array (  'onedef' =>   array (    'ho' => 'localhost',    'vus' => 'dbUser',    'vpw' => 'dbPass',    'ty' => 'mysql',    'bdd' =>     array (      'vdb' => 'dbName',      'fi' => 'somefile.sql',    ),  ),) 
This example can be built using:

php mkInstaller.php -d ":localhost==dbUser==dbPass==dbName==mysql==+somefile.sql"
See command line reference for details.
A hostname, user and password must be specified. To do it, the 'ho', 'us' and 'pw' array indexes give fixed (evaluated) values. Instead you can use the indexes 'vho', 'vus' and 'vpw' to give variable names. Such variables must be flaged for parsing (//!) in source files. They will be used by the bult installer to connect to database server, but are not used by mkInstaller for this database. The same applies for every database name, defining 'vdb' or 'db'.

• If not 'fi' is defined, data are obtained from mkInstaller using php commands. So, host, user, pass, and db name will be used not only by the installer, mkInstaller will also use them to obtain the data rows.
Every database has a set of tables to be created and a set of tables to be (partially) copied.
If mysqldump or pg_dump must be used to obtain table creation (and other settings) , array index 'dm' must be set to true. Instead, if database creation commands must be read from a file, array index 'fc' must point to filename.
If not 'fc' or 'dm' are especified, table creation commands will be constructed automatically by mkInstaller, only for mysql4 databases. In this case, the set of tables to be created is specified by 'tc' and is an array that contains table names or regular expressions defining sets of tables. If 'tc' is not defined, its its automatically definet to contain the complete list of tables.
When no file is used, the set of tables to be copied is specified by 'tp' and is an array whose indexes are the table names, and the values are also arrays. For one table, if such array is empty, the table is entierely copied. The structure of this array is: 'nins' => number, 'cols' => list of columns, 'sql' => sql select.
For example: 'col1,col2,col3', 'select col1,555,col3 from table where col1 < 666' will cause to "select ...", and "insert (col1, col2, col3) values (....)". If 'cols' is empty, all the cols are selected; if 'sql' is empty 'select * from table is assumed'. To select the columns of 'cols' use {COLS} in the select (see example).
The value 'nins' represent the number of values by insert. In postgresSQL it is always 1. Set it to 1 in conjunction with option 'idb' to update databases.

If one value (in tp) is not an array but is true and the regexp expands to one table, true is replaced by array('cols'=>list of all columns).

The 'sql' attribute cannot contain limit or offset clauses as they are controlled by mkInstaller.

Example:

 $defbdds=array ( 'def' => array ( 'ty' => 'mysql', 'ho' => 'localhost', 'vus' => 'dbUs', 'vpw' => 'dbPas', 'bdd' => array ( 'vdb' => 'dbDef', 'tc' => array ( 0 => '/^alumnos$/',        1 => '/^ayuda$/', 2 => '/^califs$/',        3 => '/^lugares$/', 4 => '/^fechas$/',      ),      'sql' =>       array (      ),      'tp' =>       array (        'lugares' =>         array (          'cols' => 'idlu,nombre,descr',          'comm' => 'select only some cols',        ),        'fechas' =>         array (          'cols' => 'orden,codi,dpcion,dpcionp,lafecha',          'sql' => 'select {COLS} from fechas where codi != \'\'',        ),      ),    ),  ),) 
This example can be built using:

php mkInstaller -d ":localhost==dbUs==dbPas==dbDef"
and then executing myinst.php and manually editing the _mkInstaller.php file.

The 'sql' at database level are a set (in the example, empty) of SQL statements taht will be executed by the installer (not by mkInstaller) after the creation of tables and before inserting data. It is mainly intended to build an installer for an update, not for a complete application, in this case, the 'tc' and 'tp' arrays will be usually empty or not present.

Summary:
• If 'fi' is defined, connection parameters are only for the built installer, all the database stuff, including data are taken from file. To achieve this from command line, use '+' in file name.
• Else, database rows are taken using 'tp', and
• If type 'ty' is defined,
• If 'fc' is defined, sql for the creation of the database tables are taken from file,
• Else mysqldump or pg_dump are employed to get sql for the creation of the database tables.
• Else mysql4 is assumed and 'tc' is used to define the tables.

#### Misc ^

1. ##### Understanding df.

The 'df' attribute of a variable is evaluated before the form is presented to the user. So, the expresion
'df' = 'uniqid("x")',
will produce: .
'df' = '\'uniqid("x")\''
will produce .

This second form is interesting if the variable is of type 'hidden' and 'ev' is set, so you can introduce code to be evaluated just before parsing the files. For example:

'df' = '\'preg_replace("/@.*/","",$v["5fb14cf"])\'', in a hidden variable, will produce preg_replace("/@.*/","",$v["5fb14cf"])
as a hidden input field, that will be sent and evaluated again obtaining the 'user' part of an email address of another variable (typed by the user at install time).

'df' = '((strftime("%m") < 10) ? (strftime("%Y")-1) : strftime("%Y"))'
(with 'ev' unset) will show into the input box the current or the past year depending on month, because the evaluation of 'df' produces a number, and will be stored literally into the variable when parsing the files.

If the build installer is not used the first time, 'df' is overwritten, except for the hidden variables, because the values typed by the user in previous installation are taken from a file. To avoid it, remove a file of the form _mkI_last_inst_... created by the installer in the install directory.

If multilingual 'df' is required, define it as:  array (  'ml' => true,  'df' =>   array (    'en' => '"Some text"',    'es' => '"Algo de texto"',    'fr' => '"Quelque text"',  ),)  And for 'select' types:  array (  'ml' => true,  'df' =>   array (    'en' =>     array (      0 => '"Some text"',      'o' => '"Some other text"',    ),    'es' =>     array (      0 => '"Algo de texto"',      'o' => '"Algún otro texto"',    ),    'fr' =>     array (      0 => '"Quelque text"',      'o' => '"Autre text"',    ),  ),  'se' => 2,)// takes second value of current lang by default 

2. ##### Other variable attributes.
• 'cp' causes 'df' to be overwritten with the current value in your script. Never use it on secret data. 'st' must be true.
• 'em' is the index (something like '68ec8746') of other variable wich value is copied if the value of the current variable at install time is empty.
• 'ev' states that the value given by the user is really an expression that must be evaluated.
• 'ml' states that 'df' is multilingual.
• 'ns' states that this variable will never be saved for re-installation.
• 'se' marks the item number as selected when 'df' causes a select.
• 'st' says the installer that the value typed by the user at install time must be treated as string, else it will be trated as code to be evaluated. So, if set to false, the 'df' attribute will be evaluated two times.
• 'ty' states the type of input, can be of type text, hidden, checkbox, password and readonly.
• 'vl' when 'df' causes a select, decides the selected value (similar to 'se' but by value). To produce a select, define 'df' as an array. To produce a textarea, define vs as the number of rows and 'sz' as the number of columns.
• 'sp' has the same structure than 'lg', and shows the thext before the field. Use it as a separator or to introduce a block of input fields.
• 'sz' determines the size of the field, even in the case of a select.
3. ##### Digital signatures.
Digital signatures can be created as follows:
1. If necessary, create (only once) a key/certificate pair with something like:
export MyPass=somepassopenssl req -newkey rsa:2048 -out C -keyout K -x509 -days 7305 -passout env:MyPass
that will create the file C containing the certificate and the file K containing the private key protected with the password.
2. Call mkInstaller to use the key:
mkInstaller -o pwd MyPass -o key K -o out myinst.php
This will generate the file myinst.php.sig

The generated signature is not standard, you can verify it with a script like this:

 <?php if ($argc < 3) die("Usage: File.php Certfile"); if (!$cert=openssl_pkey_get_public(file_get_contents($argv[2]))) die("Load cert ".openssl_error_string()); if (!openssl_public_decrypt( base64_decode(file_get_contents("$argv[1].sig")),       $hash,$cert))   die("Decrypting file ".openssl_error_string()); $hash=unserialize($hash); if (sha1_file($argv[1]) !=$hash['hash'])   die("Signature mismatch"); echo strftime("OK {$hash['hash']} %c",$hash['time']);?>  If you call this script verify.php, you call it as: php verify.php file.php certificate-file, verifying that the contents of file.php matches the signature of file.php.sig.

4. ##### Alternative databases.
mkInstaller was designed to read the current active databases in your project. I think this is very comfortable to use. But in some projects, the programmers want to give support for different database engines, i. e., a database will be active but at install time is desirable to select if using pgsql, mysql, etc. To achieve this with mkInstaller, you can use the alt attribute for a set of databases, as follows. You define several alternate databases, and mark them being the same database in different engines, so only one of them will be installed, for example, edit _mkInstaller.php with::  array (  'mydb-mysql' =>   array (    'ty' => 'mysql',    'alt' => 'dbselector',    'mydb' =>     array (      'vdb' => 'db',      'fi' => 'my.sql',    ),  ),  'mydb-pgsql' =>   array (    'ty' => 'pgsql',    'alt' => 'dbselector',    'mydb' =>     array (      'vdb' => 'db',      'fi' => 'pg.sql',    ),  ),)  The alt attribute points to varname dbselector. The different databases with the same alt attribute are considered alternatives.
Then, you run mkInstaller twice and edit _mkInstaller.php. You will find a new variable defined:  array (  'va' => 'dbselector',  'df' =>   array (    '"mydb-mysql"' => 'mysql',    '"mydb-pgsql"' => 'pgsql',  ),  'ty' => 'text',  'st' => false,  'lg' =>   array (    'en' => 'Please select the database type',  ),)  As you can see, it is a selector, you can change the lg attribute and the text of the df array. Do not modify the keys, they are the names of the alternate databases.

mkInstaller is distributed with a MIT license. This license is at the first lines of the script. The license is copied to the generated installers. If you want to change the installer license, edit mkInstaller.php and change the license, you simple must retain the copyright line.

### Examples ^

• Building an installer for

Steps to buid the installer:
• You have phpMyAdmin installed, go to the current installation dir.
• Edit config.inc.php, and select which parameters do you want to include in setup.
This file is very difficult to set up, see Caveats section.
For example, set a //! before the variables $cfg['blowfish_secret'],$cfg['Servers'][$i]['auth_type'],$cfg['Servers'][$i]['user'] and$cfg['Servers'][$i]['password'], moving all the comments to other lines. • Run: php mkInstaller.php -o out installPhpMyAdminSingle.php config.inc.php -- * */* */*/* */*/*/* This will generate a 4Mbyte installer file, ready to run. Then, you can edit _mkInstaller.php, to improve variable definitions. Then run again: php mkInstaller.php The installer is ready again. You can improve it, for example, edit autorun.php:  <?php loge('<h3>To run program, click <a target="_parent" href="index.php">here</a></h3>',true);?>  and run: php mkInstaller.php -f run autorun.php Also you can improve the aspect of the installer, creating the file en-tpl.html, and running: php mkInstaller.php -o tpl en-tpl.html If you consider that a 4Mbyte file is too big, then run: php mkInstaller.php -o big installPhpMyAdminDual.php \ -o ext URL/installPhpMyAdminDual.dat==installPhpMyAdminDual.dat • Building an installer for #### freecap. Test the installer or download it (0.5MByte file). Steps to build the installer: • Uncompress the source file. • Edit freecap.php, including //! where you want to configure. • Run: php mkInstaller.php -o out insFreecap.php freecap.php -- * .h* • Improve definitions editing _mkInstaller.php • Include an autorun.php:  <?php loge('<img src="freecap.php">',true);?>  and run: php mkInstaller.php -f run autorun.php • #### A complex example. ^ This is an installer for a script used to manage some docent activity. Run the installer in simulation mode, or download it and execute: mkIstaller.php -r somedir igespro.php Go to somedir and look at the files autorun-0 and _mkinstaller.php. Both files illustrate the fact that parse variables have 3 moments to take in care: • The value that the programmer sets to develop. This value is never copied in the installer, as may contain sensible data. In the file autorun-0 you see all the values as '', but originally, the var$dbDef contains a complex value described in the comments.
• The value set in _mkinstaller.php, that will be used as default value just before installing.
• The value when installing, that is set by the user input. Hidden vars will simple take the default values.
In this example $dbDef is a hidden var that will take the value 'value of$asig set by the user'.'-'.'value of $curso set by the user' To achieve this, it is necessary to build the installer in several steps: 1. Run _mkInstaller.php to generate a dummy installer. 2. Edit __mkInstaller.php and set the default value for$dbDef based in the indexes of $asig and$curso. This indexes have been calculated by _mkInstaller.php in the previos execution:
'$v["9380bd66"]."-".$v["ca3b40ec"]'.
Observe that this is evaluated before generate the default hidden value, so the ' are necessary.
3. Run again mkInstaller.
The file autorun-0 also illustrates how to setup some initial values into the database. The variables $DNIadm,$PASSadm, $nomYapp and$usuUJI are irrelevant to the installed program, but are inserted into database to have an initial administrator for the application. At the end of installation, the installer deletes itself.
• #### Database installer. ^

This example install only a database, really a subset of a big database. The example shows how to select from a database, and makes some visual effects during installing.
Run it in simulation mode, or download it to run by yourself to view the real effect. Note that the installer is only about 40Kbytes, and takes the data to install from some URL.
Here is the database selection:  array (  'tc' =>   array (    2 => '/^avisos$/', 4 => '/^ed2_pel$/',    5 => '/^ed2_vol$/', 6 => '/^ed2k$/',    9 => '/^fil_pel$/', 10 => '/^filmos$/',    11 => '/^help$/', 12 => '/^listas$/',    15 => '/^pel_gen$/', 16 => '/^pel_pipol$/',    17 => '/^pel_rec$/', 18 => '/^pel_urls$/',    19 => '/^pel_vol$/', 20 => '/^pelis$/',    21 => '/^pet_ed2$/', 22 => '/^pipol$/',    23 => '/^posters$/', 24 => '/^usus$/',    25 => '/^usus_ips$/', 27 => '/^valora$/',    28 => '/^vols$/', ), 'tp' => array ( 'ed2_pel' => false, 'ed2k' => false, 'filmos' => false, 'help' => false, 'valora' => false, 'pel_gen' => false, 'pel_pipol' => array ( 'cols' => '', 'sql' => 'select * from pel_pipol where pos < 40', 'comm' => 'Only a few actors from every film', ), 'pel_urls' => false, 'pelis' => false, 'pipol' => array ( 'cols' => '', 'sql' => 'select distinct pipol.* from pipol,pel_pipol where pos < 40 and pers=imdb', 'comm' => 'Only the the needed for films', ), 'posters' => array ( 'cols' => '', 'sql' => 'select distinct posters.* from posters,pelis where poster=posters.id', 'comm' => 'Only one poster for every film', ), ),)  This example also shows how to use {VER} in the template, the called URL is:  <?php$locs=array('es' => 'es_ES', 'en' => 'en_US', 'ca' => 'ca_ES');    echo "1.2";    if ($lg=$_GET['lang']) {      setlocale(LC_TIME,$locs[$lg]);      echo strftime(' - %B %Y'); // data base changes every day    }  ?> 

Suposse you have a large MySQL database dump. You want to upload it using phpMyAdmin (SQL menu), but it is very big and the server do not allow a POST of such size. You have only ftp access to the server.
To solve the problem, in your local machine, you do:
php mkInstaller.php -o big i.php -d ":localhost==:user==:pass==:dbname==mysql==+file.sql"php mkInstaller.php -o nam uploader
Where user, pass and dbname are literal values (for the server), and file.sql is the name of the local file containting the MySQL commands.
The you send by ftp in binary mode the files i.php and i.php_dat to some dir in the server tree, load the file i.php with your browser, and press "install". Then you can delete the files i.php and i.php_dat.
• #### Entiere site backup. ^

Suposse that you have a site with a lot of programs an a database. Supose that you have only an ftp access to this site, and you want to perform an entiene backup. You can proceed as follows:
1. Put via ftp the file mkInstaller.php in the web-root of your site.
4. Build the installer:
1. Declare the database in a simple way, for example:
-d :localhost==:mydbuser==:mydbpasswd==:mydbname==mysql
and press Proceed.
2. Set to ignore missing files:
-o cte
3. Select (from the web page) and copy the complete list of files and paste to command line as:
-- list-of-files
and press Proceed.
4. Do not specify "-o out".

http://yoursite/mkInstaller.php?pass=the+mkinstaller+passwd&fout=yes

For example, from Linux cron, you do:
wget -o /dev/null -O site-backup-$(date +%s).php \ "http://yoursite/mkInstaller.php?pass=the+mkinstaller+passwd&fout=yes" If you change the files of your site, you must repeat only the step 3. • #### Using hidden values. ^ Suposse that your script needs in two sepearate variables the user part and the domain part of an email address. But is a better idea for the design of the user environment, to request te complete email address. You proceed as follows: 1. Define the two vars as installable:  //!$userMail="";  //!  $domainMail="";  2. Set them as 'hidden' in _mkInstaller.php, with default values:  array ( '57697b07' => array ( 'va' => 'userMail', 'df' => '\'preg_replace("/@.*/","",$v["5fb14cf"])\'',    'st' => true,    'ty' => 'hidden',    'ev' => true,  ),  '7da3be6' =>   array (    'va' => 'domainMail',    'df' => '\'preg_replace("/.*@/","",$v["5fb14cf"])\'', 'st' => true, 'ty' => 'hidden', ), 'ev' => true,)  3. Create a dummy.php file containing:  //!$userDomainMail="";       

This will the variable requested to the user.

When te user loads the installer, default value of userMail will be evaluated to the string preg_replace("/@.*/","",$v["5fb14cf"]), wich is an php expression, and this hidden value will be sent without user intervention. Then, the installer get this value, evaluates it ('ev'), exports it as string ('st') and asigns it to$userMail.
• #### Using --info. ^

To explore the structure of a built installer, you can use mkInstaller with -r, -J, -I or -i, but it is necessary to have mkInstaller.php installed. If you do: mkInstaller -o inf -o out myinst.php myscript.php Then you run:php myinst.php --info or load in your browser http://someserver/somedir/myinst.php?info=i you will obtain the same result than using mkInstaller -i Now, mkInstaller.php its not required, but you must have internet access. You can use php myinst.php --info r somedir or http://someserver/somedir/myinst.php?info=r%20somedir to get the same effect than mkInstaller -r somedir.
See it in action (a very big file).
• #### Content filtering. ^

To filter the contents of a file before including it in the installer, yoy can specify a content filter for every file included unsig -f:
mkInstaller -f parse file1.php++filter1.php \
-f parse file2.php++filter2.php==relocate.php \
-f copy image.jpg++filterimg.php

Where filter1.php can be something like:    <?php    $outbuff=str_replace("a","b",$inbuff);    return true;  ?> 

• #### Conditionnal installing ^

Suposse you have a set of directories containing images, but at install time, only a directory called images will be created, selecting it form the set. The installer must contain all the directories, and at install time, one will be selected. If this is an acceptable overloading for you, you can act as follows. First, create a var, called, for example, $seldir:  '59bccd48' => array ( 'va' => 'seldir', 'ty' => 'text', 'st' => true, 'sz' => 2, 'df' => array ( 'orange', 'banana', 'apple', 'peach', ), 'lg' => array ( 'en' => 'Please select the image dir', ), ),  It will produce a selectable list of names. Then, use$seldir to do a conditionnal install:
php mkInstaller.php -f tree 0 orange==images%%seldir/orange/
-f tree 0 banana==images%%seldir/banana/ ......
At install time, depending on $seldir one of the directories will be used, and installed as images. • #### Version control This is a sample of a simple script intended to set a version URL, using mmGetText:  <?php echo "1.1"; // for version control if ($lg=$_GET['lang']) { // for templates forceLangSession($lg);      mmSetLang(mmIniStr('en'),'en');      echo __(' - nightmare');    }    /* mmGetText start */    ......  ?>  See also this example.

Forcing to read the license is almost impossible, but we can force to scroll the textarea containing the license, using some javascript. A simple way to add javascript is using then -f load option:
php mkInstaller.php -g force_read_lic.txtphp mkInstaller.php -f load force_read_lic.txt

### Other features ^

1. The especial comment //* can be used to mark a zone of code to be skipped by mkInstaler:    <?php    echo "Hi";    //* start of debug code    echo "This is in debug code";    echo "This also"; //* end of debug code    echo "hi";  ?> 

Will be replaced by:    <?php    echo "Hi"; // -- 4 lines of debug code removed by mkInstaller    echo "hi";  ?> 

Replacement starts from blank space before the first //*, and finishes at the end of the line containing the second //*. Of course, script must be parsed (not copied). Variables defined with //! inside the replaced text are never considered for installation.

2. When installing parseable scripts like this:    <?php    echo "hi";    // %es%: Esto es un comentario    // %en%: This is a comment    // %fr%: Ici un commentaire  ?> 

The comments written in a different languaje than the selected at install time, will be removed. So, after an english installation, this script becomes:    <?php    echo "hi";    // This is a comment  ?> 

### Caveats ^

• Multiline assignements can produce parsing errors:
 //!$x='blabla;bla';  The ; sign included in the string as the last non blank character is taken as the assignement terminator. • If you use something like: $i=0;//!$data[$i]='';$i++;//!$data[$i]='';  the two expression are different for php at runtime, but are the same for mkInstaller. • As mkInstaller do not run your source code, not when buildind the installer, nor where installing, in a code like:  //!$x=1;//!$y=2;//!$z="$x =?$y";  
the value detected for $z when making the installer is "$x =? $y", not "1 =? 2", so it is not appropriate for databasenames, for example. If you set default value for$z as "$x =?$y", this is what the user will see, you can use a hidden field. Also, when installing, you can do (not very nice):
 //!$x=1;//!$y=2;//!$z="$x =? $y";/* after install the value of$z is different, can be set by the user */if (!preg_match('/'.preg_quote("$x =?$y").'/',$z) error...  A better idea is to set in _mkInstaller.php, for variable$z:
 array (  'df' => '\'$v["index of variable$x"]."-".$v["index of variable$y"]\'',  'comm' => 'default value will be sent and computed',  'st' => false,  'ty' => 'hidden',) 

• #### ¿How to load a large installation file in a web server?.

If the large installer is called, for example inst.php, you can do: head -c 25000 inst.php >short_inst.php And then load the URL http://......../short_inst.php?scfn=inst.php . The value of scfn cannot be a URL, must be a file on the same server.

• #### ¿How to load an alternate data file?.

Load the URL http://......../inst.php?data=datafileURL This is not a usefull option to update datafiles, as they cannot be replaced, except in the case of very small changes. It is usefull to change the location of the datafile.

• #### How to avoid version testing and autoupgrades?.

Use -v or edit mkInstaller.php and remove or comment the line that states the version (usually at begining of the file).

### Final thought

mkInstaller began as a small application without options to quickly generate a simple installer. From user requests, mkInstaller has grwon and now is rather complicated to use, as some unkind novice programmer has said, seems "some kind of messy". Probably, if I should construct again mkInstaller, it will be different, but this is a project that I cannot deal now.

### Mini-changelog

• 20100329: Changed <? to <?php.
• 20100222: Introduced -X to ignore syntax errors on parsed files.
• 20091226: Introduced 'mp' for multiple select.
• 20091224: Introduced %% for conditionnal install.
• 20090420: Introduced 'tcc' to list the created tables (helps to uninstall)
• 20081014: Introduced 'ns' to do not save a variable
• 20081012: Big bug correction on 20080916 change
• 20080916: nam becomes a required parameter to setup a fixed file name
• 20080821: Added 'sp' in the variable definition
• 20080818: Added -f jump option
• 20080730: Changed prefix== for regex==
• 20080724: Added the alternate database support.
• 20080716: best template handling; changes in version handling
• 20080715: {LOGO} in templates and copy all images, not only local ones
• 20080714: option cte
• 20080714: {VER} in template
• 20080713: {IVER} in template
• 20080713: major changes in URL parameter handling
• 20080713: added charset 'cha' option, and best charset support
• 20080711: Minor changes
• 20080708: mkProgress changed, this affect templates already built
• 20080629: openssl corrected
• 20080628: best -I view
• 20080615: added intc in command mode
• 20080615: added nins on table def
• 20080611: added +[table] in database specification (command line)
• 20080203: added cip, nsv and nld options
• 20080118: added messages for different languages after //!
• 20071213: added 'sql' at database level
• 20071212: added ++content_filtering for any file
• 20071127: added -o key -o pwd
• 20071125: solved bug in php5
• 20071123: -o inf
• 20071123: Name and id for cont iframe
• 20071122: Solved security bug: eval disabled in simulation mode
• 20071121: License accepted before filter execution
• 20071121: Reordering in parameter evaluation
• 20071026: Works fine in MSWindows
• 20071021: Removed installer pcre depedendency
• 20071021: Installer editable
• 20071019: 'tree' and 'exclude==' modes
• 20071018: '--info' parameter
• 20071015: 'smo' option
• 20071013: 'ev' per variable
• 20071013: All original values stored in last_inst
• 20071012: Multilingual 'df', 'ml'
• 20071012: 'em' attribute
• 20071011: -D and -o ses
• 20071009: Treateament of // %en%:
• 20071009: Treateament of //*
• 20070930: Uniq id in images to avoid caching
• 20070613: Removed first line #! to better web interface.
• 20070613: Securized and improved web interface.
• 20070613: Converted _mkInstaller.def => _mkInstaller.php due to security issues.
• 20070605: Databse ignore errors best implemented.
• 20070605: Best error display.
• 20070605: Fixed connection in Postgresql.
• 20070604: Fixed username in Postgresql connection.
• 20070530: Changes on internel HTML, introcuced and changed some id=.
• 20070529: ?data redefined, and introduced ?src.
• 20070528: Best error handling in installer initialization.
• 20070528: New options -n and -o ngz.
• 20070524: Licenses are now multilingual.
• 20070524: New "ili" option.
• 20070524: Removed the "del" option and changed the "simu" and "fsm" options.
• 20070524: New complex examples.
• 20070524: Best checks about installed functions.
• 20070523: Some checks about installed functions.
• 20070522: Added the err option
• 20070522: Added the call to error_reporting().