
<?php
//!
$private='some secret';
//!
// %en% Please enter the site dependent value
$sitedep='depends on site';
echo $sitedep."\n";
?>
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.
http://yourserver/...../instdir/myinst.phpAn ugly installer is ready for you.
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.phpReload the installer myinst.php with your browser, you will see the new messages, and box for $private is of type 'password'.
php mkInstaller.php -inf instdir/myinst.phpthat 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.htmland reload myinst.php. The page is very ugly, you can do a better page, sure.
php mkInstaller.phpto rebuild the installer.
my secretfor private and
my sitefor sitedep. Then press "Do it".
<?php
//!
$sayhello="";
if ($sayhello)
mail("some@adress","Installation","Hello from ".
$_SERVER["HTTP_HOST"].$_SERVER["SCRIPT_NAME"]);
?>
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); quitEdit file my.php:
<?php
//!
$private='some secret';
//!
$sitedep='depends on site';
echo $sitedep."\n";
//!
$dbname='mydb';
//!
$dbhost='localhost';
//!
$dbuser='root';
//!
$dbpwd='my current passwd';
?>
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 (
),
),
),
),
)
php mkInstaller.phpIf 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.phpSimilar code has been used in this example.
php mkInstaller.phpTo avoid having a copy of mkInstaller into every directory you need, you can proceed as follows:
@echo off
\path\to\php \path\to\mkInstaller.php %*
#!/bin/bash
php /usr/local/src/mkInstaller.php "$@"
chmod a+x /usr/local/bin/mkInstaller
mkInstaller arguments...from any directory
'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.
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).
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.
php mkInstaller.php -o big instdir/myinst.phpThe file instdir/myinst.php_dat has been also created. Then:
<?php
//!
$DirectoryIndex = "irelevant dummy value";
if ($DirectoryIndex) // stated at install time
fwrite(fopen(".htaccess","w"),"DirectoryIndex $DirectoryIndex");
?>
php mkInstaller.php -f run _ht-inst.php
mkInstaller -U production_site:directoryThis 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 ...
$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.
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.
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).
Instead,
'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:
And for 'select' types:
array (
'ml' => true,
'df' =>
array (
'en' => '"Some text"',
'es' => '"Algo de texto"',
'fr' => '"Quelque text"',
),
)
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
export MyPass=somepassthat will create the file C containing the certificate and the file K containing the private key protected with the password.
openssl req -newkey rsa:2048 -out C -keyout K -x509 -days 7305 -passout env:MyPass
mkInstaller -o pwd MyPass -o key K -o out myinst.phpThis will generate the file myinst.php.sig
The generated signature is not standard, you can verify it with a script like this:
<?php 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.
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']);
?>
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.
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.
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.phpThe 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.phpAlso you can improve the aspect of the installer, creating the file en-tpl.html, and running:
php mkInstaller.php -o tpl en-tpl.htmlIf 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
php mkInstaller.php -o out insFreecap.php freecap.php -- * .h*
<?php
loge('<img src="freecap.php">',true);
?>
php mkInstaller.php -f run autorun.php
mkIstaller.php -r somedir igespro.phpGo 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:
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',
),
),
)
<?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
}
?>
php mkInstaller.php -o big i.php -d ":localhost==:user==:pass==:dbname==mysql==+file.sql"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.
php mkInstaller.php -o nam uploader
To download the backup via web, you access, periodically:
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.
//!
$userMail="";
//!
$domainMail="";
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,
)
//!
$userDomainMail="";
This will the variable requested to the user.
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.
Where filter1.php can be something like:
<?php
$outbuff=str_replace("a","b",$inbuff);
return true;
?>
'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.
<?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.
php mkInstaller.php -g force_read_lic.txt
php mkInstaller.php -f load force_read_lic.txt
<?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.
<?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
?>
//!
$x='bla
bla;
bla';
$i=0;
//!
$data[$i]='';
$i++;
//!
$data[$i]='';
//!
$x=1;
//!
$y=2;
//!
$z="$x =? $y";
//!
$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...
array (
'df' => '\'$v["index of variable $x"]."-".$v["index of variable $y"]\'',
'comm' => 'default value will be sent and computed',
'st' => false,
'ty' => 'hidden',
)
php mkInstaller.php -f copy directory1==directory2 -f copy directory1/somefilewill produce directory2 and directory1/somefile but not directory2 and directory2/somefile
mmGetText mkInstaller.php
Then, edit the arrays $pgmg iand $lang_lang inside the source, adding your translations.
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.
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.