diff options
-rw-r--r-- | win32/installer/README | 58 | ||||
-rw-r--r-- | win32/installer/gen-nsis.php | 442 | ||||
-rw-r--r-- | win32/installer/setini.php | 64 |
3 files changed, 564 insertions, 0 deletions
diff --git a/win32/installer/README b/win32/installer/README new file mode 100644 index 0000000000..107ca7d5a8 --- /dev/null +++ b/win32/installer/README @@ -0,0 +1,58 @@ +PHP Installer for Win32, by Wez Furlong <wez@thebrainroom.com> +============================================================== +$Id$ + +Here are the supporting scripts for building the win32 PHP installer. +You need to have the Super-Pimp Installer from Nullsoft (Open Source). +It is available here: + http://nsis.sourceforge.net/ + +To build an installer, you need: + + o A Source Tree + o A win32 snapshot (extracted from the .zip) + + (The source tree and snapshot should have matching versions!) + +A Script/Batch file. +I'm using this (in a .bat file): + +---------------------------------------------------------------- +cd <snapshot_root> +cli\php <source_root>\win32\installer\gen-nsis.php > php.nsi +"C:\Program Files\NSIS\makensis" /pause /nocd php.nsi +---------------------------------------------------------------- + + ** It is a good idea to examine the php.nsi file for WARNING + ** comments. These indicate inconsistencies about your source + ** tree structure. + +This will generate InstallPHP<Version>.exe, where <Version> is the version of +the php in the snapshot. The Installer will be placed in the snapshot root. + +Installer Concept +================= + +Maintaining installers is a real chore, so we use PHP to generate as much as +possible. + +The gen-nsis.php script will examine the extensions dir from the snapshot and +then attempt to extract information about the extensions from the source code. +The sapi dir is subjected to similar treatment. + +Throughout the installation, values for php.ini settings are decided; these are +appended to a temporary file. After everything has been installed, the +iniset.php script is run and merges the values from the temporary file into the +"official" php.ini. + +These scripts take advantage of features found in PHP 4.3.0 and later, so you +can't build a PHP 4.2.x distro with it. + +Hacking +======= + +While hacking, it's a good idea to comment out the SetCompressor line; it will +speed up your installer builds... +Also, switch the logic for the $SYSDIR define at the top to install vital DLLs +to a fake system dir. + diff --git a/win32/installer/gen-nsis.php b/win32/installer/gen-nsis.php new file mode 100644 index 0000000000..0907e41674 --- /dev/null +++ b/win32/installer/gen-nsis.php @@ -0,0 +1,442 @@ +; PHP Installer for NSIS +; Based on Welcome/Finish Page Example Script (Written by Joost Verburg) +; Author: Wez Furlong <wez@thebrainroom.com> +; $Id$ +<?php + +define('PHPVERSION', phpversion()); +define('SOURCEDIR', dirname(__FILE__) . "\\..\\..\\"); +define('DISTDIR', getcwd()); + +/* for testing, install system files in a safe dir */ + +if (false) { + $SYSDIR = "\$INSTDIR\\system"; +} else { + $SYSDIR = "\$SYSDIR"; +} + +$sections = array( + "core" => array( + "label" => "-PHP Core (Required)", + "files" => array( + "$SYSDIR" => array( + "dlls\\*.dll", + "php4ts.dll", + ), + "\$INSTDIR" => array( + "*.txt", + "php.gif", + "php.ini-*", + ), + ), + "extras" => "Call CopyPHPIni\nWriteUninstaller \"\$INSTDIR\\Uninstall.exe\"" + ), + + "cgi" => array( + "group" => "SAPI", + "label" => "CGI", + "description" => "The most stable SAPI for use to serve PHP scripts in your web server", + "files" => array( + "\$INSTDIR" => array( + "php.exe" + ), + "\$INSTDIR\\sapi" => array( + "sapi\\pws-php4cgi.reg" + ), + ), + ), + + "cli" => array( + "group" => "SAPI", + "label" => "CLI", + "description" => "New Command Line Interface for running PHP scripts as batch files", + "files" => array( + "\$INSTDIR\\cli" => array( + "cli\\php.exe" + ), + ), + ), + + "embed" => array( + "group" => "SAPI", + "label" => "Embed", + "description" => "Libraries for embedding PHP into your own projects", + "files" => array( + "\$INSTDIR" => array( + "*.lib" + ), + ), + ), + + "mibs" => array( + "group" => "Extras", + "label" => "MIBS for SNMP", + "description" => "MIB information for the SNMP extension", + "files" => array( + "\$INSTDIR\\mibs" => array( + "mibs\\*" + ), + ), + ), + + "pdfstuff" => array( + "group" => "Extras", + "label" => "PDF support files", + "description" => "Fonts and codepage data files for the PDF extensions", + "files" => array( + "\$INSTDIR\\pdf-related" => array( + "pdf-related\\*" + ), + ), + ), + + "mimemagic" => array( + "group" => "Extras", + "label" => "Mime Magic", + "description" => "The magic information file for the mimemagic extension", + "files" => array( + "\$INSTDIR" => array( + "magic.mime" + ), + ), + ), + + "openssl" => array( + "group" => "Extras", + "label" => "OpenSSL", + "description" => "OpenSSL configuration information which you must read if you plan to use PHP as a Certificate Authority", + "files" => array( + "\$INSTDIR\\openssl" => array( + "openssl\\*" + ), + ), + ), + + + +); + +$groups = array( + 'SAPI' => array("SAPI", "Select which Server API's to install."), + 'EXT' => array("Extensions", "Select which extensions to install."), + 'XSAPI' => array("Experimental SAPI", "Experimental Server API's - use at your own risk!"), + 'XEXT' => array("Experimental Extensions", "Experimental Extensions - use at your own risk!"), + 'Extras' => array("Extras", "Supplemental Files"), + ); + +function xglob($pattern) +{ + if (strpos($pattern, '*') === false) { + return array($pattern); + } + $dir = dirname($pattern); + $pattern = basename($pattern); + + $pattern = str_replace(array('*', '.'), array('.*', '\.'), $pattern); + + $files = array(); + + $d = opendir($dir); + while ($f = readdir($d)) { + if ($f == '.' || $f == '..' || preg_match('/^\..*\.swp$/', $f)) + continue; + if (preg_match('@' . $pattern . '@i', $f)) { + $files[] = $dir . '\\' . $f; + } + } + + return $files; +} + +/* Look for extensions and determine their info based on the source tree. + * We can determine the name and author from the CREDITS file. + * We can determine experimental status from the EXPERIMENTAL file. + * It would be nice to have a standard description line in the CREDITS too. + */ +$extension_abbreviations = array( + 'ifx' => 'informix', + 'gd2' => 'gd', + ); + +$sapi_abbreviations = array( + 'apache2' => 'apache2filter', + 'srvlt' => 'servlet', +); + +function add_sections($pattern, $groupname, $abbrev, &$sections, $sourcedirs, $instdir) +{ + $avail = xglob($pattern); + + foreach ($avail as $extname) { + /* mangle name */ + if (preg_match('/(php_|php4|php)([^_].*)\.dll/', basename($extname), $matches)) { + $ext = $matches[2]; + } else { + $ext = basename($extname); + } + + if (isset($abbrev[$ext])) { + $ext = $abbrev[$ext]; + } + + $extdir = null; + + foreach ($sourcedirs as $sourcedir) { + // Allow absolute path for separate PECL checkout + if ($sourcedir{0} == '\\' || $sourcedir{1} == ':') + $extdir = $sourcedir; + else + $extdir = SOURCEDIR . $sourcedir . '/' . $ext . '/'; + + if (is_dir($extdir)) + break; + + $extdir = null; + } + + if ($extdir === null || !is_dir($extdir)) { + echo "; WARNING: could not find source dir for extension $extname -> $extdir ($ext)\n"; + } + + $exp = file_exists($extdir . 'EXPERIMENTAL'); + if (file_exists($extdir . 'CREDITS')) { + list($title, $authors, $description) = file($extdir . 'CREDITS'); + $title = trim($title); + $authors = trim($authors); + $description = trim($description); + + if (strlen($title) == 0) + $title = $ext; + + } else { + $title = $ext; + $authors = "Unknown, or uncredited"; + $description = ""; + } + + /* build list of support files. + * in theory, only needed for the srvlt sapi, but useful to keep this + * generic */ + $filepat = preg_replace('/\.[^\.]+$/', '.*', $extname); + + if ($groupname == 'EXT') { + } + + $sections['ext_' . $ext] = array( + 'group' => ($exp ? 'X' : '') . $groupname, + 'label' => $title, + 'description' => $title . ".\$\\nAuthors: $authors", + 'files' => array( + "\$INSTDIR\\" . $instdir => array( + $filepat + ), + ), + 'extras' => $groupname == 'EXT' ? "Push \"extension=" . basename($extname) . "\"\nCall AddIniSetting\n\n" : "" + ); + + } + + +} + +add_sections('extensions\\*.dll', 'EXT', $extension_abbreviations, $sections, array('ext'), 'extensions'); +add_sections('sapi\\*.dll', 'SAPI', $sapi_abbreviations, $sections, array('sapi'), 'sapi'); + + + + + +$SECTIONS = ""; +$sections_stage1 = array(); + +/* list of files to uninstall */ +$uninstall = array(); +$rmdirs = array(); +/* description texts */ +$descriptions = array(); + +$dirs_no_delete = array("\$SYSDIR", "\$INSTDIR"); + +foreach ($sections as $sectionid => $sectiondata) { + $descriptions[] = "\t!insertmacro MUI_DESCRIPTION_TEXT \${Sec$sectionid} \"" . $sectiondata['description'] . "\""; + + if (isset($sectiondata['group'])) { + $sub = "Sub"; + $group = $sectiondata['group']; + } else { + $sub = ""; + $group = '_top_'; + } + + $body = "Section \"" . $sectiondata['label'] . "\" Sec$sectionid\n"; + + foreach ($sectiondata['files'] as $outputdir => $filelist) { + $body .= "\tSetOutPath \"$outputdir\"\n"; + foreach ($filelist as $pattern) { + $files = xglob($pattern); + foreach ($files as $filename) { + $uninstall[] = "\tDelete \"$outputdir\\" . basename($filename) . "\""; + + $body .= "\tFile \"$filename\"\n"; + } + } + if (!in_array($outputdir, $dirs_no_delete) && !isset($rmdirs[$outputdir])) { + $rmdirs[$outputdir] = "\tRMDir \"$outputdir\""; + } + } + + $body .= $sectiondata['extras']; + + $body .= "\nSectionEnd\n"; + + $sections_stage1[$group] .= $body . "\n\n"; +} + +foreach ($sections_stage1 as $group => $data) +{ + if ($group == '_top_') { + $SECTIONS .= $data . "\n"; + } else { + $descriptions[] = "\t!insertmacro MUI_DESCRIPTION_TEXT \${SecGroup$group} \"" . $groups[$group][1] . "\""; + $SECTIONS .= "SubSection \"" . $groups[$group][0] . "\" SecGroup$group\n$data\nSubSectionEnd\n\n"; + } +} + +/* Now build descriptions */ +$DESCRIPTIONS = implode("\n", $descriptions) . "\n"; + +/* And the uninstallation section */ +$UNINSTALL = implode("\n", $uninstall) . "\n" . implode("\n", $rmdirs) . "\n"; + +?> + +!define MUI_PRODUCT "PHP - Hypertext Preprocessor" +!define MUI_VERSION "<?= PHPVERSION ?>" +; The second UI has a wider area for the component names +!define MUI_UI "${NSISDIR}\Contrib\UIs\modern3.exe" + +!include "${NSISDIR}\Contrib\Modern UI\System.nsh" + +;-------------------------------- +;Configuration + +!define MUI_WELCOMEPAGE +!define MUI_LICENSEPAGE +!define MUI_COMPONENTSPAGE +!define MUI_DIRECTORYPAGE + +!define MUI_FINISHPAGE +;!define MUI_FINISHPAGE_RUN "$INSTDIR\modern.exe" + +!define MUI_ABORTWARNING + +!define MUI_UNINSTALLER +!define MUI_UNCONFIRMPAGE + +;Language +!insertmacro MUI_LANGUAGE "English" + +;General +OutFile "InstallPHP<?= PHPVERSION ?>.exe" + +SetCompressor bzip2 + +;License page +LicenseData "license.txt" + +;Folder-selection page +InstallDir "C:\PHP-<?= PHPVERSION ?>" + +;Things that need to be extracted on startup (keep these lines before any File command!) +;Only useful for BZIP2 compression +;Use ReserveFile for your own Install Options ini files too! +!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS +!insertmacro MUI_RESERVEFILE_SPECIALINI +!insertmacro MUI_RESERVEFILE_SPECIALBITMAP + +;-------------------------------- +;Modern UI System + +!insertmacro MUI_SYSTEM + + +;-------------------------------- +;Installer Sections + +Function AddIniSetting + Pop $R0 + + FileOpen $R2 "$INSTDIR\.ini-add" "a" + FileSeek $R2 0 END + FileWrite $R2 "$R0$\n" + FileClose $R2 + +FunctionEnd + +Function CopyPHPIni + ; Ensure that we have a working php.ini to reflect the + ; installation options. + ; Extensions will call a function to activate their entry + ; in the ini file as they are installed. + + ifFileExists "<?= $SYSDIR ?>\php.ini" "" +2 + Rename "<?= $SYSDIR ?>\php.ini" "<?= $SYSDIR ?>\php.ini.old" + CopyFiles "$INSTDIR\php.ini-dist" "<?= $SYSDIR ?>\php.ini" + +; For editing the ini, put the cli and the php4ts.dll in the same dir +; these files will be deleted during post-installation + CopyFiles "<?= $SYSDIR ?>\php4ts.dll" "$INSTDIR\php4ts.dll" + CopyFiles "$INSTDIR\cli\php.exe" "$INSTDIR\strap-php.exe" + File "<?= dirname(__FILE__) ?>\setini.php" + +; Set the extension_dir setting in the php.ini + Push "extension_dir=$\"$INSTDIR\extensions$\"" + Call AddIniSetting + +FunctionEnd + +; Generated Section Info +<?= $SECTIONS ?> +; --------- + +; Perform final actions after everything has been installed +Section -post + ; Merge ini settings + nsExec::ExecToLog "$\"$INSTDIR\strap-php.exe$\" $\"$INSTDIR\setini.php$\" $\"<?= $SYSDIR ?>\php.ini$\" $\"$INSTDIR\.ini-add$\"" + + Delete "$INSTDIR\.ini-add" ; Created by the AddIniSetting function + Delete "$INSTDIR\setini.php" + Delete "$INSTDIR\strap-php.exe" + Delete "$INSTDIR\php4ts.dll" + + ; Add to Add/Remove programs list + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PHP-<?= PHPVERSION ?>" "UninstallString" "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PHP-<?= PHPVERSION ?>" "DisplayName" "PHP-<?= PHPVERSION ?> (Uninstall only)" + + +SectionEnd + +;-------------------------------- +;Descriptions + +!insertmacro MUI_FUNCTIONS_DESCRIPTION_BEGIN +<?= $DESCRIPTIONS ?> +!insertmacro MUI_FUNCTIONS_DESCRIPTION_END + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" +<?= $UNINSTALL ?> + + Delete "$INSTDIR\Uninstall.exe" + RMDir "$INSTDIR" + ; Remove from Add/Remove programs list + DeleteRegKey /ifempty HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\PHP-<?= PHPVERSION ?>" + + !insertmacro MUI_UNFINISHHEADER + +SectionEnd +; vim:sw=4:ts=4: +; vim600:sw=4:ts=4:noet:fdm=marker diff --git a/win32/installer/setini.php b/win32/installer/setini.php new file mode 100644 index 0000000000..91d1b1a325 --- /dev/null +++ b/win32/installer/setini.php @@ -0,0 +1,64 @@ +<?php +/* $Id$ + * Wez Furlong <wez@thebrainroom.com> + * + * Set options in a php.ini file. + * This is a support script for the installer. + * + * $argv[1] is the path to the ini file + * $argv[2] is the path to the option file + */ + +$ini_name = $argv[1]; +$option_file = $argv[2]; + +$options = explode("\n", file_get_contents($option_file)); +$opts = array(); + +/* Parse the options */ +foreach ($options as $line) { + list($name, $value) = explode("=", $line); + + if ($name == "extension") { + $pat = "/^;?extension\s*=\s*" . $value . "/i"; + } else { + $pat = "/^;?$name\s*=\s*/i"; + } + + $opts[] = array('pat' => $pat, 'name' => $name, 'value' => $value); +} + +$new_name = $ini_name . "~"; +$dest = fopen($new_name, "w"); + +if (!$dest) { + die("Cannot create temporary file!"); +} + +$lines = file($ini_name); + +foreach ($lines as $line) { + + foreach ($opts as $k => $optdata) { + extract($optdata); + + if (preg_match($pat, $line)) { + echo "Found: $line\n"; + $line = "$name=$value\r\n"; + echo" New value: $line\n"; + + // No need to match again + unset($opts[$k]); + break; + } + } + + fwrite($dest, $line); +} + +fclose($dest); + +unlink($ini_name); +rename($new_name, $ini_name); + +?> |