|
| Tias Guns |
+----------------------------------------------------------------------+
* @category pear
* @package PEAR_Frontend_Web
* @author Christian Dickmann
* @author Tias Guns
* @copyright 1997-2007 The PHP Group
* @license http://www.php.net/license/2_02.txt PHP License 2.02
* @version CVS: $Id$
* @link http://pear.php.net/package/PEAR_Frontend_Web
* @since File available since Release 0.1
*/
/**
* base class
*/
require_once "PEAR/Frontend.php";
require_once "PEAR/Remote.php";
require_once "HTML/Template/IT.php";
/**
* PEAR_Frontend_Web is a HTML based Webfrontend for the PEAR Installer
*
* The Webfrontend provides basic functionality of the Installer, such as
* a package list grouped by categories, a search mask, the possibility
* to install/upgrade/uninstall packages and some minor things.
* PEAR_Frontend_Web makes use of the PEAR::HTML_IT Template engine which
* provides the possibillity to skin the Installer.
*
* @category pear
* @package PEAR_Frontend_Web
* @author Christian Dickmann
* @author Tias Guns
* @copyright 1997-2007 The PHP Group
* @license http://www.php.net/license/2_02.txt PHP License 2.02
* @version CVS: $Id$
* @link http://pear.php.net/package/PEAR_Frontend_Web
* @since File available since Release 0.1
*/
class PEAR_Frontend_Web extends PEAR_Frontend
{
// {{{ properties
/**
* What type of user interface this frontend is for.
* @var string
* @access public
*/
var $type = 'Web';
/**
* Container, where values can be saved temporary
* @var array
*/
var $_data = array();
/**
* Used to save output, to display it later
*/
var $_savedOutput = array();
/**
* The config object
*/
var $config;
/**
* List of packages that will not be deletable thourgh the webinterface
*/
var $_no_delete_pkgs = array(
'pear.php.net/Archive_Tar',
'pear.php.net/Console_Getopt',
'pear.php.net/HTML_Template_IT',
'pear.php.net/PEAR',
'pear.php.net/PEAR_Frontend_Web',
'pear.php.net/Structures_Graph',
);
/**
* List of channels that will not be deletable thourgh the webinterface
*/
var $_no_delete_chans = array(
'pear.php.net',
'__uri',
);
/**
* How many categories to display on one 'list-all' page
*/
var $_paging_cats = 4;
/**
* Flag to determine whether to treat all output as information from a post-install script
* @var bool
*/
var $_installScript = false;
// }}}
// {{{ constructor
function PEAR_Frontend_Web()
{
parent::PEAR();
$this->config = &$GLOBALS['_PEAR_Frontend_Web_config'];
}
function setConfig(&$config)
{
$this->config = &$config;
}
// }}}
// {{{ _initTemplate()
/**
* Initialize a TemplateObject
*
* @param string $file filename of the template file
*
* @return object Object of HTML/IT - Template - Class
*/
function _initTemplate($file)
{
// Errors here can not be displayed using the UI
PEAR::staticPushErrorHandling(PEAR_ERROR_DIE);
$tpl_dir = $this->config->get('data_dir').DIRECTORY_SEPARATOR.'PEAR_Frontend_Web'.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'templates';
if (!file_exists($tpl_dir) || !is_readable($tpl_dir)) {
PEAR::raiseError('Error: the template directory ('.$tpl_dir.') is not a directory, or not readable. Make sure the \'data_dir\' of your config file ('.$this->config->get('data_dir').') points to the correct location !');
}
$tpl = new HTML_Template_IT($tpl_dir);
$tpl->loadTemplateFile($file);
$tpl->setVariable("InstallerURL", $_SERVER["PHP_SELF"]);
PEAR::staticPopErrorHandling(); // reset error handling
return $tpl;
}
// }}}
// {{{ displayError()
/**
* Display an error page
*
* @param mixed $eobj PEAR_Error object or string containing the error message
* @param string $title (optional) title of the page
* @param string $img (optional) iconhandle for this page
* @param boolean $popup (optional) popuperror or normal?
*
* @access public
*
* @return null does not return anything, but exit the script
*/
function displayError($eobj, $title = 'Error', $img = 'error', $popup = false)
{
$msg = '';
if (PEAR::isError($eobj)) {
$msg .= trim($eobj->getMessage());
} else {
$msg .= trim($eobj);
}
$msg = nl2br($msg."\n");
$tplfile = ($popup ? "error.popup.tpl.html" : "error.tpl.html");
$tpl = $this->_initTemplate($tplfile);
$tpl->setVariable("Error", $msg);
$command_map = array(
"install" => "list",
"uninstall" => "list",
"upgrade" => "list",
);
if (isset($_GET['command'])) {
if (isset($command_map[$_GET['command']])) {
$_GET['command'] = $command_map[$_GET['command']];
}
$tpl->setVariable("param", '?command='.$_GET['command']);
}
$tpl->show();
exit;
}
// }}}
// {{{ displayFatalError()
/**
* Alias for PEAR_Frontend_Web::displayError()
*
* @see PEAR_Frontend_Web::displayError()
*/
function displayFatalError($eobj, $title = 'Error', $img = 'error')
{
$this->displayError($eobj, $title, $img);
}
// }}}
// {{{ _outputListChannels()
/**
* Output the list of channels
*/
function _outputListChannels($data)
{
$tpl = $this->_initTemplate('channel.list.tpl.html');
$tpl->setVariable("Caption", $data['caption']);
if (!isset($data['data'])) {
$data['data'] = array();
}
$reg = &$this->config->getRegistry();
foreach($data['data'] as $row) {
list($channel, $summary) = $row;
$url = sprintf('%s?command=channel-info&chan=%s',
$_SERVER['PHP_SELF'], urlencode($channel));
$channel_info = sprintf('%s', $url, $channel);
// detect whether any packages from this channel are installed
$anyinstalled = $reg->listPackages($channel);
$id = 'id="'.$channel.'_href"';
if (in_array($channel, $this->_no_delete_chans) || (is_array($anyinstalled) && count($anyinstalled))) {
// dont delete
$del = ' ';
} else {
$img = '';
$url = sprintf('%s?command=channel-delete&chan=%s',
$_SERVER["PHP_SELF"], urlencode($channel));
$del = sprintf('%s',
$url, $channel, $id, $img);
}
$tpl->setCurrentBlock("Row");
$tpl->setVariable("ImgPackage", $_SERVER["PHP_SELF"].'?img=package');
$tpl->setVariable("UpdateChannelsURL", $_SERVER['PHP_SELF']);
$tpl->setVariable("Delete", $del);
$tpl->setVariable("Channel", $channel_info);
$tpl->setVariable("Summary", nl2br($summary));
$tpl->parseCurrentBlock();
}
$tpl->show();
return true;
}
// }}}
// {{{ _outputListAll()
/**
* Output a list of packages, grouped by categories. Uses Paging
*
* @param array $data array containing all data to display the list
* @param boolean $paging (optional) use Paging or not
*
* @return boolean true (yep. i am an optimist)
*
* DEPRECATED BY list-categories
*/
function _outputListAll($data, $paging=true)
{
if (!isset($data['data'])) {
return true;
}
$tpl = $this->_initTemplate('package.list.tpl.html');
$tpl->setVariable('Caption', $data['caption']);
if (!is_array($data['data'])) {
$tpl->show();
print('
'.$data['data'].'
');
return true;
}
$command = isset($_GET['command']) ? $_GET['command']:'list-all';
$mode = isset($_GET['mode'])?$_GET['mode']:'';
$links = array('back' => '',
'next' => '',
'current' => '&mode='.$mode,
);
if ($paging) {
// Generate Linkinformation to redirect to _this_ page after performing an action
$link_str = '%s';
$pageId = isset($_GET['from']) ? $_GET['from'] : 0;
$paging_data = $this->__getData($pageId, $this->_paging_cats, count($data['data']), false);
$data['data'] = array_slice($data['data'], $pageId, $this->_paging_cats);
$from = $paging_data['from'];
$to = $paging_data['to'];
if ($paging_data['from']>1) {
$links['back'] = sprintf($link_str, $command, $paging_data['prev'], $mode, '<<');
}
if ( $paging_data['next']) {
$links['next'] = sprintf($link_str, $command, $paging_data['next'], $mode, '>>');
}
$links['current'] = '&from=' . $paging_data['from'];
$blocks = array('Paging_pre', 'Paging_post');
foreach ($blocks as $block) {
$tpl->setCurrentBlock($block);
$tpl->setVariable('Prev', $links['back']);
$tpl->setVariable('Next', $links['next']);
$tpl->setVariable('PagerFrom', $from);
$tpl->setVariable('PagerTo', $to);
$tpl->setVariable('PagerCount', $paging_data['numrows']);
$tpl->parseCurrentBlock();
}
}
$reg = &$this->config->getRegistry();
foreach($data['data'] as $category => $packages) {
foreach($packages as $row) {
list($pkgChannel, $pkgName, $pkgVersionLatest, $pkgVersionInstalled, $pkgSummary) = $row;
$parsed = $reg->parsePackageName($pkgName, $pkgChannel);
$pkgChannel = $parsed['channel'];
$pkgName = $parsed['package'];
$pkgFull = sprintf('%s/%s-%s',
$pkgChannel,
$pkgName,
substr($pkgVersionLatest, 0, strpos($pkgVersionLatest, ' ')));
$tpl->setCurrentBlock("Row");
$tpl->setVariable("ImgPackage", $_SERVER["PHP_SELF"].'?img=package');
$images = array(
'install' => '',
'uninstall' => '',
'upgrade' => '',
'info' => '',
'infoExt' => '',
);
$urls = array(
'install' => sprintf('%s?command=install&pkg=%s%s',
$_SERVER["PHP_SELF"], $pkgFull, $links['current']),
'uninstall' => sprintf('%s?command=uninstall&pkg=%s%s',
$_SERVER["PHP_SELF"], $pkgFull, $links['current']),
'upgrade' => sprintf('%s?command=upgrade&pkg=%s%s',
$_SERVER["PHP_SELF"], $pkgFull, $links['current']),
'info' => sprintf('%s?command=info&pkg=%s',
$_SERVER["PHP_SELF"], $pkgFull),
'remote-info' => sprintf('%s?command=remote-info&pkg=%s',
$_SERVER["PHP_SELF"], $pkgFull),
'infoExt' => 'http://' . $this->config->get('preferred_mirror')
. '/package/' . $row[0],
);
$compare = version_compare($pkgVersionLatest, $pkgVersionInstalled);
$id = 'id="'.$pkgName.'_href"';
if (!$pkgVersionInstalled || $pkgVersionInstalled == "- no -") {
$inst = sprintf('%s',
$urls['install'], $pkgName, $id, $images['install']);
$del = '';
$info = sprintf('%s', $urls['remote-info'], $images['info']);
} else if ($compare == 1) {
$inst = sprintf('%s',
$urls['upgrade'], $pkgName, $id, $images['upgrade']);
$del = sprintf('%s',
$urls['uninstall'], $pkgName, $id, $images['uninstall']);
$info = sprintf('%s', $urls['info'], $images['info']);
} else {
$inst = '';
$del = sprintf('%s',
$urls['uninstall'], $pkgName, $id, $images['uninstall']);
$info = sprintf('%s', $urls['info'], $images['info']);
}
$infoExt = sprintf('%s', $urls['infoExt'], $images['infoExt']);
if (in_array($pkgChannel.'/'.$pkgName, $this->_no_delete_pkgs)) {
$del = '';
}
$tpl->setVariable("Latest", $pkgVersionLatest);
$tpl->setVariable("Installed", $pkgVersionInstalled);
$tpl->setVariable("Install", $inst);
$tpl->setVariable("Delete", $del);
$tpl->setVariable("Info", $info);
$tpl->setVariable("InfoExt", $infoExt);
$tpl->setVariable("Package", $pkgName);
$tpl->setVariable("Channel", $pkgChannel);
$tpl->setVariable("Summary", nl2br($pkgSummary));
$tpl->parseCurrentBlock();
}
$tpl->setCurrentBlock("Category");
$tpl->setVariable("categoryName", $category);
$tpl->setVariable("ImgCategory", $_SERVER["PHP_SELF"].'?img=category');
$tpl->parseCurrentBlock();
}
$tpl->show();
return true;
}
// }}}
// {{{ _outputListFiles()
/**
* Output a list of files of a packagename
*
* @param array $data array containing all files of a package
*
* @return boolean true (yep. i am an optimist)
*/
function _outputListFiles($data)
{
sort($data['data']);
return $this->_outputGenericTableVertical($data['caption'], $data['data']);
}
// }}}
// {{{ _outputListDocs()
/**
* Output a list of documentation files of a packagename
*
* @param array $data array containing all documentation files of a package
*
* @return boolean true (yep. i am an optimist)
*/
function _outputListDocs($data)
{
$tpl = $this->_initTemplate('caption.tpl.html');
$tpl->setVariable('Caption', $data['caption']);
$tpl->show();
if (is_array($data['data'])) {
print $this->_getListDocsDiv($data['channel'].'/'.$data['package'], $data['data']);
} else {
print $data['data'];
}
return true;
}
/**
* Get list of the docs of a package in a HTML div
*
* @param string $pkg full package name (channel/package)
* @param array $files array of all files and there location
* @return string HTML
*/
function _getListDocsDiv($pkg, $files) {
$out = '
';
foreach($files as $name => $location) {
$out .= sprintf('
';
$styled = true;
}
// color:warning {Could not download from "http://pear.php.net/get/HTML_QuickForm-3.2.9.tgz", cannot download "pear/html_quickform" (could not open /home/tias/WASP/pear/cvs//temp/download/HTML_QuickForm-3.2.9.tgz for writing)}
$pattern = 'Could not download from';
if (substr($text, 0, strlen($pattern)) == $pattern) {
// color
$text = '