From ccbf1497dde4aef031a39544235a284641e694de Mon Sep 17 00:00:00 2001 From: Till Brehm Date: Tue, 4 Mar 2014 22:18:36 +0100 Subject: [PATCH] - Added templating library to installer. - Added function to detect the apache version to installer. - Added support for apache 2.4 to vhots templates for ispconfig vhost and apps vhost in installer. --- install/dist/lib/fedora.lib.php | 36 +- install/dist/lib/gentoo.lib.php | 30 + install/dist/lib/opensuse.lib.php | 39 +- install/install.php | 3 + install/lib/classes/tpl.inc.php | 1431 +++++++++++++++++++++ install/lib/classes/tpl_cache.inc.php | 193 +++ install/lib/classes/tpl_error.inc.php | 95 ++ install/lib/classes/tpl_ini.inc.php | 119 ++ install/lib/install.lib.php | 25 + install/lib/installer_base.lib.php | 57 +- install/tpl/apache_apps.vhost.master | 46 +- install/tpl/apache_ispconfig.conf.master | 76 +- install/tpl/apache_ispconfig.vhost.master | 30 +- install/update.php | 3 + interface/lib/config.inc.php | 1 + 15 files changed, 2087 insertions(+), 97 deletions(-) create mode 100644 install/lib/classes/tpl.inc.php create mode 100644 install/lib/classes/tpl_cache.inc.php create mode 100644 install/lib/classes/tpl_error.inc.php create mode 100644 install/lib/classes/tpl_ini.inc.php diff --git a/install/dist/lib/fedora.lib.php b/install/dist/lib/fedora.lib.php index a994b66ca1..f30a07fcb3 100644 --- a/install/dist/lib/fedora.lib.php +++ b/install/dist/lib/fedora.lib.php @@ -645,10 +645,12 @@ class installer_dist extends installer_base { $vhost_conf_dir = $conf['apache']['vhost_conf_dir']; $vhost_conf_enabled_dir = $conf['apache']['vhost_conf_enabled_dir']; - // copy('tpl/apache_ispconfig.conf.master',$vhost_conf_dir.'/ispconfig.conf'); - $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apache_ispconfig.conf.master', 'tpl/apache_ispconfig.conf.master'); + $tpl = new tpl('apache_ispconfig.conf.master'); + $tpl->setVar('apache_version',getapacheversion()); + $records = $this->db->queryAllRecords('SELECT * FROM '.$conf['mysql']['master_database'].'.server_ip WHERE server_id = '.$conf['server_id']." AND virtualhost = 'y'"); - + $ip_addresses = array(); + if(is_array($records) && count($records) > 0) { foreach($records as $rec) { if($rec['ip_type'] == 'IPv6') { @@ -661,15 +663,15 @@ class installer_dist extends installer_base { foreach($ports as $port) { $port = intval($port); if($port > 0 && $port < 65536 && $ip_address != '') { - $content .= 'NameVirtualHost '.$ip_address.":".$port."\n"; + $ip_addresses[] = array('ip_address' => $ip_address, 'port' => $port); } } } } } - $content .= "\n"; - wf($vhost_conf_dir.'/ispconfig.conf', $content); + wf($vhost_conf_dir.'/ispconfig.conf', $tpl->grab()); + unset($tpl); if(!@is_link($vhost_conf_enabled_dir."/000-ispconfig.conf")) { exec("ln -s ".$vhost_conf_dir."/ispconfig.conf ".$vhost_conf_enabled_dir."/000-ispconfig.conf"); @@ -1033,28 +1035,30 @@ class installer_dist extends installer_base { // Dont just copy over the virtualhost template but add some custom settings - $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apache_ispconfig.vhost.master', "tpl/apache_ispconfig.vhost.master"); - $content = str_replace('{vhost_port}', $conf['apache']['vhost_port'], $content); + $tpl = new tpl('apache_ispconfig.vhost.master'); + $tpl->setVar('vhost_port',$conf['apache']['vhost_port']); // comment out the listen directive if port is 80 or 443 if($conf['apache']['vhost_port'] == 80 or $conf['apache']['vhost_port'] == 443) { - $content = str_replace('{vhost_port_listen}', '#', $content); + $tpl->setVar('vhost_port_listen','#'); } else { - $content = str_replace('{vhost_port_listen}', '', $content); + $tpl->setVar('vhost_port_listen',''); } - if(is_file('/usr/local/ispconfig/interface/ssl/ispserver.crt') && is_file('/usr/local/ispconfig/interface/ssl/ispserver.key')) { - $content = str_replace('{ssl_comment}', '', $content); + if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key')) { + $tpl->setVar('ssl_comment',''); } else { - $content = str_replace('{ssl_comment}', '#', $content); + $tpl->setVar('ssl_comment','#'); } if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key') && is_file($install_dir.'/interface/ssl/ispserver.bundle')) { - $content = str_replace('{ssl_bundle_comment}', '', $content); + $tpl->setVar('ssl_bundle_comment',''); } else { - $content = str_replace('{ssl_bundle_comment}', '#', $content); + $tpl->setVar('ssl_bundle_comment','#'); } + + $tpl->setVar('apache_version',getapacheversion()); - wf("$vhost_conf_dir/ispconfig.vhost", $content); + wf($vhost_conf_dir.'/ispconfig.vhost', $tpl->grab()); //copy('tpl/apache_ispconfig.vhost.master', "$vhost_conf_dir/ispconfig.vhost"); //* and create the symlink diff --git a/install/dist/lib/gentoo.lib.php b/install/dist/lib/gentoo.lib.php index a47f0d063a..a2f3c3d741 100644 --- a/install/dist/lib/gentoo.lib.php +++ b/install/dist/lib/gentoo.lib.php @@ -495,6 +495,7 @@ class installer extends installer_base //* Copy the ISPConfig configuration include + /* $content = $this->get_template_file('apache_ispconfig.conf', true); $records = $this->db->queryAllRecords("SELECT * FROM server_ip WHERE server_id = ".$conf["server_id"]." AND virtualhost = 'y'"); @@ -507,6 +508,35 @@ class installer extends installer_base } $this->write_config_file($conf['apache']['vhost_conf_dir'].'/000-ispconfig.conf', $content); + */ + + $tpl = new tpl('apache_ispconfig.conf.master'); + $tpl->setVar('apache_version',getapacheversion()); + + $records = $this->db->queryAllRecords('SELECT * FROM '.$conf['mysql']['master_database'].'.server_ip WHERE server_id = '.$conf['server_id']." AND virtualhost = 'y'"); + $ip_addresses = array(); + + if(is_array($records) && count($records) > 0) { + foreach($records as $rec) { + if($rec['ip_type'] == 'IPv6') { + $ip_address = '['.$rec['ip_address'].']'; + } else { + $ip_address = $rec['ip_address']; + } + $ports = explode(',', $rec['virtualhost_port']); + if(is_array($ports)) { + foreach($ports as $port) { + $port = intval($port); + if($port > 0 && $port < 65536 && $ip_address != '') { + $ip_addresses[] = array('ip_address' => $ip_address, 'port' => $port); + } + } + } + } + } + + wf($conf['apache']['vhost_conf_dir'].'/000-ispconfig.conf', $tpl->grab()); + unset($tpl); //* Gentoo by default does not include .vhost files. Add include line to config file. $content = rf($conf['apache']['config_file']); diff --git a/install/dist/lib/opensuse.lib.php b/install/dist/lib/opensuse.lib.php index 657c795513..ad7ecfd6d0 100644 --- a/install/dist/lib/opensuse.lib.php +++ b/install/dist/lib/opensuse.lib.php @@ -660,10 +660,12 @@ class installer_dist extends installer_base { $vhost_conf_dir = $conf['apache']['vhost_conf_dir']; $vhost_conf_enabled_dir = $conf['apache']['vhost_conf_enabled_dir']; - //copy('tpl/apache_ispconfig.conf.master',$vhost_conf_dir.'/ispconfig.conf'); - $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apache_ispconfig.conf.master', 'tpl/apache_ispconfig.conf.master'); + $tpl = new tpl('apache_ispconfig.conf.master'); + $tpl->setVar('apache_version',getapacheversion()); + $records = $this->db->queryAllRecords('SELECT * FROM '.$conf['mysql']['master_database'].'.server_ip WHERE server_id = '.$conf['server_id']." AND virtualhost = 'y'"); - + $ip_addresses = array(); + if(is_array($records) && count($records) > 0) { foreach($records as $rec) { if($rec['ip_type'] == 'IPv6') { @@ -676,15 +678,15 @@ class installer_dist extends installer_base { foreach($ports as $port) { $port = intval($port); if($port > 0 && $port < 65536 && $ip_address != '') { - $content .= 'NameVirtualHost '.$ip_address.":".$port."\n"; + $ip_addresses[] = array('ip_address' => $ip_address, 'port' => $port); } } } } } - $content .= "\n"; - wf($vhost_conf_dir.'/ispconfig.conf', $content); + wf($vhost_conf_dir.'/ispconfig.conf', $tpl->grab()); + unset($tpl); if(!@is_link($vhost_conf_enabled_dir."/000-ispconfig.conf")) { exec("ln -s ".$vhost_conf_dir."/ispconfig.conf ".$vhost_conf_enabled_dir."/000-ispconfig.conf"); @@ -1089,31 +1091,30 @@ class installer_dist extends installer_base { // Dont just copy over the virtualhost template but add some custom settings - - $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apache_ispconfig.vhost.master', "tpl/apache_ispconfig.vhost.master"); - $content = str_replace('{vhost_port}', $conf['apache']['vhost_port'], $content); + $tpl = new tpl('apache_ispconfig.vhost.master'); + $tpl->setVar('vhost_port',$conf['apache']['vhost_port']); // comment out the listen directive if port is 80 or 443 if($conf['apache']['vhost_port'] == 80 or $conf['apache']['vhost_port'] == 443) { - $content = str_replace('{vhost_port_listen}', '#', $content); + $tpl->setVar('vhost_port_listen','#'); } else { - $content = str_replace('{vhost_port_listen}', '', $content); + $tpl->setVar('vhost_port_listen',''); } - if(is_file('/usr/local/ispconfig/interface/ssl/ispserver.crt') && is_file('/usr/local/ispconfig/interface/ssl/ispserver.key')) { - $content = str_replace('{ssl_comment}', '', $content); + if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key')) { + $tpl->setVar('ssl_comment',''); } else { - $content = str_replace('{ssl_comment}', '#', $content); + $tpl->setVar('ssl_comment','#'); } if(is_file($install_dir.'/interface/ssl/ispserver.crt') && is_file($install_dir.'/interface/ssl/ispserver.key') && is_file($install_dir.'/interface/ssl/ispserver.bundle')) { - $content = str_replace('{ssl_bundle_comment}', '', $content); + $tpl->setVar('ssl_bundle_comment',''); } else { - $content = str_replace('{ssl_bundle_comment}', '#', $content); + $tpl->setVar('ssl_bundle_comment','#'); } + + $tpl->setVar('apache_version',getapacheversion()); - $content = str_replace('/var/www/', '/srv/www/', $content); - - wf("$vhost_conf_dir/ispconfig.vhost", $content); + wf($vhost_conf_dir.'/ispconfig.vhost', $tpl->grab()); //if(!is_file('/srv/www/php-fcgi-scripts/ispconfig/.php-fcgi-starter')) { $content = rfsel($conf['ispconfig_install_dir'].'/server/conf-custom/install/apache_ispconfig_fcgi_starter.master', 'tpl/apache_ispconfig_fcgi_starter.master'); diff --git a/install/install.php b/install/install.php index e2d569e72e..a3393c1fbb 100644 --- a/install/install.php +++ b/install/install.php @@ -65,6 +65,9 @@ if(realpath(dirname(__FILE__)) != $cur_dir) { define('ISPC_LOG_FILE', '/var/log/ispconfig_install.log'); define('ISPC_INSTALL_ROOT', realpath(dirname(__FILE__).'/../')); +//** Include the templating lib +require_once 'lib/classes/tpl.inc.php'; + //** Check for existing installation /*if(is_dir("/usr/local/ispconfig")) { die('We will stop here. There is already a ISPConfig installation, use the update script to update this installation.'); diff --git a/install/lib/classes/tpl.inc.php b/install/lib/classes/tpl.inc.php new file mode 100644 index 0000000000..73ff19230b --- /dev/null +++ b/install/lib/classes/tpl.inc.php @@ -0,0 +1,1431 @@ + + * @package vLIB + * @access public + * @see vlibTemplate.html + */ + + +/* vim: set expandtab tabstop=4 shiftwidth=4: */ +// +----------------------------------------------------------------------+ +// | PHP version 4.0 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 2002 Active Fish Group | +// +----------------------------------------------------------------------+ +// | Authors: Kelvin Jones | +// +----------------------------------------------------------------------+ +// +// $Id: class.tpl.inc.php,v 1.1 2003/07/08 12:31:10 platinum Exp $ + +//** check and avoid multiple loading of class +if (!defined('vlibTemplateClassLoaded')) { + + define('vlibTemplateClassLoaded', 1); + include_once ISPC_INSTALL_ROOT.'/install/lib/classes/tpl_error.inc.php'; + include_once ISPC_INSTALL_ROOT.'/install/lib/classes/tpl_ini.inc.php'; + + class tpl{ + + /*-----------------------------------------------------------------------------\ + | ATTENTION | + | Do not touch the following variables. vlibTemplate will not work otherwise. | + \-----------------------------------------------------------------------------*/ + private $OPTIONS = array( + 'MAX_INCLUDES' => 10, + 'TEMPLATE_DIR' => null, + 'GLOBAL_VARS' => null, + 'GLOBAL_CONTEXT_VARS' => null, + 'LOOP_CONTEXT_VARS' => null, + 'SET_LOOP_VAR' => null, + 'DEFAULT_ESCAPE' => null, + 'STRICT' => null, + 'CASELESS' => null, + 'UNKNOWNS' => null, + 'TIME_PARSE' => null, + 'ENABLE_PHPINCLUDE' => null, + 'INCLUDE_PATHS' => array(), + 'CACHE_DIRECTORY' => null, + 'CACHE_LIFETIME' => null, + 'CACHE_EXTENSION' => null + ); + + /** open and close tags used for escaping */ + private $ESCAPE_TAGS = array( + 'html' => array('open' => 'htmlspecialchars(' , 'close'=> ', ENT_QUOTES)'), + 'url' => array('open' => 'urlencode(' , 'close'=> ')'), + 'rawurl' => array('open' => 'rawurlencode(' , 'close'=> ')'), + 'sq' => array('open' => 'addcslashes(' , 'close'=> ", \"'\")"), + 'dq' => array('open' => 'addcslashes(' , 'close'=> ", '\"')"), + '1' => array('open' => 'htmlspecialchars(' , 'close'=> ', ENT_QUOTES)'), + '0' => array('open' => '' , 'close'=> ''), + 'none' => array('open' => '' , 'close'=> ''), + 'hex' => array('open' => '$this->_escape_hex(' , 'close'=> ', false)'), + 'hexentity' => array('open' => '$this->_escape_hex(' , 'close'=> ', true)') + ); + + + + /** open and close tags used for formatting */ + private $FORMAT_TAGS = array( + 'strtoupper' => array('open' => 'strtoupper(', 'close'=> ')'), + 'uc' => array('open' => 'strtoupper(', 'close'=> ')'), + 'strtolower' => array('open' => 'strtolower(', 'close'=> ')'), + 'lc' => array('open' => 'strtolower(', 'close'=> ')'), + 'ucfirst' => array('open' => 'ucfirst(', 'close'=> ')'), + 'lcucfirst' => array('open' => 'ucfirst(strtolower(', 'close'=> '))'), + 'ucwords' => array('open' => 'ucwords(', 'close'=> ')'), + 'lcucwords' => array('open' => 'ucwords(strtolower(', 'close'=> '))') + ); + + /** operators allowed when using extended TMPL_IF syntax */ + private $allowed_if_ops = array('==', '!=', '<>', '<', '>', '<=', '>='); + + + + /** dbs allowed by vlibTemplate::setDbLoop(). */ + private $allowed_loop_dbs = array('MYSQL', 'POSTGRESQL', 'INFORMIX', 'INTERBASE', 'INGRES', + 'MSSQL', 'MSQL', 'OCI8', 'ORACLE', 'OVRIMOS', 'SYBASE'); + + + + /** root directory of vlibTemplate automagically filled in */ + private $VLIBTEMPLATE_ROOT = null; + + + + /** contains current directory used when doing recursive include */ + private $_currentincludedir = array(); + + + + /** current depth of includes */ + private $_includedepth = 0; + + + + /** full path to tmpl file */ + private $_tmplfilename = null; + + + + /** file data before it's parsed */ + private $_tmplfile = null; + + + + /** parsed version of file, ready for eval()ing */ + private $_tmplfilep = null; + + + + /** eval()ed version ready for printing or whatever */ + private $_tmploutput = null; + + + + /** array for variables to be kept */ + private $_vars = array(); + + + + /** array where loop variables are kept */ + private $_arrvars = array(); + + /** array which holds the current namespace during parse */ + private $_namespace = array(); + + + + /** variable is set to true once the template is parsed, to save re-parsing everything */ + private $_parsed = false; + + + + /** array holds all unknowns vars */ + private $_unknowns = array(); + + + + /** microtime when template parsing began */ + private $_firstparsetime = null; + + + + /** total time taken to parse template */ + private $_totalparsetime = null; + + + + /** name of current loop being passed in */ + private $_currloopname = null; + + + + /** rows with the above loop */ + private $_currloop = array(); + + + + /** define vars to avoid warnings */ + private $_debug = null; + private $_cache = null; + + + + /** array which holds the dynamic Includes */ + private $_dyninclude = array(); + + /*-----------------------------------------------------------------------------\ + | public functions | + \-----------------------------------------------------------------------------*/ + + + + + + /** + * Usually called by the class constructor. + * Stores the filename in $this->_tmplfilename. + * Raises an error if the template file is not found. + * @param string $tmplfile full path to template file + * @return boolean true + * @access public + */ + public function newTemplate($tmplfile) + { + if (!$tfile = $this->_fileSearch($tmplfile)){ + vlibTemplateError::raiseError('VT_ERROR_NOFILE', KILL, $tmplfile); + } + + //* make sure that any parsing vars are cleared for the new template + $this->_tmplfile = null; + $this->_tmplfilep = null; + $this->_tmploutput = null; + $this->_parsed = false; + $this->_unknowns = array(); + $this->_firstparsetime = null; + $this->_totalparsetime = null; + + //* reset debug module + if ($this->_debug){ + $this->_debugReset(); + } + $this->_tmplfilename = $tfile; + return true; + } + + /** + * Sets variables to be used by the template + * If $k is an array, then it will treat it as an associative array + * using the keys as variable names and the values as variable values. + * @param mixed $k key to define variable name + * @param mixed $v variable to assign to $k + * @return boolean true/false + * @access public + */ + public function setVar($k, $v = null) + { + if (is_array($k)) { + foreach($k as $key => $value){ + $key = ($this->OPTIONS['CASELESS']) ? strtolower(trim($key)) : trim($key); + if (preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $key) && $value !== null ) { + $this->_vars[$key] = $value; + } + } + } else { + if (preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $k) && $v !== null) { + if ($this->OPTIONS['CASELESS']) $k = strtolower($k); + $this->_vars[trim($k)] = $v; + } else { + return false; + } + } + return true; + } + + + + /** + * Sets dynamic includes to be used by the template + * If $k is an array, then it will treat it as an associative array + * using the keys as variable names and the values as variable values. + * @param mixed $k key to define variable name + * @param mixed $v variable to assign to $k + * @return boolean true/false + * @access public + */ + public function setInclude($k, $v = null) + { + if(is_array($k)) { + foreach($k as $key => $val) { + $this->_dyninclude[$key] = $val; + } + } else { + $this->_dyninclude[$k] = $v; + } + return true; + } + + /** + * Unsets a variable which has already been set + * Parse in all vars wanted for deletion in seperate parametres + * @param string var name to remove use: vlibTemplate::unsetVar(var[, var..]) + * @return boolean true/false returns true unless called with 0 params + * @access public + */ + public function unsetVar() + { + $num_args = func_num_args(); + if ($num_args < 1) return false; + + for ($i = 0; $i < $num_args; $i++) { + $var = func_get_arg($i); + if ($this->OPTIONS['CASELESS']) $var = strtolower($var); + if (!preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $var)) continue; + unset($this->_vars[$var]); + } + return true; + } + + /** + * Gets all vars currently set in global namespace. + * @return array + * @access public + */ + public function getVars() + { + return empty($this->_vars) ? false : $this->_vars; + } + + /** + * Gets a single var from the global namespace + * @return var + * @access public + */ + public function getVar($var) + { + if ($this->OPTIONS['CASELESS']) $var = strtolower($var); + return (empty($var) || !isset($this->_vars[$var])) ? false : $this->_vars[$var]; + } + + /** + * sets the GLOBAL_CONTEXT_VARS + * @return true + * @access public + */ + public function setContextVars() + { + $_phpself = @$GLOBALS['HTTP_SERVER_VARS']['PHP_SELF']; + $_pathinfo = @$GLOBALS['HTTP_SERVER_VARS']['PATH_INFO']; + $_request_uri = @$GLOBALS['HTTP_SERVER_VARS']['REQUEST_URI']; + $_qs = @$GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; + + //* the following fixes bug of $PHP_SELF on Win32 CGI and IIS. + $_self = (!empty($_pathinfo)) ? $_pathinfo : $_phpself; + $_uri = (!empty($_request_uri)) ? $_request_uri : $_self.'?'.$_qs; + + $this->setvar('__SELF__', $_self); + $this->setvar('__REQUEST_URI__', $_uri); + return true; + } + + /** + * Builds the loop construct for use with . + * @param string $k string to define loop name + * @param array $v array to assign to $k + * @return boolean true/false + * @access public + */ + public function setLoop($k, $v) + { + if (is_array($v) && preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $k)) { + $k = ($this->OPTIONS['CASELESS']) ? strtolower(trim($k)) : trim($k); + $this->_arrvars[$k] = array(); + if ($this->OPTIONS['SET_LOOP_VAR'] && !empty($v)) $this->setvar($k, 1); + if (($this->_arrvars[$k] = $this->_arrayBuild($v)) == false) { + vlibTemplateError::raiseError('VT_WARNING_INVALID_ARR', WARNING, $k); + } else { + $this->vars['_'.$k.'_num'] = count($v); + } + } + return true; + } + + /** + * [** EXPERIMENTAL **] + * Function to create a loop from a Db result resource link. + * @param string $loopname to commit loop. If not set, will use last loopname set using newLoop() + * @param string $result link to a Db result resource + * @param string $db_type, type of db that the result resource belongs to. + * @return boolean true/false + * @access public + */ + public function setDbLoop($loopname, $result, $db_type = 'MYSQL') + { + /* + $db_type = strtoupper($db_type); + if (!in_array($db_type, $this->allowed_loop_dbs)) { + vlibTemplateError::raiseError('VT_WARNING_INVALID_LOOP_DB', WARNING, $db_type); + return false; + } + + $loop_arr = array(); + // TODO: Are all these necessary as were onyl using mysql and possible postgres ? - pedro + switch ($db_type) { + + case 'MYSQL': + if (get_resource_type($result) != 'mysql result') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while($r = mysql_fetch_assoc($result)) { + $loop_arr[] = $r; + } + break; + + case 'POSTGRESQL': + if (get_resource_type($result) != 'pgsql result') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + + $nr = (function_exists('pg_num_rows')) ? pg_num_rows($result) : pg_numrows($result); + + for ($i=0; $i < $nr; $i++) { + $loop_arr[] = pg_fetch_array($result, $i, PGSQL_ASSOC); + } + break; + + case 'INFORMIX': + if (!$result) { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while($r = ifx_fetch_row($result, 'NEXT')) { + $loop_arr[] = $r; + } + break; + + case 'INTERBASE': + if (get_resource_type($result) != 'interbase result') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while($r = ibase_fetch_row($result)) { + $loop_arr[] = $r; + } + break; + + case 'INGRES': + if (!$result) { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while($r = ingres_fetch_array(INGRES_ASSOC, $result)) { + $loop_arr[] = $r; + } + break; + + case 'MSSQL': + if (get_resource_type($result) != 'mssql result') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while($r = mssql_fetch_array($result)) { + $loop_arr[] = $r; + } + break; + + case 'MSQL': + if (get_resource_type($result) != 'msql result') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while($r = msql_fetch_array($result, MSQL_ASSOC)) { + $loop_arr[] = $r; + } + break; + + case 'OCI8': + if (get_resource_type($result) != 'oci8 statement') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while(OCIFetchInto($result, &$r, OCI_ASSOC+OCI_RETURN_LOBS)) { + $loop_arr[] = $r; + } + break; + + case 'ORACLE': + if (get_resource_type($result) != 'oracle Cursor') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while(ora_fetch_into($result, &$r, ORA_FETCHINTO_ASSOC)) { + $loop_arr[] = $r; + } + break; + + case 'OVRIMOS': + if (!$result) { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + while(ovrimos_fetch_into($result, &$r, 'NEXT')) { + $loop_arr[] = $r; + } + break; + + case 'SYBASE': + if (get_resource_type($result) != 'sybase-db result') { + vlibTemplateError::raiseError('VT_WARNING_INVALID_RESOURCE', WARNING, $db_type); + return false; + } + + while($r = sybase_fetch_array($result)) { + $loop_arr[] = $r; + } + break; + } + $this->setLoop($loopname, $loop_arr); + return true; + */ + } + + /** + * Sets the name for the curent loop in the 3 step loop process. + * @param string $name string to define loop name + * @return boolean true/false + * @access public + */ + public function newLoop($loopname) + { + if (preg_match('/^[a-z_]+[a-z0-9_]*$/i', $loopname)) { + $this->_currloopname[$loopname] = $loopname; + $this->_currloop[$loopname] = array(); + return true; + } else { + return false; + } + } + + /** + * Adds a row to the current loop in the 3 step loop process. + * @param array $row loop row to add to current loop + * @param string $loopname loop to which you want to add row, if not set will use last loop set using newLoop(). + * @return boolean true/false + * @access public + */ + public function addRow($row, $loopname = null) + { + if (!$loopname) $loopname = $this->_currloopname[(count($this->_currloopname)-1)]; + + if (!isset($this->_currloop[$loopname]) || empty($this->_currloopname)) { + vlibTemplateError::raiseError('VT_WARNING_LOOP_NOT_SET', WARNING); + return false; + } + if (is_array($row)) { + $this->_currloop[$loopname][] = $row; + return true; + } else { + return false; + } + } + + /** + * Completes the 3 step loop process. This assigns the rows and resets + * the variables used. + * @param string $loopname to commit loop. If not set, will use last loopname set using newLoop() + * @return boolean true/false + * @access public + */ + public function addLoop($loopname = null) + { + if ($loopname == null) { // add last loop used + if (!empty($this->_currloop)) { + foreach ($this->_currloop as $k => $v) { + $this->setLoop($k, $v); + unset($this->_currloop[$k]); + } + $this->_currloopname = array(); + return true; + } else { + return false; + } + } elseif (!isset($this->_currloop[$loopname]) || empty($this->_currloopname)) { // newLoop not yet envoked + vlibTemplateError::raiseError('VT_WARNING_LOOP_NOT_SET', WARNING); + return false; + } else { // add a specific loop + $this->setLoop($loopname, $this->_currloop[$loopname]); + unset($this->_currloopname[$loopname], $this->_currloop[$loopname]); + } + return true; + } + + /** + * Unsets a loop which has already been set. + * Can only unset top level loops. + * @param string loop to remove use: vlibTemplate::unsetLoop(loop[, loop..]) + * @return boolean true/false returns true unless called with 0 params + * @access public + */ + public function unsetLoop() + { + $num_args = func_num_args(); + if ($num_args < 1) return false; + + for ($i = 0; $i < $num_args; $i++) { + $var = func_get_arg($i); + if ($this->OPTIONS['CASELESS']) $var = strtolower($var); + if (!preg_match('/^[A-Za-z_]+[A-Za-z0-9_]*$/', $var)) continue; + unset($this->_arrvars[$var]); + } + return true; + } + + /** + * Resets the vlibTemplate object. After using vlibTemplate::reset() you must + * use vlibTemplate::newTemplate(tmpl) to reuse, not passing in the options array. + * @return boolean true + * @access public + */ + public function reset() + { + $this->clearVars(); + $this->clearLoops(); + $this->_tmplfilename = null; + $this->_tmplfile = null; + $this->_tmplfilep = null; + $this->_tmploutput = null; + $this->_parsed = false; + $this->_unknowns = array(); + $this->_firstparsetime = null; + $this->_totalparsetime = null; + $this->_currloopname = null; + $this->_currloop = array(); + return true; + } + + /** + * Unsets all variables in the template + * @return boolean true + * @access public + */ + public function clearVars() + { + $this->_vars = array(); + return true; + } + + /** + * Unsets all loops in the template + * @return boolean true + * @access public + */ + public function clearLoops() + { + $this->_arrvars = array(); + $this->_currloopname = null; + $this->_currloop = array(); + return true; + } + + /** + * Unsets all variables and loops set using setVar/Loop() + * @return boolean true + * @access public + */ + public function clearAll() + { + $this->clearVars(); + $this->clearLoops(); + return true; + } + + /** + * Returns true if unknowns were found after parsing. + * Function MUST be called AFTER one of the parsing functions to have any relevance. + * @return boolean true/false + * @access public + */ + public function unknownsExist() + { + return !empty($this->_unknowns); + } + + /** + * Alias for unknownsExist. + * @access public + */ + public function unknowns() + { + return $this->unknownsExist(); + } + + /** + * Returns an array of all unknown vars found when parsing. + * This function is only relevant after parsing a document. + * @return array + * @access public + */ + public function getUnknowns() + { + return $this->_unknowns; + } + + /** + * Sets how you want to handle variables that were found in the + * template but not set in vlibTemplate using vlibTemplate::setVar(). + * @param string $arg ignore, remove, print, leave or comment + * @return boolean + * @access public + */ + public function setUnknowns($arg) + { + $arg = strtolower(trim($arg)); + if (preg_match('/^ignore|remove|print|leave|comment$/', $arg)) { + $this->OPTIONS['UNKNOWNS'] = $arg; + return true; + } + return false; + } + + /** + * function sets the paths to use when including files. + * Use of this function: vlibTemplate::setPath(string path [, string path, ..]); + * i.e. if $tmpl is your template object do: $tmpl->setPath('/web/htdocs/templates','/web/htdocs/www'); + * with as many paths as you like. + * if this function is called without any arguments, it will just delete any previously set paths. + * + * @param string path (mulitple) + * @return bool success + * @access public + */ + public function setPath() + { + $num_args = func_num_args(); + if ($num_args < 1) { + $this->OPTIONS['INCLUDE_PATHS'] = array(); + return true; + } + for ($i = 0; $i < $num_args; $i++) { + $thispath = func_get_arg($i); + array_push($this->OPTIONS['INCLUDE_PATHS'], realpath($thispath)); + } + return true; + } + + /** + * After using one of the parse functions, this will allow you + * access the time taken to parse the template. + * see OPTION 'TIME_PARSE'. + * + * @return float time taken to parse template + * @access public + */ + public function getParseTime() + { + if ($this->OPTIONS['TIME_PARSE'] && $this->_parsed) { + return $this->_totalparsetime; + } + return false; + } + + + /** + * Identical to pparse() except that it uses output buffering w/ gz compression thus + * printing the output directly and compressed if poss. + * Will possibly if parsing a huge template. + * + * @access public + * @return boolean true/false + */ + public function fastPrint() + { + $ret = $this->_parse('ob_gzhandler'); + print($this->_tmploutput); + return $ret; + } + + + /** + * Calls parse, and then prints out $this->_tmploutput + * @access public + * @return boolean true/false + */ + public function pparse() + { + if (!$this->_parsed) $this->_parse(); + print($this->_tmploutput); + return true; + } + + /** + * Alias for pparse() + * @access public + */ + public function pprint() + { + return $this->pparse(); + } + + + /** + * Returns the parsed output, ready for printing, passing to mail() ...etc. + * Invokes $this->_parse() if template has not yet been parsed. + * + * @access public + * @return boolean true/false + */ + public function grab() + { + if (!$this->_parsed) $this->_parse(); + return $this->_tmploutput; + } + + /*-----------------------------------------------------------------------------\ + | private functions | + \-----------------------------------------------------------------------------*/ + + /** + * vlibTemplate constructor. + * if $tmplfile has been passed to it, it will send to $this->newTemplate() + * @param string $tmplfile full path to template file + * @param array $options see above + * @return boolean true/false + * @access private + */ + public function __construct($tmplfile = null, $options = null) + { + if (is_array($tmplfile) && $options == null) { + $options = $tmplfile; + unset($tmplfile); + } + + $this->VLIBTEMPLATE_ROOT = dirname(realpath(__FILE__)); + + if (is_array(vlibIni::vlibTemplate())) { + foreach (vlibIni::vlibTemplate() as $name => $val) { + $this->OPTIONS[$name] = $val; + } + } + + if (is_array($options)) { + foreach($options as $key => $val) { + $key = strtoupper($key); + if ($key == 'PATH') { + $this->setPath($val); + } else { + $this->_setOption($key, strtolower($val)); + } + } + } + if($tmplfile) $this->newTemplate($tmplfile); + if ($this->OPTIONS['GLOBAL_CONTEXT_VARS']) $this->setContextVars(); + return true; + } + + /** + * function returns the text from the file, or if we're using cache, the text + * from the cache file. MUST RETURN DATA. + * @param string tmplfile contains path to template file + * @param do_eval used for included files. If set then this function must do the eval()'ing. + * @access private + * @return mixed data/string or boolean + */ + private function _getData ($tmplfile, $do_eval=false) + { + //* check the current file depth + if ($this->_includedepth > $this->OPTIONS['MAX_INCLUDES'] || $tmplfile == false) { + return; + } else { + if ($this->_debug){ + array_push($this->_debugIncludedfiles, $tmplfile); + } + if ($do_eval) { + array_push($this->_currentincludedir, dirname($tmplfile)); + $this->_includedepth++; + } + } + + + if($this->_cache && $this->_checkCache($tmplfile)) { //* cache exists so lets use it + $data = fread($fp = fopen($this->_cachefile, 'r'), filesize($this->_cachefile)); + fclose($fp); + } else { //* no cache lets parse the file + $data = fread($fp = fopen($tmplfile, 'r'), filesize($tmplfile)); + fclose($fp); + + $regex = '/(<|<\/|{|{\/|){1}'; + $regex.= '/i'; + $data = preg_replace_callback($regex, array($this, '_parseTag'), $data); + + if ($this->_cache) { // add cache if need be + $this->_createCache($data); + } + } + + //* now we must parse the $data and check for any 's + if ($this->_debug) $this->doDebugWarnings(file($tmplfile), $tmplfile); + + if ($do_eval) { + $success = @eval('?>'.$data.'_includedepth--; + array_pop($this->_currentincludedir); + return $success; + } else { + return $data; + } + } + + /** + * Searches for all possible instances of file { $file } + * @param string $file path of file we're looking for + * @access private + * @return mixed fullpath to file or boolean false + */ + private function _fileSearch($file) + { + + $filename = basename($file); + $filepath = dirname($file); + + if(isset($_SESSION['s']['module']['name']) && isset($_SESSION['s']['theme'])) { + if(is_file(ISPC_THEMES_PATH.'/'.$_SESSION['s']['theme'].'/templates/'.$_SESSION['s']['module']['name'].'/'.$filename)) { + return ISPC_THEMES_PATH.'/'.$_SESSION['s']['theme'].'/templates/'.$_SESSION['s']['module']['name'].'/'.$filename; + } + } + + //* check fullpath first.. + $fullpath = $filepath.'/'.$filename; + if (is_file($fullpath)) return $fullpath; + + //* ..then check for relative path for current directory.. + if (!empty($this->_currentincludedir)) { + $currdir = $this->_currentincludedir[(count($this->_currentincludedir) -1)]; + $relativepath = realpath($currdir.'/'.$filepath.'/'.$filename); + if (is_file($relativepath)) { + array_push($this->_currentincludedir, dirname($relativepath)); + return $relativepath; + } + } + + //* ..then check for relative path for all additional given paths.. + if (!empty($this->OPTIONS['INCLUDE_PATHS'])) { + foreach ($this->OPTIONS['INCLUDE_PATHS'] as $currdir) { + $relativepath = realpath($currdir.'/'.$filepath.'/'.$filename); + if (is_file($relativepath)) { + return $relativepath; + } + } + } + + //* ..then check path from TEMPLATE_DIR.. + if (!empty($this->OPTIONS['TEMPLATE_DIR'])) { + $fullpath = realpath($this->OPTIONS['TEMPLATE_DIR'].'/'.$filepath.'/'.$filename); + if (is_file($fullpath)) return $fullpath; + } + + //* ..then check relative path from executing php script.. + $fullpath = realpath($filepath.'/'.$filename); + if (is_file($fullpath)) return $fullpath; + + //* ..then check path from template file. + if (!empty($this->VLIBTEMPLATE_ROOT)) { + $fullpath = realpath($this->VLIBTEMPLATE_ROOT.'/'.$filepath.'/'.$filename); + if (is_file($fullpath)) return $fullpath; + } + + return false; // uh oh, file not found + } + + /** + * Modifies the array $arr to add Template variables, __FIRST__, __LAST__ ..etc + * if $this->OPTIONS['LOOP_CONTEXT_VARS'] is true. + * Used by $this->setloop(). + * @param array $arr + * @return array new look array + * @access private + */ + private function _arrayBuild($arr) + { + if (is_array($arr) && !empty($arr)) { + $arr = array_values($arr); // to prevent problems w/ non sequential arrays + for ($i = 0; $i < count($arr); $i++) { + if(!is_array($arr[$i])) return false; + foreach ($arr[$i] as $k => $v) { + unset($arr[$i][$k]); + if ($this->OPTIONS['CASELESS']) $k = strtolower($k); + if (preg_match('/^[0-9]+$/', $k)) $k = '_'.$k; + + if (is_array($v)) { + if (($arr[$i][$k] = $this->_arrayBuild($v)) == false) return false; + } else { // reinsert the var + $arr[$i][$k] = $v; + } + } + if ($this->OPTIONS['LOOP_CONTEXT_VARS']) { + if ($i == 0) $arr[$i]['__FIRST__'] = true; + if (($i + 1) == count($arr)) $arr[$i]['__LAST__'] = true; + if ($i != 0 && (($i + 1) < count($arr))) $arr[$i]['__INNER__'] = true; + if (is_int(($i+1) / 2)) $arr[$i]['__EVEN__'] = true; + if (!is_int(($i+1) / 2)) $arr[$i]['__ODD__'] = true; + $arr[$i]['__ROWNUM__'] = ($i + 1); + } + } + return $arr; + } elseif (empty($arr)) { + return true; + } + } + + /** + * returns a string used for parsing in tmpl_if statements. + * @param string $varname + * @param string $value + * @param string $op + * @param string $namespace current namespace + * @access private + * @return string used for eval'ing + */ + private function _parseIf($varname, $value = null, $op = null, $namespace = null, $format = null) + { + if (isset($namespace)) $namespace = substr($namespace, 0, -1); + $comp_str = ''; // used for extended if statements + + // work out what to put on the end id value="whatever" is used + if (isset($value)) { + + // add the correct operator depending on whether it's been specified or not + if (!empty($op)) { + if (in_array($op, $this->allowed_if_ops)) { + $comp_str .= $op; + } else { + vlibTemplateError::raiseError('VT_WARNING_INVALID_IF_OP', WARNING, $op); + } + } else { + $comp_str .= '=='; + } + + // now we add the value, if it's numeric, then we leave the quotes off + if (is_numeric($value)) { + $comp_str .= $value; + } else { + $comp_str .= '\''.$value.'\''; + } + } + + if (count($this->_namespace) == 0 || $namespace == 'global') return '$this->_vars[\''.$varname.'\']'.$comp_str; + $retstr = '$this->_arrvars'; + $numnamespaces = count($this->_namespace); + for ($i=0; $i < $numnamespaces; $i++) { + if ($this->_namespace[$i] == $namespace || (($i + 1) == $numnamespaces && !empty($namespace))) { + $retstr .= "['".$namespace."'][\$_".$i."]"; + break 1; + } else { + $retstr .= "['".$this->_namespace[$i]."'][\$_".$i."]"; + } + } + if ($this->OPTIONS['GLOBAL_VARS'] && empty($namespace)) { + $retstr = '(('.$retstr.'[\''.$varname.'\'] !== null) ? '.$retstr.'[\''.$varname.'\'] : $this->_vars[\''.$varname.'\'])'; + if(isset($format) && isset($value) && $format == 'version') { + return 'version_compare(' . $retstr . ', \'' . $value . '\', \'' . (!empty($op) ? $op : '==') . '\')'; + } else { + return $retstr.$comp_str; + } + } + else { + if(isset($format) && isset($value) && $format == 'version') { + return 'version_compare(' . $retstr."['".$varname."']" . ', \'' . $value . '\', \'' . (!empty($op) ? $op : '==') . '\')'; + } else { + return $retstr."['".$varname."']".$comp_str; + } + } + } + + + /** + * returns a string used for parsing in tmpl_loop statements. + * @param string $varname + * @access private + * @return string used for eval'ing + */ + private function _parseLoop ($varname) + { + array_push($this->_namespace, $varname); + $tempvar = count($this->_namespace) - 1; + $retstr = "for (\$_".$tempvar."=0 ; \$_".$tempvar." < count(\$this->_arrvars"; + for ($i=0; $i < count($this->_namespace); $i++) { + $retstr .= "['".$this->_namespace[$i]."']"; + if ($this->_namespace[$i] != $varname) $retstr .= "[\$_".$i."]"; + } + return $retstr."); \$_".$tempvar."++) {"; + } + + /** + * returns a string used for parsing in tmpl_var statements. + * @param string $wholetag + * @param string $tag + * @param string $varname + * @param string $escape + * @param string $format + * @param string $namespace + * @access private + * @return string used for eval'ing + */ + private function _parseVar ($wholetag, $tag, $varname, $escape, $format, $namespace) + { + if (!empty($namespace)) $namespace = substr($namespace, 0, -1); + $wholetag = stripslashes($wholetag); + + if (count($this->_namespace) == 0 || $namespace == 'global') { + $var1 = '$this->_vars[\''.$varname.'\']'; + } else { + $var1build = "\$this->_arrvars"; + $numnamespaces = count($this->_namespace); + for ($i=0; $i < $numnamespaces; $i++) { + if ($this->_namespace[$i] == $namespace || (($i + 1) == $numnamespaces && !empty($namespace))) { + $var1build .= "['".$namespace."'][\$_".$i."]"; + break 1; + } else { + $var1build .= "['".$this->_namespace[$i]."'][\$_".$i."]"; + } + } + $var1 = $var1build . "['$varname']"; + if ($this->OPTIONS['GLOBAL_VARS'] && empty($namespace)) { + $var2 = '$this->_vars[\''.$varname.'\']'; + } + } + + $beforevar = ''; + $aftervar = ''; + if (!empty($escape)&& isset($this->ESCAPE_TAGS[$escape])) { + $beforevar .= $this->ESCAPE_TAGS[$escape]['open']; + $aftervar = $this->ESCAPE_TAGS[$escape]['close'] . $aftervar; + } + + if (!empty($format)&& isset($this->FORMAT_TAGS[$format])) { + $beforevar .= $this->FORMAT_TAGS[$format]['open']; + $aftervar = $this->FORMAT_TAGS[$format]['close'] . $aftervar; + } + + //* build return values + $retstr = 'if ('.$var1.' !== null) { '; + $retstr .= 'print('.$beforevar.$var1.$aftervar.'); '; + $retstr .= '}'; + + if (@$var2) { + $retstr .= ' elseif ('.$var2.' !== null) { '; + $retstr .= 'print('.$beforevar.$var2.$aftervar.'); '; + $retstr .= '}'; + } + + switch (strtolower($this->OPTIONS['UNKNOWNS'])) { + case 'comment': + $comment = addcslashes('/', '', $wholetag).'//-->', '"'); + $retstr .= ' else { print("'.$comment.'"); $this->_setUnknown("'.$varname.'"); }'; + return $retstr; + + case 'leave': + $retstr .= ' else { print("'.addcslashes($wholetag, '"').'"); $this->_setUnknown("'.$varname.'"); }'; + return $retstr; + + case 'print': + $retstr .= ' else { print("'.htmlspecialchars($wholetag, ENT_QUOTES).'"); $this->_setUnknown("'.$varname.'"); }'; + return $retstr; + + case 'ignore': + return $retstr; + + case 'remove': + default: + $retstr .= ' else { $this->_setUnknown("'.$varname.'"); }'; + return $retstr; + + } + } + + /** + * takes values from preg_replace in $this->_intparse() and determines + * the replace string. + * + * @param array $args array of all matches found by preg_replace + * @access private + * @return string replace values + */ + private function _parseTag ($args) + { + $wholetag = $args[0]; + $openclose = $args[1]; + $tag = strtolower($args[2]); + + if ($tag == 'else') return ''; + if ($tag == 'tmpl_include') return $wholetag; // ignore tmpl_include tags + + if (preg_match("/^<\/|{\/|