home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 April / PCWorld_2005-04_cd.bin / akce / web / phptriad / phptriad2-2-1.exe / php / pear / PEAR / WebInstaller.php < prev   
PHP Script  |  2001-11-14  |  20KB  |  632 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4; */
  3. // +---------------------------------------------------------------------+
  4. // |  PHP version 4.0                                                    |
  5. // +---------------------------------------------------------------------+
  6. // |  Copyright (c) 1997-2001 The PHP Group                              |
  7. // +---------------------------------------------------------------------+
  8. // |  This source file is subject to version 2.0 of the PHP license,     |
  9. // |  that is bundled with this package in the file LICENSE, and is      |
  10. // |  available through the world-wide-web at                            |
  11. // |  http://www.php.net/license/2_02.txt.                               |
  12. // |  If you did not receive a copy of the PHP license and are unable to |
  13. // |  obtain it through the world-wide-web, please send a note to        |
  14. // |  license@php.net so we can mail you a copy immediately.             |
  15. // +---------------------------------------------------------------------+
  16. // |  Authors:  Christian Stocker <chregu@phant.ch>                      |
  17. // +---------------------------------------------------------------------+
  18.  
  19.  
  20. /* This class should simplify the task of installing PEAR-packages, if you
  21.  *  don't have a cgi-php binary on your system or you don't have access to
  22.  *  the system-wide pear directory.
  23.  *
  24.  *  To use it, make the following php-script:
  25.  *
  26.  *  <?php
  27.  *      require("PEAR/WebInstaller.php");
  28.  *      $installer = new PEAR_WebInstaller("/path/to/your/install/dir","http://php.chregu.tv/pear/");
  29.  *      $installer->start();
  30.  *  ?>
  31.  *
  32.  *  and put PEAR/WebInstaller.php (this script) anywhere in your include_path.
  33.  *
  34.  *  (http://php.chregu.tv/pear/ is just for testing purposes until this
  35.  *    system runs on pear.php.net, but feel free to use it till then)
  36.  *
  37.  *  Both parameters are optional. If the install dir is ommitted, the
  38.  *  installer takes either the system wide pear-directory (mostly
  39.  *  /usr/local/lib/php on unix), if it's writeable, or else the directory
  40.  *  the script is started. Be advised, that the directory, where the
  41.  *  PEAR::Packages will be installed, has to be writeable for the web-server.
  42.  *
  43.  *  The second parameter points to the server/directory where all the
  44.  *  packages and especially Packages.xml is located. If not given, the
  45.  *  standard PEAR-Repository is taken (http://pear.php.net/whatever..)
  46.  *
  47.  *  After installation, just add the install-dir to your include_path and
  48.  *  the packages should work.
  49.  *
  50.  *  If you are System Adminisitrator and want the installed packages to be
  51.  *  made available for everyone, just copy the files to the systemwide
  52.  *  pear-dir after installation on the commandline. Or also add the
  53.  *  install-dir to the systemwide include_path (and maybe don't forget to
  54.  *  take the writeable off the directory..)
  55.  *
  56.  *  TODO:
  57.  *      - More Error Detection
  58.  *      - Grouping of Packages
  59.  *      - Show installed Packages (from /var/lib/php/packages.lst?)
  60.  *      - Add possibility to install a package (.tgz) from the local file
  61.  *           system without a global Packages.xml (useful if no cgi-php
  62.  *           around and you need this package you downloaded installed :) )
  63.  *      - Search Function (maybe needed if we have hundreds of packages)
  64.  *      - Only download Packages.xml, if it actually changed.
  65.  *
  66.  *  This Code is highly experimental.
  67.  */
  68.  
  69. require_once "PEAR.php";
  70.  
  71. class PEAR_WebInstaller extends PEAR
  72. {
  73.     // {{{ properties
  74.  
  75.     /** stack of elements, gives some sort of XML context */
  76.     var $element_stack;
  77.  
  78.     /** name of currently parsed XML element */
  79.     var $current_element;
  80.  
  81.     /** array of attributes of the currently parsed XML element */
  82.     var $current_attributes = array();
  83.  
  84.     /** assoc with information about a package */
  85.     var $pkginfo = array();
  86.  
  87.     /** assoc with information about all packages */
  88.     var $AllPackages;
  89.  
  90.     /** URL to the server containing all packages in tgz-Format and the Package.xml */
  91.     var $remotedir = "http://php.chregu.tv/pear/";
  92.  
  93.     /*  Directory where the to be installed files should be put
  94.         per default PEAR_INSTALL_DIR (/usr/local/lib/php) if it's writeable for the webserver,
  95.         else current directory, or user defined directory (provided as first parameter in constructor)
  96.         The Directory hast to be writeable for the php-module (webserver)
  97.     */
  98.     var $installdir;
  99.  
  100.     /** how many seconds we should cache Packages.xml */
  101.     var $cachetime = 3600;
  102.  
  103.     var $printlogger = True;
  104.     // }}}
  105.  
  106.     // {{{ constructor
  107.  
  108.     function PEAR_Webinstaller($installdir = Null,$remotedir = Null)
  109.     {
  110.         $this->PEAR();
  111.         if ($installdir)
  112.         {
  113.             $this->installdir = $installdir;
  114.         }
  115.         else
  116.         {
  117.             if (is_writeable(PEAR_INSTALL_DIR))
  118.             {
  119.                 $this->installdir = PEAR_INSTALL_DIR;
  120.             }
  121.             else
  122.             {
  123.                 $this->installdir = getcwd();
  124.             }
  125.         }
  126.  
  127.         if ($remotedir)
  128.         {
  129.             $this->remotedir = $remotedir;
  130.         }
  131.     }
  132.  
  133.     // }}}
  134.     // {{{ start()
  135.  
  136.     function start() {
  137.         global $HTTP_POST_VARS,$HTTP_GET_VARS;
  138.  
  139.         //print header
  140.         $this->header();
  141.  
  142.         $this->loggerStart();
  143.  
  144.         //if some checkboxes for installation were selected, install.
  145.         if ($HTTP_GET_VARS["help"]) {
  146.  
  147.             $this->help($HTTP_GET_VARS["help"]);
  148.         }
  149.  
  150.         elseif ($HTTP_POST_VARS["InstPack"]) {
  151.             $this->installPackages(array_keys($HTTP_POST_VARS["InstPack"]));
  152.         }
  153.  
  154.         //else print all modules
  155.         else {
  156.             $this->printTable();
  157.         }
  158.         $this->footer();
  159.     }
  160.     // }}}
  161.     // {{{ installPackages()
  162.  
  163.     /* installs the Packages and prints if successfull or not */
  164.  
  165.     function installPackages($packages)
  166.     {
  167.         require_once "PEAR/Installer.php";
  168.         $installer =& new PEAR_Installer();
  169.         $installer->phpdir = $this->installdir;
  170.         $this->loggerEnd();
  171.         print "<TABLE CELLSPACING=0 BORDER=0 CELLPADDING=1>";
  172.         print "<TR><TD BGCOLOR=\"#000000\">\n";
  173.         print "<TABLE CELLSPACING=1 BORDER=0 CELLPADDING=3 width=100%>\n";
  174.         print " <TR BGCOLOR=\"#e0e0e0\">\n";
  175.         print "  <TH>Package</TH>\n";
  176.         print "  <TH>Status</TH>\n";
  177.  
  178.         foreach ($packages as $package)
  179.         {
  180.  
  181.  
  182.             if (++$i % 2) {
  183.                 $bg1 = "#ffffff";
  184.                 $bg2 = "#f0f0f0";
  185.             }
  186.             else {
  187.                 $bg1 = "#f0f0f0";
  188.                 $bg2 = "#e0e0e0";
  189.             }
  190.             print " <TR>\n";
  191.  
  192.             print "<TD BGCOLOR=\"$bg1\">";
  193.             print $package;
  194.             print "</TD>\n";
  195.  
  196.  
  197.             /*
  198.             print "<TD BGCOLOR=\"$bg2\">";
  199.             print "Installing ...";
  200.             print "</td>";
  201.             print " <TR>\n";
  202.             print "<TD BGCOLOR=\"$bg1\">";
  203.             print " ";
  204.             print "</TD>\n";
  205.             */
  206.             print "<TD BGCOLOR=\"$bg2\">";
  207.             if (PEAR::isError($installer->Install($this->remotedir."/".$package.".tgz"))) {
  208.                 print "\ninstall failed\n";
  209.             }
  210.             else {
  211.  
  212.                 print "install ok\n";
  213.             }
  214.             print "</td></tr>\n";
  215.         }
  216.         print "</td></tr>";
  217.         print "</table>";
  218.         print "<TABLE CELLSPACING=1 BORDER=0 CELLPADDING=3 width=\"100%\">\n";
  219.         print " <TR BGCOLOR=\"$bg1\">\n";
  220.         print "<th colspan=\"2\">";
  221.         print "<a href=\"$GLOBALS[PHP_SELF]\">Back to the Packages</a>\n";
  222.         print "</th></tr></table>";
  223.         print"</td></tr></table>";
  224.     }
  225.  
  226.     // }}}
  227.     // {{{ printTable()
  228.     /*  Prints a table with all modules available on the server-directory */
  229.  
  230.     function printTable()
  231.     {
  232.     global $PHP_SELF;
  233.         $Packages = $this->getPackages();
  234.         if (PEAR::IsError($Packages))
  235.         {
  236.             if ($this->printlogger) {
  237.                 $this->logger($Packages->message);
  238.             }
  239.             else
  240.             {
  241.                 print $Packages->message;
  242.             }
  243.             return $Packages;
  244.         }
  245.         $this->loggerEnd();
  246.         print "<FORM action=\"$GLOBALS[PHP_SELF]\" method=\"post\">\n";
  247.         print "<TABLE CELLSPACING=0 BORDER=0 CELLPADDING=1>";
  248.         print "<TR><TD BGCOLOR=\"#000000\">\n";
  249.         print "<TABLE CELLSPACING=1 BORDER=0 CELLPADDING=3 width=\"100%\">\n";
  250.         print "<tr bgcolor=\"f0f0f0\">";
  251.         print "<td COLSPAN=\"6\" ><input type=\"submit\" value=\"Install\"></td>";
  252.         print "</tr>";
  253.  
  254.         print " <TR BGCOLOR=\"#e0e0e0\" >\n";
  255.         print "  <TH>Inst.</TH>\n";
  256.         print "  <TH>Package</TH>\n";
  257.         print "  <TH>Summary</TH>\n";
  258.         print "  <TH>Version</TH>\n";
  259.         print "  <TH>Release date</TH>\n";
  260.         print "  <TH>Release notes</TH>\n";
  261.         print " </TR>\n";
  262.         $i = 0;
  263.  
  264.         ksort($Packages);
  265.         foreach ( $Packages as $package) {
  266.  
  267.             if (++$i % 2) {
  268.                 $bg1 = "#ffffff";
  269.                 $bg2 = "#f0f0f0";
  270.             }
  271.             else {
  272.                 $bg1 = "#f0f0f0";
  273.                 $bg2 = "#e0e0e0";
  274.             }
  275.  
  276.  
  277.             print "<TR>\n";
  278.  
  279.             print "<TD align=\"middle\" BGCOLOR=\"$bg2\">";
  280.             print "<input type=\"checkbox\" name=\"InstPack[".$package["name"]."-".$package["version"]."]\">\n";
  281.             print "</TD>\n";
  282.  
  283.             print "  <TD BGCOLOR=\"$bg1\">";
  284.             print $this->printCell ($package["name"],"http://pear.php.net/pkginfo.php?package=$package[name]");
  285.             print "</TD>\n";
  286.  
  287.             print "<TD BGCOLOR=\"$bg2\">";
  288.             $this->printCell ($package["summary"]);
  289.             print "</TD>\n";
  290.  
  291.             print "<TD BGCOLOR=\"$bg2\">";
  292.             $this->printCell ($package["version"],$this->remotedir."/".$package["name"]."-".$package["version"].".tgz");
  293.             print "</TD>\n";
  294.  
  295.             print "<TD BGCOLOR=\"$bg2\">";
  296.             $this->printCell ($package["release_date"]);
  297.             print "</TD>\n";
  298.  
  299.             print "<TD BGCOLOR=\"$bg2\">";
  300.             $this->printCell (nl2br($package["release_notes"]));
  301.             print "</TD>\n";
  302.             print " </TR>\n";
  303.  
  304.         }
  305.         print "<tr bgcolor=\"$bg1\">";
  306.         print "<td COLSPAN=\"6\" ><input type=\"submit\" value=\"Install\"></td>";
  307.         print "</tr>";
  308.         print "</TABLE> \n";
  309.  
  310.  
  311.         print "<TABLE CELLSPACING=1 BORDER=0 CELLPADDING=3 width=\"100%\">\n";
  312.         print " <TR BGCOLOR=\"#e0e0e0\">\n";
  313.  
  314.         print "<th align=left width=\"10%\" nowrap>\n";
  315.         print "Install Directory: </th><td>$this->installdir";
  316.         if (!is_writable($this->installdir))
  317.         {
  318.             print " <font color=\"red\">(Directory is NOT writeable!)</font>";
  319.         }
  320.  
  321.         print "</td></tr>\n";
  322.  
  323.         print " <TR BGCOLOR=\"#f0f0f0\">\n";
  324.         print "<th align=left width=\"10%\" nowrap>\n";
  325.         print "PEAR Repository: </th><td>$this->remotedir</td></tr>\n";
  326.  
  327.         print " <TR BGCOLOR=\"#e0e0e0\">\n";
  328.         print "<th align=left width=\"10%\" nowrap>\n";
  329.         print "Caching Time: </th><td>$this->cachetime seconds</td></tr>\n";
  330.  
  331.         print "</table>\n";
  332.         print "</tr></td></table></FORM>\n";
  333.         print "<a href=\"$PHP_SELF?help=1\">Help</A>\n";
  334.     }
  335.  
  336.     // }}}
  337.     // {{{ getPackages()
  338.  
  339.     /** gets the Packages.xml from the server and saves it on the local disc for caching (if possible)
  340.       * If the zlib-extension is compiled in, Packages.xml.gz is used instead.
  341.       */
  342.  
  343.     function getPackages ($TryGz = True)
  344.     {
  345.  
  346.         // if we can write to the installdir, cache the Packages.xml there
  347.  
  348.         $PackageFile = "Packages.xml";
  349.  
  350.         // check if we have the zlib-extension compiled in
  351.         if ($TryGz && function_exists("gzfile")) { $useGz = True; $PackageFile .= ".gz";}
  352.  
  353.         // check if we can write the Package.xml file for caching
  354.  
  355.         if ( (file_exists($this->installdir."/$PackageFile") && is_writeable($this->installdir."/$PackageFile")) || !file_exists($this->installdir."/$PackageFile") && is_writeable($this->installdir) )
  356.         {
  357.             $time = filemtime($this->installdir."/$PackageFile");
  358.  
  359.             if ($time < (time () - $this->cachetime )) {
  360.                 $this->logger("$PackageFile too old. Get new one.");
  361.                 $fp =  @fopen($this->remotedir."/$PackageFile","r");
  362.                 if (!$fp) {
  363.                     if ($useGz)
  364.                     {
  365.                         $this->logger("$PackageFile could not be read. Try uncompressed one");
  366.                         return $this->getPackages(False);
  367.                     }
  368.                     else {
  369.                         $this->logger("$PackageFile could not be read.");
  370.                         return $this->raiseError("$PackageFile could not be read.");
  371.                     }
  372.                 }
  373.                 $fout = fopen($this->installdir."/$PackageFile","w");
  374.                 while ($data = fread($fp,8192)) {
  375.                     fwrite ($fout, $data);
  376.                 }
  377.                 fclose($fout);
  378.                 fclose($fp);
  379.                 $this->logger("Got $PackageFile");
  380.             }
  381.             else {
  382.                 $this->logger("Cached $PackageFile seems new enough");
  383.             }
  384.             $Packages = $this->infoFromDescriptionFile($this->installdir."/$PackageFile");
  385.         }
  386.         else
  387.         {
  388.             $this->logger("$PackageFile can not be cached, because Install-Dir or $PackageFile is not writeable. Get it each time from the server");
  389.             $Packages = $this->infoFromDescriptionFile($this->remotedir."/Packages.xml");
  390.         }
  391.         $this->logger("Got Packages");
  392.         return $Packages;
  393.     }
  394.  
  395.     // }}}
  396.     // {{{ printCell()
  397.  
  398.     function printCell($text,$link = Null)
  399.     {
  400.         if ($text)
  401.         {
  402.             if ($link) {
  403.                 print "<a href=\"$link\" style=\"color: #000000;\">";
  404.             }
  405.  
  406.             print "$text";
  407.  
  408.             if ($link) {
  409.                 print "</a>";
  410.             }
  411.  
  412.         }
  413.         else
  414.         {
  415.             print " ";
  416.         }
  417.     }
  418.  
  419.     // }}}
  420.     /* The following 4 functions are taken from PEAR/Common.php written by Stig Bakken
  421.         I had to adjust to use the Packages.xml format.
  422.     */
  423.     // {{{ _element_start()
  424.  
  425.  
  426.     function _element_start($xp, $name, $attribs)
  427.     {
  428.         array_push($this->element_stack, $name);
  429.         $this->current_element = $name;
  430.         $this->current_attributes = $attribs;
  431.     }
  432.  
  433.     // }}}
  434.     // {{{ _element_end()
  435.  
  436.     function _element_end($xp, $name)
  437.     {
  438.         array_pop($this->element_stack);
  439.         if ($name == "PACKAGE")
  440.         {
  441.             $this->AllPackages[$this->pkginfo["name"]] = $this->pkginfo;
  442.             $this->pkginfo = array();
  443.  
  444.         }
  445.  
  446.         $this->current_element = $this->element_stack[sizeof($this->element_stack)-1];
  447.     }
  448.  
  449.     // }}}
  450.     // {{{ _pkginfo_cdata()
  451.  
  452.     function _pkginfo_cdata($xp, $data)
  453.     {
  454.         $next = $this->element_stack[sizeof($this->element_stack)-1];
  455.         switch ($this->current_element) {
  456.         case "NAME":
  457.                 $this->pkginfo["name"] .= $data;
  458.             break;
  459.         case "SUMMARY":
  460.             $this->pkginfo["summary"] .= $data;
  461.             break;
  462.         case "USER":
  463.             $this->pkginfo["maintainer_handle"] .= $data;
  464.             break;
  465.         case "EMAIL":
  466.             $this->pkginfo["maintainer_email"] .= $data;
  467.             break;
  468.         case "VERSION":
  469.             $this->pkginfo["version"] .= $data;
  470.             break;
  471.         case "DATE":
  472.             $this->pkginfo["release_date"] .= $data;
  473.             break;
  474.         case "NOTES":
  475.             $this->pkginfo["release_notes"] .= $data;
  476.             break;
  477.         case "DIR":
  478.             if (!$this->installdir) {
  479.                 break;
  480.             }
  481.             $dir = trim($data);
  482.             // XXX add to file list
  483.             break;
  484.         case "FILE":
  485.             $role = strtolower($this->current_attributes["ROLE"]);
  486.             $file = trim($data);
  487.             // XXX add to file list
  488.             break;
  489.         }
  490.     }
  491.  
  492.     // }}}
  493.     // {{{ infoFromDescriptionFile()
  494.  
  495.     function infoFromDescriptionFile($descfile)
  496.     {
  497.         $fp = @fopen($descfile,"r");
  498.         if (!$fp) {
  499.             return  $this->raiseError("Unable to open $descfile in ".__FILE__.":".__LINE__);
  500.         }
  501.         $xp = @xml_parser_create();
  502.  
  503.         if (!$xp) {
  504.             return $this->raiseError("Unable to create XML parser.");
  505.         }
  506.  
  507.         xml_set_object($xp, $this);
  508.  
  509.         xml_set_element_handler($xp, "_element_start", "_element_end");
  510.         xml_set_character_data_handler($xp, "_pkginfo_cdata");
  511.         xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, true);
  512.  
  513.         $this->element_stack = array();
  514.         $this->pkginfo = array();
  515.         $this->current_element = false;
  516.         $this->destdir = '';
  517.  
  518.         // read the whole thing so we only get one cdata callback
  519.         // for each block of cdata
  520.  
  521.         if (preg_match("/\.gz$/",$descfile))
  522.         {
  523.             $data = implode("",gzfile($descfile));
  524.         }
  525.         else
  526.         {
  527.             $data = implode("",file($descfile));
  528.         }
  529.  
  530.         if (!@xml_parse($xp, $data, 1)) {
  531.             $msg = sprintf("XML error: %s at line %d",
  532.                            xml_error_string(xml_get_error_code($xp)),
  533.                            xml_get_current_line_number($xp));
  534.             xml_parser_free($xp);
  535.             return $this->raiseError($msg);
  536.         }
  537.  
  538.         xml_parser_free($xp);
  539.  
  540.         foreach ($this->pkginfo as $k => $v) {
  541.             $this->pkginfo[$k] = trim($v);
  542.         }
  543.  
  544.         return $this->AllPackages;
  545.     }
  546.  
  547.     // }}}
  548.     // {{{ header()
  549.  
  550.     function header ()
  551.     {
  552.         print "<html>
  553.         <head>
  554.         <title>PEAR::WebInstaller</title>\n";
  555.         if (file_exists("./style.css"))
  556.         {
  557.             print '<link rel="stylesheet" href="/style.css">';
  558.         }
  559.         print "</head>
  560.         <body bgcolor=\"#FFFFFF\">
  561.         <h3>PEAR::WebInstaller</h3>";
  562.  
  563.     }
  564.  
  565.     // }}}
  566.     // {{{ footer()
  567.  
  568.     function footer () {
  569.         print "</body></html>";
  570.     }
  571.  
  572.     // }}}
  573.  
  574.     function logger ($text) {
  575.  
  576.         if ($this->printlogger) {
  577.             if (++$this->logcol % 2) {
  578.                 $bg1 = "#ffffff";
  579.                 $bg2 = "#f0f0f0";
  580.             }
  581.             else {
  582.                 $bg1 = "#f0f0f0";
  583.                 $bg2 = "#e0e0e0";
  584.             }
  585.             print "<TR>\n";
  586.             print "<TD BGCOLOR=\"$bg1\">".date("h:m:i",time())."</td>";
  587.             print "<TD BGCOLOR=\"$bg2\">";
  588.             print "$text\n";
  589.             print "</TD>\n";
  590.             print "</tr>";
  591.         }
  592.     }
  593.     function loggerStart () {
  594.         if ($this->printlogger) {
  595.             print "<TABLE CELLSPACING=0 BORDER=0 CELLPADDING=1>";
  596.             print "<TR><TD BGCOLOR=\"#000000\">\n";
  597.             print "<TABLE CELLSPACING=1 BORDER=0 CELLPADDING=3 width=\"100%\">\n";
  598.         }
  599.     }
  600.  
  601.     function loggerEnd () {
  602.         if ($this->printlogger) {
  603.             print "</table></td></tr></table>";
  604.         }
  605.     }
  606.     function help ($Full = False) {
  607.         global $PHP_SELF;
  608.         $this->loggerEnd();
  609.         print "From the WebInstaller.php introduction: <p>";
  610.  
  611.         $file = file(__FILE__);
  612.         foreach($file as $line)
  613.         {
  614.             if ($Full != 2 && strstr($line,"require_once")){
  615.                 break;
  616.             }
  617.             $help .= $line;
  618.         }
  619.  
  620.         highlight_string($help);
  621.         print "<p>";
  622.         if ($Full != 2) {
  623.             print "<a href=\"$PHP_SELF?help=2\">See the full source</a><p>\n";
  624.         }
  625.  
  626.         print "<a href=\"$PHP_SELF\">Back to the packages overview</A>\n";
  627.     }
  628.  
  629. }
  630.  
  631. ?>
  632.