Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Tue, Apr 29, 11:06 PM

in-portal

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: branches/5.0.x/core/kernel/processors/tag_processor.php
===================================================================
--- branches/5.0.x/core/kernel/processors/tag_processor.php (revision 12322)
+++ branches/5.0.x/core/kernel/processors/tag_processor.php (revision 12323)
@@ -1,339 +1,313 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class TagProcessor extends kBase {
/**
* Processes tag
*
* @param Tag $tag
* @return string
* @access public
*/
function ProcessTag(&$tag)
{
return $this->ProcessParsedTag($tag->Tag, $tag->NP, $tag->getPrefixSpecial());
-
- /*$Method=$tag->Tag;
- if(method_exists($this, $Method))
- {
- //echo htmlspecialchars($tag->GetFullTag()).'<br>';
- return $this->$Method($tag->NP);
- }
- else
- {
- if ($this->Application->hasObject('TagsAggregator')) {
- $aggregator =& $this->Application->recallObject('TagsAggregator');
- $tag_mapping = $aggregator->GetArrayValue($tag->Prefix, $Method);
- if ($tag_mapping) {
-
- $mapped_tag = new Tag('', $this->Application->Parser);
- $mapped_tag->CopyFrom($tag);
- $mapped_tag->Processor = $tag_mapping[0];
- $mapped_tag->Tag = $tag_mapping[1];
- $mapped_tag->NP['PrefixSpecial'] = $tag->getPrefixSpecial();
- $mapped_tag->RebuildTagData();
- return $mapped_tag->DoProcessTag();
- }
- }
- trigger_error('Tag '.$Method.' Undefined in '.get_class($this).'[Agregated Tag]:<br><b>'.$tag->RebuildTagData().'</b>',E_USER_WARNING);
- return false;
- }*/
}
function CheckTag($tag, $prefix)
{
$Method = $tag;
if(method_exists($this, $Method))
{
return true;
}
else {
if ($this->Application->hasObject('TagsAggregator')) {
$aggregator =& $this->Application->recallObject('TagsAggregator');
$tmp = $this->Application->processPrefix($prefix);
$tag_mapping = $aggregator->GetArrayValue($tmp['prefix'], $Method);
if ($tag_mapping) {
return true;
}
}
}
}
function FormCacheKey($tag, $params, $prefix)
{
$k = $this->Application->Parser->TemplateName;
$k .= $prefix.'_'.$tag;
foreach (array('m_cat_id','m_cat_page','m_lang','m_theme') as $m_var) {
$params[$m_var] = $this->Application->GetVar($m_var);
}
ksort($params);
foreach ($params as $p => $v) {
$k .= "$p=$v&";
}
return md5($k);
}
function ProcessParsedTag($tag, $params, $prefix, $file='unknown', $line=0)
{
$Method = $tag;
if (method_exists($this, $Method)) {
- if ($this->Application->isDebugMode() && constOn('DBG_SHOW_TAGS')) {
+ if (defined('DEBUG_MODE') && defined('DBG_SHOW_TAGS') && DBG_SHOW_TAGS && $this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('Processing PreParsed Tag '.$Method.' in '.$this->Prefix);
}
$backup_prefix = $this->Prefix;
$backup_special = $this->Special;
if ($this->Application->ConfigValue('SystemTagCache') && isset($params['cache_timeout'])) {
if ($res = $this->Application->CacheGet($this->FormCacheKey($tag, $params, $prefix))) {
return $res;
}
}
$original_params = $params;
$flag_values = $this->PreparePostProcess($params);
// pass_params for non ParseBlock tags :)
if ($flag_values['pass_params']) {
$params = array_merge_recursive2($this->Application->Parser->Params, $params);
}
$ret = $this->$Method($params);
$this->Prefix = $backup_prefix;
$this->Special = $backup_special;
$ret = $this->PostProcess($ret, $flag_values);
if ($this->Application->ConfigValue('SystemTagCache') && $flag_values['cache_timeout'] && isset($this->Application->Memcached)) {
$this->Application->CacheSet($this->FormCacheKey($tag, $original_params, $prefix), $ret, $flag_values['cache_timeout']);
}
return $ret;
}
else {
list ($ret, $tag_found) = $this->processAggregatedTag($tag, $params, $prefix, $file, $line);
if ($tag_found) {
return $ret;
}
$this->Application->handleError(E_USER_ERROR, 'Tag Undefined:<br><b>'.$prefix.':'.$tag.'</b>', $file, $line);
return false;
}
}
function processAggregatedTag($tag, $params, $prefix, $file = 'unknown', $line = 0)
{
if ($this->Application->hasObject('TagsAggregator')) {
$Method = $tag;
$aggregator =& $this->Application->recallObject('TagsAggregator');
$tmp = $this->Application->processPrefix($prefix);
$tag_mapping = $aggregator->GetArrayValue($tmp['prefix'], $Method);
if ($tag_mapping) {
// aggregated tag defined
$tmp = $this->Application->processPrefix($tag_mapping[0]);
$__tag_processor = $tmp['prefix'].'_TagProcessor';
$processor =& $this->Application->recallObject($__tag_processor);
$processor->Prefix = $tmp['prefix'];
$processor->Special = getArrayValue($tag_mapping, 2) ? $tag_mapping[2] : $tmp['special'];
$params['original_tag'] = $Method; // allows to define same method for different aggregated tags in same tag processor
$params['PrefixSpecial'] = $this->getPrefixSpecial(); // $prefix;
$ret = $processor->ProcessParsedTag($tag_mapping[1], $params, $prefix);
if (isset($params['result_to_var'])) {
$this->Application->Parser->SetParam($params['result_to_var'], $ret);
$ret = '';
}
return Array ($ret, true);
}
else {
// aggregated tag not defined
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
$this->Application->handleError(E_USER_ERROR, 'Tag <b>'.$Method.'</b> Undefined in '.get_class($this).'[Agregated Tag]:<br><b>'.$tag.'</b>', $file, $line);
}
}
return Array ('', false);
}
function PreparePostProcess(&$params)
{
$flags = Array('js_escape', 'equals_to', 'result_to_var', 'pass_params', 'html_escape', 'strip_nl', 'trim', 'cache_timeout');
$flag_values = Array();
foreach ($flags as $flag_name) {
$flag_values[$flag_name] = false;
if (isset($params[$flag_name])) {
$flag_values[$flag_name] = $params[$flag_name];
unset($params[$flag_name]);
}
}
return $flag_values;
}
function PostProcess($ret, $flag_values)
{
if ($flag_values['html_escape']) {
$ret = htmlspecialchars($ret);
}
if ($flag_values['js_escape']) {
$ret = addslashes($ret);
$ret = str_replace(Array("\r", "\n"), Array('\r', '\n'), $ret);
$ret = str_replace('</script>', "</'+'script>", $ret);
}
if ($flag_values['strip_nl']) {
// 1 - strip \r,\n; 2 - strip tabs too
$ret = preg_replace($flag_values['strip_nl'] == 2 ? "/[\r\n\t]/" : "/[\r\n]/", '', $ret);
}
if ($flag_values['trim']) {
$ret = trim($ret);
}
// TODO: in new parser implement this parameter in compiled code (by Alex)
if ($flag_values['equals_to'] !== false) {
$equals_to = explode('|', $flag_values['equals_to']);
$ret = in_array($ret, $equals_to);
}
if ($flag_values['result_to_var']) {
$this->Application->Parser->SetParam($flag_values['result_to_var'], $ret);
$ret = '';
}
return $ret;
}
/**
* Not tag, method for parameter
* selection from list in this TagProcessor
*
* @param Array $params
* @param string $possible_names
* @return string
* @access public
*/
function SelectParam($params, $possible_names = null)
{
if (!isset($possible_names)) {
// select 1st parameter non-empty parameter value
$possible_names = explode(',', $params['possible_names']);
foreach ($possible_names as $param_name) {
$value = $this->Application->Parser->GetParam($param_name);
if (((string)$value != '') && ((string)$value != '0')) {
return $value;
}
}
return '';
}
if (!is_array($params)) {
// really happens?
return;
}
if (!is_array($possible_names)) {
$possible_names = explode(',', $possible_names);
}
foreach ($possible_names as $name) {
if( isset($params[$name]) ) return $params[$name];
}
return false;
}
/**
* Returns templates path for module, which is gathered from prefix module
*
* @param Array $params
* @return string
* @author Alex
*/
function ModulePath($params)
{
$force_module = getArrayValue($params, 'module');
if ($force_module) {
if ($force_module == '#session#') {
$force_module = preg_replace('/([^:]*):.*/', '\1', $this->Application->RecallVar('module'));
if (!$force_module) $force_module = 'core';
}
else {
$force_module = mb_strtolower($force_module);
}
if ($force_module == 'core') {
$module_folder = 'core';
}
else {
$module_folder = trim( $this->Application->findModule('Name', $force_module, 'Path'), '/');
}
}
else {
$module_folder = $this->Application->getUnitOption($this->Prefix, 'ModuleFolder');
}
return '../../'.$module_folder.'/admin_templates/';
}
}
/*class ProcessorsPool {
var $Processors = Array();
var $Application;
var $Prefixes = Array();
var $S;
function ProcessorsPool()
{
$this->Application =& KernelApplication::Instance();
$this->S =& $this->Application->Session;
}
function RegisterPrefix($prefix, $path, $class)
{
// echo " RegisterPrefix $prefix, $path, $class <br>";
$prefix_item = Array(
'path' => $path,
'class' => $class
);
$this->Prefixes[$prefix] = $prefix_item;
}
function CreateProcessor($prefix, &$tag)
{
// echo " prefix : $prefix <br>";
if (!isset($this->Prefixes[$prefix]))
$this->Application->ApplicationDie ("<b>Filepath and ClassName for prefix $prefix not defined while processing ".htmlspecialchars($tag->GetFullTag())."!</b>");
include_once($this->Prefixes[$prefix]['path']);
$ClassName = $this->Prefixes[$prefix]['class'];
$a_processor = new $ClassName($prefix);
$this->SetProcessor($prefix, $a_processor);
}
function SetProcessor($prefix, &$a_processor)
{
$this->Processors[$prefix] =& $a_processor;
}
function &GetProcessor($prefix, &$tag)
{
if (!isset($this->Processors[$prefix]))
$this->CreateProcessor($prefix, $tag);
return $this->Processors[$prefix];
}
}*/
\ No newline at end of file
Index: branches/5.0.x/core/kernel/processors/main_processor.php
===================================================================
--- branches/5.0.x/core/kernel/processors/main_processor.php (revision 12322)
+++ branches/5.0.x/core/kernel/processors/main_processor.php (revision 12323)
@@ -1,1161 +1,1002 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kMainTagProcessor extends TagProcessor {
function Init($prefix, $special, $event_params = null)
{
parent::Init($prefix, $special, $event_params);
$actions =& $this->Application->recallObject('kActions');
$actions->Set('t', $this->Application->GetVar('t'));
$actions->Set('sid', $this->Application->GetSID());
$actions->Set('m_opener', $this->Application->GetVar('m_opener') );
}
/**
- * Used to handle calls where tag name
- * match with existing php function name
- *
- * @param Tag $tag
- * @return string
- */
- function ProcessTag(&$tag)
- {
- if ($tag->Tag=='include') $tag->Tag='MyInclude';
- return parent::ProcessTag($tag);
- }
-
- /**
* Base folder for all template includes
*
* @param Array $params
* @return string
*/
function TemplatesBase($params)
{
$force_admin = array_key_exists('force_admin', $params) && $params['force_admin'];
$module = array_key_exists('module', $params) ? $params['module'] : 'core';
if ($this->Application->IsAdmin() || $force_admin) {
if ($module == 'in-portal') {
$module = 'kernel';
}
$path = $force_admin ? '/core/admin_templates' : THEMES_PATH;
$path = preg_replace('/\/(.*?)\/(.*)/', $module.'/\\2', $path); // remove leading slash + substitute module
}
else {
$path = mb_substr(THEMES_PATH, 1);
if (mb_strtolower($module) == 'in-portal') {
$module_folder = 'platform';
}
else {
$module_folder = $this->Application->findModule('Name', $module, 'TemplatePath');
}
$path .= rtrim('/' . trim($module_folder, '/'), '/') . '/';
}
return $this->Application->BaseURL() . $path;
}
/**
* Creates <base href ..> HTML tag for all templates
* affects future css, js files and href params of links
*
* @return string
* @access public
*/
function Base_Ref($params)
{
return '<base href="'.$this->TemplatesBase($params).'/" />';
}
/**
* Returns base url for web-site
*
* @return string
* @access public
*/
function BaseURL()
{
return $this->Application->BaseURL();
}
//for compatability with K3 tags
function Base($params)
{
return $this->TemplatesBase($params).'/';
}
function ProjectBase($params)
{
return $this->Application->BaseURL();
}
/*function Base($params)
{
return $this->Application->BaseURL().$params['add'];
}*/
/**
* Used to create link to any template.
* use "pass" paramter if "t" tag to specify
* prefix & special of object to be represented
* in resulting url
*
* @param Array $params
* @return string
* @access public
*/
function T($params)
{
//by default link to current template
$t = $this->SelectParam($params, 't,template');
unset($params['t']);
unset($params['template']);
$prefix=isset($params['prefix']) ? $params['prefix'] : ''; unset($params['prefix']);
$index_file = isset($params['index_file']) ? $params['index_file'] : null; unset($params['index_file']);
return $this->Application->HREF($t, $prefix, $params, $index_file);
}
function Link($params)
{
if (isset($params['template'])) {
$params['t'] = $params['template'];
unset($params['template']);
}
if (!isset($params['pass']) && !isset($params['no_pass'])) $params['pass'] = 'm';
if (isset($params['no_pass'])) unset($params['no_pass']);
if ( $this->Application->GetVar('admin') ) {
$params['admin'] = 1;
if (!array_key_exists('editing_mode', $params)) {
$params['editing_mode'] = EDITING_MODE;
}
}
return $this->T($params);
}
function Env($params)
{
$t = $params['template'];
unset($params['template']);
return $this->Application->BuildEnv($t, $params, 'm', null, false);
}
function FormAction($params)
{
$params['pass'] = 'all,m';
$params['pass_category'] = 1;
return $this->Application->HREF('', '', $params);
}
/*// NEEDS TEST
function Config($params)
{
return $this->Application->ConfigOption($params['var']);
}
function Object($params)
{
$name = $params['name'];
$method = $params['method'];
$tmp =& $this->Application->recallObject($name);
if ($tmp != null) {
if (method_exists($tmp, $method))
return $tmp->$method($params);
else
echo "Method $method does not exist in object ".get_class($tmp)." named $name<br>";
}
else
echo "Object $name does not exist in the appliaction<br>";
}*/
/**
* Tag, that always returns true.
* For parser testing purposes
*
* @param Array $params
* @return bool
* @access public
*/
function True($params)
{
return true;
}
/**
* Tag, that always returns false.
* For parser testing purposes
*
* @param Array $params
* @return bool
* @access public
*/
function False($params)
{
return false;
}
/**
- * Returns block parameter by name
+ * Returns block parameter by name (used only as "check" parameter value for "m_if" tag !)
*
* @param Array $params
* @return stirng
* @access public
*/
function Param($params)
{
- //$parser =& $this->Application->recallObject('TemplateParser');
$name = $params['name'];
- if (isset($this->Application->LateParsed[$name])) {
+
+ /*if (isset($this->Application->LateParsed[$name])) {
$f = $this->Application->PreParsedBlocks['capture_'.$name.$this->Application->LateParsed[$name]];
$this->Application->Parser->SetParam($name, $f(array()));
- }
+ }*/
$res = $this->Application->Parser->GetParam($params['name']);
- if ($res === false) $res = '';
- if (isset($params['plus']))
- $res += $params['plus'];
- return $res;
- }
-
- function DefaultParam($params)
- {
- foreach ($params as $key => $val) {
- if ($this->Application->Parser->GetParam($key) === false) {
- $this->Application->Parser->SetParam($key, $val);
- }
+ if ($res === false) {
+ $res = '';
}
- }
-
- /**
- * Gets value of specified field from specified prefix_special and set it as parser param
- *
- * @param Array $params
- */
- /*function SetParam($params)
- {
- // <inp2:m_SetParam param="custom_name" src="cf:FieldName"/>
- list($prefix_special, $field_name) = explode(':', $params['src']);
- $object =& $this->Application->recallObject($prefix_special);
- $name = $this->SelectParam($params, 'param,name,var');
+ if (isset($params['plus'])) {
+ $res += $params['plus'];
+ }
- $this->Application->Parser->SetParam($name, $object->GetField($field_name) );
- }*/
+ return $res;
+ }
/**
* Compares block parameter with value specified
*
* @param Array $params
* @return bool
* @access public
*/
function ParamEquals($params)
{
- //$parser =& $this->Application->recallObject('TemplateParser');
$name = $this->SelectParam($params, 'name,var,param');
$value = $params['value'];
+
return ($this->Application->Parser->GetParam($name) == $value);
}
/*function PHP_Self($params)
{
return $HTTP_SERVER_VARS['PHP_SELF'];
}
*/
/**
* Returns session variable value by name
*
* @param Array $params
* @return string
* @access public
*/
function Recall($params)
{
$var_name = $this->SelectParam($params,'name,var,param');
if (isset($params['persistent']) && $params['persistent']) {
$ret = $this->Application->RecallPersistentVar($var_name);
}
else {
$ret = $this->Application->RecallVar($var_name);
}
$ret = ($ret === false && isset($params['no_null'])) ? '' : $ret;
if (getArrayValue($params, 'special') || getArrayValue($params, 'htmlchars')) {
$ret = htmlspecialchars($ret);
}
if (getArrayValue($params, 'urlencode')) {
$ret = urlencode($ret);
}
return $ret;
}
function RemoveVar($params)
{
$this->Application->RemoveVar( $this->SelectParam($params,'name,var,param') );
}
// bad style to store something from template to session !!! (by Alex)
// Used here only to test how session works, nothing more
function Store($params)
{
//echo"Store $params[name]<br>";
$name = $params['name'];
$value = $params['value'];
$this->Application->StoreVar($name,$value);
}
/**
* Sets application variable value(-s)
*
* @param Array $params
* @access public
*/
function Set($params)
{
foreach ($params as $param => $value) {
$this->Application->SetVar($param, $value);
}
}
/**
* Increment application variable
* specified by number specified
*
* @param Array $params
* @access public
*/
function Inc($params)
{
$this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']);
}
/**
* Retrieves application variable
* value by name
*
* @param Array $params
* @return string
* @access public
*/
function Get($params)
{
$ret = $this->Application->GetVar($this->SelectParam($params, 'name,var,param'), '');
return getArrayValue($params, 'htmlchars') ? htmlspecialchars($ret) : $ret;
}
/**
* Retrieves application constant
* value by name
*
* @param Array $params
* @return string
* @access public
*/
function GetConst($params)
{
- return defined($this->SelectParam($params, 'name,const')) ? constant($this->SelectParam($params, 'name,const,param')) : '';
+ $constant_name = $this->SelectParam($params, 'name,const');
+
+ return defined($constant_name) ? constant($constant_name) : '';
}
/**
* Retrieves configuration variable value by name
*
* @param Array $params
* @return string
* @access public
*/
function GetConfig($params)
{
$config_name = $this->SelectParam($params, 'name,var');
$ret = $this->Application->ConfigValue($config_name);
if( getArrayValue($params, 'escape') ) $ret = addslashes($ret);
return $ret;
}
function ConfigEquals($params)
{
$option = $this->SelectParam($params, 'name,option,var');
return $this->Application->ConfigValue($option) == getArrayValue($params, 'value');
}
/**
* Creates all hidden fields
* needed for kernel_form
*
* @param Array $params
* @return string
* @access public
*/
function DumpSystemInfo($params)
{
$actions =& $this->Application->recallObject('kActions');
$actions->Set('t', $this->Application->GetVar('t') );
$params = $actions->GetParams();
$o='';
foreach ($params AS $name => $val)
{
$o .= "<input type='hidden' name='$name' id='$name' value='$val'>\n";
}
return $o;
}
/**
* Used for search sidebox on front-end only
*
* @param Array $params
* @return string
* @author Alex
*/
function GetFormHiddens($params)
{
$t = $this->SelectParam($params, 'template,t');
unset($params['template']);
$form_fields = Array ();
if ($this->Application->RewriteURLs()) {
$session =& $this->Application->recallObject('Session');
if ($session->NeedQueryString()) {
$form_fields['sid'] = $this->Application->GetSID();
}
}
else {
$form_fields['env'] = $this->Application->BuildEnv($t, $params, 'm', null, false);
}
if ($this->Application->GetVar('admin') == 1) {
$form_fields['admin'] = 1;
}
$ret = '';
$field_tpl = '<input type="hidden" name="%1$s" id="%1$s" value="%2$s"/>'."\n";
foreach ($form_fields as $form_field => $field_value) {
$ret .= sprintf($field_tpl, $form_field, $field_value);
}
return $ret;
}
function Odd_Even($params)
{
$odd = $params['odd'];
$even = $params['even'];
if (!isset($params['var'])) {
$var = 'odd_even';
}
else {
$var = $params['var'];
}
if ($this->Application->GetVar($var) == 'even') {
if (!isset($params['readonly']) || !$params['readonly']) {
$this->Application->SetVar($var, 'odd');
}
return $even;
}
else {
if (!isset($params['readonly']) || !$params['readonly']) {
$this->Application->SetVar($var, 'even');
}
return $odd;
}
}
/**
* Returns phrase translation by name
*
* @param Array $params
* @return string
* @access public
*/
function Phrase($params)
{
// m:phrase name="phrase_name" default="Tr-alala" updated="2004-01-29 12:49"
$phrase_name = $this->SelectParam($params, 'label,name,title');
if (isset($params['source']) && $params['source']) {
$phrase_name = $this->Application->GetVar($phrase_name);
if (array_key_exists('default', $params) && !$phrase_name) {
$phrase_name = $params['default'];
}
}
$no_editing = array_key_exists('no_editing', $params) && $params['no_editing'];
$translation = $this->Application->Phrase($phrase_name, !$no_editing);
if (isset($params['escape']) && $params['escape']) {
$translation = htmlspecialchars($translation, ENT_QUOTES);
$translation = addslashes($translation);
}
return $translation;
}
// for tabs
function is_active($params)
{
$test_templ = $this->SelectParam($params, 'templ,template,t');
if ( !getArrayValue($params,'allow_empty') )
{
$if_true=getArrayValue($params,'true') ? $params['true'] : 1;
$if_false=getArrayValue($params,'false') ? $params['false'] : 0;
}
else
{
$if_true=$params['true'];
$if_false=$params['false'];
}
if ( preg_match("/^".str_replace('/', '\/', $test_templ)."/i", $this->Application->GetVar('t'))) {
return $if_true;
}
else {
return $if_false;
}
}
function IsNotActive($params)
{
return !$this->is_active($params);
}
function IsActive($params)
{
return $this->is_active($params);
}
function is_t_active($params)
{
return $this->is_active($params);
}
function CurrentTemplate($params)
{
return $this->is_active($params);
}
/**
* Checks if session variable
* specified by name value match
* value passed as parameter
*
* @param Array $params
* @return string
* @access public
*/
function RecallEquals($params)
{
$name = $this->SelectParam($params, 'name,var');
$value = $params['value'];
if (isset($params['persistent']) && $params['persistent']) {
return $this->Application->RecallPersistentVar($name) == $value;
}
return ($this->Application->RecallVar($name) == $value);
}
/**
* Checks if application variable
* specified by name value match
* value passed as parameter
*
* @param Array $params
* @return bool
* @access public
*/
function GetEquals($params)
{
$name = $this->SelectParam($params, 'var,name,param');
$value = $params['value'];
if ($this->Application->GetVar($name) == $value) {
return 1;
}
}
- /**
- * Includes template
- * and returns it's
- * parsed version
- *
- * @param Array $params
- * @return string
- * @access public
- */
- function MyInclude($params)
- {
- if (defined('NPARSER') && NPARSER) {
- return $this->Application->Parser->IncludeTemplate($params, isset($params['is_silent']) ? 1 : 0);
- }
-
- $BlockParser =& $this->Application->makeClass('TemplateParser');
- /* @var $BlockParser TemplateParser */
-
-// $BlockParser->SetParams($params);
- $parser =& $this->Application->Parser;
- $this->Application->Parser =& $BlockParser;
-
- // this is for the parser to know the master template in case an error occurs,
- // ParseTemplate will reset it anyway, but this will allow error handler to display the tempalte
- // which tries to include missing template for example
- $this->Application->Parser->TemplateName = $parser->TemplateName;
-
- $t = $this->SelectParam($params, 't,template,block,name');
- $t = eregi_replace("\.tpl$", '', $t);
-
- if (!$t) {
- trigger_error('Template name not specified in <b>&lt;inp2:m_include .../&gt;</b> tag', E_USER_ERROR);
- }
-
- if (isset($this->Application->PreParsedBlocks[$t]) ) {
- $params['name'] = $t;
- $res = $this->Application->ParseBlock($params);
- }
- else {
- $res = $BlockParser->ParseTemplate($t, 1, $params, isset($params['is_silent']) ? 1 : 0 );
- }
-
- if (!$BlockParser->DataExists && ((isset($params['data_exists']) && $params['data_exists']) || isset($params['block_no_data']))) {
- if ($block_no_data = getArrayValue($params, 'block_no_data')) {
- if (isset($this->Application->PreParsedBlocks[$block_no_data]) ) {
- // block_no_data is another block name
- $res = $this->Application->ParseBlock(Array('name' => $block_no_data));
- }
- else {
- // block_no_data is template name (only looks through real templates)
- $res = $BlockParser->ParseTemplate($block_no_data, 1, Array(), getArrayValue($params, 'is_silent'));
- }
- }
- else {
- $res = '';
- }
- }
-
- $this->Application->Parser =& $parser;
- $this->Application->Parser->DataExists = $this->Application->Parser->DataExists || $BlockParser->DataExists;
-
- if (isset($params['return_params']) && $params['return_params']) {
- $new_params = array_merge($this->Application->Parser->Params, $BlockParser->ParamsStack[0]);
- $this->Application->Parser->SetParams($new_params, false);
- }
-
- return $res;
- }
-
function ModuleInclude($params)
{
$ret = '';
$block_params = array_merge($params, Array('is_silent' => 2)); // don't make fatal errors in case if template is missing
$current_template = $this->Application->GetVar('t');
$replace_main = isset($params['replace_m']) && $params['replace_m'];
$skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array();
$cms_mode = $this->Application->GetVar('admin');
foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
$module_key = mb_strtolower($module_name);
if ($module_name == 'In-Portal') {
if (!$cms_mode && $this->Application->IsAdmin()) {
// don't process In-Portal templates in admin
continue;
}
// Front-End still relies on In-Portal module
$module_prefix = $module_data['TemplatePath'];
}
else {
$module_prefix = $this->Application->IsAdmin() ? $module_key.'/' : rtrim($module_data['TemplatePath'], '/').'/';
}
$block_params['t'] = $module_prefix.$this->SelectParam($params, $module_key.'_template,'.$module_key.'_t,template,t');
$check_prefix = $module_data['Var'];
if ($check_prefix == 'adm' && $replace_main) {
$check_prefix = 'c';
}
if ($block_params['t'] == $current_template || in_array($check_prefix, $skip_prefixes)) {
continue;
}
$no_data = $this->SelectParam($params, $module_key.'_block_no_data,block_no_data');
if ($no_data) {
$block_params['block_no_data'] = $module_prefix.'/'.$no_data;
}
- $ret .= $this->MyInclude($block_params);
+
+ $ret .= $this->Application->Parser->IncludeTemplate($block_params, isset($block_params['is_silent']) ? 1 : 0);
}
return $ret;
}
function ModuleEnabled($params)
{
return $this->Application->isModuleEnabled( $params['module'] );
}
- /*function Kernel_Scripts($params)
- {
- return '<script type="text/javascript" src="'.PROTOCOL.SERVER_NAME.BASE_PATH.'/kernel3/js/grid.js"></script>';
- }*/
-
-
- /*function GetUserPermission($params)
- {
- // echo"GetUserPermission $params[name]";
- if ($this->Application->RecallVar('user_type') == 1)
- return 1;
- else {
- $perm_name = $params[name];
- $aPermissions = unserialize($this->Application->RecallVar('user_permissions'));
- if ($aPermissions)
- return $aPermissions[$perm_name];
- }
- }*/
-
-
- /**
- * Set's parser block param value
- *
- * @param Array $params
- * @access public
- */
- function AddParam($params)
- {
- $parser =& $this->Application->Parser; // recallObject('TemplateParser');
- foreach ($params as $param => $value) {
- $this->Application->SetVar($param, $value);
- $parser->SetParam($param, $value);
- $parser->AddParam('/\$'.$param.'/', $value);
- }
- }
-
- /*function ParseToVar($params)
- {
- $var = $params['var'];
- $tagdata = $params['tag'];
- $parser =& $this->Application->Parser; //recallObject('TemplateParser');
- $res = $this->Application->ProcessTag($tagdata);
-
- $parser->SetParam($var, $res);
- $parser->AddParam('/\$'.$var.'/', $res);
- return '';
- }*/
-
- /*function TagNotEmpty($params)
- {
- $tagdata = $params['tag'];
- $res = $this->Application->ProcessTag($tagdata);
- return $res != '';
- }*/
-
- /*function TagEmpty($params)
- {
- return !$this->TagNotEmpty($params);
- }*/
-
/**
* Checks if debug mode is on
*
* @param Array $params
* @return bool
* @access public
*/
function IsDebugMode($params)
{
- return $this->Application->isDebugMode();
+ return defined('DEBUG_MODE') && $this->Application->isDebugMode();
}
- function MassParse($params)
+ /*function MassParse($params)
{
$qty = $params['qty'];
$block = $params['block'];
$mode = $params['mode'];
$o = '';
if ($mode == 'func') {
$func = create_function('$params', '
$o = \'<tr>\';
$o.= \'<td>a\'.$params[\'param1\'].\'</td>\';
$o.= \'<td>a\'.$params[\'param2\'].\'</td>\';
$o.= \'<td>a\'.$params[\'param3\'].\'</td>\';
$o.= \'<td>a\'.$params[\'param4\'].\'</td>\';
$o.= \'</tr>\';
return $o;
');
for ($i=1; $i<$qty; $i++) {
$block_params['param1'] = rand(1, 10000);
$block_params['param2'] = rand(1, 10000);
$block_params['param3'] = rand(1, 10000);
$block_params['param4'] = rand(1, 10000);
$o .= $func($block_params);
}
return $o;
}
$block_params['name'] = $block;
for ($i=0; $i<$qty; $i++) {
$block_params['param1'] = rand(1, 10000);
$block_params['param2'] = rand(1, 10000);
$block_params['param3'] = rand(1, 10000);
$block_params['param4'] = rand(1, 10000);
$block_params['passed'] = $params['passed'];
$block_params['prefix'] = 'm';
$o.= $this->Application->ParseBlock($block_params, 1);
}
return $o;
- }
+ }*/
function LoggedIn($params)
{
return $this->Application->LoggedIn();
}
/**
* Allows to check if permission exists directly in template and perform additional actions if required
*
* @param Array $params
* @return bool
*/
function CheckPermission($params)
{
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
return $perm_helper->TagPermissionCheck($params);
}
/**
* Checks if user is logged in and if not redirects it to template passed
*
* @param Array $params
*/
function RequireLogin($params)
{
$t = $this->Application->GetVar('t');
if ($next_t = getArrayValue($params, 'next_template')) {
$t = $next_t;
}
// check by permissions: begin
if ((isset($params['perm_event']) && $params['perm_event']) ||
(isset($params['perm_prefix']) && $params['perm_prefix']) ||
(isset($params['permissions']) && $params['permissions'])) {
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$perm_status = $perm_helper->TagPermissionCheck($params);
if (!$perm_status) {
list($redirect_template, $redirect_params) = $perm_helper->getPermissionTemplate($params);
$this->Application->Redirect($redirect_template, $redirect_params);
}
else {
return ;
}
}
// check by permissions: end
// check by configuration value: begin
$condition = getArrayValue($params, 'condition');
if (!$condition) {
$condition = true;
}
else {
if (substr($condition, 0, 1) == '!') {
$condition = !$this->Application->ConfigValue(substr($condition, 1));
}
else {
$condition = $this->Application->ConfigValue($condition);
}
}
// check by configuration value: end
// check by belonging to group: begin
$group = $this->SelectParam($params, 'group');
$group_access = true;
if ($group) {
$conn =& $this->Application->GetADODBConnection();
$group_id = $conn->GetOne('SELECT GroupId FROM '.TABLE_PREFIX.'PortalGroup WHERE Name = '.$conn->qstr($group));
if ($group_id) {
$groups = explode(',', $this->Application->RecallVar('UserGroups'));
$group_access = in_array($group_id, $groups);
}
}
// check by belonging to group: end
if ((!$this->Application->LoggedIn() || !$group_access) && $condition) {
$redirect_params = $this->Application->HttpQuery->getRedirectParams(true);
$redirect_params['next_template'] = $t;
if (array_key_exists('pass_category', $params)) {
$redirect_params['pass_category'] = $params['pass_category'];
}
if ( $this->Application->LoggedIn() && !$group_access) {
$this->Application->Redirect( $params['no_group_perm_template'], $redirect_params);
}
$this->Application->Redirect($params['login_template'], $redirect_params);
}
}
function IsMember($params)
{
$group = getArrayValue($params, 'group');
$conn =& $this->Application->DB;
$group_id = $conn->GetOne('SELECT GroupId FROM '.TABLE_PREFIX.'PortalGroup WHERE Name = '.$conn->qstr($group));
if ($group_id) {
$groups = explode(',', $this->Application->RecallVar('UserGroups'));
$group_access = in_array($group_id, $groups);
}
return $group_access;
}
/**
* Checks if SSL is on and redirects to SSL URL if needed
* If SSL_URL is not defined in config - the tag does not do anything
* If for_logged_in_only="1" exits if user is not logged in.
* If called without params forces https right away. If called with by_config="1" checks the
* Require SSL setting from General Config and if it is ON forces https
*
* @param unknown_type $params
*/
function CheckSSL($params)
{
$ssl = $this->Application->IsAdmin() ? $this->Application->ConfigValue('AdminSSL_URL') : false;
if (!$ssl) {
// not in admin or admin ssl url is empty
$ssl = $this->Application->ConfigValue('SSL_URL');
}
if (!$ssl) return; //SSL URL is not set - no way to require SSL
$require = false;
if (isset($params['mode']) && $params['mode'] == 'required') {
$require = true;
if (isset($params['for_logged_in_only']) && $params['for_logged_in_only'] && !$this->Application->LoggedIn()) {
$require = false;
}
if (isset($params['condition'])) {
if (!$this->Application->ConfigValue($params['condition'])) {
$require = false;
}
}
}
$http_query =& $this->Application->recallObject('HTTPQuery');
$pass = $http_query->getRedirectParams();
if ($require) {
if (PROTOCOL == 'https://') {
$this->Application->SetVar('__KEEP_SSL__', 1);
return;
}
$this->Application->Redirect('', array_merge_recursive2($pass, Array('__SSL__' => 1)));
}
else {
if (PROTOCOL == 'https://' && $this->Application->ConfigValue('Force_HTTP_When_SSL_Not_Required')) {
if ($this->Application->GetVar('__KEEP_SSL__')) return;
// $pass_more = Array ('pass' => 'm', 'm_cat_id' => 0, '__SSL__' => 0);
$this->Application->Redirect('', array_merge_recursive2($pass, Array('__SSL__' => 0))); // $pass_more
}
}
}
function ConstOn($params)
{
$name = $this->SelectParam($params,'name,const');
return constOn($name);
}
function SetDefaultCategory($params)
{
$category_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
$this->Application->SetVar('m_cat_id', $category_id);
}
function XMLTemplate($params)
{
safeDefine('DBG_SKIP_REPORTING', 1);
if (isset($params['cache']) && $params['cache']) {
$nextyear = intval(date('Y') + 1);
$format = "D, d M Y H:i:s";
$expiration = gmdate($format, mktime() + $params['cache']).' GMT';
$last_modified = mktime();
header ('Cache-Control: public, cache, max-age='.$params['cache']);
header ("Expires: $expiration");
header ('Pragma: public');
// Getting headers sent by the client.
$headers = request_headers();
// Checking if the client is validating his cache and if it is current.
if (isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) > $last_modified-$params['cache'])) {
// Client's cache IS current, so we just respond '304 Not Modified'.
header('Last-Modified: '.date($format, strtotime($headers['If-Modified-Since'])).' GMT', true, 304);
exit();
} else {
// Image not cached or cache outdated, we respond '200 OK' and output the image.
header('Last-Modified: '.gmdate($format, $last_modified).' GMT', true, 200);
}
}
// xml documents are usually long
set_time_limit(0);
ini_set('memory_limit', -1);
return $this->Application->XMLHeader(getArrayValue($params, 'xml_version'));
}
function Header($params)
{
header($params['data']);
}
function NoDebug($params)
{
if (!$this->Application->GetVar('debug')) {
define('DBG_SKIP_REPORTING', 1);
}
}
function RootCategoryName($params)
{
$root_phrase = $this->Application->ConfigValue('Root_Name');
return $this->Application->Phrase($root_phrase);
}
/**
* Allows to attach file directly from email event template
*
* @param Array $params
*/
function AttachFile($params)
{
$esender =& $application->recallObject('EmailSender'.(isset($params['special']) ? '.'.$params['special'] : ''));
/* @var $esender kEmailSendingHelper */
$path = FULL_PATH.'/'.$params['path'];
if (file_exists($path)) {
$esender->AddAttachment($path);
}
}
function CaptchaImage($params){
$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
/* @var $captcha_helper kCaptchaHelper */
$captcha_helper->GenerateCaptchaImage(
$this->Application->RecallVar($this->Application->GetVar('var')),
$this->Application->GetVar('w'),
$this->Application->GetVar('h'),
true
);
}
function SID($params)
{
return $this->Application->GetSID();
}
function ModuleInfo($params)
{
return $this->Application->findModule($params['key'], $params['value'], $params['return']);
}
function Random($params)
{
return rand(1, 100000000);
}
/**
* Prints parser params, available at current deep level
*
* @param Array $params
* @return string
*/
function PrintCurrentParams($params)
{
$current_params = $this->Application->Parser->Params;
foreach ($current_params as $param_name => $param_value) {
$current_params[$param_name] = $param_name . ' = "' . $param_value . '"';
}
return '<pre>' . implode("\n", $current_params) . '</pre>';
}
/**
* Gets previously defined counter result
*
* @param Array $params
* @return int
*/
function GetCounter($params)
{
return $this->Application->getCounter($params['name'], $params);
}
/**
* Increments PageHit counter
*
* @param Array $params
* @return int
*/
function RegisterPageHit($params)
{
if ($this->Application->ConfigValue('UsePageHitCounter')) {
$db =& $this->Application->GetADODBConnection();
// get current counte
$sql = 'SELECT VariableValue
FROM '.TABLE_PREFIX.'ConfigurationValues
WHERE VariableName = "PageHitCounter"';
$page_counter = (int)$db->GetOne($sql);
$sql = 'UPDATE LOW_PRIORITY '.TABLE_PREFIX.'ConfigurationValues
SET VariableValue = '.($page_counter + 1).'
WHERE VariableName = "PageHitCounter"';
$db->Query($sql);
}
}
function Timestamp($params)
{
$format = isset($params['format']) ? $params['format'] : 'd.m.Y H:i:s';
return adodb_date($format);
}
}
Index: branches/5.0.x/core/kernel/session/session.php
===================================================================
--- branches/5.0.x/core/kernel/session/session.php (revision 12322)
+++ branches/5.0.x/core/kernel/session/session.php (revision 12323)
@@ -1,1173 +1,1173 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/*
The session works the following way:
1. When a visitor loads a page from the site the script checks if cookies_on varibale has been passed to it as a cookie.
2. If it has been passed, the script tries to get Session ID (SID) from the request:
3. Depending on session mode the script is getting SID differently.
The following modes are available:
- AUTO
Automatic mode: if cookies are on at the client side, the script relays only on cookies and
ignore all other methods of passing SID. If cookies are off at the client side, the script relays on SID
passed through query string and referal passed by the client. THIS METHOD IS NOT 100% SECURE, as long as
attacker may get SID and substitude referal to gain access to user' session. One of the faults of this method
is that the session is only created when the visitor clicks the first link on the site, so there
is NO session at the first load of the page. (Actually there is a session, but it gets lost after
the first click because we do not use SID in query string while we are not sure if we need it)
- smCOOKIES_ONLY
Cookies only: in this mode the script relays solely on cookies passed from the browser and ignores
all other methods. In this mode there is no way to use sessions for clients without cookies support
or cookies support disabled. The cookies are stored with the full domain name and path to base-directory
of script installation.
- smGET_ONLY
GET only: the script will not set any cookies and will use only SID passed in query string using GET,
it will also check referal. The script will set SID at the first load of the page
- smCOOKIES_AND_GET
Combined mode: the script will use both cookies and GET right from the start. If client has cookies enabled,
the script will check SID stored in cookie and passed in query string, and will use this SID only if both
cookie and query string matches. However if cookies are disabled on the client side, the script will work
the same way as in GET_ONLY mode.
4. After the script has the SID it tries to load it from the Storage (default is database)
5. If such SID is found in the database, the script checks its expiration time. If session is not expired,
it updates its expiration, and resend the cookie (if applicable to session mode)
6. Then the script loads all the data (session variables) pertaining to the SID.
Usage:
$session = new Session(smAUTO); //smAUTO is default, you could just leave the brackets empty, or provide another mode
$session->SetCookieDomain('my.domain.com');
$session->SetCookiePath('/myscript');
$session->SetCookieName('my_sid_cookie');
$session->SetGETName('sid');
$session->InitSession();
...
//link output:
echo "<a href='index.php?'". ( $session->NeedQueryString() ? 'sid='.$session->SID : '' ) .">My Link</a>";
*/
/**
* Implements Session Store in the Database
*
*/
class SessionStorage extends kDBBase {
var $Expiration;
var $SessionTimeout=0;
var $DirectVars = Array();
var $ChangedDirectVars = Array();
var $PersistentVars = Array ();
var $OriginalData=Array();
var $TimestampField;
var $SessionDataTable;
var $DataValueField;
var $DataVarField;
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->setTableName('sessions');
$this->setIDField('sid');
$this->TimestampField = 'expire';
$this->SessionDataTable = 'SessionData';
$this->DataValueField = 'value';
$this->DataVarField = 'var';
}
function setSessionTimeout($new_timeout)
{
$this->SessionTimeout = $new_timeout;
}
function StoreSession(&$session, $additional_fields = Array())
{
if (defined('IS_INSTALL') && IS_INSTALL && !$this->Application->TableFound($this->TableName)) {
return false;
}
$fields_hash = Array (
$this->IDField => $session->SID,
$this->TimestampField => $session->Expiration
);
$fields_hash = array_merge($fields_hash, $additional_fields);
$this->Conn->doInsert($fields_hash, $this->TableName);
foreach ($additional_fields as $field_name => $field_value) {
$this->SetField($session, $field_name, $field_value);
}
}
function DeleteSession(&$session)
{
$query = ' DELETE FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
$query = ' DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
$this->OriginalData = Array();
}
function UpdateSession(&$session, $timeout=0)
{
$this->SetField($session, $this->TimestampField, $session->Expiration);
$query = ' UPDATE '.$this->TableName.' SET '.$this->TimestampField.' = '.$session->Expiration.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
}
function LocateSession($sid)
{
$query = ' SELECT * FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($sid);
$result = $this->Conn->GetRow($query);
if ($result === false) {
return false;
}
$this->DirectVars = $result;
$this->Expiration = $result[$this->TimestampField];
return true;
}
function GetExpiration()
{
return $this->Expiration;
}
function LoadData(&$session)
{
$query = 'SELECT '.$this->DataValueField.','.$this->DataVarField.' FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->OriginalData = $this->Conn->GetCol($query, $this->DataVarField);
return $this->OriginalData;
}
/**
* Enter description here...
*
* @param Session $session
* @param string $var_name
* @param mixed $default
*/
function GetField(&$session, $var_name, $default = false)
{
return isset($this->DirectVars[$var_name]) ? $this->DirectVars[$var_name] : $default;
//return $this->Conn->GetOne('SELECT '.$var_name.' FROM '.$this->TableName.' WHERE `'.$this->IDField.'` = '.$this->Conn->qstr($session->GetID()) );
}
function SetField(&$session, $var_name, $value)
{
$value_changed = !isset($this->DirectVars[$var_name]) || ($this->DirectVars[$var_name] != $value);
if ($value_changed) {
$this->DirectVars[$var_name] = $value;
$this->ChangedDirectVars[] = $var_name;
$this->ChangedDirectVars = array_unique($this->ChangedDirectVars);
}
//return $this->Conn->Query('UPDATE '.$this->TableName.' SET '.$var_name.' = '.$this->Conn->qstr($value).' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->GetID()) );
}
function SaveData(&$session)
{
if(!$session->SID) return false; // can't save without sid
$ses_data = $session->Data->GetParams();
$replace = '';
foreach ($ses_data as $key => $value)
{
if ( isset($this->OriginalData[$key]) && $this->OriginalData[$key] == $value)
{
continue; //skip unchanged session data
}
else
{
$replace .= sprintf("(%s, %s, %s),",
$this->Conn->qstr($session->SID),
$this->Conn->qstr($key),
$this->Conn->qstr($value));
}
}
$replace = rtrim($replace, ',');
if ($replace != '') {
$query = ' REPLACE INTO '.$this->SessionDataTable. ' ('.$this->IDField.', '.$this->DataVarField.', '.$this->DataValueField.') VALUES '.$replace;
$this->Conn->Query($query);
}
if ($this->ChangedDirectVars) {
$changes = array();
foreach ($this->ChangedDirectVars as $var) {
$changes[] = $var.' = '.$this->Conn->qstr($this->DirectVars[$var]);
}
$query = 'UPDATE '.$this->TableName.' SET '.implode(',', $changes).' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->GetID());
$this->Conn->Query($query);
}
}
function RemoveFromData(&$session, $var)
{
$query = 'DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID).
' AND '.$this->DataVarField.' = '.$this->Conn->qstr($var);
$this->Conn->Query($query);
unset($this->OriginalData[$var]);
}
function GetFromData(&$session, $var)
{
return getArrayValue($this->OriginalData, $var);
}
function GetExpiredSIDs()
{
$query = ' SELECT '.$this->IDField.' FROM '.$this->TableName.' WHERE '.$this->TimestampField.' > '.adodb_mktime();
return $this->Conn->GetCol($query);
}
function DeleteExpired()
{
$expired_sids = $this->GetExpiredSIDs();
if ($expired_sids) {
$sessionlog_table = $this->Application->getUnitOption('session-log', 'TableName');
$session_log_sql =
' UPDATE '.$sessionlog_table.'
SET Status = 2, SessionEnd =
( SELECT '.$this->TimestampField.' - '.$this->SessionTimeout.'
FROM '.$this->TableName.'
WHERE '.$this->IDField.' = '.$sessionlog_table.'.SessionId
)
WHERE Status = 0 AND SessionId IN ('.join(',', $expired_sids).')';
if ($sessionlog_table) {
$this->Conn->Query($session_log_sql);
}
$where_clause = ' WHERE '.$this->IDField.' IN ("'.implode('","',$expired_sids).'")';
$sql = 'DELETE FROM '.$this->SessionDataTable.$where_clause;
$this->Conn->Query($sql);
$sql = 'DELETE FROM '.$this->TableName.$where_clause;
$this->Conn->Query($sql);
// delete debugger ouputs left of expired sessions
foreach ($expired_sids as $expired_sid) {
$debug_file = WRITEABLE . '/cache/debug_@' . $expired_sid . '@.txt';
if (file_exists($debug_file)) {
@unlink($debug_file);
}
}
}
return $expired_sids;
}
function LoadPersistentVars(&$session)
{
$user_id = $session->RecallVar('user_id');
if ($user_id != -2) {
// root & normal users
$sql = 'SELECT VariableValue, VariableName
FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE PortalUserId = '.$user_id;
$this->PersistentVars = $this->Conn->GetCol($sql, 'VariableName');
}
else {
$this->PersistentVars = Array ();
}
}
/**
* Stores variable to persistent session
*
* @param Session $session
* @param string $var_name
* @param mixed $var_value
*/
function StorePersistentVar(&$session, $var_name, $var_value)
{
$user_id = $session->RecallVar('user_id');
if ($user_id == -2 || $user_id === false) {
// -2 (when not logged in), false (when after u:OnLogout event)
$session->StoreVar($var_name, $var_value);
return ;
}
$this->PersistentVars[$var_name] = $var_value;
$key_clause = 'PortalUserId = '.$user_id.' AND VariableName = '.$this->Conn->qstr($var_name);
$sql = 'SELECT VariableName
FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE '.$key_clause;
$record_found = $this->Conn->GetOne($sql);
$fields_hash = Array (
'PortalUserId' => $user_id,
'VariableName' => $var_name,
'VariableValue' => $var_value,
);
if ($record_found) {
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'PersistantSessionData', $key_clause);
}
else {
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'PersistantSessionData');
}
}
/**
* Gets persistent variable
*
* @param Session $session
* @param string $var_name
* @param mixed $default
* @return mixed
*/
function RecallPersistentVar(&$session, $var_name, $default = false)
{
if ($session->RecallVar('user_id') == -2) {
if ($default == ALLOW_DEFAULT_SETTINGS) {
$default = null;
}
return $session->RecallVar($var_name, $default);
}
if (array_key_exists($var_name, $this->PersistentVars)) {
return $this->PersistentVars[$var_name];
}
elseif ($default == ALLOW_DEFAULT_SETTINGS) {
$default_user_id = $this->Application->ConfigValue('DefaultSettingsUserId');
if (!$default_user_id) {
$default_user_id = -1;
}
$sql = 'SELECT VariableValue, VariableName
FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE VariableName = '.$this->Conn->qstr($var_name).' AND PortalUserId = '.$default_user_id;
$value = $this->Conn->GetOne($sql);
$this->PersistentVars[$var_name] = $value;
if ($value !== false) {
$this->StorePersistentVar($session, $var_name, $value); //storing it, so next time we don't load default user setting
}
return $value;
}
else {
return $default;
}
}
function RemovePersistentVar(&$session, $var_name)
{
unset($this->PersistentVars[$var_name]);
$user_id = $session->RecallVar('user_id');
if ($user_id != -2) {
$sql = 'DELETE FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE PortalUserId = '.$user_id.' AND VariableName = '.$this->Conn->qstr($var_name);
$this->Conn->Query($sql);
}
}
}
define('smAUTO', 1);
define('smCOOKIES_ONLY', 2);
define('smGET_ONLY', 3);
define('smCOOKIES_AND_GET', 4);
class Session extends kBase {
var $Checkers;
var $Mode;
var $OriginalMode = null;
var $GETName = 'sid';
var $CookiesEnabled = true;
var $CookieName = 'sid';
var $CookieDomain;
var $CookiePath;
var $CookieSecure = 0;
var $SessionTimeout = 3600;
var $Expiration;
var $SID;
var $CachedSID;
var $SessionSet = false;
/**
* Enter description here...
*
* @var SessionStorage
*/
var $Storage;
var $CachedNeedQueryString = null;
/**
* Session Data array
*
* @var Params
*/
var $Data;
/**
* Names of optional session keys (which does not need to be always stored
*
* @var array
*/
var $OptionalData = array();
function Session($mode=smAUTO)
{
parent::kBase();
$this->SetMode($mode);
}
function SetMode($mode)
{
$this->Mode = $mode;
$this->CachedNeedQueryString = null;
$this->CachedSID = null;
}
function SetCookiePath($path)
{
$this->CookiePath = str_replace(' ', '%20', $path);
}
/**
* Setting cookie domain. Set false for local domains, because they don't contain dots in their names.
*
* @param string $domain
*/
function SetCookieDomain($domain)
{
$this->CookieDomain = substr_count($domain, '.') ? '.'.ltrim($domain, '.') : false;
}
function SetGETName($get_name)
{
$this->GETName = $get_name;
}
function SetCookieName($cookie_name)
{
$this->CookieName = $cookie_name;
}
function InitStorage($special)
{
$this->Storage =& $this->Application->recallObject('SessionStorage.'.$special);
$this->Storage->setSessionTimeout($this->SessionTimeout);
}
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->CheckIfCookiesAreOn();
if ($this->CookiesEnabled) $_COOKIE['cookies_on'] = 1;
$this->Checkers = Array();
$this->InitStorage($special);
$this->Data = new Params();
$tmp_sid = $this->GetPassedSIDValue();
$check = $this->Check();
if ($this->Application->IsAdmin()) {
// 1. Front-End session may not be created (SID is present, but no data in database).
// Check expiration LATER from kApplication::Init, because template, used in session
// expiration redirect should be retrieved from mod-rewrite url first.
// 2. Admin sessions are always created, so case when SID is present,
// but session in database isn't is 100% session expired. Check expiration
// HERE because Session::SetSession will create missing session in database
// and when Session::ValidateExpired will be called later from kApplication::Init
// it won't consider such session as expired !!!
$this->ValidateExpired();
}
if ($check) {
$this->SID = $this->GetPassedSIDValue();
$this->Refresh();
$this->LoadData();
}
else {
$this->SetSession();
}
if (!is_null($this->OriginalMode)) $this->SetMode($this->OriginalMode);
}
function ValidateExpired()
{
if (defined('IS_INSTALL') && IS_INSTALL) {
return ;
}
$expired_sids = $this->DeleteExpired();
$my_sid_expired = in_array($this->CachedSID, $expired_sids);
if ( ($expired_sids && $my_sid_expired) || ($this->CachedSID && !$this->SessionSet) ) {
$this->RemoveSessionCookie();
// true was here to force new session creation, but I (kostja) used
// RemoveCookie a line above, to avoid redirect loop with expired sid
// not being removed setSession with true was used before, to set NEW
// session cookie
$this->SetSession();
// case #1: I've OR other site visitor expired my session
// case #2: I have no session in database, but SID is present
$expire_event = new kEvent('u:OnSessionExpire');
$this->Application->HandleEvent($expire_event);
}
}
function IsHTTPSRedirect()
{
$http_referer = getArrayValue($_SERVER, 'HTTP_REFERER');
return (
( PROTOCOL == 'https://' && preg_match('#http:\/\/#', $http_referer) )
||
( PROTOCOL == 'http://' && preg_match('#https:\/\/#', $http_referer) )
);
}
function CheckReferer($for_cookies=0)
{
if (!$for_cookies) {
if ( !$this->Application->ConfigValue('SessionReferrerCheck') || $_SERVER['REQUEST_METHOD'] != 'POST') {
return true;
}
}
$path = preg_replace('/admin[\/]{0,1}$/', '', $this->CookiePath); // removing /admin for compatability with in-portal (in-link/admin/add_link.php)
$reg = '#^'.preg_quote(PROTOCOL.ltrim($this->CookieDomain, '.').$path).'#';
return preg_match($reg, getArrayValue($_SERVER, 'HTTP_REFERER') ) || (defined('IS_POPUP') && IS_POPUP);
}
/*function CheckDuplicateCookies()
{
if (isset($_SERVER['HTTP_COOKIE'])) {
$cookie_str = $_SERVER['HTTP_COOKIE'];
$cookies = explode('; ', $cookie_str);
$all_cookies = array();
foreach ($cookies as $cookie) {
list($name, $value) = explode('=', $cookie);
if (isset($all_cookies[$name])) {
//double cookie name!!!
$this->RemoveCookie($name);
}
else $all_cookies[$name] = $value;
}
}
}
function RemoveCookie($name)
{
$path = $_SERVER['PHP_SELF'];
$path_parts = explode('/', $path);
$cur_path = '';
setcookie($name, false, null, $cur_path);
foreach ($path_parts as $part) {
$cur_path .= $part;
setcookie($name, false, null, $cur_path);
$cur_path .= '/';
setcookie($name, false, null, $cur_path);
}
}*/
function CheckIfCookiesAreOn()
{
// $this->CheckDuplicateCookies();
if ($this->Mode == smGET_ONLY)
{
//we don't need to bother checking if we would not use it
$this->CookiesEnabled = false;
return;
}
$http_query =& $this->Application->recallObject('HTTPQuery');
$cookies_on = isset($http_query->Cookie['cookies_on']); // not good here
$get_sid = getArrayValue($http_query->Get, $this->GETName);
if ($this->IsHTTPSRedirect() && $get_sid) { //Redirect from http to https on different domain
$this->OriginalMode = $this->Mode;
$this->SetMode(smGET_ONLY);
}
if (!$cookies_on || $this->IsHTTPSRedirect()) {
//If referer is our server, but we don't have our cookies_on, it's definetly off
$is_install = defined('IS_INSTALL') && IS_INSTALL;
if (!$is_install && $this->CheckReferer(1) && !$this->Application->GetVar('admin') && !$this->IsHTTPSRedirect()) {
$this->CookiesEnabled = false;
}
else {
//Otherwise we still suppose cookies are on, because may be it's the first time user visits the site
//So we send cookies on to get it next time (when referal will tell us if they are realy off
$this->SetCookie('cookies_on', 1, adodb_mktime() + 31104000); //one year should be enough
}
}
else
$this->CookiesEnabled = true;
return $this->CookiesEnabled;
}
/**
* Sets cookie for current site using path and domain
*
* @param string $name
* @param mixed $value
* @param int $expires
*/
function SetCookie($name, $value, $expires = null)
{
setcookie($name, $value, $expires, $this->CookiePath, $this->CookieDomain, $this->CookieSecure);
}
function Check()
{
// we should check referer if cookies are disabled, and in combined mode
// auto mode would detect cookies, get only mode would turn it off - so we would get here
// and we don't care about referal in cookies only mode
if ( $this->Mode != smCOOKIES_ONLY && (!$this->CookiesEnabled || $this->Mode == smCOOKIES_AND_GET) ) {
if (!$this->CheckReferer())
return false;
}
$sid = $this->GetPassedSIDValue();
if (empty($sid)) return false;
//try to load session by sid, if everything is fine
$result = $this->LoadSession($sid);
$this->SessionSet = $result;
return $result;
}
function LoadSession($sid)
{
if( $this->Storage->LocateSession($sid) ) {
//if we have session with such SID - get its expiration
$this->Expiration = $this->Storage->GetExpiration();
//If session has expired
if ($this->Expiration < adodb_mktime()) {
$this->Destroy();
// when Destory methods calls SetSession inside and new session get created
return $this->SessionSet;
}
//Otherwise it's ok
return true;
}
else //fake or deleted due to expiration SID
return false;
}
function GetPassedSIDValue($use_cache = 1)
{
if (!empty($this->CachedSID) && $use_cache) return $this->CachedSID;
$http_query =& $this->Application->recallObject('HTTPQuery');
$get_sid = getArrayValue($http_query->Get, $this->GETName);
if ($this->Application->GetVar('admin') == 1 && $get_sid) {
$sid = $get_sid;
}
else {
switch ($this->Mode) {
case smAUTO:
//Cookies has the priority - we ignore everything else
$sid = $this->CookiesEnabled ? $this->GetSessionCookie() : $get_sid;
break;
case smCOOKIES_ONLY:
$sid = $this->GetSessionCookie();
break;
case smGET_ONLY:
$sid = $get_sid;
break;
case smCOOKIES_AND_GET:
$cookie_sid = $this->GetSessionCookie();
//both sids should match if cookies are enabled
if (!$this->CookiesEnabled || ($cookie_sid == $get_sid))
{
$sid = $get_sid; //we use get here just in case cookies are disabled
}
else
{
$sid = '';
}
break;
}
}
$this->CachedSID = $sid;
return $this->CachedSID;
}
/**
* Returns session id
*
* @return int
* @access public
*/
function GetID()
{
return $this->SID;
}
/**
* Generates new session id
*
* @return int
* @access private
*/
function GenerateSID()
{
list($usec, $sec) = explode(" ",microtime());
$sid_part_1 = substr($usec, 4, 4);
$sid_part_2 = mt_rand(1,9);
$sid_part_3 = substr($sec, 6, 4);
$digit_one = substr($sid_part_1, 0, 1);
if ($digit_one == 0) {
$digit_one = mt_rand(1,9);
$sid_part_1 = ereg_replace("^0","",$sid_part_1);
$sid_part_1=$digit_one.$sid_part_1;
}
$this->setSID($sid_part_1.$sid_part_2.$sid_part_3);
return $this->SID;
}
/**
* Set's new session id
*
* @param int $new_sid
* @access private
*/
function setSID($new_sid)
{
$this->SID = $this->CachedSID = $new_sid;
$this->Application->SetVar($this->GETName,$new_sid);
}
function NeedSession()
{
$data = $this->Data->GetParams();
$data_keys = array_keys($data);
$optional_keys = array_unique($this->OptionalData);
$real_keys = array_diff($data_keys, $optional_keys);
return $real_keys ? true : false;
}
function SetSession($force = false)
{
if ($this->SessionSet && !$force) return true;
if (!$force && !($this->Application->IsAdmin() || $this->Application->GetVar('admin')) && !$this->NeedSession()) {
// don't create session (in db) on Front-End, when sid is present (GPC), but data in db isn't
$this->GenerateSID();
return false;
}
if (!$this->SID || $force) $this->GenerateSID();
$this->Expiration = adodb_mktime() + $this->SessionTimeout;
switch ($this->Mode) {
case smAUTO:
if ($this->CookiesEnabled) {
$this->SetSessionCookie();
}
break;
case smGET_ONLY:
break;
case smCOOKIES_ONLY:
case smCOOKIES_AND_GET:
$this->SetSessionCookie();
break;
}
$this->Storage->StoreSession($this);
if ($this->Application->IsAdmin() || $this->Special == 'admin') {
$this->StoreVar('admin', 1);
}
$this->SessionSet = true; // should be called before SaveData, because SaveData will try to SetSession again
if ($this->Special != '') {
// front-session called from admin or otherwise, then save it's data
$this->SaveData();
}
$this->Application->resetCounters('UserSession');
return true;
}
/**
* Returns SID from cookie.
*
* Use 2 cookies to have 2 expiration:
* - 1. for normal expiration when browser is not closed (30 minutes by default), configurable
* - 2. for advanced expiration when browser is closed
*
* @return int
*/
function GetSessionCookie()
{
$keep_session_on_browser_close = $this->Application->ConfigValue('KeepSessionOnBrowserClose');
if (isset($this->Application->HttpQuery->Cookie[$this->CookieName]) &&
( $keep_session_on_browser_close ||
(
!$keep_session_on_browser_close &&
isset($this->Application->HttpQuery->Cookie[$this->CookieName.'_live'])
&&
$this->Application->HttpQuery->Cookie[$this->CookieName] == $this->Application->HttpQuery->Cookie[$this->CookieName.'_live']
)
)
) {
return $this->Application->HttpQuery->Cookie[$this->CookieName];
}
return false;
}
/**
* Updates SID in cookie with new value
*
*/
function SetSessionCookie()
{
$this->SetCookie($this->CookieName, $this->SID, $this->Expiration);
$this->SetCookie($this->CookieName.'_live', $this->SID);
$_COOKIE[$this->CookieName] = $this->SID; // for compatibility with in-portal
}
function RemoveSessionCookie()
{
$this->SetCookie($this->CookieName, '');
$this->SetCookie($this->CookieName.'_live', '');
$_COOKIE[$this->CookieName] = null; // for compatibility with in-portal
}
/**
* Refreshes session expiration time
*
* @access private
*/
function Refresh()
{
if ($this->Application->GetVar('skip_session_refresh')) {
return ;
}
if ($this->CookiesEnabled) {
// we need to refresh the cookie
$this->SetSessionCookie();
}
$this->Storage->UpdateSession($this);
}
function Destroy()
{
$this->Storage->DeleteSession($this);
$this->Data = new Params();
$this->SID = $this->CachedSID = '';
$this->SessionSet = false;
if ($this->CookiesEnabled) $this->SetSessionCookie(); //will remove the cookie due to value (sid) is empty
$this->SetSession(true); //will create a new session, true to force
}
function NeedQueryString($use_cache = 1)
{
if ($this->CachedNeedQueryString != null && $use_cache) return $this->CachedNeedQueryString;
$result = false;
switch ($this->Mode)
{
case smAUTO:
if (!$this->CookiesEnabled) $result = true;
break;
/*case smCOOKIES_ONLY:
break;*/
case smGET_ONLY:
case smCOOKIES_AND_GET:
$result = true;
break;
}
$this->CachedNeedQueryString = $result;
return $result;
}
function LoadData()
{
$this->Data->AddParams($this->Storage->LoadData($this));
}
function PrintSession($comment='')
{
- if($this->Application->isDebugMode() && constOn('DBG_SHOW_SESSIONDATA')) {
+ if (defined('DEBUG_MODE') && $this->Application->isDebugMode() && constOn('DBG_SHOW_SESSIONDATA')) {
// dump session data
$this->Application->Debugger->appendHTML('SessionStorage [' . ($this->RecallVar('admin') == 1 ? 'Admin' : 'Front-End') . '] ('.$comment.'):');
$session_data = $this->Data->GetParams();
ksort($session_data);
foreach ($session_data as $session_key => $session_value) {
if (IsSerialized($session_value)) {
$session_data[$session_key] = unserialize($session_value);
}
}
$this->Application->Debugger->dumpVars($session_data);
}
- if ($this->Application->isDebugMode() && constOn('DBG_SHOW_PERSISTENTDATA')) {
+ if (defined('DEBUG_MODE') && $this->Application->isDebugMode() && constOn('DBG_SHOW_PERSISTENTDATA')) {
// dump persistent session data
if ($this->Storage->PersistentVars) {
$this->Application->Debugger->appendHTML('Persistant Session:');
$session_data = $this->Storage->PersistentVars;
ksort($session_data);
foreach ($session_data as $session_key => $session_value) {
if (IsSerialized($session_value)) {
$session_data[$session_key] = unserialize($session_value);
}
}
$this->Application->Debugger->dumpVars($session_data);
}
}
}
function SaveData($params = Array ())
{
if (!$this->SetSession()) { // call it here - it may be not set before, because there was no need; if there is a need, it will be set here
return;
}
if (!$this->Application->GetVar('skip_last_template') && $this->Application->GetVar('ajax') != 'yes') {
$this->SaveLastTemplate( $this->Application->GetVar('t'), $params );
}
$this->PrintSession('after save');
$this->Storage->SaveData($this);
}
/**
* Save last template
*
* @param string $t
* @param Array $params
*/
function SaveLastTemplate($t, $params = Array ())
{
$wid = $this->Application->GetVar('m_wid');
$last_env = $this->getLastTemplateENV($t, Array('m_opener' => 'u'));
$last_template = basename($_SERVER['PHP_SELF']).'|'.mb_substr($last_env, mb_strlen(ENV_VAR_NAME) + 1);
$this->StoreVar(rtrim('last_template_'.$wid, '_'), $last_template);
// prepare last_template for opener stack, module & session could be added later
$last_env = $this->getLastTemplateENV($t, null, false);
$last_template = basename($_SERVER['PHP_SELF']).'|'.mb_substr($last_env, mb_strlen(ENV_VAR_NAME) + 1);
// save last_template in persistant session
if (!$wid) {
if ($this->Application->IsAdmin()) {
// only for main window, not popups, not login template, not temp mode (used in adm:MainFrameLink tag)
$temp_mode = false;
$passed = explode(',', $this->Application->GetVar('passed'));
foreach ($passed as $passed_prefix) {
if ($this->Application->GetVar($passed_prefix.'_mode')) {
$temp_mode = true;
break;
}
}
if (!$temp_mode) {
if (isset($this->Application->HttpQuery->Get['section'])) {
// check directly in GET, bacause LinkVar (session -> request) used on these vars
$last_template .= '&section='.$this->Application->GetVar('section').'&module='.$this->Application->GetVar('module');
}
$this->StorePersistentVar('last_template_popup', $last_template);
}
}
elseif ($this->Application->GetVar('admin')) {
// admin checking by session data to prevent recursive session save
if (!$this->RecallVar('admin')) {
$admin_session =& $this->Application->recallObject('Session.admin');
/* @var $admin_session Session */
// save to admin last_template too, because when F5 is pressed in frameset Front-End frame should reload as well
$admin_session->StoreVar('last_template_popup', '../' . $last_template);
$admin_session->StorePersistentVar('last_template_popup', '../' . $last_template);
$admin_session->SaveData( Array ('save_last_template' => false) );
}
else {
// don't allow admin=1 & editing_mode=* to get in admin last_template
$last_template = preg_replace('/&(admin|editing_mode)=[\d]/', '', $last_template);
}
}
}
// save other last... variables for mistical purposes (customizations may be)
$this->StoreVar('last_url', $_SERVER['REQUEST_URI']); // needed by ord:StoreContinueShoppingLink
$this->StoreVar('last_env', mb_substr($last_env, mb_strlen(ENV_VAR_NAME)+1));
$save_last_template = array_key_exists('save_last_template', $params) ? $params['save_last_template'] : true;
if ($save_last_template) {
// save last template here, becase section & module could be added before
$this->StoreVar(rtrim('last_template_popup_'.$wid, '_'), $last_template);
}
}
function getLastTemplateENV($t, $params = null, $encode = true)
{
if (!isset($params)) {
$params = Array ();
}
$params['__URLENCODE__'] = 1; // uses "&" instead of "&amp;" for url part concatenation + replaces "\" to "%5C" (works in HTML)
$params = array_merge($this->Application->getPassThroughVariables($params), $params);
$ret = $this->Application->BuildEnv($t, $params, 'all');
if (!$encode) {
// cancels 2nd part of replacements, that URLENCODE does
$ret = str_replace('%5C', '\\', $ret);
}
return $ret;
}
function StoreVar($name, $value, $optional = false)
{
$this->Data->Set($name, $value);
if ($optional) {
$this->OptionalData[] = $name;
}
}
function StorePersistentVar($name, $value)
{
$this->Storage->StorePersistentVar($this, $name, $value);
}
function LoadPersistentVars()
{
$this->Storage->LoadPersistentVars($this);
}
function StoreVarDefault($name, $value, $optional=false)
{
$tmp = $this->RecallVar($name);
if($tmp === false || $tmp == '')
{
$this->StoreVar($name, $value, $optional);
}
}
function RecallVar($name, $default = false)
{
$ret = $this->Data->Get($name);
return ($ret === false) ? $default : $ret;
}
function RecallPersistentVar($name, $default = false)
{
return $this->Storage->RecallPersistentVar($this, $name, $default);
}
function RemoveVar($name)
{
$this->Storage->RemoveFromData($this, $name);
$this->Data->Remove($name);
}
function RemovePersistentVar($name)
{
return $this->Storage->RemovePersistentVar($this, $name);
}
/**
* Ignores session varible value set before
*
* @param string $name
*/
function RestoreVar($name)
{
return $this->StoreVar($name, $this->Storage->GetFromData($this, $name));
}
function GetField($var_name, $default = false)
{
return $this->Storage->GetField($this, $var_name, $default);
}
function SetField($var_name, $value)
{
$this->Storage->SetField($this, $var_name, $value);
}
/**
* Deletes expired sessions
*
* @return Array expired sids if any
* @access private
*/
function DeleteExpired()
{
return $this->Storage->DeleteExpired();
}
/**
* Allows to check if user in this session is logged in or not
*
* @return bool
*/
function LoggedIn()
{
$user_id = $this->RecallVar('user_id');
$ret = $user_id > 0;
if (($this->RecallVar('admin') == 1 || defined('ADMIN')) && ($user_id == -1)) {
$ret = true;
}
return $ret;
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/utility/debugger.php
===================================================================
--- branches/5.0.x/core/kernel/utility/debugger.php (revision 12322)
+++ branches/5.0.x/core/kernel/utility/debugger.php (revision 12323)
@@ -1,1475 +1,1475 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
if( !class_exists('Debugger') ) {
class Debugger {
/**
* Holds reference to global KernelApplication instance
*
* @access public
* @var kApplication
*/
var $Application = null;
/**
* Set to true if fatal error occured
*
* @var bool
*/
var $IsFatalError = false;
/**
* Allows to track compile errors, like "stack-overflow"
*
* @var bool
*/
var $_compileError = false;
/**
* Debugger data for building report
*
* @var Array
*/
var $Data = Array();
var $ProfilerData = Array();
var $ProfilerTotals = Array();
var $ProfilerTotalCount = Array();
var $ProfilePoints = Array();
/**
* Prevent recursion when processing debug_backtrace() function results
*
* @var Array
*/
var $RecursionStack = Array();
var $scrollbarWidth = 0;
/**
* Long errors are saved here, because trigger_error doesn't support error messages over 1KB in size
*
* @var Array
*/
var $longErrors = Array();
var $IncludesData = Array();
var $IncludeLevel = 0;
var $reportDone = false;
/**
* Transparent spacer image used in case of none spacer image defined via SPACER_URL contant.
* Used while drawing progress bars (memory usage, time usage, etc.)
*
* @var string
*/
var $dummyImage = '';
/**
* Temporary files created by debugger will be stored here
*
* @var string
*/
var $tempFolder = '';
/**
* Debug rows will be separated using this string before writing to debug file
*
* @var string
*/
var $rowSeparator = '@@';
/**
* Base URL for debugger includes
*
* @var string
*/
var $baseURL = '';
/**
* Holds last recorded timestamp (for appendTimestamp)
*
* @var int
*/
var $LastMoment;
/**
* Determines, that current request is AJAX request
*
* @var bool
*/
var $_isAjax = false;
function Debugger()
{
global $start, $dbg_options;
// check if user haven't defined DEBUG_MODE contant directly
if (defined('DEBUG_MODE') && DEBUG_MODE) {
die('error: contant DEBUG_MODE defined directly, please use <strong>$dbg_options</strong> array instead');
}
// check IP before enabling debug mode
$ip_match = $this->ipMatch(isset($dbg_options['DBG_IP']) ? $dbg_options['DBG_IP'] : '');
if (!$ip_match) {
define('DEBUG_MODE', 0);
return ;
}
// debug is allowed for user, continue initialization
$this->InitDebugger();
$this->profileStart('kernel4_startup', 'Startup and Initialization of kernel4', $start);
$this->profileStart('script_runtime', 'Script runtime', $start);
$this->LastMoment = $start;
error_reporting(E_ALL);
ini_set('display_errors', $this->constOn('DBG_ZEND_PRESENT') ? 0 : 1); // show errors on screen in case if not in Zend Studio debugging
$this->scrollbarWidth = $this->isGecko() ? 22 : 25; // vertical scrollbar width differs in Firefox and other browsers
$this->appendRequest();
}
/**
* Checks, that user IP address is within allowed range
*
* @param string $ip_list semi-column (by default) separated ip address list
* @param string $separator ip address separator (default ";")
*
* @return bool
*/
function ipMatch($ip_list, $separator = ';')
{
$ip_match = false;
$ip_addresses = $ip_list ? explode($separator, $ip_list) : Array ();
foreach ($ip_addresses as $ip_address) {
if ($this->netMatch($ip_address, $_SERVER['REMOTE_ADDR'])) {
$ip_match = true;
break;
}
}
return $ip_match;
}
/**
* Set's default values to constants debugger uses
*
*/
function InitDebugger()
{
global $dbg_options;
unset($_REQUEST['debug_host'], $_REQUEST['debug_fastfile'], $_REQUEST['debug_session_id'], $_REQUEST['debug_start_session'], $dbg_options['DBG_IP']); // this var messed up whole detection stuff :(
// Detect fact, that this session beeing debugged by Zend Studio
foreach ($_REQUEST as $rq_name => $rq_value) {
if (substr($rq_name, 0, 6) == 'debug_') {
$this->safeDefine('DBG_ZEND_PRESENT', 1);
break;
}
}
$this->safeDefine('DBG_ZEND_PRESENT', 0); // set this constant value to 0 (zero) to debug debugger using Zend Studio
// set default values for debugger constants
$dbg_constMap = Array (
'DBG_USE_HIGHLIGHT' => 1, // highlight output same as php code using "highlight_string" function
'DBG_WINDOW_WIDTH' => 700, // set width of debugger window (in pixels) for better viewing large amount of debug data
'DBG_USE_SHUTDOWN_FUNC' => DBG_ZEND_PRESENT ? 0 : 1, // use shutdown function to include debugger code into output
'DBG_HANDLE_ERRORS' => DBG_ZEND_PRESENT ? 0 : 1, // handle all allowed by php (see php manual) errors instead of default handler
'DBG_IGNORE_STRICT_ERRORS' => 1, // ignore PHP5 errors about private/public view modified missing in class declarations
'DBG_DOMVIEWER' => '/temp/domviewer.html', // path to DOMViewer on website
'DOC_ROOT' => str_replace('\\', '/', realpath($_SERVER['DOCUMENT_ROOT']) ), // windows hack
'DBG_LOCAL_BASE_PATH' => 'w:', // replace DOC_ROOT in filenames (in errors) using this path
);
// only for IE, in case if no windows php script editor defined
if (!defined('DBG_EDITOR')) {
// $dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\UltraEdit\uedit32.exe %F/%L';
$dbg_constMap['DBG_EDITOR'] = 'c:\Program Files\Zend\ZendStudio-5.2.0\bin\ZDE.exe %F';
}
// debugger is initialized before kHTTPQuery, so do jQuery headers check here too
if (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
$this->_isAjax = true;
}
elseif (array_key_exists('ajax', $_GET) && $_GET['ajax'] == 'yes') {
$this->_isAjax = true;
}
// user defined options override debugger defaults
$dbg_constMap = $this->array_merge_recursive2($dbg_constMap, $dbg_options);
if ($this->_isAjax && array_key_exists('DBG_SKIP_AJAX', $dbg_constMap) && $dbg_constMap['DBG_SKIP_AJAX']) {
$dbg_constMap['DBG_SKIP_REPORTING'] = 1;
}
// when validation configs, don't show sqls for better validation error displaying
if (array_key_exists('DBG_VALIDATE_CONFIGS', $dbg_constMap) && $dbg_constMap['DBG_VALIDATE_CONFIGS']) {
$dbg_constMap['DBG_SQL_PROFILE'] = 0;
}
// when showing explain make shure, that debugger window is large enough
if (array_key_exists('DBG_SQL_EXPLAIN', $dbg_constMap) && $dbg_constMap['DBG_SQL_EXPLAIN']) {
$dbg_constMap['DBG_WINDOW_WIDTH'] = 1000;
}
foreach ($dbg_constMap as $dbg_constName => $dbg_constValue) {
$this->safeDefine($dbg_constName, $dbg_constValue);
}
}
function constOn($const_name)
{
return defined($const_name) && constant($const_name);
}
function safeDefine($const_name, $const_value) {
if (!defined($const_name)) {
define($const_name, $const_value);
}
}
function array_merge_recursive2($paArray1, $paArray2)
{
if (!is_array($paArray1) or !is_array($paArray2)) {
return $paArray2;
}
foreach ($paArray2 AS $sKey2 => $sValue2) {
$paArray1[$sKey2] = isset($paArray1[$sKey2]) ? array_merge_recursive2($paArray1[$sKey2], $sValue2) : $sValue2;
}
return $paArray1;
}
function netMatch($network, $ip) {
$network = trim($network);
$ip = trim($ip);
if ($network == $ip) {
// comparing two ip addresses directly
return true;
}
$d = strpos($network, '-');
if ($d !== false) {
// ip address range specified
$from = ip2long(trim(substr($network, 0, $d)));
$to = ip2long(trim(substr($network, $d + 1)));
$ip = ip2long($ip);
return ($ip >= $from && $ip <= $to);
}
elseif (strpos($network, '/') !== false) {
// sigle subnet specified
$ip_arr = explode('/', $network);
if (!preg_match("@\d*\.\d*\.\d*\.\d*@", $ip_arr[0], $matches)) {
$ip_arr[0] .= '.0'; // Alternate form 194.1.4/24
}
$network_long = ip2long($ip_arr[0]);
$x = ip2long($ip_arr[1]);
$mask = long2ip($x) == $ip_arr[1] ? $x : (0xffffffff << (32 - $ip_arr[1]));
$ip_long = ip2long($ip);
return ($ip_long & $mask) == ($network_long & $mask);
}
return false;
}
function InitReport()
{
if (!class_exists('kApplication')) return false;
$application =& kApplication::Instance();
// string used to separate debugger records while in file (used in debugger dump filename too)
$this->rowSeparator = '@'.(is_object($application->Factory) ? $application->GetSID() : 0).'@';
// $this->rowSeparator = '@'.rand(0,100000).'@';
// include debugger files from this url
$reg_exp = '/^'.preg_quote(FULL_PATH, '/').'/';
$kernel_path = preg_replace($reg_exp, '', KERNEL_PATH, 1);
$this->baseURL = PROTOCOL.SERVER_NAME.rtrim(BASE_PATH, '/').$kernel_path.'/utility/debugger';
// save debug output in this folder
$this->tempFolder = WRITEABLE . '/cache';
}
function mapLongError($msg)
{
$key = $this->generateID();
$this->longErrors[$key] = $msg;
return $key;
}
/**
* Appends all passed variable values (wihout variable names) to debug output
*
*/
function dumpVars()
{
$dump_mode = 'var_dump';
$dumpVars = func_get_args();
if ($dumpVars[count($dumpVars) - 1] === 'STRICT') {
$dump_mode = 'strict_var_dump';
array_pop($dumpVars);
}
foreach ($dumpVars as $varValue) {
$this->Data[] = Array('value' => $varValue, 'debug_type' => $dump_mode);
}
}
function prepareHTML($dataIndex)
{
$Data =& $this->Data[$dataIndex];
if ($Data['debug_type'] == 'html') {
return $Data['html'];
}
switch ($Data['debug_type']) {
case 'error':
$fileLink = $this->getFileLink($Data['file'], $Data['line']);
$ret = '<b class="debug_error">'.$this->getErrorNameByCode($Data['no']).'</b>: '.$Data['str'];
$ret .= ' in <b>'.$fileLink.'</b> on line <b>'.$Data['line'].'</b>';
return $ret;
break;
case 'var_dump':
return $this->highlightString( $this->print_r($Data['value'], true) );
break;
case 'strict_var_dump':
return $this->highlightString( var_export($Data['value'], true) );
break;
case 'trace':
ini_set('memory_limit', '500M');
$trace =& $Data['trace'];
$i = 0; $traceCount = count($trace);
$ret = '';
while ($i < $traceCount) {
$traceRec =& $trace[$i];
$argsID = 'trace_args_'.$dataIndex.'_'.$i;
$has_args = isset($traceRec['args']);
if (isset($traceRec['file'])) {
$func_name = isset($traceRec['class']) ? $traceRec['class'].$traceRec['type'].$traceRec['function'] : $traceRec['function'];
$args_link = $has_args ? '<a href="javascript:$Debugger.ToggleTraceArgs(\''.$argsID.'\');" title="Show/Hide Function Arguments"><b>Function</b></a>' : '<b>Function</b>';
$ret .= $args_link.': '.$this->getFileLink($traceRec['file'], $traceRec['line'], $func_name);
$ret .= ' in <b>'.basename($traceRec['file']).'</b> on line <b>'.$traceRec['line'].'</b><br>';
}
else {
$ret .= 'no file information available';
}
if ($has_args) {
// if parameter value is longer then 200 symbols, then leave only first 50
$args = $this->highlightString($this->print_r($traceRec['args'], true));
$ret .= '<div id="'.$argsID.'" style="display: none;">'.$args.'</div>';
}
$i++;
}
return $ret;
break;
case 'profiler':
$profileKey = $Data['profile_key'];
$Data =& $this->ProfilerData[$profileKey];
$runtime = ($Data['ends'] - $Data['begins']); // in seconds
$totals_key = getArrayValue($Data, 'totalsKey');
if ($totals_key) {
$total_before = $Data['totalsBefore'];
$total = $this->ProfilerTotals[$totals_key];
$div_width = Array();
$total_width = ($this->getWindowWidth() - 10);
$div_width['before'] = round(($total_before / $total) * $total_width);
$div_width['current'] = round(($runtime / $total) * $total_width);
$div_width['left'] = round((($total - $total_before - $runtime) / $total) * $total_width);
$ret = '<b>Name</b>: '.$Data['description'].'<br />';
$additional = isset($Data['additional']) ? $Data['additional'] : Array ();
if (isset($Data['file'])) {
array_unshift($additional, Array('name' => 'File', 'value' => $this->getFileLink($Data['file'], $Data['line'], basename($Data['file']).':'.$Data['line'])));
}
array_unshift($additional, Array('name' => 'Runtime', 'value' => $runtime.'s'));
$ret .= '<div>'; //FF 3.5 needs this!
foreach ($additional as $mixed_param) {
$ret .= '[<strong>'.$mixed_param['name'].'</strong>: '.$mixed_param['value'].'] ';
}
/*if (isset($Data['file'])) {
$ret .= '[<b>Runtime</b>: '.$runtime.'s] [<b>File</b>: '.$this->getFileLink($Data['file'], $Data['line'], basename($Data['file']).':'.$Data['line']).']<br />';
}
else {
$ret .= '<b>Runtime</b>: '.$runtime.'s<br />';
}*/
$ret .= '</div>';
$ret .= '<div class="dbg_profiler" style="width: '.$div_width['before'].'px; border-right: 0px; background-color: #298DDF;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
$ret .= '<div class="dbg_profiler" style="width: '.$div_width['current'].'px; border-left: 0px; border-right: 0px; background-color: #EF4A4A;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
$ret .= '<div class="dbg_profiler" style="width: '.$div_width['left'].'px; border-left: 0px; background-color: #DFDFDF;"><img src="'.$this->dummyImage.'" width="1" height="1"/></div>';
return $ret;
}
else {
return '<b>Name</b>: '.$Data['description'].'<br><b>Runtime</b>: '.$runtime.'s';
}
break;
default:
return 'incorrect debug data';
break;
}
}
function getWindowWidth()
{
return DBG_WINDOW_WIDTH - $this->scrollbarWidth - 8;
}
/**
* Tells debugger to skip objects that are heavy in plan of memory usage while printing debug_backtrace results
*
* @param Object $object
* @return bool
*/
function IsBigObject(&$object)
{
$skip_classes = Array(
defined('APPLICATION_CLASS') ? APPLICATION_CLASS : 'kApplication',
'kFactory',
'kUnitConfigReader',
- 'TemplateParser',
+ 'NParser',
);
foreach ($skip_classes as $class_name) {
if (strtolower(get_class($object)) == strtolower($class_name)) {
return true;
}
}
return false;
}
/**
* Advanced version of print_r (for debugger only). Don't print objects recursively
*
* @param Array $array
* @param bool $return_output return output or print it out
* @param int $tab_count offset in tabs
* @return string
*/
function print_r(&$array, $return_output = false, $tab_count = -1)
{
static $first_line = true;
// not an array at all
if (!is_array($array)) {
switch (gettype($array)) {
case 'NULL':
return 'NULL'."\n";
break;
case 'object':
return $this->processObject($array, $tab_count);
break;
default:
// number or string
if (strlen($array) > 200) {
$array = substr($array, 0, 50).' ...';
}
return $array."\n";
break;
}
}
$output = '';
$tab_count++;
$output .= "Array\n".str_repeat(' ', $tab_count)."(\n";
$tab_count++;
$tabsign = $tab_count ? str_repeat(' ', $tab_count) : '';
$array_keys = array_keys($array);
foreach ($array_keys as $key) {
switch (gettype($array[$key])) {
case 'array':
$output .= $tabsign.'['.$key.'] = '.$this->print_r($array[$key], true, $tab_count);
break;
case 'boolean':
$output .= $tabsign.'['.$key.'] = '.($array[$key] ? 'true' : 'false')."\n";
break;
case 'integer':
case 'double':
case 'string':
if (strlen($array[$key]) > 200) {
$array[$key] = substr($array[$key], 0, 50).' ...';
}
$output .= $tabsign.'['.$key.'] = '.$array[$key]."\n";
break;
case 'NULL':
$output .= $tabsign.'['.$key."] = NULL\n";
break;
case 'object':
$output .= $tabsign.'['.$key."] = ";
$output .= "Object (".get_class($array[$key]).") = \n".str_repeat(' ', $tab_count + 1)."(\n";
$output .= $this->processObject($array[$key], $tab_count + 2);
$output .= str_repeat(' ', $tab_count + 1).")\n";
break;
default:
$output .= $tabsign.'['.$key.'] unknown = '.gettype($array[$key])."\n";
break;
}
}
$tab_count--;
$output .= str_repeat(' ', $tab_count).")\n";
if ($first_line) {
$first_line = false;
$output .= "\n";
}
$tab_count--;
if ($return_output) {
return $output;
}
else {
echo $output;
}
return true;
}
function processObject(&$object, $tab_count)
{
$object_class = get_class($object);
if (!in_array($object_class, $this->RecursionStack)) {
if ($this->IsBigObject($object)) {
return 'SKIPPED (class: '.$object_class.")\n";
}
$attribute_names = get_class_vars($object_class);
if (!$attribute_names) {
return "NO_ATTRIBUTES\n";
}
else {
$output = '';
array_push($this->RecursionStack, $object_class);
$tabsign = $tab_count ? str_repeat(' ', $tab_count) : '';
foreach ($attribute_names as $attribute_name => $attribute_value) {
if (is_object($object->$attribute_name)) {
// it is object
$output .= $tabsign.'['.$attribute_name.'] = '.$this->processObject($object->$attribute_name, $tab_count + 1);
}
else {
$output .= $tabsign.'['.$attribute_name.'] = '.$this->print_r($object->$attribute_name, true, $tab_count);
}
}
array_pop($this->RecursionStack);
return $output;
}
}
else {
// object [in recursion stack]
return '*** RECURSION *** (class: '.$object_class.")\n";
}
}
/**
* Format SQL Query using predefined formatting
* and highlighting techniques
*
* @param string $sql
* @return string
*/
function formatSQL($sql)
{
$sql = trim( preg_replace('/(\n|\t| )+/is', ' ', $sql) );
// whitespace in the beginning of the regex is to avoid splitting inside words, for exmaple "FROM int_ConfigurationValues" into "FROM intConfiguration\n\tValues"
$formatted_sql = preg_replace('/\s(CREATE TABLE|DROP TABLE|SELECT|UPDATE|SET|REPLACE|INSERT|DELETE|VALUES|FROM|LEFT JOIN|INNER JOIN|LIMIT|WHERE|HAVING|GROUP BY|ORDER BY)\s/is', "\n\t$1 ", ' ' . $sql);
$formatted_sql = $this->highlightString($formatted_sql);
if (defined('DBG_SQL_EXPLAIN') && DBG_SQL_EXPLAIN) {
if (substr($sql, 0, 6) == 'SELECT') {
$formatted_sql .= '<br/>' . '<strong>Explain</strong>:<br /><br />';
$explain_result = $this->Application->Conn->Query('EXPLAIN ' . $sql, null, true);
$explain_table = '';
foreach ($explain_result as $explain_row) {
if (!$explain_table) {
// first row -> draw header
$explain_table .= '<tr class="explain_header"><td>' . implode('</td><td>', array_keys($explain_row)) . '</td></tr>';
}
$explain_table .= '<tr><td>' . implode('</td><td>', $explain_row) . '</td></tr>';
}
$formatted_sql .= '<table class="dbg_explain_table">' . $explain_table . '</table>';
}
}
return $formatted_sql;
}
function highlightString($string)
{
if (!(defined('DBG_USE_HIGHLIGHT') && DBG_USE_HIGHLIGHT) || $this->_compileError) {
return nl2br($string);
}
$string = str_replace( Array('\\', '/') , Array('_no_match_string_', '_n_m_s_'), $string);
$this->_compileError = true; // next line is possible cause of compile error
$string = highlight_string('<?php '.$string.' ?>', true);
$this->_compileError = false;
$string = str_replace( Array('_no_match_string_', '_n_m_s_'), Array('\\', '/'), $string);
if (strlen($string) >= 65536) {
// preg_replace will fail, when string is longer, then 65KB
return str_replace(Array ('&lt;?php&nbsp;', '?&gt;'), '', $string);
}
return preg_replace('/&lt;\?(.*)php&nbsp;(.*)\?&gt;/Us', '\\2', $string);
}
/**
* Determine by php type of browser used to show debugger
*
* @return bool
*/
function isGecko()
{
// we need isset because we may run scripts from shell with no user_agent at all
return isset($_SERVER['HTTP_USER_AGENT']) && strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'firefox') !== false;
}
/**
* Returns link for editing php file (from error) in external editor
*
* @param string $file filename with path from root folder
* @param int $lineno line number in file where error is found
* @param string $title text to show on file edit link
* @return string
*/
function getFileLink($file, $lineno = 1, $title = '')
{
if (!$title) {
$title = str_replace('/', '\\', $this->getLocalFile($file));
}
if ($this->isGecko()) {
return '<a href="file://'.$this->getLocalFile($file).'">'.$title.'</a>';
}
else {
return '<a href="javascript:$Debugger.editFile(\''.$this->getLocalFile($file).'\', '.$lineno.');" title="'.$file.'">'.$title.'</a>';
}
}
/**
* Converts filepath on server to filepath in mapped DocumentRoot on developer pc
*
* @param string $remoteFile
* @return string
*/
function getLocalFile($remoteFile)
{
return preg_replace('/^'.preg_quote(DOC_ROOT, '/').'/', DBG_LOCAL_BASE_PATH, $remoteFile, 1);
}
/**
* Appends call trace till this method call
*
*/
function appendTrace()
{
$trace = debug_backtrace();
array_shift($trace);
$this->Data[] = Array('trace' => $trace, 'debug_type' => 'trace');
}
function appendMemoryUsage($msg, $used = null)
{
if (!isset($used)) {
$used = round(memory_get_usage() / 1024);
}
$this->appendHTML('<b>Memory usage</b> '.$msg.' '.$used.'Kb');
}
/**
* Appends HTML code whithout transformations
*
* @param string $html
*/
function appendHTML($html)
{
$this->Data[] = Array('html' => $html, 'debug_type' => 'html');
}
/**
* Change debugger info that was already generated before.
* Returns true if html was set.
*
* @param int $index
* @param string $html
* @param string $type = {'append','prepend','replace'}
* @return bool
*/
function setHTMLByIndex($index, $html, $type = 'append')
{
if (!isset($this->Data[$index]) || $this->Data[$index]['debug_type'] != 'html') {
return false;
}
switch ($type) {
case 'append':
$this->Data[$index]['html'] .= '<br>'.$html;
break;
case 'prepend':
$this->Data[$index]['html'] = $this->Data[$index]['html'].'<br>'.$html;
break;
case 'replace':
$this->Data[$index]['html'] = $html;
break;
}
return true;
}
/**
* Move $debugLineCount lines of input from debug output
* end to beginning.
*
* @param int $debugLineCount
*/
function moveToBegin($debugLineCount)
{
$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
$this->Data = array_merge($lines,$this->Data);
}
function moveAfterRow($new_row, $debugLineCount)
{
$lines = array_splice($this->Data,count($this->Data)-$debugLineCount,$debugLineCount);
$rows_before = array_splice($this->Data,0,$new_row,$lines);
$this->Data = array_merge($rows_before,$this->Data);
}
function appendRequest()
{
if (isset($_SERVER['SCRIPT_FILENAME'])) {
$script = $_SERVER['SCRIPT_FILENAME'];
}
else {
$script = $_SERVER['DOCUMENT_ROOT'].$_SERVER['PHP_SELF'];
}
$this->appendHTML('ScriptName: <b>'.$this->getFileLink($script, 1, basename($script)).'</b> (<b>'.dirname($script).'</b>)');
if ($this->_isAjax) {
$this->appendHTML('RequestURI: '.$_SERVER['REQUEST_URI'].' (QS Length:'.strlen($_SERVER['QUERY_STRING']).')');
}
$tools_html = ' <table style="width: ' . $this->getWindowWidth() . 'px;">
<tr>
<td>' . $this->_getDomViewerHTML() . '</td>
<td>' . $this->_getToolsHTML() . '</td>
</tr>
</table>';
$this->appendHTML($tools_html);
ob_start();
?>
<table border="0" cellspacing="0" cellpadding="0" class="dbg_flat_table" style="width: <?php echo $this->getWindowWidth(); ?>px;">
<thead style="font-weight: bold;">
<td width="20">Src</td><td>Name</td><td>Value</td>
</thead>
<?php
foreach ($_REQUEST as $key => $value) {
if(!is_array($value) && trim($value) == '') {
$value = '<b class="debug_error">no value</b>';
}
else {
$value = htmlspecialchars($this->print_r($value, true));
}
$in_cookie = isset($_COOKIE[$key]);
$src = isset($_GET[$key]) && !$in_cookie ? 'GE' : (isset($_POST[$key]) && !$in_cookie ? 'PO' : ($in_cookie ? 'CO' : '?') );
echo '<tr><td>'.$src.'</td><td>'.$key.'</td><td>'.$value.'</td></tr>';
}
?>
</table>
<?php
$this->appendHTML(ob_get_contents());
ob_end_clean();
}
/**
* Appends php session content to debugger output
*
*/
function appendSession()
{
if (isset($_SESSION) && $_SESSION) {
$this->appendHTML('PHP Session: [<b>'.ini_get('session.name').'</b>]');
$this->dumpVars($_SESSION);
$this->moveToBegin(2);
}
}
function profileStart($key, $description = null, $timeStamp = null)
{
if (!isset($timeStamp)) {
$timeStamp = $this->getMoment();
}
$this->ProfilerData[$key] = Array('begins' => $timeStamp, 'ends' => 5000, 'debuggerRowID' => count($this->Data));
if (isset($description)) {
$this->ProfilerData[$key]['description'] = $description;
}
if (substr($key, 0, 4) == 'sql_') {
// append place from what was called
$trace_results = debug_backtrace();
$trace_count = count($trace_results);
$i = 0;
while ($i < $trace_count) {
$trace_file = basename($trace_results[$i]['file']);
if ($trace_file != 'db_connection.php' && $trace_file != 'adodb.inc.php') {
break;
}
$i++;
}
$this->ProfilerData[$key]['file'] = $trace_results[$i]['file'];
$this->ProfilerData[$key]['line'] = $trace_results[$i]['line'];
unset($trace_results);
}
$this->Data[] = Array('profile_key' => $key, 'debug_type' => 'profiler');
}
function profileFinish($key, $description = null, $timeStamp = null)
{
if (!isset($timeStamp)) {
$timeStamp = $this->getMoment();
}
$this->ProfilerData[$key]['ends'] = $timeStamp;
if (isset($description)) {
$this->ProfilerData[$key]['description'] = $description;
}
if (substr($key, 0, 4) == 'sql_') {
$func_arguments = func_get_args();
$rows_affected = $func_arguments[3];
$additional = Array ();
if ($rows_affected > 0) {
$additional[] = Array ('name' => 'Affected Rows', 'value' => $rows_affected);
if (isset($func_arguments[4])) {
if (strlen($func_arguments[4]) > 200) {
$func_arguments[4] = substr($func_arguments[4], 0, 50) . ' ...';
}
$additional[] = Array ('name' => 'Result', 'value' => $func_arguments[4]);
}
}
$additional[] = Array ('name' => 'Query Number', 'value' => $func_arguments[5]);
$this->ProfilerData[$key]['additional'] =& $additional;
}
}
function profilerAddTotal($total_key, $key = null, $value = null)
{
if (!isset($this->ProfilerTotals[$total_key])) {
$this->ProfilerTotals[$total_key] = 0;
$this->ProfilerTotalCount[$total_key] = 0;
}
if (!isset($value)) {
$value = $this->ProfilerData[$key]['ends'] - $this->ProfilerData[$key]['begins'];
}
if (isset($key)) {
$this->ProfilerData[$key]['totalsKey'] = $total_key;
$this->ProfilerData[$key]['totalsBefore'] = $this->ProfilerTotals[$total_key];
}
$this->ProfilerTotals[$total_key] += $value;
$this->ProfilerTotalCount[$total_key]++;
}
function getMoment()
{
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
function appendTimestamp($message)
{
global $start;
$time = $this->getMoment();
$from_last = $time - $this->LastMoment;
$from_start = $time - $start;
$this->appendHTML(sprintf("<b>%s</b> %.5f from last %.5f from start", $message, $from_last, $from_start));
$this->LastMoment = $time;
}
function generateID()
{
list($usec, $sec) = explode(' ', microtime());
$id_part_1 = substr($usec, 4, 4);
$id_part_2 = mt_rand(1,9);
$id_part_3 = substr($sec, 6, 4);
$digit_one = substr($id_part_1, 0, 1);
if ($digit_one == 0) {
$digit_one = mt_rand(1,9);
$id_part_1 = ereg_replace("^0",'',$id_part_1);
$id_part_1=$digit_one.$id_part_1;
}
return $id_part_1.$id_part_2.$id_part_3;
}
function getErrorNameByCode($error_code)
{
$error_map = Array(
'Fatal Error' => Array(E_USER_ERROR),
'Warning' => Array(E_WARNING, E_USER_WARNING),
'Notice' => Array(E_NOTICE, E_USER_NOTICE),
);
if (defined('E_STRICT')) {
$error_map['PHP5 Strict'] = Array(E_STRICT);
}
if (defined('E_RECOVERABLE_ERROR')) {
$error_map['Fatal Error (recoverable)'] = Array(E_RECOVERABLE_ERROR);
}
foreach ($error_map as $error_name => $error_codes) {
if (in_array($error_code, $error_codes)) {
return $error_name;
}
}
return '';
}
/**
* Returns profile total key (check against unexisting key too)
*
* @param string $key
* @return int
*/
function getProfilerTotal($key)
{
if (isset($this->ProfilerTotalCount[$key])) {
return (int)$this->ProfilerTotalCount[$key];
}
return 0;
}
function ProfilePoint($title, $level=1)
{
$trace_results = debug_backtrace();
$level = min($level,count($trace_results)-1);
do {
$point = $trace_results[$level];
$location = $point['file'].':'.$point['line'];
$level++;
$has_more = isset($trace_results[$level]);
} while ($has_more && $point['function'] == $trace_results[$level]['function'] );
if (!isset($this->ProfilePoints[$title])) {
$this->ProfilePoints[$title] = array();
}
if (!isset($this->ProfilePoints[$title][$location])) {
$this->ProfilePoints[$title][$location] = 0;
}
$this->ProfilePoints[$title][$location]++;
}
/**
* Generates report
*
*/
function printReport($returnResult = false, $clean_output_buffer = true)
{
if ($this->reportDone) {
// don't print same report twice (in case if shutdown function used + compression + fatal error)
return '';
}
$this->profileFinish('script_runtime');
$this->breakOutofBuffering(!$returnResult);
$debugger_start = memory_get_usage();
if (defined('SPACER_URL')) {
$this->dummyImage = SPACER_URL;
}
$this->InitReport(); // set parameters required by AJAX
// defined here, because user can define this contant while script is running, not event before debugger is started
$this->safeDefine('DBG_RAISE_ON_WARNINGS', 0);
$this->safeDefine('DBG_TOOLBAR_BUTTONS', 1);
$this->appendSession(); // show php session if any
// ensure, that 1st line of debug output always is this one:
$top_line = '<table cellspacing="0" cellpadding="0" style="width: '.$this->getWindowWidth().'px; margin: 0px;"><tr><td align="left" width="50%">[<a href="javascript:window.location.reload();">Reload Frame</a>] [<a href="javascript:$Debugger.Toggle(27);">Hide Debugger</a>] [<a href="javascript:$Debugger.Clear();">Clear Debugger</a>]</td><td align="right" width="50%">[Current Time: <b>'.date('H:i:s').'</b>] [File Size: <b>#DBG_FILESIZE#</b>]</td></tr></table>';
$this->appendHTML($top_line);
$this->moveToBegin(1);
if (count($this->ProfilePoints)>0) {
foreach($this->ProfilePoints as $point => $locations) {
arsort($this->ProfilePoints[$point]);
}
$this->appendHTML($this->highlightString($this->print_r($this->ProfilePoints, true)));
/*foreach ($this->ProfilePoints as $point => $locations) {
foreach ($locations as $location => $occurences) {
}
}*/
}
if ($this->constOn('DBG_SQL_PROFILE') && isset($this->ProfilerTotals['sql'])) {
// sql query profiling was enabled -> show totals
$this->appendHTML('<b>SQL Total time:</b> '.$this->ProfilerTotals['sql'].' <b>Number of queries</b>: '.$this->ProfilerTotalCount['sql']);
}
if ($this->constOn('DBG_PROFILE_INCLUDES') && isset($this->ProfilerTotals['includes'])) {
// included file profiling was enabled -> show totals
$this->appendHTML('<b>Included Files Total time:</b> '.$this->ProfilerTotals['includes'].' Number of includes: '.$this->ProfilerTotalCount['includes']);
}
if ($this->constOn('DBG_PROFILE_MEMORY')) {
// detailed memory usage reporting by objects was enabled -> show totals
$this->appendHTML('<b>Memory used by Objects:</b> '.round($this->ProfilerTotals['objects'] / 1024, 2).'Kb');
}
if ($this->constOn('DBG_INCLUDED_FILES')) {
$files = get_included_files();
$this->appendHTML('<b>Included files:</b>');
foreach ($files as $file) {
$this->appendHTML($this->getFileLink($this->getLocalFile($file)).' ('.round(filesize($file) / 1024, 2).'Kb)');
}
}
if ($this->constOn('DBG_PROFILE_INCLUDES')) {
$this->appendHTML('<b>Included files statistics:</b>'.( $this->constOn('DBG_SORT_INCLUDES_MEM') ? ' (sorted by memory usage)':''));
$totals = Array( 'mem' => 0, 'time' => 0);
$totals_configs = Array( 'mem' => 0, 'time' => 0);
if (is_array($this->IncludesData['mem'])) {
if ( $this->constOn('DBG_SORT_INCLUDES_MEM') ) {
array_multisort($this->IncludesData['mem'], SORT_DESC, $this->IncludesData['file'], $this->IncludesData['time'], $this->IncludesData['level']);
}
foreach ($this->IncludesData['file'] as $key => $file_name) {
$this->appendHTML( str_repeat('&nbsp;->&nbsp;', ($this->IncludesData['level'][$key] >= 0 ? $this->IncludesData['level'][$key] : 0)).$file_name.' Mem: '.sprintf("%.4f Kb", $this->IncludesData['mem'][$key]/1024).' Time: '.sprintf("%.4f", $this->IncludesData['time'][$key]));
if ($this->IncludesData['level'][$key] == 0) {
$totals['mem'] += $this->IncludesData['mem'][$key];
$totals['time'] += $this->IncludesData['time'][$key];
}
else if ($this->IncludesData['level'][$key] == -1) {
$totals_configs['mem'] += $this->IncludesData['mem'][$key];
$totals_configs['time'] += $this->IncludesData['time'][$key];
}
}
$this->appendHTML('<b>Sub-Total classes:</b> '.' Mem: '.sprintf("%.4f Kb", $totals['mem']/1024).' Time: '.sprintf("%.4f", $totals['time']));
$this->appendHTML('<b>Sub-Total configs:</b> '.' Mem: '.sprintf("%.4f Kb", $totals_configs['mem']/1024).' Time: '.sprintf("%.4f", $totals_configs['time']));
$this->appendHTML('<span class="error"><b>Grand Total:</b></span> '.' Mem: '.sprintf("%.4f Kb", ($totals['mem']+$totals_configs['mem'])/1024).' Time: '.sprintf("%.4f", $totals['time']+$totals_configs['time']));
}
}
$skip_reporting = $this->constOn('DBG_SKIP_REPORTING') || $this->constOn('DBG_ZEND_PRESENT');
if (($this->_isAjax && !$this->constOn('DBG_SKIP_AJAX')) || !$skip_reporting) {
$debug_file = $this->tempFolder.'/debug_'.$this->rowSeparator.'.txt';
if (file_exists($debug_file)) unlink($debug_file);
$i = 0;
$fp = fopen($debug_file, 'a');
$lineCount = count($this->Data);
while ($i < $lineCount) {
fwrite($fp, $this->prepareHTML($i).$this->rowSeparator);
$i++;
}
fclose($fp);
}
if ($skip_reporting) {
// let debugger write report and then don't output anything
$this->reportDone = true;
return '';
}
$application =& kApplication::Instance();
$dbg_path = str_replace(FULL_PATH, '', $this->tempFolder);
ob_start();
// the <script .. /script> and hidden div helps browser to break out of script tag or attribute esacped
// with " or ' in case fatal error (or user-error) occurs inside it in compiled template,
// otherwise it has no effect
?>
<div style="display: none" x='nothing'><script></script></div><html><body></body></html>
<script type="text/javascript" src="<?php echo $this->baseURL; ?>/debugger.js"></script>
<link rel="stylesheet" rev="stylesheet" href="<?php echo $this->baseURL; ?>/debugger.css" type="text/css" media="screen" />
<script type="text/javascript">
var $Debugger = new Debugger(<?php echo "'".$this->rowSeparator."', ".$this->getProfilerTotal('error_handling').', '.($this->IsFatalError ? 'true' : 'false').', '.$this->getProfilerTotal('sql'); ?>);
$Debugger.createEnvironment(<?php echo DBG_WINDOW_WIDTH; ?>, <?php echo $this->getWindowWidth(); ?>);
$Debugger.DOMViewerURL = '<?php echo constant('DBG_DOMVIEWER'); ?>';
$Debugger.EditorPath = '<?php echo defined('DBG_EDITOR') ? addslashes(DBG_EDITOR) : '' ?>';
$Debugger.DebugURL = '<?php echo $this->baseURL.'/debugger_responce.php?sid='.$this->rowSeparator.'&path='.urlencode($dbg_path); ?>';
$Debugger.EventURL = '<?php echo is_object($application->Factory) ? $application->HREF('dummy', '', Array ('pass' => 'm')) : ''; ?>';
<?php
if ($this->IsFatalError || DBG_RAISE_ON_WARNINGS) {
echo '$Debugger.Toggle();';
}
if (DBG_TOOLBAR_BUTTONS) {
echo '$Debugger.AddToolbar("$Debugger");';
}
?>
window.focus();
</script>
<?php
if (!isset($this->ProfilerTotals['error_handling'])) {
$memory_used = $debugger_start;
$this->ProfilerTotalCount['error_handling'] = 0;
}
else {
$memory_used = $debugger_start - $this->ProfilerTotals['error_handling'];
}
if ($returnResult) {
$ret = ob_get_contents();
if ($clean_output_buffer) {
ob_end_clean();
}
$ret .= $this->getShortReport($memory_used);
$this->reportDone = true;
return $ret;
}
else {
if (!$this->constOn('DBG_HIDE_FULL_REPORT')) {
$this->breakOutofBuffering();
}
elseif ($clean_output_buffer) {
ob_clean();
}
echo $this->getShortReport($memory_used);
$this->reportDone = true;
}
}
/**
* Format's memory usage report by debugger
*
* @return string
* @access private
*/
function getShortReport($memory_used)
{
if ($this->constOn('DBG_TOOLBAR_BUTTONS')) {
// we have sql & error count in toolbar, don't duplicate here
$info = Array(
'Script Runtime' => 'PROFILE:script_runtime',
'SQL\'s Runtime' => 'PROFILE_T:sql',
);
}
else {
// toolbar not visible, then show sql & error count too
$info = Array (
'Script Runtime' => 'PROFILE:script_runtime',
'SQL\'s Runtime' => 'PROFILE_T:sql',
'-' => 'SEP:-',
'Notice / Warning' => 'PROFILE_TC:error_handling',
'SQLs Count' => 'PROFILE_TC:sql',
);
}
$ret = '<tr><td>Application:</td><td><b>'.$this->formatSize($memory_used).'</b> ('.$memory_used.')</td></tr>';
foreach ($info as $title => $value_key) {
list ($record_type, $record_data) = explode(':', $value_key, 2);
switch ($record_type) {
case 'PROFILE': // profiler totals value
$Data =& $this->ProfilerData[$record_data];
$profile_time = ($Data['ends'] - $Data['begins']); // in seconds
$ret .= '<tr><td>'.$title.':</td><td><b>'.sprintf('%.5f', $profile_time).' s</b></td></tr>';
break;
case 'PROFILE_TC': // profile totals record count
$record_cell = '<td>';
if ($record_data == 'error_handling' && $this->ProfilerTotalCount[$record_data] > 0) {
$record_cell = '<td class="debug_error">';
}
$ret .= '<tr>'.$record_cell.$title.':</td>'.$record_cell.'<b>'.$this->ProfilerTotalCount[$record_data].'</b></td></tr>';
break;
case 'PROFILE_T': // profile total
$record_cell = '<td>';
$total = array_key_exists($record_data, $this->ProfilerTotals) ? $this->ProfilerTotals[$record_data] : 0;
$ret .= '<tr>'.$record_cell.$title.':</td>'.$record_cell.'<b>'.sprintf('%.5f', $total).' s</b></td></tr>';
break;
case 'SEP':
$ret .= '<tr><td colspan="2" style="height: 1px; background-color: #000000; padding: 0px;"><img src="'.$this->dummyImage.'" height="1" alt=""/></td></tr>';
break;
}
}
return '<br /><table class="dbg_stats_table"><tr><td style="border-color: #FFFFFF;"><table class="dbg_stats_table" align="left">'.$ret.'</table></td></tr></table>';
}
/**
* User-defined error handler
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param array $errcontext
*/
function saveError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
{
$this->ProfilerData['error_handling']['begins'] = memory_get_usage();
$errorType = $this->getErrorNameByCode($errno);
if (!$errorType) {
trigger_error('Unknown error type ['.$errno.']', E_USER_ERROR);
return false;
}
if ($this->constOn('DBG_IGNORE_STRICT_ERRORS') && defined('E_STRICT') && ($errno == E_STRICT)) return;
if (preg_match('/(.*)#([\d]+)$/', $errstr, $rets) ) {
// replace short message with long one (due triger_error limitations on message size)
$long_id = $rets[2];
$errstr = $this->longErrors[$long_id];
unset($this->longErrors[$long_id]);
}
if (strpos($errfile,'eval()\'d code') !== false) {
$errstr = '[<b>EVAL</b>, line <b>'.$errline.'</b>]: '.$errstr;
$tmpStr = $errfile;
$pos = strpos($tmpStr,'(');
$errfile = substr($tmpStr, 0, $pos);
$pos++;
$errline = substr($tmpStr,$pos,strpos($tmpStr,')',$pos)-$pos);
}
$this->Data[] = Array('no' => $errno, 'str' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => $errcontext, 'debug_type' => 'error');
$this->ProfilerData['error_handling']['ends'] = memory_get_usage();
$this->profilerAddTotal('error_handling', 'error_handling');
if (substr($errorType, 0, 5) == 'Fatal') {
$this->IsFatalError = true;
// append debugger report to data in buffer & clean buffer afterwards
die( $this->breakOutofBuffering(false) . $this->printReport(true) );
}
}
function breakOutofBuffering($flush = true)
{
$buffer_content = Array();
while (ob_get_level()) {
$buffer_content[] = ob_get_clean();
}
$ret = implode('', array_reverse($buffer_content));
if ($flush) {
echo $ret;
flush();
}
return $ret;
}
function saveToFile($msg)
{
$fp = fopen($_SERVER['DOCUMENT_ROOT'].'/vb_debug.txt', 'a');
fwrite($fp, $msg."\n");
fclose($fp);
}
/**
* Formats file/memory size in nice way
*
* @param int $bytes
* @return string
* @access public
*/
function formatSize($bytes)
{
if ($bytes >= 1099511627776) {
$return = round($bytes / 1024 / 1024 / 1024 / 1024, 2);
$suffix = "TB";
} elseif ($bytes >= 1073741824) {
$return = round($bytes / 1024 / 1024 / 1024, 2);
$suffix = "GB";
} elseif ($bytes >= 1048576) {
$return = round($bytes / 1024 / 1024, 2);
$suffix = "MB";
} elseif ($bytes >= 1024) {
$return = round($bytes / 1024, 2);
$suffix = "KB";
} else {
$return = $bytes;
$suffix = "Byte";
}
$return .= ' '.$suffix;
return $return;
}
function printConstants($constants)
{
if (!is_array($constants)) {
$constants = explode(',', $constants);
}
$contant_tpl = '<tr><td>%s</td><td><b>%s</b></td></tr>';
$ret = '<table class="dbg_flat_table" style="width: '.$this->getWindowWidth().'px;">';
foreach ($constants as $constant_name) {
$ret .= sprintf($contant_tpl, $constant_name, constant($constant_name));
}
$ret .= '</table>';
$this->appendHTML($ret);
}
function AttachToApplication() {
if (!$this->constOn('DBG_HANDLE_ERRORS')) {
return true;
}
if (class_exists('kApplication')) {
restore_error_handler(); // replace application error handler with own
$this->Application =& kApplication::Instance();
$this->Application->Debugger =& $this;
$this->Application->errorHandlers[] = Array (&$this, 'saveError');
}
else {
set_error_handler(Array(&$this, 'saveError'));
}
}
/**
* Returns HTML for tools section
*
* @return string
*/
function _getToolsHTML()
{
$html = '<table>
<tr>
<td>System Tools:</td>
<td>
<select id="reset_cache" style="border: 1px solid #000000;">
<option value=""></option>
<option value="events[adm][OnResetModRwCache]">Reset mod_rewrite Cache</option>
<option value="events[adm][OnResetCMSMenuCache]">Reset SMS Menu Cache</option>
<option value="events[adm][OnResetSections]">Reset Sections Cache</option>
<option value="events[adm][OnResetConfigsCache]">Reset Configs Cache</option>
<option value="events[adm][OnRebuildThemes]">Re-build Themes Files</option>
<option value="events[lang][OnReflectMultiLingualFields]">Re-build Multilanguage Fields</option>
</select>
</td>
<td>
<input type="button" class="button" onclick="$Debugger.resetCache(\'reset_cache\');" value="Go"/>
</td>
</tr>
</table>';
return $html;
}
/**
* Returns HTML for dom viewer section
*
* @return string
*/
function _getDomViewerHTML()
{
$html = '<table>
<tr>
<td>
<a href="http://www.brainjar.com/dhtml/domviewer/" target="_blank">DomViewer</a>:
</td>
<td>
<input id="dbg_domviewer" type="text" value="window" style="border: 1px solid #000000;"/>
</td>
<td>
<button class="button" onclick="return $Debugger.OpenDOMViewer();">Show</button>
</td>
</tr>
</table>';
return $html;
}
}
if (!function_exists('memory_get_usage')) {
function memory_get_usage(){ return -1; }
}
if (!Debugger::constOn('DBG_ZEND_PRESENT')) {
$debugger = new Debugger();
}
if (Debugger::constOn('DBG_USE_SHUTDOWN_FUNC')) {
register_shutdown_function( Array(&$debugger, 'printReport') );
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/utility/http_query.php
===================================================================
--- branches/5.0.x/core/kernel/utility/http_query.php (revision 12322)
+++ branches/5.0.x/core/kernel/utility/http_query.php (revision 12323)
@@ -1,658 +1,649 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kHTTPQuery extends Params {
/**
* $_POST vars
*
* @var Array
* @access private
*/
var $Post;
/**
* $_GET vars
*
* @var Array
* @access private
*/
var $Get;
/**
* $_COOKIE vars
*
* @var Array
* @access private
*/
var $Cookie;
/**
* $_SERVER vars
*
* @var Array
* @access private
*/
var $Server;
/**
* $_ENV vars
*
* @var Array
* @access private
*/
var $Env;
/**
* Order in what write
* all vars together in
* the same array
*
* @var string
*/
var $Order;
/**
* Uploaded files info
*
* @var Array
* @access private
*/
var $Files;
var $specialsToRemove = Array();
var $Admin = false;
/**
* Description
*
* @var kDBConnection
* @access public
*/
var $Conn;
/**
* Loads info from $_POST, $_GET and
* related arrays into common place
*
* @param string $order
* @return HTTPQuery
* @access public
*/
function kHTTPQuery($order = 'CGPF')
{
parent::Params();
$this->Conn =& $this->Application->GetADODBConnection();
$this->Order = $order;
$this->Admin = $this->Application->IsAdmin(); // better cache this value, not to calculate it each time in foreach
if (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
// when AJAX request is made from jQuery, then create ajax variable,
// so any logic based in it (like redirects) will not break down
$_GET['ajax'] = 'yes';
}
}
function Init($prefix, $special)
{
$this->AddAllVars();
$this->specialsToRemove = $this->Get('remove_specials');
if ($this->specialsToRemove) {
foreach ($this->specialsToRemove as $prefix_special => $flag) {
if ($flag && strpos($prefix_special, '.') === false) {
unset($this->specialsToRemove[$prefix_special]);
trigger_error('Incorrect usage of "<strong>remove_specials['.$prefix_special.']</strong>" field (no special found)', E_USER_WARNING);
}
}
$this->_Params = $this->removeSpecials($this->_Params);
}
ini_set('magic_quotes_gpc', 0);
}
function removeSpecials($array)
{
$ret = Array();
$removed = false;
foreach ($this->specialsToRemove as $prefix_special => $flag) {
if ($flag) {
$removed = true;
list ($prefix,$special) = explode('.', $prefix_special, 2);
foreach ($array as $key => $val) {
$new_key = preg_match("/^".$prefix."[._]{1}".$special."(.*)/", $key, $regs) ? $prefix.$regs[1] : $key;
$ret[$new_key] = is_array($val) ? $this->removeSpecials($val) : $val;
}
}
}
return $removed ? $ret : $array;
}
/**
* All all requested vars to
* common storage place
*
* @access private
*/
function AddAllVars()
{
for ($i=0; $i < strlen($this->Order); $i++)
{
$current = $this->Order[$i];
switch ($current) {
case 'G':
$this->Get = $this->AddVars($_GET);
$vars = $this->processQueryString( $this->Get(ENV_VAR_NAME) );
$this->AddParams($vars);
break;
case 'P':
$this->Post = $this->AddVars($_POST);
$this->convertPostEvents();
$this->_processPostEnvVariables();
break;
case 'C':
$this->Cookie = $this->AddVars($_COOKIE);
break;
case 'E';
$this->Env = $this->AddVars($_ENV);
break;
case 'S';
$this->Server = $this->AddVars($_SERVER);
break;
case 'F';
$this->convertFiles();
$this->Files = $this->MergeVars($_FILES, false); //do not strip slashes!
break;
}
}
// $this->AfterInit();
}
/**
* Allow POST variables, that names were transformed by PHP ("." replaced with "_") to
* override variables, that were virtually created through enviroment variable parsing
*
*/
function _processPostEnvVariables()
{
$passed = $this->Get('passed');
if (!$passed) {
return ;
}
$passed = explode(',', $passed);
foreach ($passed as $prefix_special) {
if (strpos($prefix_special, '.') === false) {
continue;
}
list ($prefix, $special) = explode('.', $prefix_special);
$query_map = $this->Application->EventManager->getQueryMap($prefix);
$post_prefix_special = $prefix . '_' . $special;
foreach ($query_map as $index => $var_name) {
if (array_key_exists($post_prefix_special . '_' . $var_name, $this->Post)) {
$this->Set($prefix_special . '_' . $var_name, $this->Post[$post_prefix_special . '_' . $var_name]);
}
}
}
}
function AfterInit()
{
// $vars = $this->processQueryString($this->Get(ENV_VAR_NAME));
// $this->AddParams($vars);
// $this->convertPostEvents();
// if ($this->Application->RewriteURLs()) {
if ($this->Application->RewriteURLs() || $this->Get('_mod_rw_url_')) {
- if( $this->Application->isDebugMode() )
- {
+ if (defined('DEBUG_MODE') && $this->Application->isDebugMode()) {
$this->Application->Debugger->profileStart('url_parsing');
$this->processRewriteURL();
$description = 'Parsing <b>MOD_REWRITE</b> url (template: <b>'.$this->Get('t').'</b>)';
$this->Application->Debugger->profileFinish('url_parsing', $description);
}
- else
- {
+ else {
$this->processRewriteURL();
}
}
else {
$this->Application->VerifyLanguageId();
$this->Application->VerifyThemeId();
}
}
function convertFiles()
{
if (!$_FILES)
{
return false;
}
$file_keys = Array('error','name','size','tmp_name','type');
$tmp = Array();
foreach($_FILES as $file_name => $file_info)
{
if( is_array($file_info['error']) )
{
$tmp[$file_name] = $this->getArrayLevel( $file_info['error'], $file_name );
}
else
{
$normal_files[$file_name] = $file_info;
}
}
if(!$tmp) return false;
$files = $_FILES;
$_FILES = Array();
foreach($tmp as $prefix => $prefix_files)
{
$anchor =& $_FILES;
foreach($prefix_files['keys'] as $key)
{
$anchor =& $anchor[$key];
}
foreach($prefix_files['value'] as $field_name)
{
unset($inner_anchor);
unset($copy);
$work_copy = $prefix_files['keys'];
foreach($file_keys as $file_key)
{
$inner_anchor =& $files[$prefix][$file_key];
if (isset($copy))
{
$work_copy = $copy;
}
else
{
$copy = $work_copy;
}
array_shift($work_copy);
foreach($work_copy as $prefix_file_key)
{
$inner_anchor =& $inner_anchor[$prefix_file_key];
}
$anchor[$field_name][$file_key] = $inner_anchor[$field_name];
}
}
}
// keys: img_temp, 0, values: LocalPath, ThumbPath
}
function getArrayLevel(&$level, $prefix='')
{
$ret['keys'] = $prefix ? Array($prefix) : Array();
$ret['value'] = Array();
foreach($level as $level_key => $level_value)
{
if( is_array($level_value) )
{
$ret['keys'][] = $level_key;
$tmp = $this->getArrayLevel($level_value);
$ret['keys'] = array_merge($ret['keys'], $tmp['keys']);
$ret['value'] = array_merge($ret['value'], $tmp['value']);
}
else
{
$ret['value'][] = $level_key;
}
}
return $ret;
}
/**
* Owerwrites GET events with POST events in case if they are set and not empty
*
*/
function convertPostEvents()
{
$events = $this->Get('events');
if (is_array($events)) {
foreach ($events as $prefix_special => $event_name) {
if ($event_name) {
$this->Set($prefix_special.'_event', $event_name);
}
}
}
}
function finalizeParsing($passed = Array(), $module_params = Array() )
{
if ($passed) {
$event_manger =& $this->Application->recallObject('EventManager');
foreach ($passed as $passed_prefix) {
$event_manger->setQueryMap($passed_prefix);
}
$this->Set('passed', implode(',', array_keys($event_manger->queryMaps)));
}
// get joined version (env var + mod rewrite parsed)
$passed = $this->Application->GetVar('passed');
$env = $this->Application->BuildEnv( $this->Get('t'), $module_params, $passed, false, false );
$this->Set(ENV_VAR_NAME, $env);
$_REQUEST['env'] = $_GET['env'] = $env; // for capability with old in-portal code
}
function processRewriteURL()
{
$mod_rw_helper = $this->Application->recallObject('ModRewriteHelper');
$mod_rw_helper->processRewriteURL();
}
function getDefaultTemplate($t)
{
$t = $this->getTemplateName( trim($t, '/') );
if (!$t) $t = 'index';
return trim($t, '/');
}
function extractSIDAndTemplate(&$parts)
{
$vars = Array ();
- if (defined('INPORTAL_ENV') && INPORTAL_ENV) { // SID-TEMPLATE
- $sub_parts = array_shift($parts);
- list($sid, $t) = explode('-', $sub_parts, 2);
+ $sub_parts = array_shift($parts);
- // Save Session ID
- if ($sid) {
- $this->Set('sid', $sid);
- $vars['sid'] = $sid;
- }
- }
- else { // SID:TEMPLATE
- // Save Session ID
- $sid = array_shift($parts);
- if ($sid) $vars['sid'] = $sid;
+ list ($sid, $t) = explode('-', $sub_parts, 2);
- $t = array_shift($parts);
+ if ($sid) {
+ // Save Session ID
+ $this->Set('sid', $sid);
+ $vars['sid'] = $sid;
}
// Save Template Name
$vars['t'] = $this->getDefaultTemplate($t);
+
return $vars;
}
/**
* Process QueryString only, create
* events, ids, based on config
* set template name and sid in
* desired application variables.
*
* @param string $env_var enviroment string value
*
* @access public
*/
function processQueryString($env_var, $pass_name = 'passed')
{
// env=SID:TEMPLATE:m-1-1-1-1:l0-0-0:n-0-0-0:bb-0-0-1-1-1-0
$vars = Array ();
if ($env_var) {
$more_vars = strpos($env_var, '&');
if ($more_vars !== false) {
parse_str(substr($env_var, $more_vars + 1), $vars);
$env_var = substr($env_var, 0, $more_vars);
}
// replace escaped ":" symbol not to explode by it
$env_var = str_replace('\:','_&+$$+&_', $env_var); // replace escaped "=" with spec-chars :)
$parts = explode(':', $env_var);
if (!$this->Application->RewriteURLs() || ($this->Application->RewriteURLs() && $this->Get('rewrite') != 'on')) {
$vars = array_merge_recursive2($vars, $this->extractSIDAndTemplate($parts));
}
if ($parts) {
$passed = Array ();
foreach ($parts as $mixed_part) {
list ($passed[], $processed_vars) = $this->_parseEnvPart($mixed_part);
$vars = array_merge_recursive2($vars, $processed_vars);
}
$vars[$pass_name] = implode(',', array_unique($passed));
}
}
else {
$t = $this->getTemplateName('index');
$vars['t'] = $t;
}
return $vars;
}
/**
* Converts enviroment part into variable array (based on query map for given prefix)
*
* @param string $mixed_part
* @return Array
*/
function _parseEnvPart($mixed_part)
{
// In-portal old style env conversion - adds '-' between prefix and first var
$mixed_part = str_replace('_&+$$+&_', ':', $mixed_part);
$mixed_part = preg_replace("/^([a-zA-Z]+)([0-9]+)-(.*)/", "$1-$2-$3", $mixed_part);
// replace escaped "-" symbol not to explode by it
$escaped_part = str_replace('\-', '_&+$$+&_', $mixed_part);
$escaped_part = explode('-', $escaped_part);
$mixed_part = Array();
foreach ($escaped_part as $escaped_val) {
$mixed_part[] = str_replace('_&+$$+&_', '-', $escaped_val);
}
$prefix_special = array_shift($mixed_part); // l.pick, l
$query_map = $this->Application->EventManager->setQueryMap($prefix_special);
$vars = Array ();
// if config is not defined for prefix in QueryString, then don't process it
if ($query_map) {
foreach ($query_map as $index => $var_name) {
// l_id, l_page, l_bla-bla-bla
$val = $mixed_part[$index - 1];
if ($val == '') $val = false;
$vars[$prefix_special.'_'.$var_name] = $val;
}
}
return Array ($prefix_special, $vars);
}
/**
* Removes tpl part from template name + resolved template ID to name
*
* @param string $t
* @return string
* @access private
*/
function getTemplateName($t)
{
if (isset($this->Get['t']) && $this->Get['t']) {
// template name is passed directly in url (GET method)
$t = $this->Get['t'];
}
// if t was set through env, even in mod_rewrite mode!
if ($this->Get('env') && $this->Application->RewriteURLs() && $this->Get('t')) {
$t = $this->Get('t');
}
if (is_numeric($t)) {
$sql = 'SELECT CONCAT(FilePath, \'/\', FileName)
FROM '.TABLE_PREFIX.'ThemeFiles
WHERE FileId = '.$t;
$t = $this->Conn->GetOne($sql);
}
return preg_replace('/\.tpl$/', '', $t);
}
/**
* Saves variables from array specified
* into common variable storage place
*
* @param Array $array
* @return Array
* @access private
*/
function AddVars($array)
{
$array = $this->StripSlashes($array);
foreach($array as $key => $value)
{
$this->Set($key,$value);
}
return $array;
}
function MergeVars($array, $strip_slashes=true)
{
if ($strip_slashes) $array = $this->StripSlashes($array);
foreach($array as $key => $value)
{
$this->_Params = array_merge_recursive2($this->_Params, Array($key=>$value));
}
return $array;
}
function StripSlashes($array)
{
//if( !get_magic_quotes_gpc() ) return $array;
foreach($array as $key=>$value)
{
if( is_array($value) )
{
$array[$key] = $this->StripSlashes($value);
}
else
{
// $value = iconv('UTF-8', 'windows-1257', $value);
if( get_magic_quotes_gpc() ) $value = stripslashes($value);
if(!$this->Admin) $value = htmlspecialchars($value);
$array[$key] = $value;
}
//$array[$key]=is_array($value)?$this->StripSlashes($value):stripslashes($value);
}
return $array;
}
/**
* Returns all $_GET array excluding system parameters, that are not allowed to be passed through generated urls
*
* @param bool $access_error Method is called during no_permission, require login, session expiration link preparation
* @return Array
*/
function getRedirectParams($access_error = false)
{
$unset_vars = Array (ENV_VAR_NAME, 'rewrite', '_mod_rw_url_', 'Action');
$ret = $this->Get;
foreach ($unset_vars as $var_name) {
if( isset($ret[$var_name]) ) {
unset( $ret[$var_name] );
}
}
if ($access_error) {
$ret = $this->_removePassThroughVariables($ret);
if ($this->Application->IsAdmin()) {
// place 1 of 2 (also in UsersEventHandler::OnSessionExpire)
$ret['m_cat_id'] = 0; // category means nothing on admin login screen
$ret['m_wid'] = ''; // remove wid, otherwise parent window may add wid to its name breaking all the frameset (for <a> targets)
$ret['pass'] = 'm'; // don't pass any other (except "m") prefixes to admin login template
}
}
return $ret;
}
/**
* Removes all pass_though variables from redirect params
*
* @param Array $url_params
* @return Array
*/
function _removePassThroughVariables($url_params)
{
$pass_through = array_key_exists('pass_through', $url_params) ? $url_params['pass_through'] : '';
if (!$pass_through) {
return $url_params;
}
$pass_through = explode(',', $pass_through . ',pass_through');
foreach ($pass_through as $pass_through_var) {
unset($url_params[$pass_through_var]);
}
$url_params['no_pass_through'] = 1; // this way kApplication::HREF won't add them again
return $url_params;
}
function writeRequestLog($filename)
{
$folder_path = dirname(FULL_PATH.'/'.$filename);
if (is_writable($folder_path)) {
$fp = fopen(FULL_PATH.'/'.$filename, 'a');
if ($fp) {
$session =& $this->Application->recallObject('Session');
$user_id = $session->GetField('PortalUserId');
$admin_mark = $this->Application->IsAdmin() ? 'ADMIN' : 'FRONT';
$data = '['.date('D M d H:i:s Y').'] '.$admin_mark.'; ip: '.$_SERVER['REMOTE_ADDR'].'; user_id: '.$user_id.'; sid: '.$this->Application->GetSID().'; request: '."\n";
if ($this->Get) {
$data .= "_GET:\n".print_r($this->Get, true);
}
if ($this->Post) {
$data .= "_POST:\n".print_r($this->Post, true);
}
if ($this->Cookie) {
$data .= "_COOKIE:\n".print_r($this->Cookie, true);
}
$data .= str_repeat('=', 100)."\n";
fwrite($fp, $data);
fclose($fp);
}
else {
trigger_error('Requrest Log directory not writable', E_USER_WARNING);
}
}
else {
trigger_error('Requrest Log directory not writable', E_USER_WARNING);
}
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/utility/unit_config_reader.php
===================================================================
--- branches/5.0.x/core/kernel/utility/unit_config_reader.php (revision 12322)
+++ branches/5.0.x/core/kernel/utility/unit_config_reader.php (revision 12323)
@@ -1,977 +1,977 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kUnitConfigReader extends kBase {
/**
* Configs readed
*
* @var Array
* @access private
*/
var $configData = Array();
var $configFiles = Array();
var $CacheExpired = false;
var $prefixFiles = array();
var $ProcessAllConfigs = false;
var $FinalStage = false;
var $StoreCache = false;
var $AfterConfigProcessed = array();
/**
* Escaped directory separator for using in regular expressions
*
* @var string
*/
var $_directorySeparator = '';
/**
* Folders to skip during unit config search
*
* @var Array
*/
var $_skipFolders = Array ('CVS', '.svn', 'admin_templates', 'libchart');
/**
* Scan kernel and user classes
* for available configs
*
* @access protected
*/
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->_directorySeparator = preg_quote( DIRECTORY_SEPARATOR );
$this->_skipFolders[] = trim(WRITEBALE_BASE, '/'); // system folder (where web server can write)
$this->_skipFolders[] = array_pop( explode('/', trim(EDITOR_PATH, '/')) ); // last of cmseditor folders
}
function CacheParsedData()
{
$event_manager =& $this->Application->recallObject('EventManager');
$aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
$config_vars = Array (
'SessionTimeout',
'SessionCookieName',
'SessionReferrerCheck',
'CookieSessions',
'UseCronForRegularEvent',
'User_GuestGroup',
'User_LoggedInGroup',
'SessionTimeout',
'UseModRewrite',
'UseOutputCompression',
'OutputCompressionLevel',
'KeepSessionOnBrowserClose',
'Config_Server_Time',
'Config_Site_Time',
'UseChangeLog',
);
foreach ($config_vars as $var) {
$this->Application->ConfigValue($var);
}
$cache = Array(
'Factory.Files' => $this->Application->Factory->Files,
'Factory.realClasses' => $this->Application->Factory->realClasses,
'Factory.Dependencies' => $this->Application->Factory->Dependencies,
'ConfigReader.prefixFiles' => $this->prefixFiles,
'EventManager.buildEvents' => $event_manager->buildEvents,
'EventManager.beforeRegularEvents' => $event_manager->beforeRegularEvents,
'EventManager.afterRegularEvents' => $event_manager->afterRegularEvents,
'EventManager.beforeHooks' => $event_manager->beforeHooks,
'EventManager.afterHooks' => $event_manager->afterHooks,
'TagsAggregator.data' => $aggregator->_Array,
// the following caches should be reset based on admin interaction (adjusting config, enabling modules etc)
'Application.Caches.ConfigVariables' => $this->Application->Caches['ConfigVariables'],
'Application.ConfigCacheIds' => $this->Application->ConfigCacheIds,
'Application.ConfigHash' => $this->Application->ConfigHash,
'Application.ReplacementTemplates' => $this->Application->ReplacementTemplates,
'Application.RewriteListeners' => $this->Application->RewriteListeners,
'Application.ModuleInfo' => $this->Application->ModuleInfo,
);
$conn =& $this->Application->GetADODBConnection();
if (isset($this->Application->Memcached)) {
$this->Application->Memcached->set('master:configs_parsed', serialize($cache));
$this->Application->Memcached->set('master:config_files', serialize($this->configFiles));
}
else {
$conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("configs_parsed", '.$conn->qstr(serialize($cache)).', '.adodb_mktime().')');
$conn->Query('REPLACE '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ("config_files", '.$conn->qstr(serialize($this->configFiles)).', '.adodb_mktime().')');
}
$cache_rebuild_by = SERVER_NAME . ' (' . getenv('REMOTE_ADDR') . ') - ' . adodb_date('d/m/Y H:i:s');
$conn->Query('REPLACE ' . TABLE_PREFIX . 'Cache (VarName, Data, Cached) VALUES ("last_cache_rebuild", ' . $conn->qstr($cache_rebuild_by) . ', ' . adodb_mktime() . ')');
unset($this->configFiles);
}
function RestoreParsedData()
{
$conn =& $this->Application->GetADODBConnection();
if (!isset($this->Application->Memcached) || !($data = $this->Application->Memcached->get('master:configs_parsed'))) {
$data = $conn->GetOne('SELECT Data FROM '.TABLE_PREFIX.'Cache WHERE VarName = "configs_parsed"');
}
if ($data) {
$cache = unserialize($data);
$this->Application->Factory->Files = $cache['Factory.Files'];
$this->Application->Factory->realClasses = $cache['Factory.realClasses'];
$this->Application->Factory->Dependencies = $cache['Factory.Dependencies'];
$this->prefixFiles = $cache['ConfigReader.prefixFiles'];
$event_manager =& $this->Application->recallObject('EventManager');
$event_manager->buildEvents = $cache['EventManager.buildEvents'];
$event_manager->beforeRegularEvents = $cache['EventManager.beforeRegularEvents'];
$event_manager->afterRegularEvents = $cache['EventManager.afterRegularEvents'];
$event_manager->beforeHooks = $cache['EventManager.beforeHooks'];
$event_manager->afterHooks = $cache['EventManager.afterHooks'];
$aggregator =& $this->Application->recallObject('TagsAggregator', 'kArray');
$aggregator->_Array = $cache['TagsAggregator.data'];
$this->Application->ConfigHash = $cache['Application.ConfigHash'];
$this->Application->Caches['ConfigVariables'] = $cache['Application.ConfigCacheIds'];
$this->Application->ConfigCacheIds = $cache['Application.ConfigCacheIds'];
$this->Application->ReplacementTemplates = $cache['Application.ReplacementTemplates'];
$this->Application->RewriteListeners = $cache['Application.RewriteListeners'];
$this->Application->ModuleInfo = $cache['Application.ModuleInfo'];
return true;
}
else return false;
}
function ResetParsedData($include_sections = false)
{
$conn =& $this->Application->GetADODBConnection();
$conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "configs_parsed"');
if (isset($this->Application->Memcached)) {
$this->Application->Memcached->delete('master:configs_parsed');
}
if ($include_sections) {
$conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "sections_parsed"');
if (isset($this->Application->Memcached)) {
$this->Application->Memcached->delete('master:sections_parsed');
}
}
}
function scanModules($folderPath, $cache = true)
{
if (defined('IS_INSTALL') && IS_INSTALL && !defined('FORCE_CONFIG_CACHE')) {
// disable config caching during installation
$cache = false;
}
if ($cache) {
$restored = $this->RestoreParsedData();
if ($restored) return;
}
$this->ProcessAllConfigs = true;
$this->includeConfigFiles($folderPath, $cache);
$this->ParseConfigs();
// tell AfterConfigRead to store cache if neede
// can't store it here beacuse AfterConfigRead needs ability to change config data
$this->StoreCache = $cache;
}
function findConfigFiles($folderPath, $level = 0)
{
/*if ($level == 0) {
if ($this->Application->isDebugMode()) {
$start_time = getmicrotime();
$this->Application->Debugger->appendHTML('kUnitConfigReader::findConfigFiles("' . $folderPath . '")');
$this->Application->Debugger->appendTrace();
}
}*/
// if FULL_PATH = "/" ensure, that all "/" in $folderPath are not deleted
$reg_exp = '/^' . preg_quote(FULL_PATH, '/') . '/';
$folderPath = preg_replace($reg_exp, '', $folderPath, 1); // this make sense, since $folderPath may NOT contain FULL_PATH
$base_folder = FULL_PATH . $folderPath . DIRECTORY_SEPARATOR;
$sub_folders = glob($base_folder . '*', GLOB_ONLYDIR);
if (!$sub_folders) {
return ;
}
if ($level == 0) {
// don't scan Front-End themes because of extensive directory structure
$sub_folders = array_diff($sub_folders, Array ($base_folder . 'themes', $base_folder . 'tools'));
}
foreach ($sub_folders as $full_path) {
$sub_folder = substr($full_path, strlen($base_folder));
if (in_array($sub_folder, $this->_skipFolders)) {
continue;
}
if (preg_match('/^\./', $sub_folder)) {
// don't scan ".folders"
continue;
}
$config_name = $this->getConfigName($folderPath . DIRECTORY_SEPARATOR . $sub_folder);
if (file_exists(FULL_PATH . $config_name)) {
$this->configFiles[] = $config_name;
}
$this->findConfigFiles($full_path, $level + 1);
}
/*if ($level == 0) {
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendHTML('kUnitConfigReader::findConfigFiles("' . FULL_PATH . $folderPath . '"): ' . (getmicrotime() - $start_time));
}
}*/
}
function includeConfigFiles($folderPath, $cache = true)
{
$this->Application->refreshModuleInfo();
$conn =& $this->Application->GetADODBConnection();
if (!isset($this->Application->Memcached) || !($data = $this->Application->Memcached->get('master:config_files'))) {
$data = $conn->GetOne('SELECT Data FROM ' . TABLE_PREFIX . 'Cache WHERE VarName = "config_files"');
}
if ($cache && $data) {
$this->configFiles = unserialize($data);
shuffle($this->configFiles);
}
else {
$this->findConfigFiles($folderPath); // search from base directory
}
foreach ($this->configFiles as $filename)
{
$prefix = $this->PreloadConfigFile($filename);
if (!$prefix) {
trigger_error('Prefix not defined in config file ' . $filename, E_USER_ERROR);
}
}
}
/**
* Process all read config files - called ONLY when there is no cache!
*
*/
function ParseConfigs()
{
// 1. process normal configs and their dependencies
$prioritized_configs = array();
foreach ($this->configData as $prefix => $config) {
if (isset($config['ConfigPriority'])) {
$prioritized_configs[$prefix] = $config['ConfigPriority'];
continue;
}
$this->parseConfig($prefix);
}
foreach ($this->configData as $prefix => $config) {
$this->ProcessDependencies($prefix);
$this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
$clones = $this->postProcessConfig($prefix, 'Clones', 'prefix');
}
// 2. process prioritized configs and their dependencies
asort($prioritized_configs);
foreach ($prioritized_configs as $prefix => $priority) {
$this->parseConfig($prefix);
}
foreach ($prioritized_configs as $prefix => $priority) {
$this->ProcessDependencies($prefix);
}
}
function AfterConfigRead($store_cache = null)
{
// if (!$this->ProcessAllConfigs) return ;
$this->FinalStage = true;
foreach ($this->configData as $prefix => $config) {
if (in_array($prefix, $this->AfterConfigProcessed)) {
continue;
}
$this->Application->HandleEvent( new kEvent($prefix.':OnAfterConfigRead') );
$this->AfterConfigProcessed[] = $prefix;
}
if (!isset($store_cache)) {
// store cache not overrided -> use global setting
$store_cache = $this->StoreCache;
}
if ($store_cache || (defined('IS_INSTALL') && IS_INSTALL)) {
// cache is not stored during install, but dynamic clones should be processed in any case
$this->processDynamicClones();
}
if ($store_cache) {
$this->_sortRewriteListeners();
$this->CacheParsedData();
- if ($this->Application->isDebugMode(false) && constOn('DBG_VALIDATE_CONFIGS')) {
+ if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_VALIDATE_CONFIGS') && DBG_VALIDATE_CONFIGS) {
// validate configs here to have changes from OnAfterConfigRead hooks to prefixes
foreach ($this->configData as $prefix => $config) {
if (!isset($config['TableName'])) continue;
$this->ValidateConfig($prefix);
}
}
$after_event = new kEvent('adm:OnAfterCacheRebuild');
$this->Application->HandleEvent($after_event);
}
}
/**
* Sort rewrite listeners according to RewritePriority (non-prioritized listeners goes first)
*
*/
function _sortRewriteListeners()
{
$listeners = Array ();
$prioritized_listeners = Array ();
// process non-prioritized listeners
foreach ($this->Application->RewriteListeners as $prefix => $listener_data) {
if ($listener_data['priority'] === false) {
$listeners[$prefix] = $listener_data;
}
else {
$prioritized_listeners[$prefix] = $listener_data['priority'];
}
}
// process prioritized listeners
asort($prioritized_listeners);
foreach ($prioritized_listeners as $prefix => $priority) {
$listeners[$prefix] = $this->Application->RewriteListeners[$prefix];
}
$this->Application->RewriteListeners = $listeners;
}
/**
* Re-reads all configs
*
*/
function ReReadConfigs()
{
// clear restored cache (not in db)
$this->Application->Factory->Files = Array ();
$this->Application->Factory->realClasses = Array ();
$this->Application->Factory->Dependencies = Array ();
$this->Application->EventManager->beforeRegularEvents = Array ();
$this->Application->EventManager->afterRegularEvents = Array ();
$this->Application->EventManager->beforeHooks = Array ();
$this->Application->EventManager->afterHooks = Array ();
// otherwise ModulesHelper indirectly used from includeConfigFiles won't work
$this->Application->RegisterDefaultClasses();
// parse all configs
$this->ProcessAllConfigs = true;
$this->includeConfigFiles(MODULES_PATH, false);
$this->ParseConfigs();
$this->AfterConfigRead(false);
$this->processDynamicClones();
}
/**
* Process clones, that were defined via OnAfterConfigRead event
*
*/
function processDynamicClones()
{
$new_clones = Array();
foreach ($this->configData as $prefix => $config) {
$clones = $this->postProcessConfig($prefix, 'Clones', 'prefix');
if ($clones) {
$new_clones = array_merge($new_clones, $clones);
}
}
// call OnAfterConfigRead for cloned configs
$new_clones = array_unique($new_clones);
foreach ($new_clones as $prefix) {
if (in_array($prefix, $this->AfterConfigProcessed)) {
continue;
}
$this->Application->HandleEvent( new kEvent($prefix.':OnAfterConfigRead') );
$this->AfterConfigProcessed[] = $prefix;
}
}
/**
* Register nessasary classes
* This method should only process the data which is cached!
*
* @param string $prefix
* @access private
*/
function parseConfig($prefix)
{
$config =& $this->configData[$prefix];
$event_manager =& $this->Application->recallObject('EventManager');
/* @var $event_manager kEventManager */
$register_classes = getArrayValue($config,'RegisterClasses');
if (!$register_classes) $register_classes = Array();
$class_params=Array('ItemClass','ListClass','EventHandlerClass','TagProcessorClass');
foreach($class_params as $param_name)
{
if ( !(isset($config[$param_name]) ) ) continue;
$config[$param_name]['pseudo'] = $this->getPrefixByParamName($param_name,$prefix);
$register_classes[] = $config[$param_name];
}
foreach($register_classes as $class_info)
{
$require_classes = getArrayValue($class_info, 'require_classes');
if ($require_classes) {
if (!is_array($require_classes)) {
$require_classes = array($require_classes);
}
if (!isset($config['_Dependencies'][$class_info['class']])) {
$config['_Dependencies'][$class_info['class']] = array();
}
$config['_Dependencies'][$class_info['class']] = array_merge($config['_Dependencies'][$class_info['class']], $require_classes);
}
$this->Application->registerClass(
$class_info['class'],
$config['BasePath'] . DIRECTORY_SEPARATOR . $class_info['file'],
$class_info['pseudo']/*,
getArrayValue($class_info, 'require_classes')*/
);
if (getArrayValue($class_info, 'build_event')) {
$event_manager->registerBuildEvent($class_info['pseudo'],$class_info['build_event']);
}
}
$regular_events = getArrayValue($config, 'RegularEvents');
if ($regular_events) {
foreach ($regular_events as $short_name => $regular_event_info) {
$event_status = array_key_exists('Status', $regular_event_info) ? $regular_event_info['Status'] : STATUS_ACTIVE;
$event_manager->registerRegularEvent( $short_name, $config['Prefix'].':'.$regular_event_info['EventName'], $regular_event_info['RunInterval'], $regular_event_info['Type'], $event_status);
}
}
$hooks = getArrayValue($config, 'Hooks');
if (is_array($hooks) && count($hooks) > 0) {
foreach ($hooks as $hook) {
if (isset($config['ParentPrefix']) && $hook['HookToPrefix'] == $config['ParentPrefix']) {
trigger_error('Depricated Hook Usage [prefix: <b>'.$config['Prefix'].'</b>; do_prefix: <b>'.$hook['DoPrefix'].'</b>] use <b>#PARENT#</b> as <b>HookToPrefix</b> value, where HookToPrefix is same as ParentPrefix', E_USER_NOTICE);
}
if ($hook['HookToPrefix'] == '') {
$hook['HookToPrefix'] = $config['Prefix']; // new: set hooktoprefix to current prefix if not set
}
if (isset($config['ParentPrefix'])) {
// new: allow to set hook to parent prefix what ever it is
if ($hook['HookToPrefix'] == '#PARENT#') {
$hook['HookToPrefix'] = $config['ParentPrefix'];
}
if ($hook['DoPrefix'] == '#PARENT#') {
$hook['DoPrefix'] = $config['ParentPrefix'];
}
}
elseif ($hook['HookToPrefix'] == '#PARENT#' || $hook['DoPrefix'] == '#PARENT#') {
continue; // we need parent prefix but it's not set !
}
$do_prefix = $hook['DoPrefix'] == '' ? $config['Prefix'] : $hook['DoPrefix'];
if ( !is_array($hook['HookToEvent']) ) {
$hook_events = Array( $hook['HookToEvent'] );
}
else {
$hook_events = $hook['HookToEvent'];
}
foreach ($hook_events as $hook_event) {
$this->Application->registerHook($hook['HookToPrefix'], $hook['HookToSpecial'], $hook_event, $hook['Mode'], $do_prefix, $hook['DoSpecial'], $hook['DoEvent'], $hook['Conditional']);
}
}
}
if ( is_array(getArrayValue($config, 'AggregateTags')) ) {
foreach ($config['AggregateTags'] as $aggregate_tag) {
if (isset($config['ParentPrefix'])) {
if ($aggregate_tag['AggregateTo'] == $config['ParentPrefix']) {
trigger_error('Depricated Aggregate Tag Usage [prefix: <b>'.$config['Prefix'].'</b>; AggregateTo: <b>'.$aggregate_tag['AggregateTo'].'</b>] use <b>#PARENT#</b> as <b>AggregateTo</b> value, where AggregateTo is same as ParentPrefix', E_USER_NOTICE);
}
if ($aggregate_tag['AggregateTo'] == '#PARENT#') {
$aggregate_tag['AggregateTo'] = $config['ParentPrefix'];
}
}
$aggregate_tag['LocalPrefix'] = $config['Prefix'];
$this->Application->registerAggregateTag($aggregate_tag);
}
}
if (array_key_exists('ReplacementTemplates', $config) && $config['ReplacementTemplates']) {
// replacement templates defined in this config
$this->Application->ReplacementTemplates = array_merge($this->Application->ReplacementTemplates, $config['ReplacementTemplates']);
}
if (array_key_exists('RewriteListener', $config) && $config['RewriteListener']) {
// replacement templates defined in this config
$rewrite_listener = $config['RewriteListener'];
if (strpos($rewrite_listener, ':') === false) {
$rewrite_listener = $prefix . '_EventHandler:' . $rewrite_listener;
}
$rewrite_priority = array_key_exists('RewritePriority', $config) ? $config['RewritePriority'] : false;
$this->Application->RewriteListeners[$prefix] = Array ('listener' => $rewrite_listener, 'priority' => $rewrite_priority);
}
}
function ValidateConfig($prefix)
{
global $debugger;
$config =& $this->configData[$prefix];
$tablename = $config['TableName'];
$float_types = Array ('float', 'double', 'numeric');
$conn =& $this->Application->GetADODBConnection();
$table_found = $conn->Query('SHOW TABLES LIKE "'.$tablename.'"');
if (!$table_found) {
// config present, but table missing, strange
$debugger->appendHTML("<b class='debug_error'>Config Warning: </b>Table <strong>$tablename</strong> missing, but prefix <b>".$config['Prefix']."</b> requires it!");
safeDefine('DBG_RAISE_ON_WARNINGS', 1);
return ;
}
$res = $conn->Query('DESCRIBE '.$tablename);
$config_link = $debugger->getFileLink(FULL_PATH.$this->prefixFiles[$config['Prefix']], 1, $config['Prefix']);
$error_messages = Array (
'field_not_found' => 'Field <strong>%s</strong> exists in the database, but <strong>is not defined</strong> in config',
'default_missing' => 'Default value for field <strong>%s</strong> not set in config',
'not_null_error1' => 'Field <strong>%s</strong> is NOT NULL in the database, but is not configured as not_null', // or required',
'not_null_error2' => 'Field <strong>%s</strong> is described as NOT NULL in config, but <strong>does not have DEFAULT value</strong>',
'not_null_error3' => 'Field <strong>%s</strong> is described as <strong>NOT NULL in config</strong>, but is <strong>NULL in db</strong>',
'invalid_default' => '<strong>Default value</strong> for field %s<strong>%s</strong> not sync. to db (in config = %s, in db = %s)',
'type_missing' => '<strong>Type definition</strong> for field <strong>%s</strong> missing in config',
);
$config_errors = Array ();
$tablename = preg_replace('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', '\\1', $tablename); // remove table prefix
foreach ($res as $field) {
$f_name = $field['Field'];
if (getArrayValue($config, 'Fields')) {
if (preg_match('/l[\d]+_[\w]/', $f_name)) {
// skip multilingual fields
continue;
}
if (!array_key_exists ($f_name, $config['Fields'])) {
$config_errors[] = sprintf($error_messages['field_not_found'], $f_name);
}
else {
if (is_numeric($field['Default'])) {
$field['Default'] = preg_match('/[\.,]/', $field['Default']) ? (float)$field['Default'] : (int)$field['Default'];
}
$options = $config['Fields'][$f_name];
$default_missing = false;
if (!array_key_exists('default', $options)) {
$config_errors[] = sprintf($error_messages['default_missing'], $f_name);
$default_missing = true;
}
if ($field['Null'] != 'YES') {
// field is NOT NULL in database (MySQL5 for null returns "NO", but MySQL4 returns "")
if ( $f_name != $config['IDField'] && !isset($options['not_null']) /*&& !isset($options['required'])*/ ) {
$config_errors[] = sprintf($error_messages['not_null_error1'], $f_name);
}
if (isset($options['not_null']) && $options['not_null'] && !isset($options['default']) ) {
$config_errors[] = sprintf($error_messages['not_null_error2'], $f_name);
}
}
else {
if (isset($options['not_null']) && $options['not_null']) {
$config_errors[] = sprintf($error_messages['not_null_error3'], $f_name);
}
}
if (!array_key_exists('type', $options)) {
$config_errors[] = sprintf($error_messages['type_missing'], $f_name);
}
if (!$default_missing) {
if ($f_name == $config['IDField'] && $options['type'] != 'string' && $options['default'] !== 0) {
$config_errors[] = sprintf($error_messages['invalid_default'], '<span class="debug_error">IDField</span> ', $f_name, $this->varDump($options['default']), $this->varDump($field['Default']));
}
else if ($options['default'] != '#NOW#' && $field['Default'] !== $options['default'] && !in_array($options['type'], $float_types)) {
$config_errors[] = sprintf($error_messages['invalid_default'], '', $f_name, $this->varDump($options['default']), $this->varDump($field['Default']));
}
}
}
}
}
if ($config_errors) {
$error_prefix = '<strong class="debug_error">Config Error'.(count($config_errors) > 1 ? 's' : '').': </strong> for prefix <strong>'.$config_link.'</strong> ('.$tablename.') in unit config:<br />';
$config_errors = $error_prefix.'&nbsp;&nbsp;&nbsp;'.implode('<br />&nbsp;&nbsp;&nbsp;', $config_errors);
$debugger->appendHTML($config_errors);
safeDefine('DBG_RAISE_ON_WARNINGS', 1);
}
}
function varDump($value)
{
return '<strong>'.var_export($value, true).'</strong> of '.gettype($value);
}
function ProcessDependencies($prefix)
{
$config =& $this->configData[$prefix];
$deps = getArrayValue($config, '_Dependencies');
if (!$deps) return ;
foreach ($deps as $real_class => $requires) {
foreach ($requires as $class) {
$this->Application->registerDependency($real_class, $class);
}
}
unset($config['_Dependencies']);
}
function postProcessConfig($prefix, $config_key, $dst_prefix_var)
{
$main_config =& $this->configData[$prefix];
$sub_configs = isset($main_config[$config_key]) && $main_config[$config_key] ? $main_config[$config_key] : false; // getArrayValue($main_config, $config_key);
if (!$sub_configs) {
return array();
}
unset($main_config[$config_key]);
$processed = array();
foreach ($sub_configs as $sub_prefix => $sub_config) {
if ($config_key == 'AggregateConfigs' && !isset($this->configData[$sub_prefix])) {
$this->loadConfig($sub_prefix);
}
$sub_config['Prefix'] = $sub_prefix;
$this->configData[$sub_prefix] = array_merge_recursive2($this->configData[$$dst_prefix_var], $sub_config);
// when merging empty array to non-empty results non-empty array, but empty is required
foreach ($sub_config as $sub_key => $sub_value) {
if (!$sub_value) {
unset($this->configData[$sub_prefix][$sub_key]);
}
}
if ($config_key == 'Clones') {
$this->prefixFiles[$sub_prefix] = $this->prefixFiles[$prefix];
}
$this->postProcessConfig($sub_prefix, $config_key, $dst_prefix_var);
if ($config_key == 'AggregateConfigs') {
$processed = array_merge($this->postProcessConfig($sub_prefix, 'Clones', 'prefix'), $processed);
}
elseif ($this->ProcessAllConfigs) {
$this->parseConfig($sub_prefix);
}
array_push($processed, $sub_prefix);
}
if (!$prefix) {
// configs, that used only for cloning & not used ifself
unset($this->configData[$prefix]);
}
return array_unique($processed);
}
function PreloadConfigFile($filename)
{
$config_found = file_exists(FULL_PATH.$filename) && $this->configAllowed($filename);
if (defined('DEBUG_MODE') && DEBUG_MODE && defined('DBG_PROFILE_INCLUDES') && DBG_PROFILE_INCLUDES) {
if ( in_array($filename, get_required_files()) ) {
return;
}
global $debugger;
if ($config_found) {
$file = FULL_PATH . $filename;
$file_crc = crc32($file);
$debugger->ProfileStart('inc_' . $file_crc, $file);
include_once($file);
$debugger->ProfileFinish('inc_' . $file_crc);
$debugger->profilerAddTotal('includes', 'inc_' . $file_crc);
}
}
elseif ($config_found) {
include_once(FULL_PATH . $filename);
}
if ($config_found) {
if (isset($config) && $config) {
// config file is included for 1st time -> save it's content for future processing
$prefix = array_key_exists('Prefix', $config) ? $config['Prefix'] : '';
preg_match('#' . $this->_directorySeparator . '(.*)' . $this->_directorySeparator . '#U', $filename, $rets);
$config['ModuleFolder'] = $rets[1];
$config['BasePath'] = dirname(FULL_PATH . $filename);
if (array_key_exists('AdminTemplatePath', $config)) {
// append template base folder for admin templates path of this prefix
$module_templates = $rets[1] == 'core' ? '' : $rets[1] . '/';
$config['AdminTemplatePath'] = $module_templates . $config['AdminTemplatePath'];
}
if (array_key_exists($prefix, $this->prefixFiles) && ($this->prefixFiles[$prefix] != $filename)) {
trigger_error(
'Single unit config prefix "<strong>' . $prefix . '</strong>" ' .
'is used in multiple unit config files: ' .
'"<strong>' . $this->prefixFiles[$prefix] . '</strong>", "<strong>' . $filename . '</strong>"',
E_USER_WARNING
);
}
$this->configData[$prefix] = $config;
$this->prefixFiles[$prefix] = $filename;
return $prefix;
}
elseif ($prefix = array_search($filename, $this->prefixFiles)) {
// attempt is made to include config file twice or more, but include_once prevents that,
// but file exists on hdd, then it is already saved to all required arrays, just return it's prefix
return $prefix;
}
}
return 'dummy';
}
function loadConfig($prefix)
{
if (!isset($this->prefixFiles[$prefix])) {
if ($this->Application->isDebugMode()) $this->Application->Debugger->appendTrace();
trigger_error('Configuration file for prefix <b>'.$prefix.'</b> is unknown', E_USER_ERROR);
return ;
}
$file = $this->prefixFiles[$prefix];
$prefix = $this->PreloadConfigFile($file);
$clones = $this->postProcessConfig($prefix, 'AggregateConfigs', 'sub_prefix');
$clones = array_merge($this->postProcessConfig($prefix, 'Clones', 'prefix'), $clones);
if ($this->FinalStage) {
array_unshift($clones, $prefix);
$clones = array_unique($clones);
foreach ($clones as $a_prefix) {
$this->Application->HandleEvent( new kEvent($a_prefix.':OnAfterConfigRead') );
}
}
}
/**
* Reads unit (specified by $prefix)
* option specified by $option
*
* @param string $prefix
* @param string $name
* @param mixed $default
* @return string
* @access public
*/
function getUnitOption($prefix, $name, $default = false)
{
if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) {
if (!isset($this->configData[$rets[1]])) {
$this->loadConfig($rets[1]);
}
$ret = isset($this->configData[$rets[1]][$name][$rets[2]]) ? $this->configData[$rets[1]][$name][$rets[2]] : false;
// $ret = getArrayValue($this->configData, $rets[1], $name, $rets[2]);
}
else {
if (!isset($this->configData[$prefix])) {
$this->loadConfig($prefix);
}
$ret = isset($this->configData[$prefix][$name]) ? $this->configData[$prefix][$name] : false;
// $ret = getArrayValue($this->configData, $prefix, $name);
}
return $ret === false ? $default : $ret;
}
/**
* Read all unit with $prefix options
*
* @param string $prefix
* @return Array
* @access public
*/
function getUnitOptions($prefix)
{
if (!isset($this->configData[$prefix])) {
$this->loadConfig($prefix);
}
return $this->configData[$prefix];
}
/**
* Set's new unit option value
*
* @param string $prefix
* @param string $name
* @param string $value
* @access public
*/
function setUnitOption($prefix, $name, $value)
{
if (preg_match('/(.*)\.(.*)/', $prefix, $rets)) {
if (!isset($this->configData[$rets[1]])) {
$this->loadConfig($rets[1]);
}
$this->configData[$rets[1]][$name][$rets[2]] = $value;
}
else {
if (!isset($this->configData[$prefix])) {
$this->loadConfig($prefix);
}
$this->configData[$prefix][$name] = $value;
}
}
function getPrefixByParamName($paramName,$prefix)
{
$pseudo_class_map=Array(
'ItemClass'=>'%s',
'ListClass'=>'%s_List',
'EventHandlerClass'=>'%s_EventHandler',
'TagProcessorClass'=>'%s_TagProcessor'
);
return sprintf($pseudo_class_map[$paramName],$prefix);
}
/**
* Get's config file name based
* on folder name supplied
*
* @param string $folderPath
* @return string
* @access private
*/
function getConfigName($folderPath)
{
return $folderPath . DIRECTORY_SEPARATOR . basename($folderPath) . '_config.php';
}
/**
* Checks if config file is allowed for includion (if module of config is installed)
*
* @param string $config_path relative path from in-portal directory
*/
function configAllowed($config_path)
{
if (defined('IS_INSTALL') && IS_INSTALL) {
// at installation start no modules in db and kernel configs could not be read
return true;
}
if (preg_match('#' . $this->_directorySeparator . 'plugins' . $this->_directorySeparator . '|' . $this->_directorySeparator . 'core#', $config_path)) {
// always allow to include configs from core and plugins folder
return true;
}
$module_found = false;
if (!$this->Application->ModuleInfo) {
return false;
}
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
$module_path = DIRECTORY_SEPARATOR . trim($module_info['Path'], '/') . DIRECTORY_SEPARATOR;
// config file path starts with module folder path
if (substr($config_path, 0, strlen($module_path)) == $module_path) {
// if (preg_match('#^' . preg_quote($module_path, '/') . '#', $config_path)) {
$module_found = true;
break;
}
}
return $module_found;
}
/**
* Returns true if config exists and is allowed for reading
*
* @param string $prefix
* @return bool
*/
function prefixRegistred($prefix)
{
return isset($this->prefixFiles[$prefix]) ? true : false;
}
/**
* Returns config file for given prefix
*
* @param string $prefix
* @return string
*/
function getPrefixFile($prefix)
{
return array_key_exists($prefix, $this->prefixFiles) ? $this->prefixFiles[$prefix] : false;
}
function iterateConfigs($callback_function, $params)
{
$this->includeConfigFiles(MODULES_PATH); //make sure to re-read all configs
$this->AfterConfigRead();
foreach ($this->configData as $prefix => $config_data) {
$callback_function[0]->$callback_function[1]($prefix, $config_data, $params);
}
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/utility/factory.php
===================================================================
--- branches/5.0.x/core/kernel/utility/factory.php (revision 12322)
+++ branches/5.0.x/core/kernel/utility/factory.php (revision 12323)
@@ -1,330 +1,331 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kFactory extends kBase {
/**
* Where all created objects are stored
*
* @var Array
* @access private
*/
var $Storage=Array();
/**
* Map between class name and file name
* where class definition can be found.
* File path absolute!
*
* @var Array
* @access private
*/
var $Files=Array();
/**
* Map class names to their pseudo
* class names, e.g. key=pseudo_class,
* value=real_class_name
*
* @var Array
* @access private
*/
var $realClasses=Array();
/**
* class name vs other classnames it's require for existing
*
* @var Array
*/
var $Dependencies=Array();
/**
* Splits any mixing of prefix and
* special into correct ones
*
* @param string $prefix_special
* @return Array
* @access public
*/
function processPrefix($prefix_special)
{
// l.pick, l, m.test_TagProcessor
//preg_match("/(.*)\.*(.*)(_*)(.*)/", $prefix_special, $regs);
//return Array('prefix'=>$regs[1].$regs[3].$regs[4], 'special'=>$regs[2]);
$tmp=explode('_',$prefix_special,2);
$tmp[0]=explode('.',$tmp[0]);
$prefix=$tmp[0][0];
$prefix_special=$prefix; // new1
if( isset($tmp[1]) )
{
$prefix.='_'.$tmp[1];
}
$special= isset($tmp[0][1]) ? $tmp[0][1] : '';
$prefix_special.='.'.$special; // new2
return Array('prefix'=>$prefix,'special'=>$special,'prefix_special'=>$prefix_special);
}
/**
* Returns object using params specified,
* creates it if is required
*
* @param string $name
* @param string $pseudo_class
* @param Array $event_params
* @return Object
*/
function &getObject($name,$pseudo_class='',$event_params=Array())
{
$name=rtrim($name,'.');
if( isset($this->Storage[$name]) ) return $this->Storage[$name];
$ret=$this->processPrefix($name);
if (!$pseudo_class) $pseudo_class = $ret['prefix'];
if (!isset($this->realClasses[$pseudo_class]))
{
if( $this->Application->isDebugMode() ) $this->Application->Debugger->appendTrace();
$error_level = $this->Application->isInstalled() ? E_USER_ERROR : E_USER_WARNING;
trigger_error('RealClass not defined for pseudo_class <b>'.$pseudo_class.'</b>', $error_level);
$false = false;
return $false;
}
- if ($this->Application->isDebugMode() && constOn('DBG_FACTORY')) {
+ if (defined('DEBUG_MODE') && defined('DBG_FACTORY') && DBG_FACTORY && $this->Application->isDebugMode()) {
global $debugger;
+
$debugger->appendHTML('<b>Creating object:</b> Pseudo class: '.$pseudo_class.' Prefix: '.$name);
$debugger->appendTrace();
}
$this->Storage[$name] =& $this->makeClass($pseudo_class);
$this->Storage[$name]->Init($ret['prefix'],$ret['special'],$event_params);
$prefix=$this->Storage[$name]->Prefix;
$special=$this->Storage[$name]->Special;
// $event_manager =& $this->Storage['EventManager'];
$event =& $this->Application->EventManager->getBuildEvent($pseudo_class);
if($event)
{
$event->Init($prefix,$special);
foreach($event_params as $param_name=>$param_value)
{
$event->setEventParam($param_name,$param_value);
}
$this->Application->HandleEvent($event);
}
return $this->Storage[$name];
}
/**
* Returns object using Variable number of params specified,
* creates it if is required
* all params after 4th are passed to object constructor
*
* @param string $name
* @param string $pseudo_class
* @param Array $event_params
* @return Object
*/
function &getObjectP($name,$pseudo_class='',$event_params=Array())
{
$ret=$this->processPrefix($name);
if (!$pseudo_class) $pseudo_class = $ret['prefix'];
$name=rtrim($name,'.');
if( isset($this->Storage[$name]) ) return $this->Storage[$name];
if (!isset($this->realClasses[$pseudo_class]))
{
if( $this->Application->isDebugMode() ) $this->Application->Debugger->appendTrace();
$error_level = $this->Application->isInstalled() ? E_USER_ERROR : E_USER_WARNING;
trigger_error('RealClass not defined for pseudo_class <b>'.$pseudo_class.'</b>', $error_level);
$false = false;
return $false;
}
- if ($this->Application->isDebugMode() && constOn('DBG_FACTORY')) {
+ if (defined('DEBUG_MODE') && defined('DBG_FACTORY') && DBG_FACTORY && $this->Application->isDebugMode()) {
global $debugger;
$debugger->appendHTML('<b>Creating object:</b> Pseudo class: '.$pseudo_class.' Prefix: '.$name);
$debugger->appendTrace();
}
$funs_args = func_get_args();
array_splice($funs_args, 0, 3, Array($pseudo_class) );
$this->Storage[$name] =& ref_call_user_func_array( Array(&$this,'makeClass'), $funs_args);
$this->Storage[$name]->Init($ret['prefix'],$ret['special'],$event_params);
$prefix=$this->Storage[$name]->Prefix;
$special=$this->Storage[$name]->Special;
$event_manager =& $this->getObject('EventManager');
$event =& $event_manager->getBuildEvent($pseudo_class);
if($event)
{
$event->Init($prefix,$special);
foreach($event_params as $param_name=>$param_value)
{
$event->setEventParam($param_name,$param_value);
}
$this->Application->HandleEvent($event);
}
return $this->Storage[$name];
}
/**
* Removes object from storage, so next time it could be created from scratch
*
* @param string $name Object's name in the Storage
*/
function DestroyObject($name)
{
unset($this->Storage[$name]);
}
/**
* Includes file containing class
* definition for real class name
*
* @param string $real_class
* @access private
*/
function includeClassFile($real_class)
{
if (class_exists($real_class)) return;
if(!isset($this->Files[$real_class])) {
trigger_error('Real Class <b>'.$real_class.'</b> is not registered with the Factory', E_USER_ERROR);
}
if(!file_exists(FULL_PATH.$this->Files[$real_class])) {
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
trigger_error('Include file for class <b>'.$real_class.'</b> (<b>'.FULL_PATH.$this->Files[$real_class].'</b>) does not exists', E_USER_ERROR);
}
if( isset( $this->Dependencies[$real_class] ) )
{
foreach($this->Dependencies[$real_class] as $dep_class_name)
{
$this->includeClassFile($dep_class_name);
}
}
k4_include_once(FULL_PATH.$this->Files[$real_class]);
}
/**
* Get's real class name for pseudo class,
* includes class file and creates class
* instance.
* All parameters except first one are passed to object constuctor
* through mediator method makeClass that creates instance of class
*
* @param string $pseudo_class
* @return Object
* @access private
*/
function &makeClass($pseudo_class)
{
$real_class = $this->realClasses[$pseudo_class];
if (!class_exists($real_class)) $this->includeClassFile($real_class);
$mem_before = memory_get_usage();
$time_before = getmicrotime();
if( func_num_args() == 1 )
{
$class = new $real_class();
}
else
{
$func_args = func_get_args();
$pseudo_class = array_shift($func_args);
$class =& ref_call_user_func_array( Array($real_class,'makeClass'), $func_args );
}
if( defined('DEBUG_MODE') && DEBUG_MODE && constOn('DBG_PROFILE_MEMORY') )
{
$mem_after = memory_get_usage();
$time_after = getmicrotime();
$mem_used = $mem_after - $mem_before;
$time_used = $time_after - $time_before;
global $debugger;
$debugger->appendHTML('Factroy created <b>'.$real_class.'</b> - used '.round($mem_used/1024, 3).'Kb time: '.round($time_used, 5));
$debugger->profilerAddTotal('objects', null, $mem_used);
}
return $class;
}
/**
* Registers new class in the factory
*
* @param string $real_class Real name of class as in class declaration
* @param string $file Filename in what $real_class is declared
* @param string $pseudo_class Name under this class object will be accessed using getObject method
* @param Array $dependecies List of classes required for this class functioning
* @access public
*/
function registerClass($real_class, $file, $pseudo_class=null, $dependecies = Array() )
{
if(!isset($pseudo_class)) $pseudo_class = $real_class;
if (!isset($this->Files[$real_class])) {
$this->Files[$real_class] = preg_replace('/^'.preg_quote(FULL_PATH, '/').'/', '', $file, 1);
}
if (isset($this->realClasses[$pseudo_class])) {
$this->registerDependency($real_class, $pseudo_class);
}
if($dependecies)
{
if (!is_array($dependecies)) $dependecies = array($dependecies);
foreach ($dependecies as $required_class) {
$this->registerDependency($real_class, $required_class);
}
}
$this->realClasses[$pseudo_class]=$real_class;
}
/**
* Add $class_name to required classes list for $depended_class class.
* All required class files are included before $depended_class file is included
*
* @param string $depended_class
* @param string $class_name
* @author Alex
*/
function registerDependency($depended_class, $class_name)
{
$dependencies =& $this->Dependencies[$depended_class];
$conditions = Array();
$conditions['exists'] = is_array($dependencies) && in_array($this->realClasses[$class_name], $dependencies);
$conditions['same_class'] = $this->realClasses[$class_name] == $depended_class;
if (!$conditions['exists'] && !$conditions['same_class']) {
$dependencies[] = $this->realClasses[$class_name];
}
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/db/db_tag_processor.php
===================================================================
--- branches/5.0.x/core/kernel/db/db_tag_processor.php (revision 12322)
+++ branches/5.0.x/core/kernel/db/db_tag_processor.php (revision 12323)
@@ -1,2512 +1,2514 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kDBTagProcessor extends TagProcessor {
/**
* Description
*
* @var kDBConnection
* @access public
*/
var $Conn;
function kDBTagProcessor()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
/**
* Returns true if "new" button was pressed in toolbar
*
* @param Array $params
* @return bool
*/
function IsNewMode($params)
{
$object =& $this->getObject($params);
return $object->GetID() <= 0;
}
/**
* Returns view menu name for current prefix
*
* @param Array $params
* @return string
*/
function GetItemName($params)
{
$item_name = $this->Application->getUnitOption($this->Prefix, 'ViewMenuPhrase');
return $this->Application->Phrase($item_name);
}
function ViewMenu($params)
{
$block_params = $params;
unset($block_params['block']);
$block_params['name'] = $params['block'];
$list =& $this->GetList($params);
$block_params['PrefixSpecial'] = $list->getPrefixSpecial();
return $this->Application->ParseBlock($block_params);
}
function SearchKeyword($params)
{
$list =& $this->GetList($params);
return $this->Application->RecallVar($list->getPrefixSpecial().'_search_keyword');
}
/**
* Draw filter menu content (for ViewMenu) based on filters defined in config
*
* @param Array $params
* @return string
*/
function DrawFilterMenu($params)
{
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['spearator_block'];
$separator = $this->Application->ParseBlock($block_params);
$filter_menu = $this->Application->getUnitOption($this->Prefix,'FilterMenu');
if (!$filter_menu) {
trigger_error('<span class="debug_error">no filters defined</span> for prefix <b>'.$this->Prefix.'</b>, but <b>DrawFilterMenu</b> tag used', E_USER_WARNING);
return '';
}
// Params: label, filter_action, filter_status
$block_params['name'] = $params['item_block'];
$view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
if ($view_filter === false) {
$event_params = Array ('prefix' => $this->Prefix, 'special' => $this->Special, 'name' => 'OnRemoveFilters');
$this->Application->HandleEvent( new kEvent($event_params) );
$view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
}
$view_filter = unserialize($view_filter);
$filters = Array();
$prefix_special = $this->getPrefixSpecial();
foreach ($filter_menu['Filters'] as $filter_key => $filter_params) {
$group_params = isset($filter_params['group_id']) ? $filter_menu['Groups'][ $filter_params['group_id'] ] : Array();
if (!isset($group_params['element_type'])) {
$group_params['element_type'] = 'checkbox';
}
if (!$filter_params) {
$filters[] = $separator;
continue;
}
$block_params['label'] = addslashes( $this->Application->Phrase($filter_params['label']) );
if (getArrayValue($view_filter,$filter_key)) {
$submit = 0;
if (isset($params['old_style'])) {
$status = $group_params['element_type'] == 'checkbox' ? 1 : 2;
}
else {
$status = $group_params['element_type'] == 'checkbox' ? '[\'img/check_on.gif\']' : '[\'img/menu_dot.gif\']';
}
}
else {
$submit = 1;
$status = 'null';
}
$block_params['filter_action'] = 'set_filter("'.$prefix_special.'","'.$filter_key.'","'.$submit.'",'.$params['ajax'].');';
$block_params['filter_status'] = $status; // 1 - checkbox, 2 - radio, 0 - no image
$filters[] = $this->Application->ParseBlock($block_params);
}
return implode('', $filters);
}
/**
* Draws auto-refresh submenu in View Menu.
*
* @param Array $params
* @return string
*/
function DrawAutoRefreshMenu($params)
{
$refresh_intervals = $this->Application->ConfigValue('AutoRefreshIntervals');
if (!$refresh_intervals) {
trigger_error('<span class="debug_error">no filters defined</span> for prefix <strong>'.$this->Prefix.'</strong>, but <strong>DrawAutoRefreshMenu</strong> tag used', E_USER_WARNING);
return '';
}
$refresh_intervals = explode(',', $refresh_intervals);
$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
$current_refresh_interval = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name);
if ($current_refresh_interval === false) {
// if no interval was selected before, then choose 1st interval
$current_refresh_interval = $refresh_intervals[0];
}
$ret = '';
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['render_as'];
foreach ($refresh_intervals as $refresh_interval) {
$block_params['label'] = $this->_formatInterval($refresh_interval);
$block_params['refresh_interval'] = $refresh_interval;
$block_params['selected'] = $current_refresh_interval == $refresh_interval;
$ret .= $this->Application->ParseBlock($block_params);
}
return $ret;
}
/**
* Tells, that current grid is using auto refresh
*
* @param Array $params
* @return bool
*/
function UseAutoRefresh($params)
{
$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_auto_refresh.'.$view_name);
}
/**
* Returns current grid refresh interval
*
* @param Array $params
* @return bool
*/
function AutoRefreshInterval($params)
{
$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name);
}
/**
* Formats time interval using given text for hours and minutes
*
* @param int $intervalmMinutes
* @param string $hour_text Text for hours
* @param string $min_text Text for minutes
* @return unknown
*/
function _formatInterval($interval, $hour_text = 'h', $min_text = 'min')
{
// 65
$minutes = $interval % 60;
$hours = ($interval - $minutes) / 60;
$ret = '';
if ($hours) {
$ret .= $hours.$hour_text.' ';
}
if ($minutes) {
$ret .= $minutes.$min_text;
}
return $ret;
}
function IterateGridFields($params)
{
$mode = $params['mode'];
$def_block = isset($params['block']) ? $params['block'] : '';
$force_block = isset($params['force_block']) ? $params['force_block'] : false;
$grids = $this->Application->getUnitOption($this->Prefix,'Grids');
$grid_config = $grids[$params['grid']]['Fields'];
$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
/* @var $picker_helper kColumnPickerHelper */
$picker_helper->ApplyPicker($this->getPrefixSpecial(), $grid_config, $params['grid']);
if ($mode == 'fields') {
return "'".join("','", array_keys($grid_config))."'";
}
$std_params['pass_params'] = 'true';
$std_params['PrefixSpecial'] = $this->getPrefixSpecial();
$object =& $this->GetList($params);
$o = '';
$i = 0;
foreach ($grid_config as $field => $options) {
$i++;
$block_params = Array();
$block_params['name'] = $force_block ? $force_block : (isset($options[$mode.'_block']) ? $options[$mode.'_block'] : $def_block);
$block_params['field'] = $field;
$block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field;
$block_params['filter_field'] = isset($options['filter_field']) ? $options['filter_field'] : $field;
$w = $picker_helper->GetWidth($field);
if ($w) $options['width'] = $w;
/*if (isset($options['filter_width'])) {
$block_params['filter_width'] = $options['filter_width'];
}
elseif (isset($options['width'])) {
if (isset($options['filter_block']) && preg_match('/range/', $options['filter_block'])) {
if ($options['width'] < 60) {
$options['width'] = 60;
$block_params['filter_width'] = 20;
}
else {
$block_params['filter_width'] = $options['width'] - 40;
}
}
else {
$block_params['filter_width'] = max($options['width']-10, 20);
}
}*/
/*if (isset($block_params['filter_width'])) $block_params['filter_width'] .= 'px';
if (isset($options['filter_block']) && preg_match('/range/', $options['filter_block'])) {
$block_params['filter_width'] = '20px';
}
else {
$block_params['filter_width'] = '97%';
// $block_params['filter_width'] = max($options['width']-10, 20);
}*/
$field_options = $object->GetFieldOptions($field);
if (array_key_exists('use_phrases', $field_options)) {
$block_params['use_phrases'] = $field_options['use_phrases'];
}
$block_params['is_last'] = ($i == count($grid_config));
$block_params = array_merge($std_params, $options, $block_params);
$o.= $this->Application->ParseBlock($block_params, 1);
}
return $o;
}
function PickerCRC($params)
{
/* @var $picker_helper kColumnPickerHelper */
$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
$picker_helper->SetGridName($params['grid']);
$data = $picker_helper->LoadColumns($this->getPrefixSpecial());
return $data['crc'];
}
function FreezerPosition($params)
{
/* @var $picker_helper kColumnPickerHelper */
$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
$picker_helper->SetGridName($params['grid']);
$data = $picker_helper->LoadColumns($this->getPrefixSpecial());
$freezer_pos = array_search('__FREEZER__', $data['order']);
return $freezer_pos === false || in_array('__FREEZER__', $data['hidden_fields']) ? 1 : ++$freezer_pos;
}
function GridFieldsCount($params)
{
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
$grid_config = $grids[$params['grid']]['Fields'];
return count($grid_config);
}
/**
* Prints list content using block specified
*
* @param Array $params
* @return string
* @access public
*/
function PrintList($params)
{
$params['no_table'] = 1;
return $this->PrintList2($params);
}
function InitList($params)
{
$list_name = isset($params['list_name']) ? $params['list_name'] : '';
$names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
if( !getArrayValue($names_mapping, $this->Prefix, $list_name) )
{
$list =& $this->GetList($params);
}
}
function BuildListSpecial($params)
{
return $this->Special;
}
/**
* Returns key, that identifies each list on template (used internally, not tag)
*
* @param Array $params
* @return string
*/
function getUniqueListKey($params)
{
$types = $this->SelectParam($params, 'types');
$except = $this->SelectParam($params, 'except');
$list_name = $this->SelectParam($params, 'list_name');
if (!$list_name) {
$list_name = $this->Application->Parser->GetParam('list_name');
}
return $types.$except.$list_name;
}
/**
* Enter description here...
*
* @param Array $params
* @return kDBList
*/
function &GetList($params)
{
$list_name = $this->SelectParam($params, 'list_name,name');
if (!$list_name) {
$list_name = $this->Application->Parser->GetParam('list_name');
}
$requery = isset($params['requery']) && $params['requery'];
if ($list_name && !$requery) {
$names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
$special = is_array($names_mapping) && isset($names_mapping[$this->Prefix]) && isset($names_mapping[$this->Prefix][$list_name]) ? $names_mapping[$this->Prefix][$list_name] : false;
// $special = getArrayValue($names_mapping, $this->Prefix, $list_name);
if (!$special) {
$special = $this->BuildListSpecial($params);
}
}
else {
$special = $this->BuildListSpecial($params);
}
$prefix_special = rtrim($this->Prefix.'.'.$special, '.');
$params['skip_counting'] = true;
$list =& $this->Application->recallObject( $prefix_special, $this->Prefix.'_List', $params);
/* @var $list kDBList */
if (!array_key_exists('skip_quering', $params) || !$params['skip_quering']) {
if ($requery) {
$this->Application->HandleEvent($an_event, $prefix_special.':OnListBuild', $params);
}
if (array_key_exists('offset', $params)) {
$list->Offset += $params['offset']; // apply custom offset
}
$list->Query($requery);
if (array_key_exists('offset', $params)) {
$list->Offset -= $params['offset']; // remove custom offset
}
}
$this->Special = $special;
if ($list_name) {
$names_mapping[$this->Prefix][$list_name] = $special;
$this->Application->SetVar('NamesToSpecialMapping', $names_mapping);
}
return $list;
}
function ListMarker($params)
{
$list =& $this->GetList($params);
$ret = $list->getPrefixSpecial();
if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
return $ret;
}
/**
* Prepares name for field with event in it (used only on front-end)
*
* @param Array $params
* @return string
*/
function SubmitName($params)
{
$list =& $this->GetList($params);
$prefix_special = $list->getPrefixSpecial();
return 'events['.$prefix_special.']['.$params['event'].']';
}
/**
* Prints list content using block specified
*
* @param Array $params
* @return string
* @access public
*/
function PrintList2($params)
{
$per_page = $this->SelectParam($params, 'per_page,max_items');
if ($per_page !== false) $params['per_page'] = $per_page;
$list =& $this->GetList($params);
$o = '';
$direction = (isset($params['direction']) && $params['direction']=="H")?"H":"V";
$columns = (isset($params['columns'])) ? $params['columns'] : 1;
$id_field = (isset($params['id_field'])) ? $params['id_field'] : $this->Application->getUnitOption($this->Prefix, 'IDField');
if ($columns > 1 && $direction == 'V') {
$records_left = array_splice($list->Records, $list->SelectedCount); // because we have 1 more record for "More..." link detection (don't need to sort it)
$list->Records = $this->LinearToVertical($list->Records, $columns, $list->GetPerPage());
$list->Records = array_merge($list->Records, $records_left);
}
$list->GoFirst();
$block_params=$this->prepareTagParams($params);
$block_params['name'] = $this->SelectParam($params, 'render_as,block');
$block_params['pass_params'] = 'true';
$block_params['column_width'] = $params['column_width'] = 100 / $columns;
$block_start_row_params = $this->prepareTagParams($params);
$block_start_row_params['name'] = $this->SelectParam($params, 'row_start_render_as,block_row_start,row_start_block');
$block_end_row_params=$this->prepareTagParams($params);
$block_end_row_params['name'] = $this->SelectParam($params, 'row_end_render_as,block_row_end,row_end_block');
$block_empty_cell_params = $this->prepareTagParams($params);
$block_empty_cell_params['name'] = $this->SelectParam($params, 'empty_cell_render_as,block_empty_cell,empty_cell_block');
$i=0;
$backup_id=$this->Application->GetVar($this->Prefix."_id");
$displayed = array();
$column_number = 1;
$cache_mod_rw = $this->Application->getUnitOption($this->Prefix, 'CacheModRewrite') && $this->Application->RewriteURLs();
$limit = isset($params['limit']) ? $params['limit'] : false;
while (!$list->EOL() && (!$limit || $i<$limit))
{
$this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) ); // for edit/delete links using GET
$this->Application->SetVar( $this->Prefix.'_id', $list->GetDBField($id_field) );
$block_params['is_last'] = ($i == $list->SelectedCount - 1);
$block_params['last_row'] = ($i + (($i+1) % $columns) >= $list->SelectedCount - 1);
$block_params['not_last'] = !$block_params['is_last']; // for front-end
if ($cache_mod_rw) {
if ($this->Prefix == 'c') {
// for listing subcategories in category
$this->Application->setCache('filenames', $this->Prefix.'_'.$list->GetDBField($id_field), $list->GetDBField('NamedParentPath'));
$this->Application->setCache('category_tree', $list->GetDBField($id_field), $list->GetDBField('TreeLeft') . ';' . $list->GetDBField('TreeRight'));
} else {
// for listing items in category
$this->Application->setCache('filenames', 'c_'.$list->GetDBField('CategoryId'), $list->GetDBField('CategoryFilename'));
$this->Application->setCache('filenames', $this->Prefix.'_'.$list->GetDBField($id_field), $list->GetDBField('Filename'));
}
}
if ($i % $columns == 0) {
// record in this iteration is first in row, then open row
$column_number = 1;
$o.= $block_start_row_params['name'] ?
$this->Application->ParseBlock($block_start_row_params, 1) :
(!isset($params['no_table']) ? '<tr>' : '');
}
else {
$column_number++;
}
$block_params['first_col'] = $column_number == 1 ? 1 : 0;
$block_params['last_col'] = $column_number == $columns ? 1 : 0;
$block_params['column_number'] = $column_number;
$block_params['num'] = ($i+1);
$this->PrepareListElementParams($list, $block_params); // new, no need to rewrite PrintList
$o.= $this->Application->ParseBlock($block_params, 1);
array_push($displayed, $list->GetDBField($id_field));
if($direction == 'V' && $list->SelectedCount % $columns > 0 && $column_number == ($columns - 1) && ceil(($i + 1) / $columns) > $list->SelectedCount % ceil($list->SelectedCount / $columns)) {
// if vertical output, then draw empty cells vertically, not horizontally
$o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params, 1) : '<td>&nbsp;</td>';
$i++;
}
if (($i + 1) % $columns == 0) {
// record in next iteration is first in row too, then close this row
$o.= $block_end_row_params['name'] ?
$this->Application->ParseBlock($block_end_row_params, 1) :
(!isset($params['no_table']) ? '</tr>' : '');
}
$list->GoNext();
$i++;
}
// append empty cells in place of missing cells in last row
while ($i % $columns != 0) {
// until next cell will be in new row append empty cells
$o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params, 1) : '<td>&nbsp;</td>';
if (($i+1) % $columns == 0) {
// record in next iteration is first in row too, then close this row
$o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params, 1) : '</tr>';
}
$i++;
}
$cur_displayed = $this->Application->GetVar($this->Prefix.'_displayed_ids');
if (!$cur_displayed) {
$cur_displayed = Array();
}
else {
$cur_displayed = explode(',', $cur_displayed);
}
$displayed = array_unique(array_merge($displayed, $cur_displayed));
$this->Application->SetVar($this->Prefix.'_displayed_ids', implode(',',$displayed));
$this->Application->SetVar( $this->Prefix.'_id', $backup_id);
$this->Application->SetVar( $this->getPrefixSpecial().'_id', '');
if (isset($params['more_link_render_as'])) {
$block_params = $params;
$params['render_as'] = $params['more_link_render_as'];
$o .= $this->MoreLink($params);
}
return $o;
}
/**
* Allows to modify block params & current list record before PrintList parses record
*
* @param kDBList $object
* @param Array $block_params
*/
function PrepareListElementParams(&$object, &$block_params)
{
// $fields_hash =& $object->getCurrentRecord();
}
function MoreLink($params)
{
$per_page = $this->SelectParam($params, 'per_page,max_items');
if ($per_page !== false) $params['per_page'] = $per_page;
$list =& $this->GetList($params);
if ($list->PerPage < $list->RecordsCount) {
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $this->SelectParam($params, 'render_as,block');
return $this->Application->ParseBlock($block_params);
}
}
function NotLastItem($params)
{
$object =& $this->getList($params); // maybe we should use $this->GetList($params) instead
return ($object->CurrentIndex < min($object->PerPage == -1 ? $object->RecordsCount : $object->PerPage, $object->RecordsCount) - 1);
}
function PageLink($params)
{
$t = isset($params['template']) ? $params['template'] : '';
unset($params['template']);
if (!$t) $t = $this->Application->GetVar('t');
if (isset($params['page'])) {
$this->Application->SetVar($this->getPrefixSpecial().'_Page', $params['page']);
unset($params['page']);
}
if (!isset($params['pass'])) {
$params['pass'] = 'm,'.$this->getPrefixSpecial();
}
return $this->Application->HREF($t, '', $params);
}
function ColumnWidth($params)
{
$columns = $this->Application->Parser->GetParam('columns');
+
return round(100/$columns).'%';
}
/**
* Append prefix and special to tag
* params (get them from tagname) like
* they were really passed as params
*
* @param Array $tag_params
* @return Array
* @access protected
*/
function prepareTagParams($tag_params = Array())
{
/*if (isset($tag_params['list_name'])) {
$list =& $this->GetList($tag_params);
$this->Init($list->Prefix, $list->Special);
}*/
$ret = $tag_params;
$ret['Prefix'] = $this->Prefix;
$ret['Special'] = $this->Special;
$ret['PrefixSpecial'] = $this->getPrefixSpecial();
return $ret;
}
function GetISO($currency)
{
if ($currency == 'selected') {
$iso = $this->Application->RecallVar('curr_iso');
}
elseif ($currency == 'primary' || $currency == '') {
$iso = $this->Application->GetPrimaryCurrency();
}
else { //explicit currency
$iso = $currency;
}
return $iso;
}
function ConvertCurrency($value, $iso)
{
$converter =& $this->Application->recallObject('kCurrencyRates');
// convery primary currency to selected (if they are the same, converter will just return)
$value = $converter->Convert($value, 'PRIMARY', $iso);
return $value;
}
function AddCurrencySymbol($value, $iso)
{
$currency =& $this->Application->recallObject('curr.-'.$iso, null, Array('skip_autoload' => true));
if( !$currency->isLoaded() ) $currency->Load($iso, 'ISO');
$symbol = $currency->GetDBField('Symbol');
if (!$symbol) $symbol = $currency->GetDBField('ISO').'&nbsp;';
if ($currency->GetDBField('SymbolPosition') == 0) {
$value = $symbol.$value;
}
if ($currency->GetDBField('SymbolPosition') == 1) {
$value = $value.$symbol;
}
return $value;
}
/**
* Get's requested field value
*
* @param Array $params
* @return string
* @access public
*/
function Field($params)
{
$field = $this->SelectParam($params, 'name,field');
if( !$this->Application->IsAdmin() ) $params['no_special'] = 'no_special';
$object =& $this->getObject($params);
if ( $this->HasParam($params, 'db') )
{
$value = $object->GetDBField($field);
}
else
{
if( $this->HasParam($params, 'currency') )
{
$iso = $this->GetISO($params['currency']);
$original = $object->GetDBField($field);
$value = $this->ConvertCurrency($original, $iso);
$object->SetDBField($field, $value);
$object->Fields[$field]['converted'] = true;
}
$format = getArrayValue($params, 'format');
if (!$format || $format == '$format') {
$format = null;
}
$value = $object->GetField($field, $format);
if( $this->SelectParam($params, 'negative') )
{
if(strpos($value, '-') === 0)
{
$value = substr($value, 1);
}
else
{
$value = '-'.$value;
}
}
if( $this->HasParam($params, 'currency') )
{
$value = $this->AddCurrencySymbol($value, $iso);
$params['no_special'] = 1;
}
}
if( !$this->HasParam($params, 'no_special') ) $value = htmlspecialchars($value);
if( getArrayValue($params,'checked' ) ) $value = ($value == ( isset($params['value']) ? $params['value'] : 1)) ? 'checked' : '';
if( isset($params['plus_or_as_label']) ) {
$value = substr($value, 0,1) == '+' ? substr($value, 1) : $this->Application->Phrase($value);
}
elseif( isset($params['as_label']) && $params['as_label'] ) $value = $this->Application->Phrase($value);
$first_chars = $this->SelectParam($params,'first_chars,cut_first');
if($first_chars)
{
$needs_cut = mb_strlen($value) > $first_chars;
$value = mb_substr($value, 0, $first_chars);
if ($needs_cut) $value .= ' ...';
}
if( getArrayValue($params,'nl2br' ) ) $value = nl2br($value);
if ($value != '') $this->Application->Parser->DataExists = true;
if( $this->HasParam($params, 'currency') )
{
//restoring value in original currency, for other Field tags to work properly
$object->SetDBField($field, $original);
}
return $value;
}
function SetField($params)
{
// <inp2:SetField field="Value" src=p:cust_{$custom_name}"/>
$object =& $this->getObject($params);
$dst_field = $this->SelectParam($params, 'name,field');
list($prefix_special, $src_field) = explode(':', $params['src']);
$src_object =& $this->Application->recallObject($prefix_special);
$object->SetDBField($dst_field, $src_object->GetDBField($src_field));
}
/**
* Checks if parameter is passed
* Note: works like Tag and line simple method too
*
* @param Array $params
* @param string $param_name
* @return bool
*/
function HasParam($params, $param_name = null)
{
- if( !isset($param_name) )
- {
+ if ( !isset($param_name) ) {
$param_name = $this->SelectParam($params, 'name');
$params = $this->Application->Parser->Params;
}
+
$value = isset($params[$param_name]) ? $params[$param_name] : false;
+
return $value && ($value != '$'.$param_name);
}
function PhraseField($params)
{
$field_label = $this->Field($params);
$translation = $this->Application->Phrase( $field_label );
return $translation;
}
function Error($params)
{
$field = $this->SelectParam($params, 'name,field');
$object =& $this->getObject($params);
$msg = $object->GetErrorMsg($field, false);
return $msg;
}
function HasError($params)
{
if ($params['field'] == 'any')
{
$object =& $this->getObject($params);
$skip_fields = getArrayValue($params, 'except');
$skip_fields = $skip_fields ? explode(',', $skip_fields) : Array();
return $object->HasErrors($skip_fields);
}
else
{
$fields = $this->SelectParam($params, 'field,fields');
$fields = explode(',', $fields);
$res = false;
foreach($fields as $field)
{
$params['field'] = $field;
$res = $res || ($this->Error($params) != '');
}
return $res;
}
}
function ErrorWarning($params)
{
if (!isset($params['field'])) {
$params['field'] = 'any';
}
if ($this->HasError($params)) {
$params['prefix'] = $this->getPrefixSpecial();
return $this->Application->ParseBlock($params);
}
}
function IsRequired($params)
{
$field = $params['field'];
$object =& $this->getObject($params);;
$formatter_class = getArrayValue($object->Fields, $field, 'formatter');
if ($formatter_class == 'kMultiLanguage')
{
$formatter =& $this->Application->recallObject($formatter_class);
$field = $formatter->LangFieldName($field);
}
$options = $object->GetFieldOptions($field);
return getArrayValue($options,'required');
}
function FieldOption($params)
{
$object =& $this->getObject($params);;
$options = $object->GetFieldOptions($params['field']);
$ret = isset($options[$params['option']]) ? $options[$params['option']] : '';
if (isset($params['as_label']) && $params['as_label']) $ret = $this->Application->ReplaceLanguageTags($ret);
return $ret;
}
function PredefinedOptions($params)
{
$object =& $this->getObject($params);
$field = $params['field'];
$value = array_key_exists('value', $params) ? $params['value'] : $object->GetDBField($field);
$field_options = $object->GetFieldOptions($field);
if (!array_key_exists('options', $field_options) || !is_array($field_options['options'])) {
trigger_error('Options not defined for <strong>'.$object->Prefix.'</strong> field <strong>'.$field.'</strong>', E_USER_WARNING);
return '';
}
$options = $field_options['options'];
if ($this->HasParam($params, 'has_empty')) {
$empty_value = array_key_exists('empty_value', $params) ? $params['empty_value'] : '';
$options = array_merge_recursive2(Array ($empty_value => ''), $options); // don't use other array merge function, because they will reset keys !!!
}
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $this->SelectParam($params, 'render_as,block');
$block_params['pass_params'] = 'true';
if (method_exists($object, 'EOL') && count($object->Records) == 0) {
// for drawing grid column filter
$block_params['field_name'] = '';
}
else {
$block_params['field_name'] = $this->InputName($params); // depricated (produces warning when used as grid filter), but used in Front-End (submission create), admin (submission view)
}
$selected_param_name = getArrayValue($params, 'selected_param');
if (!$selected_param_name) {
$selected_param_name = $params['selected'];
}
$selected = $params['selected'];
$o = '';
if ($this->HasParam($params, 'no_empty') && !getArrayValue($options, '')) {
// removes empty option, when present (needed?)
array_shift($options);
}
if (strpos($value, '|') !== false) {
// multiple checkboxes OR multiselect
$value = explode('|', substr($value, 1, -1) );
foreach ($options as $key => $val) {
$block_params['key'] = $key;
$block_params['option'] = $val;
$block_params[$selected_param_name] = ( in_array($key, $value) ? ' '.$selected : '');
$o .= $this->Application->ParseBlock($block_params, 1);
}
}
else {
// single selection radio OR checkboxes OR dropdown
foreach ($options as $key => $val) {
$block_params['key'] = $key;
$block_params['option'] = $val;
$block_params[$selected_param_name] = (strlen($key) == strlen($value) && ($key == $value) ? ' '.$selected : '');
$o .= $this->Application->ParseBlock($block_params, 1);
}
}
return $o;
}
function PredefinedSearchOptions($params)
{
$object =& $this->GetList($params);
/* @var $object kDBList */
$params['value'] = $this->SearchField($params);
return $this->PredefinedOptions($params);
}
function Format($params)
{
$field = $this->SelectParam($params, 'name,field');
$object =& $this->getObject($params);
$options = $object->GetFieldOptions($field);
$format = $options[ $this->SelectParam($params, 'input_format') ? 'input_format' : 'format' ];
$formatter_class = getArrayValue($options,'formatter');
if ($formatter_class) {
$formatter =& $this->Application->recallObject($formatter_class);
$human_format = getArrayValue($params,'human');
$edit_size = getArrayValue($params,'edit_size');
$sample = getArrayValue($params,'sample');
if($sample)
{
return $formatter->GetSample($field, $options, $object);
}
elseif($human_format || $edit_size)
{
$format = $formatter->HumanFormat($format);
return $edit_size ? strlen($format) : $format;
}
}
return $format;
}
/**
* Returns grid padination information
* Can return links to pages
*
* @param Array $params
* @return mixed
*/
function PageInfo($params)
{
$object =& $this->GetList($params);
/* @var $object kDBList */
$type = $params['type'];
unset($params['type']); // remove parameters used only by current tag
$ret = '';
switch ($type) {
case 'current':
$ret = $object->Page;
break;
case 'total':
$ret = $object->GetTotalPages();
break;
case 'prev':
$ret = $object->Page > 1 ? $object->Page - 1 : false;
break;
case 'next':
$ret = $object->Page < $object->GetTotalPages() ? $object->Page + 1 : false;
break;
}
if ($ret && isset($params['as_link']) && $params['as_link']) {
unset($params['as_link']); // remove parameters used only by current tag
$params['page'] = $ret;
$current_page = $object->Page; // backup current page
$ret = $this->PageLink($params);
$this->Application->SetVar($object->getPrefixSpecial().'_Page', $current_page); // restore page
}
return $ret;
}
/**
* Print grid pagination using
* block names specified
*
* @param Array $params
* @return string
* @access public
*/
function PrintPages($params)
{
$list =& $this->GetList($params);
$prefix_special = $list->getPrefixSpecial();
$total_pages = $list->GetTotalPages();
if ($total_pages > 1) $this->Application->Parser->DataExists = true;
if($total_pages == 0) $total_pages = 1; // display 1st page as selected in case if we have no pages at all
$o = '';
// what are these 2 lines for?
$this->Application->SetVar($prefix_special.'_event','');
$this->Application->SetVar($prefix_special.'_id','');
$current_page = $list->Page; // $this->Application->RecallVar($prefix_special.'_Page');
$block_params = $this->prepareTagParams($params);
$split = ( isset($params['split'] ) ? $params['split'] : 10 );
$split_start = $current_page - ceil($split/2);
if ($split_start < 1){
$split_start = 1;
}
$split_end = $split_start + $split-1;
if ($split_end > $total_pages) {
$split_end = $total_pages;
$split_start = max($split_end - $split + 1, 1);
}
if ($current_page > 1){
$prev_block_params = $this->prepareTagParams();
if ($total_pages > $split){
$prev_block_params['page'] = max($current_page-$split, 1);
$prev_block_params['name'] = $this->SelectParam($params, 'prev_page_split_render_as,prev_page_split_block');
if ($prev_block_params['name']){
$o .= $this->Application->ParseBlock($prev_block_params, 1);
}
}
$prev_block_params['name'] = 'page';
$prev_block_params['page'] = $current_page-1;
$prev_block_params['name'] = $this->SelectParam($params, 'prev_page_render_as,block_prev_page,prev_page_block');
if ($prev_block_params['name']) {
$this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page-1);
$o .= $this->Application->ParseBlock($prev_block_params, 1);
}
}
else {
if ( $no_prev_page_block = $this->SelectParam($params, 'no_prev_page_render_as,block_no_prev_page') ) {
$block_params['name'] = $no_prev_page_block;
$o .= $this->Application->ParseBlock($block_params, 1);
}
}
$separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator');
for ($i = $split_start; $i <= $split_end; $i++)
{
if ($i == $current_page) {
$block = $this->SelectParam($params, 'current_render_as,active_render_as,block_current,active_block');
}
else {
$block = $this->SelectParam($params, 'link_render_as,inactive_render_as,block_link,inactive_block');
}
$block_params['name'] = $block;
$block_params['page'] = $i;
$this->Application->SetVar($this->getPrefixSpecial().'_Page', $i);
$o .= $this->Application->ParseBlock($block_params, 1);
if ($this->SelectParam($params, 'separator_render_as,block_separator')
&& $i < $split_end)
{
$o .= $this->Application->ParseBlock($separator_params, 1);
}
}
if ($current_page < $total_pages){
$next_block_params = $this->prepareTagParams();
$next_block_params['page']=$current_page+1;
$next_block_params['name'] = $this->SelectParam($params, 'next_page_render_as,block_next_page,next_page_block');
if ($next_block_params['name']){
$this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page+1);
$o .= $this->Application->ParseBlock($next_block_params, 1);
}
if ($total_pages > $split){
$next_block_params['page']=min($current_page+$split, $total_pages);
$next_block_params['name'] = $this->SelectParam($params, 'next_page_split_render_as,next_page_split_block');
if ($next_block_params['name']){
$o .= $this->Application->ParseBlock($next_block_params, 1);
}
}
}
else {
if ( $no_next_page_block = $this->SelectParam($params, 'no_next_page_render_as,block_no_next_page') ) {
$block_params['name'] = $no_next_page_block;
$o .= $this->Application->ParseBlock($block_params, 1);
}
}
$this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page);
return $o;
}
/**
* Print grid pagination using
* block names specified
*
* @param Array $params
* @return string
* @access public
*/
function PaginationBar($params)
{
return $this->PrintPages($params);
}
/**
* Returns field name (processed by kMultiLanguage formatter
* if required) and item's id from it's IDField or field required
*
* @param Array $params
* @return Array (id,field)
* @access private
*/
function prepareInputName($params)
{
$field = $this->SelectParam($params, 'name,field');
$object =& $this->getObject($params);
$formatter_class = getArrayValue($object->Fields, $field, 'formatter');
if ($formatter_class == 'kMultiLanguage') {
$formatter =& $this->Application->recallObject($formatter_class);
/* @var $formatter kMultiLanguage */
$force_primary = isset($object->Fields[$field]['force_primary']) && $object->Fields[$field]['force_primary'];
$field = $formatter->LangFieldName($field, $force_primary);
}
if (array_key_exists('force_id', $params)) {
$id = $params['force_id'];
}
else {
$id_field = getArrayValue($params, 'IdField');
$id = $id_field ? $object->GetDBField($id_field) : $object->GetID();
}
return Array($id, $field);
}
/**
* Returns input field name to
* be placed on form (for correct
* event processing)
*
* @param Array $params
* @return string
* @access public
*/
function InputName($params)
{
list($id, $field) = $this->prepareInputName($params);
$ret = $this->getPrefixSpecial().'['.$id.']['.$field.']';
if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
return $ret;
}
/**
* Allows to override various field options through hidden fields with specific names in submit.
* This tag generates this special names
*
* @param Array $params
* @return string
* @author Alex
*/
function FieldModifier($params)
{
list($id, $field) = $this->prepareInputName($params);
$ret = 'field_modifiers['.$this->getPrefixSpecial().']['.$field.']['.$params['type'].']';
if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
if (isset($params['value'])) {
$object =& $this->getObject($params);
$field_modifiers[$field][$params['type']] = $params['value'];
$object->ApplyFieldModifiers($field_modifiers);
}
return $ret;
}
/**
* Returns index where 1st changable sorting field begins
*
* @return int
* @access private
*/
function getUserSortIndex()
{
$list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings');
$sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
$user_sorting_start = 0;
if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
$user_sorting_start = count($forced_sorting);
}
return $user_sorting_start;
}
/**
* Returns order direction for given field
*
*
*
* @param Array $params
* @return string
* @access public
*/
function Order($params)
{
$field = $params['field'];
$user_sorting_start = $this->getUserSortIndex();
$list =& $this->GetList($params);
if ($list->GetOrderField($user_sorting_start) == $field)
{
return strtolower($list->GetOrderDirection($user_sorting_start));
}
elseif($this->Application->ConfigValue('UseDoubleSorting') && $list->GetOrderField($user_sorting_start+1) == $field)
{
return '2_'.strtolower($list->GetOrderDirection($user_sorting_start+1));
}
else
{
return 'no';
}
}
/**
* Detects, that current sorting is not default
*
* @param Array $params
* @return bool
*/
function OrderChanged($params)
{
$list =& $this->GetList($params);
$user_sorting_start = $this->getUserSortIndex();
$sorting_configs = $this->Application->getUnitOption($this->Prefix, 'ConfigMapping', Array ());
$list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings', Array ());
$sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
if (array_key_exists('DefaultSorting1Field', $sorting_configs)) {
$list_sortings[$sorting_prefix]['Sorting'] = Array (
$this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
$this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
);
}
$sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting');
$sort_fields = is_array($sorting) ? array_keys($sorting) : Array ();
for ($order_number = 0; $order_number < 2; $order_number++) {
// currect sorting in list
$sorting_pos = $user_sorting_start + $order_number;
$current_order_field = $list->GetOrderField($sorting_pos, true);
$current_order_direction = $list->GetOrderDirection($sorting_pos, true);
if (!$current_order_field || !$current_order_direction) {
// no sorting defined for this sorting position
continue;
}
// user sorting found
if (array_key_exists($order_number, $sort_fields)) {
// default sorting found
$default_order_field = $sort_fields[$order_number];
$default_order_direction = $sorting[$default_order_field];
if ($current_order_field != $default_order_field || $current_order_direction != $default_order_direction) {
// #1. user sorting differs from default sorting -> changed
return true;
}
}
else {
// #2. user sorting + no default sorting -> changed
return true;
}
}
// #3. user sorting match default or not defined -> not changed
return false;
}
/**
* Get's information of sorting field at "pos" position,
* like sorting field name (type="field") or sorting direction (type="direction")
*
* @param Array $params
* @return mixed
*/
function OrderInfo($params)
{
$user_sorting_start = $this->getUserSortIndex() + --$params['pos'];
$list =& $this->GetList($params);
// $object =& $this->Application->recallObject( $this->getPrefixSpecial() );
if($params['type'] == 'field') return $list->GetOrderField($user_sorting_start);
if($params['type'] == 'direction') return $list->GetOrderDirection($user_sorting_start);
}
/**
* Checks if sorting field/direction matches passed field/direction parameter
*
* @param Array $params
* @return bool
*/
function IsOrder($params)
{
$params['type'] = isset($params['field']) ? 'field' : 'direction';
$value = $this->OrderInfo($params);
if( isset($params['field']) ) return $params['field'] == $value;
if( isset($params['direction']) ) return $params['direction'] == $value;
}
/**
* Returns list perpage
*
* @param Array $params
* @return int
*/
function PerPage($params)
{
$object =& $this->getObject($params);
return $object->PerPage;
}
/**
* Checks if list perpage matches value specified
*
* @param Array $params
* @return bool
*/
function PerPageEquals($params)
{
$object =& $this->getObject($params);
return $object->PerPage == $params['value'];
}
function SaveEvent($params)
{
// SaveEvent is set during OnItemBuild, but we may need it before any other tag calls OnItemBuild
$object =& $this->getObject($params);
return $this->Application->GetVar($this->getPrefixSpecial().'_SaveEvent');
}
function NextId($params)
{
$object =& $this->getObject($params);
$wid = $this->Application->GetTopmostWid($this->Prefix);
$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
$ids = explode(',', $this->Application->RecallVar($session_name));
$cur_id = $object->GetID();
$i = array_search($cur_id, $ids);
if ($i !== false) {
return $i < count($ids) - 1 ? $ids[$i + 1] : '';
}
return '';
}
function PrevId($params)
{
$object =& $this->getObject($params);
$wid = $this->Application->GetTopmostWid($this->Prefix);
$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
$ids = explode(',', $this->Application->RecallVar($session_name));
$cur_id = $object->GetID();
$i = array_search($cur_id, $ids);
if ($i !== false) {
return $i > 0 ? $ids[$i - 1] : '';
}
return '';
}
function IsSingle($params)
{
return ($this->NextId($params) === '' && $this->PrevId($params) === '');
}
function IsLast($params)
{
return ($this->NextId($params) === '');
}
function IsFirst($params)
{
return ($this->PrevId($params) === '');
}
/**
* Checks if field value is equal to proposed one
*
* @param Array $params
* @return bool
*/
function FieldEquals($params)
{
$object =& $this->getObject($params);
$ret = $object->GetDBField($this->SelectParam($params, 'name,field')) == $params['value'];
// if( getArrayValue($params,'inverse') ) $ret = !$ret;
return $ret;
}
/**
* Checks, that grid has icons defined and they should be shown
*
* @param Array $params
* @return bool
*/
function UseItemIcons($params)
{
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
return array_key_exists('Icons', $grids[ $params['grid'] ]);
}
/**
* Returns corresponding to grid layout selector column width
*
* @param Array $params
* @return int
*/
function GridSelectorColumnWidth($params)
{
$width = 0;
if ($params['selector']) {
$width += $params['selector_width'];
}
if ($this->UseItemIcons($params)) {
$width += $params['icon_width'];
}
return $width;
}
/**
* Returns grids item selection mode (checkbox, radio, )
*
* @param Array $params
* @return string
*/
function GridSelector($params)
{
$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
return array_key_exists('Selector', $grids[ $params['grid'] ]) ? $grids[ $params['grid'] ]['Selector'] : $params['default'];
}
function ItemIcon($params)
{
$object =& $this->getObject($params);
$grids = $this->Application->getUnitOption($this->Prefix,'Grids');
$icons =& $grids[ $params['grid'] ]['Icons'];
$key = '';
$status_fields = $this->Application->getUnitOption($this->Prefix,'StatusField');
if(!$status_fields) return $icons['default'];
foreach($status_fields as $status_field)
{
$key .= $object->GetDBField($status_field).'_';
}
$key = rtrim($key,'_');
$value = ($key !== false) ? $key : 'default';
return isset($icons[$value]) ? $icons[$value] : $icons['default'];
}
/**
* Generates bluebar title + initializes prefixes used on page
*
* @param Array $params
* @return string
*/
function SectionTitle($params)
{
$preset_name = replaceModuleSection($params['title_preset']);
$title_presets = $this->Application->getUnitOption($this->Prefix,'TitlePresets');
$title_info = getArrayValue($title_presets, $preset_name);
if ($title_info === false) {
$title = str_replace('#preset_name#', $preset_name, $params['title']);
if ($this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title']) {
$title .= ' - '.$params['group_title'];
}
return $title;
}
if (getArrayValue($title_presets,'default')) {
// use default labels + custom labels specified in preset used
$title_info = array_merge_recursive2($title_presets['default'], $title_info);
}
$title = $title_info['format'];
// 1. get objects in use for title construction
$objects = Array();
$object_status = Array();
$status_labels = Array();
$prefixes = getArrayValue($title_info,'prefixes');
$all_tag_params = getArrayValue($title_info,'tag_params');
if ($prefixes) {
// extract tag_perams passed directly to SectionTitle tag for specific prefix
foreach ($params as $tp_name => $tp_value) {
if (preg_match('/(.*)\[(.*)\]/', $tp_name, $regs)) {
$all_tag_params[ $regs[1] ][ $regs[2] ] = $tp_value;
unset($params[$tp_name]);
}
}
$tag_params = Array();
foreach ($prefixes as $prefix_special) {
$prefix_data = $this->Application->processPrefix($prefix_special);
$prefix_data['prefix_special'] = rtrim($prefix_data['prefix_special'],'.');
if ($all_tag_params) {
$tag_params = getArrayValue($all_tag_params, $prefix_data['prefix_special']);
if (!$tag_params) $tag_params = Array();
}
$tag_params = array_merge_recursive2($params, $tag_params);
$objects[ $prefix_data['prefix_special'] ] =& $this->Application->recallObject($prefix_data['prefix_special'], $prefix_data['prefix'], $tag_params);
$object_status[ $prefix_data['prefix_special'] ] = $objects[ $prefix_data['prefix_special'] ]->IsNewItem() ? 'new' : 'edit';
// a. set object's status field (adding item/editing item) for each object in title
if (getArrayValue($title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ],$prefix_data['prefix_special'])) {
$status_labels[ $prefix_data['prefix_special'] ] = $title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ][ $prefix_data['prefix_special'] ];
$title = str_replace('#'.$prefix_data['prefix_special'].'_status#', $status_labels[ $prefix_data['prefix_special'] ], $title);
}
// b. setting object's titlefield value (in titlebar ONLY) to default in case if object beeing created with no titlefield filled in
if ($object_status[ $prefix_data['prefix_special'] ] == 'new') {
$new_value = $this->getInfo( $objects[ $prefix_data['prefix_special'] ], 'titlefield' );
if(!$new_value && getArrayValue($title_info['new_titlefield'],$prefix_data['prefix_special']) ) $new_value = $this->Application->Phrase($title_info['new_titlefield'][ $prefix_data['prefix_special'] ]);
$title = str_replace('#'.$prefix_data['prefix_special'].'_titlefield#', $new_value, $title);
}
}
}
// replace to section title
$section = array_key_exists('section', $params) ? $params['section'] : false;
if ($section) {
$sections_helper =& $this->Application->recallObject('SectionsHelper');
/* @var $sections_helper kSectionsHelper */
$section_data =& $sections_helper->getSectionData($section);
$title = str_replace('#section_label#', '!' . $section_data['label'] . '!', $title);
}
// 2. replace phrases if any found in format string
$title = $this->Application->ReplaceLanguageTags($title, false);
// 3. find and replace any replacement vars
preg_match_all('/#(.*_.*)#/Uis',$title,$rets);
if ($rets[1]) {
$replacement_vars = array_keys( array_flip($rets[1]) );
foreach ($replacement_vars as $replacement_var) {
$var_info = explode('_',$replacement_var,2);
$object =& $objects[ $var_info[0] ];
$new_value = $this->getInfo($object,$var_info[1]);
$title = str_replace('#'.$replacement_var.'#', $new_value, $title);
}
}
// replace trailing spaces inside title preset + '' occurences into single space
$title = preg_replace('/[ ]*\'\'[ ]*/', ' ', $title);
if ($this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title']) {
$title .= ' - '.$params['group_title'];
}
$cut_first = getArrayValue($params, 'cut_first');
if ($cut_first && mb_strlen($title) > $cut_first) {
if (!preg_match('/<a href="(.*)">(.*)<\/a>/',$title)) {
$title = mb_substr($title, 0, $cut_first).' ...';
}
}
return $title;
}
function getInfo(&$object, $info_type)
{
switch ($info_type)
{
case 'titlefield':
$field = $this->Application->getUnitOption($object->Prefix,'TitleField');
return $field !== false ? $object->GetField($field) : 'TitleField Missing';
break;
case 'recordcount':
$of_phrase = $this->Application->Phrase('la_of');
return $object->NoFilterCount != $object->RecordsCount ? $object->RecordsCount.' '.$of_phrase.' '.$object->NoFilterCount : $object->RecordsCount;
break;
default:
return $object->GetField($info_type);
break;
}
}
function GridInfo($params)
{
$object =& $this->GetList($params);
/* @var $object kDBList */
switch ($params['type']) {
case 'filtered':
return $object->GetRecordsCount();
case 'total':
return $object->GetNoFilterCount();
case 'from':
return $object->RecordsCount ? $object->Offset+1 : 0; //0-based
case 'to':
return $object->PerPage > 0 ? min($object->Offset + $object->PerPage, $object->RecordsCount) : $object->RecordsCount;
case 'total_pages':
return $object->GetTotalPages();
case 'needs_pagination':
return ($object->PerPage != -1) && (($object->RecordsCount > $object->PerPage) || ($object->Page > 1));
}
}
/**
* Parses block depending on its element type.
* For radio and select elements values are taken from 'value_list_field' in key1=value1,key2=value2
* format. key=value can be substituted by <SQL>SELECT f1 AS OptionName, f2 AS OptionValue... FROM <PREFIX>TableName </SQL>
* where prefix is TABLE_PREFIX
*
* @param Array $params
* @return string
*/
function ConfigFormElement($params)
{
$object =& $this->getObject($params);
$field = $params['field'];
$helper =& $this->Application->recallObject('InpCustomFieldsHelper');
/* @var $helper InpCustomFieldsHelper */
$element_type = $object->GetDBField($params['element_type_field']);
if($element_type == 'label') $element_type = 'text';
$params['name'] = $params['blocks_prefix'].$element_type;
switch ($element_type) {
case 'select':
case 'multiselect':
case 'radio':
$field_options = $object->GetFieldOptions($field, 'options');
if ($object->GetDBField('DirectOptions')) {
// used for custom fields
$field_options['options'] = $object->GetDBField('DirectOptions');
}
else {
// used for configuration
$field_options['options'] = $helper->GetValuesHash($object->GetDBField($params['value_list_field']), ',');
}
$object->SetFieldOptions($field, $field_options);
break;
case 'text':
case 'textarea':
$params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field']));
break;
case 'password':
case 'checkbox':
default:
break;
}
return $this->Application->ParseBlock($params, 1);
}
/**
* Get's requested custom field value
*
* @param Array $params
* @return string
* @access public
*/
function CustomField($params)
{
$params['name'] = 'cust_'.$this->SelectParam($params, 'name,field');
return $this->Field($params);
}
function CustomFieldLabel($params)
{
$object =& $this->getObject($params);
$field = $this->SelectParam($params, 'name,field');
$sql = 'SELECT FieldLabel
FROM '.$this->Application->getUnitOption('cf', 'TableName').'
WHERE FieldName = '.$this->Conn->qstr($field);
return $this->Application->Phrase($this->Conn->GetOne($sql));
}
/**
* transposes 1-dimensional array elements for vertical alignment according to given columns and per_page parameters
*
* @param array $arr
* @param int $columns
* @param int $per_page
* @return array
*/
function LinearToVertical(&$arr, $columns, $per_page)
{
$rows = $columns;
// in case if after applying per_page limit record count less then
// can fill requrested column count, then fill as much as we can
$cols = min(ceil($per_page / $columns), ceil(count($arr) / $columns));
$imatrix = array();
for ($row = 0; $row < $rows; $row++) {
for ($col = 0; $col < $cols; $col++) {
$source_index = $row * $cols + $col;
if (!isset($arr[$source_index])) {
// in case if source array element count is less then element count in one row
continue;
}
$imatrix[$col * $rows + $row] = $arr[$source_index];
}
}
ksort($imatrix);
return array_values($imatrix);
}
/**
* If data was modfied & is in TempTables mode, then parse block with name passed;
* remove modification mark if not in TempTables mode
*
* @param Array $params
* @return string
* @access public
* @author Alexey
*/
function SaveWarning($params)
{
$main_prefix = getArrayValue($params, 'main_prefix');
if ($main_prefix && $main_prefix != '$main_prefix') {
$top_prefix = $main_prefix;
}
else {
$top_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
}
$temp_tables = substr($this->Application->GetVar($top_prefix.'_mode'), 0, 1) == 't';
$modified = $this->Application->RecallVar($top_prefix.'_modified');
if ($temp_tables && $modified) {
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $this->SelectParam($params, 'render_as,name');
$block_params['edit_mode'] = $temp_tables ? 1 : 0;
return $this->Application->ParseBlock($block_params);
}
$this->Application->RemoveVar($top_prefix.'_modified');
return '';
}
/**
* Returns list record count queries (on all pages)
*
* @param Array $params
* @return int
*/
function TotalRecords($params)
{
$list =& $this->GetList($params);
if (!$list->Counted) $list->CountRecs();
return $list->RecordsCount;
}
/**
* Range filter field name
*
* @param Array $params
* @return string
*/
function SearchInputName($params)
{
$field = $this->SelectParam($params, 'field,name');
$ret = 'custom_filters['.$this->getPrefixSpecial().']['.$params['grid'].']['.$field.']['.$params['filter_type'].']';
if (isset($params['type'])) {
$ret .= '['.$params['type'].']';
}
return $ret;
}
/**
* Return range filter field value
*
* @param Array $params
* @return string
*/
function SearchField($params) // RangeValue
{
$field = $this->SelectParam($params, 'field,name');
$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
$custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_custom_filter.'.$view_name/*, ALLOW_DEFAULT_SETTINGS*/);
$custom_filter = $custom_filter ? unserialize($custom_filter) : Array();
if (isset($custom_filter[ $params['grid'] ][$field])) {
$ret = $custom_filter[ $params['grid'] ][$field][ $params['filter_type'] ]['submit_value'];
if (isset($params['type'])) {
$ret = $ret[ $params['type'] ];
}
if( !$this->HasParam($params, 'no_special') ) $ret = htmlspecialchars($ret);
return $ret;
}
return '';
}
function SearchFormat($params)
{
$field = $params['field'];
$object =& $this->GetList($params);
$options = $object->GetFieldOptions($field);
$format = $options[ $this->SelectParam($params, 'input_format') ? 'input_format' : 'format' ];
$formatter_class = getArrayValue($options,'formatter');
if($formatter_class)
{
$formatter =& $this->Application->recallObject($formatter_class);
$human_format = getArrayValue($params,'human');
$edit_size = getArrayValue($params,'edit_size');
$sample = getArrayValue($params,'sample');
if($sample)
{
return $formatter->GetSample($field, $options, $object);
}
elseif($human_format || $edit_size)
{
$format = $formatter->HumanFormat($format);
return $edit_size ? strlen($format) : $format;
}
}
return $format;
}
/**
* Returns error of range field
*
* @param unknown_type $params
* @return unknown
*/
function SearchError($params)
{
$field = $this->SelectParam($params, 'field,name');
$error_var_name = $this->getPrefixSpecial().'_'.$field.'_error';
$pseudo = $this->Application->RecallVar($error_var_name);
if ($pseudo) {
$this->Application->RemoveVar($error_var_name);
}
$object =& $this->Application->recallObject($this->Prefix.'.'.$this->Special.'-item', null, Array('skip_autoload' => true));
/* @var $object kDBItem */
$object->SetError($field, $pseudo);
return $object->GetErrorMsg($field, false);
}
/**
* Returns object used in tag processor
*
* @access public
* @return kDBBase
*/
function &getObject($params = Array())
{
$object =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix, $params);
if (isset($params['requery']) && $params['requery']) {
$this->Application->HandleEvent($q_event, $this->getPrefixSpecial().':LoadItem', $params);
}
return $object;
}
/**
* Checks if object propery value matches value passed
*
* @param Array $params
* @return bool
*/
function PropertyEquals($params)
{
$object =& $this->getObject($params);
$property_name = $this->SelectParam($params, 'name,var,property');
return $object->$property_name == $params['value'];
}
/**
* Group list records by header, saves internal order in group
*
* @param Array $records
* @param string $heading_field
*/
function groupRecords(&$records, $heading_field)
{
$sorted = Array();
$i = 0; $record_count = count($records);
while ($i < $record_count) {
$sorted[ $records[$i][$heading_field] ][] = $records[$i];
$i++;
}
$records = Array();
foreach ($sorted as $heading => $heading_records) {
$records = array_merge_recursive($records, $heading_records);
}
}
function DisplayOriginal($params)
{
return false;
}
/*function MultipleEditing($params)
{
$wid = $this->Application->GetTopmostWid($this->Prefix);
$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
$selected_ids = explode(',', $this->Application->RecallVar($session_name));
$ret = '';
if ($selected_ids) {
$selected_ids = explode(',', $selected_ids);
$object =& $this->getObject( array_merge_recursive2($params, Array('skip_autoload' => true)) );
$params['name'] = $params['render_as'];
foreach ($selected_ids as $id) {
$object->Load($id);
$ret .= $this->Application->ParseBlock($params);
}
}
return $ret;
}*/
/**
* Returns import/export process percent
*
* @param Array $params
* @return int
* @deprecated Please convert to event-model, not tag based
*/
function ExportStatus($params)
{
$export_object =& $this->Application->recallObject('CatItemExportHelper');
$event = new kEvent($this->getPrefixSpecial().':OnDummy');
$action_method = 'perform'.ucfirst($this->Special);
$field_values = $export_object->$action_method($event);
// finish code is done from JS now
if ($field_values['start_from'] >= $field_values['total_records'])
{
if ($this->Special == 'import') {
// this is used?
$this->Application->StoreVar('PermCache_UpdateRequired', 1);
$this->Application->Redirect('categories/cache_updater', Array('m_opener' => 'r', 'pass' => 'm', 'continue' => 1, 'no_amp' => 1));
}
elseif ($this->Special == 'export') {
// used for orders export in In-Commerce
$finish_t = $this->Application->RecallVar('export_finish_t');
$this->Application->Redirect($finish_t, Array('pass' => 'all'));
$this->Application->RemoveVar('export_finish_t');
}
}
$export_options = $export_object->loadOptions($event);
return $export_options['start_from'] * 100 / $export_options['total_records'];
}
/**
* Returns path where exported category items should be saved
*
* @param Array $params
*/
function ExportPath($params)
{
$ret = EXPORT_PATH.'/';
if( getArrayValue($params, 'as_url') )
{
$ret = str_replace( FULL_PATH.'/', $this->Application->BaseURL(), $ret);
}
$export_options = unserialize($this->Application->RecallVar($this->getPrefixSpecial().'_options'));
$ret .= $export_options['ExportFilename'].'.'.($export_options['ExportFormat'] == 1 ? 'csv' : 'xml');
return $ret;
}
function FieldTotal($params)
{
$list =& $this->GetList($params);
return $list->GetFormattedTotal($this->SelectParam($params, 'field,name'), $params['function']);
}
/**
* Returns FCKEditor locale, that matches default site language
*
* @return string
*/
function _getFCKLanguage()
{
static $language_code = null;
if (!isset($language_code)) {
$language_code = 'en'; // defaut value
$sql = 'SELECT Locale
FROM '. $this->Application->getUnitOption('lang', 'TableName') . '
WHERE LanguageId = ' . $this->Application->GetDefaultLanguageId(); // $this->Application->GetVar('m_lang');
$locale = strtolower( $this->Conn->GetOne($sql) );
if (file_exists(FULL_PATH . EDITOR_PATH . 'editor/lang/' . $locale . '.js')) {
// found language file, that exactly matches locale name (e.g. "en")
$language_code = $locale;
}
else {
$locale = explode('-', $locale);
if (file_exists(FULL_PATH . EDITOR_PATH . 'editor/lang/' . $locale[0] . '.js')) {
// language file matches first part of locale (e.g. "ru-RU")
$language_code = $locale[0];
}
}
}
return $language_code;
}
function FCKEditor($params)
{
$params['no_special'] = 1;
$params['format'] = array_key_exists('format', $params) ? $params['format'] . ';fck_ready' : 'fck_ready';
$value = $this->Field($params);
$name = array_key_exists('name', $params) ? $params['name'] : $this->InputName($params);
$theme_path = substr($this->Application->GetFrontThemePath(), 1) . '/inc/';
if (!file_exists(FULL_PATH . '/' . $theme_path . 'style.css')) {
$theme_path = EDITOR_PATH;
}
$styles_xml = $this->Application->BaseURL() . $theme_path . 'styles.xml';
$styles_css = $this->Application->BaseURL() . $theme_path . 'style.css';
$bgcolor = array_key_exists('bgcolor', $params) ? $params['bgcolor'] : $this->Application->GetVar('bgcolor');
if (!$bgcolor) {
$bgcolor = '#ffffff';
}
$preview_url = '';
$page_id = $this->Application->GetVar('c_id');
$content_id = $this->Application->GetVar('content_id');
if ($page_id && $content_id) {
// editing content block from Front-End, not category in admin
$sql = 'SELECT NamedParentPath
FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
WHERE ' . $this->Application->getUnitOption('c', 'IDField') . ' = ' . $page_id;
$template = strtolower( $this->Conn->GetOne($sql) );
$url_params = Array ('m_cat_id' => $page_id, 'no_amp' => 1, 'editing_mode' => EDITING_MODE_CONTENT, 'pass' => 'm');
$preview_url = $this->Application->HREF($template, '_FRONT_END_', $url_params, 'index.php');
$preview_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $preview_url);
}
include_once(FULL_PATH . EDITOR_PATH . 'fckeditor.php');
$oFCKeditor = new FCKeditor($name);
$oFCKeditor->FullUrl = $this->Application->BaseURL();
$oFCKeditor->BaseUrl = BASE_PATH . '/';
$oFCKeditor->BasePath = BASE_PATH . EDITOR_PATH;
$oFCKeditor->Width = $params['width'] ;
$oFCKeditor->Height = $params['height'] ;
$oFCKeditor->ToolbarSet = $page_id && $content_id ? 'Advanced' : 'Default';
$oFCKeditor->Value = $value;
$oFCKeditor->PreviewUrl = $preview_url;
$oFCKeditor->DefaultLanguage = $this->_getFCKLanguage();
$oFCKeditor->LateLoad = array_key_exists('late_load', $params) && $params['late_load'];
$oFCKeditor->Config = Array (
//'UserFilesPath' => $pathtoroot.'kernel/user_files',
'ProjectPath' => BASE_PATH . '/',
'CustomConfigurationsPath' => $this->Application->BaseURL() . 'core/admin_templates/js/inp_fckconfig.js',
'StylesXmlPath' => $styles_xml,
'EditorAreaCSS' => $styles_css,
'DefaultStyleLabel' => $this->Application->Phrase('la_editor_default_style'),
// 'Debug' => 1,
'Admin' => 1,
'K4' => 1,
'newBgColor' => $bgcolor,
'PreviewUrl' => $preview_url,
'BaseUrl' => BASE_PATH . '/',
'DefaultLanguage' => $this->_getFCKLanguage(),
'EditorAreaStyles' => 'body { background-color: '.$bgcolor.' }',
);
return $oFCKeditor->CreateHtml();
}
function IsNewItem($params)
{
$object =& $this->getObject($params);
return $object->IsNewItem();
}
/**
* Creates link to an item including only it's id
*
* @param Array $params
* @return string
*/
function ItemLink($params)
{
$object =& $this->getObject($params);
if (!isset($params['pass'])) {
$params['pass'] = 'm';
}
$params[$object->getPrefixSpecial().'_id'] = $object->GetID();
$m =& $this->Application->recallObject('m_TagProcessor');
return $m->t($params);
}
/**
* Calls OnNew event from template, when no other event submitted
*
* @param Array $params
*/
function PresetFormFields($params)
{
$prefix = $this->getPrefixSpecial();
if (!$this->Application->GetVar($prefix.'_event')) {
$this->Application->HandleEvent(new kEvent($prefix.':OnNew'));
}
}
function PrintSerializedFields($params)
{
$object =& $this->getObject();
$field = $this->SelectParam($params, 'field');
$data = unserialize($object->GetDBField($field));
$o = '';
$std_params['name'] = $params['render_as'];
$std_params['field'] = $params['field'];
$std_params['pass_params'] = true;
foreach ($data as $key => $row) {
$block_params = array_merge($std_params, $row, array('key'=>$key));
$o .= $this->Application->ParseBlock($block_params);
}
return $o;
}
/**
* Checks if current prefix is main item
*
* @param Array $params
* @return bool
*/
function IsTopmostPrefix($params)
{
return $this->Prefix == $this->Application->GetTopmostPrefix($this->Prefix);
}
function PermSection($params)
{
$section = $this->SelectParam($params, 'section,name');
$perm_sections = $this->Application->getUnitOption($this->Prefix, 'PermSection');
return isset($perm_sections[$section]) ? $perm_sections[$section] : '';
}
function PerPageSelected($params)
{
$list =& $this->GetList($params);
return $list->PerPage == $params['per_page'] ? $params['selected'] : '';
}
/**
* Returns prefix + generated sepcial + any word
*
* @param Array $params
* @return string
*/
function VarName($params)
{
$list =& $this->GetList($params);
return $list->getPrefixSpecial().'_'.$params['type'];
}
/**
* Returns edit tabs by specified preset name or false in case of error
*
* @param string $preset_name
* @return mixed
*/
function getEditTabs($preset_name)
{
$presets = $this->Application->getUnitOption($this->Prefix, 'EditTabPresets');
if (!$presets || !isset($presets[$preset_name]) || count($presets[$preset_name]) == 0) {
return false;
}
return count($presets[$preset_name]) > 1 ? $presets[$preset_name] : false;
}
/**
* Detects if specified preset has tabs in it
*
* @param Array $params
* @return bool
*/
function HasEditTabs($params)
{
return $this->getEditTabs($params['preset_name']) ? true : false;
}
/**
* Sorts edit tabs based on their priority
*
* @param Array $tab_a
* @param Array $tab_b
* @return int
*/
function sortEditTabs($tab_a, $tab_b)
{
if ($tab_a['priority'] == $tab_b['priority']) {
return 0;
}
return $tab_a['priority'] < $tab_b['priority'] ? -1 : 1;
}
/**
* Prints edit tabs based on preset name specified
*
* @param Array $params
* @return string
*/
function PrintEditTabs($params)
{
$edit_tabs = $this->getEditTabs($params['preset_name']);
if (!$edit_tabs) {
return ;
}
usort($edit_tabs, Array (&$this, 'sortEditTabs'));
$ret = '';
$block_params = $this->prepareTagParams($params);
$block_params['name'] = $params['render_as'];
foreach ($edit_tabs as $tab_info) {
$block_params['title'] = $tab_info['title'];
$block_params['template'] = $tab_info['t'];
$ret .= $this->Application->ParseBlock($block_params);
}
return $ret;
}
/**
* Performs image resize to required dimensions and returns resulting url (cached resized image)
*
* @param Array $params
* @return string
*/
function ImageSrc($params)
{
$max_width = isset($params['MaxWidth']) ? $params['MaxWidth'] : false;
$max_height = isset($params['MaxHeight']) ? $params['MaxHeight'] : false;
$logo_filename = isset($params['LogoFilename']) ? $params['LogoFilename'] : false;
$logo_h_margin = isset($params['LogoHMargin']) ? $params['LogoHMargin'] : false;
$logo_v_margin = isset($params['LogoVMargin']) ? $params['LogoVMargin'] : false;
$object =& $this->getObject($params);
$field = $this->SelectParam($params, 'name,field');
return $object->GetField($field, 'resize:'.$max_width.'x'.$max_height.';wm:'.$logo_filename.'|'.$logo_h_margin.'|'.$logo_v_margin);
}
/**
* Allows to retrieve given setting from unit config
*
* @param Array $params
* @return mixed
*/
function UnitOption($params)
{
return $this->Application->getUnitOption($this->Prefix, $params['name']);
}
/**
* Returns list of allowed toolbar buttons or false, when all is allowed
*
* @param Array $params
* @return string
*/
function VisibleToolbarButtons($params)
{
$preset_name = replaceModuleSection($params['title_preset']);
$title_presets = $this->Application->getUnitOption($this->Prefix, 'TitlePresets');
if (!array_key_exists($preset_name, $title_presets)) {
trigger_error('Title preset not specified or missing (in tag "<strong>' . $this->getPrefixSpecial() . ':' . __METHOD__ . '</strong>")', E_USER_WARNING);
return false;
}
$preset_info = $title_presets[$preset_name];
if (!array_key_exists('toolbar_buttons', $preset_info) || !is_array($preset_info['toolbar_buttons'])) {
return false;
}
// always add search buttons
array_push($preset_info['toolbar_buttons'], 'search', 'search_reset_alt');
$toolbar_buttons = array_map('addslashes', $preset_info['toolbar_buttons']);
return $toolbar_buttons ? "'" . implode("', '", $toolbar_buttons) . "'" : 'false';
}
/**
* Checks, that "To" part of at least one of range filters is used
*
* @param Array $params
* @return bool
*/
function RangeFiltersUsed($params)
{
$search_helper =& $this->Application->recallObject('SearchHelper');
/* @var $search_helper kSearchHelper */
return $search_helper->rangeFiltersUsed($this->getPrefixSpecial(), $params['grid']);
}
/**
* This is abstract tag, used to modify unit config data based on template, where it's used.
* Tag is called from "combined_header" block in admin only.
*
* @param Array $params
*/
function ModifyUnitConfig($params)
{
}
/**
* Checks, that field is visible on edit form
*
* @param Array $params
* @return bool
*/
function FieldVisible($params)
{
$check_field = $params['field'];
$fields = $this->Application->getUnitOption($this->Prefix, 'Fields');
if (!array_key_exists($check_field, $fields)) {
// field not found in real fields array -> it's 100% virtual then
$fields = $this->Application->getUnitOption($this->Prefix, 'VirtualFields');
}
if (!array_key_exists($check_field, $fields)) {
$params['field'] = 'Password';
return $check_field == 'VerifyPassword' ? $this->FieldVisible($params) : true;
}
$show_mode = array_key_exists('show_mode', $fields[$check_field]) ? $fields[$check_field]['show_mode'] : true;
if ($show_mode === smDEBUG) {
return defined('DEBUG_MODE') && DEBUG_MODE;
}
return $show_mode;
}
/**
* Checks, that there area visible fields in given section on edit form
*
* @param Array $params
* @return bool
*/
function FieldsVisible($params)
{
if (!$params['fields']) {
return true;
}
$check_fields = explode(',', $params['fields']);
$fields = $this->Application->getUnitOption($this->Prefix, 'Fields');
$virtual_fields = $this->Application->getUnitOption($this->Prefix, 'VirtualFields');
foreach ($check_fields as $check_field) {
// when at least one field in subsection is visible, then subsection is visible too
if (array_key_exists($check_field, $fields)) {
$show_mode = array_key_exists('show_mode', $fields[$check_field]) ? $fields[$check_field]['show_mode'] : true;
}
else {
$show_mode = array_key_exists('show_mode', $virtual_fields[$check_field]) ? $virtual_fields[$check_field]['show_mode'] : true;
}
if (($show_mode === true) || (($show_mode === smDEBUG) && (defined('DEBUG_MODE') && DEBUG_MODE))) {
// field is visible
return true;
}
}
return false;
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/db/dblist.php
===================================================================
--- branches/5.0.x/core/kernel/db/dblist.php (revision 12322)
+++ branches/5.0.x/core/kernel/db/dblist.php (revision 12323)
@@ -1,994 +1,994 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/**
* DBList
*
* Desciption
* @package kernel4
*/
class kDBList extends kDBBase {
/**
* Holds totals for fields specified in config
*
* @var Array
*/
var $Totals = Array();
/**
* Description
*
* @var array
* @access public
*/
var $OrderFields;
/**
* Holds counted total number of records in the query - without pagination (system+user filters)
*
* @var int
* @access public
*/
var $RecordsCount;
/**
* Records count with system filters only applied
*
* @var int
* @access private
*/
var $NoFilterCount = 0;
/**
* Record count selected to be
* showed on current page
*
* @var int
*/
var $SelectedCount=0;
/**
* Array of records selected
*
* @var Array
* @access private
*/
var $Records;
var $CurrentIndex = 0;
/**
* List items per-page
*
* @var int
* @access public
*/
var $PerPage;
/**
* Pages count in list based on PerPage & RecordsCount attributes
*
* @var int
* @access public
*/
var $TotalPages;
/**
* Description
*
* @var int
* @access public
*/
var $Direction;
/**
* Holds current page number - used when forming LIMIT clause of SELECT statement
*
* @var int
* @access public
*/
var $Page;
/**
* Holds offset for LIMIT clause, calculated in {@link kDBList::PerPage()}
*
* @var int
* @access private
*/
var $Offset;
/**
* Count SQL was already issued on query
*
* @var bool
* @access private
*/
var $hasCounted = false;
/**
* Holds list WHERE filter object
*
* @var kMultipleFilter
* @access private
*/
var $WhereFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
/**
* Holds list HAVING filter object
*
* @var kMultipleFilter
* @access private
*/
var $HavingFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null, FLT_SEARCH => null, FLT_VIEW => null);
var $AggregateFilter = Array(FLT_SYSTEM => null, FLT_NORMAL => null);
var $GroupByFields = Array();
var $Queried = false;
var $Counted = false;
var $TotalsCalculated = false;
/**
* Creates kDBList
*
* @return kDBList
*/
function kDBList()
{
parent::kDBBase();
$this->OrderFields = Array();
$filters = $this->getFilterStructure();
foreach ($filters as $filter_params) {
$filter =& $this->$filter_params['type'];
$filter[ $filter_params['class'] ] =& $this->Application->makeClass('kMultipleFilter', $filter_params['join_using']);
}
$this->PerPage = -1;
}
/**
* Returns information about all possible filter types
*
* @return Array
*/
function getFilterStructure()
{
$filters = Array (
Array ('type' => 'WhereFilter', 'class' => FLT_SYSTEM, 'join_using' => FLT_TYPE_AND),
Array ('type' => 'WhereFilter', 'class' => FLT_NORMAL, 'join_using' => FLT_TYPE_OR),
Array ('type' => 'WhereFilter', 'class' => FLT_SEARCH, 'join_using' => FLT_TYPE_OR),
Array ('type' => 'WhereFilter', 'class' => FLT_VIEW, 'join_using' => FLT_TYPE_AND),
Array ('type' => 'WhereFilter', 'class' => FLT_CUSTOM, 'join_using' => FLT_TYPE_AND),
Array ('type' => 'HavingFilter', 'class' => FLT_SYSTEM, 'join_using' => FLT_TYPE_AND),
Array ('type' => 'HavingFilter', 'class' => FLT_NORMAL, 'join_using' => FLT_TYPE_OR),
Array ('type' => 'HavingFilter', 'class' => FLT_SEARCH, 'join_using' => FLT_TYPE_OR),
Array ('type' => 'HavingFilter', 'class' => FLT_VIEW, 'join_using' => FLT_TYPE_AND),
Array ('type' => 'HavingFilter', 'class' => FLT_CUSTOM, 'join_using' => FLT_TYPE_AND),
Array ('type' => 'AggregateFilter', 'class' => FLT_SYSTEM, 'join_using' => FLT_TYPE_AND),
Array ('type' => 'AggregateFilter', 'class' => FLT_NORMAL, 'join_using' => FLT_TYPE_OR),
Array ('type' => 'AggregateFilter', 'class' => FLT_VIEW, 'join_using' => FLT_TYPE_AND),
);
return $filters;
}
/**
* Adds new or replaces old filter with same name
*
* @param string $name filter name (for internal use)
* @param string $clause where/having clause part (no OR/AND allowed)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW,FLT_CUSTOM
* @access public
*/
function addFilter($name, $clause, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
{
$filter_source = Array( WHERE_FILTER => 'WhereFilter',
HAVING_FILTER => 'HavingFilter',
AGGREGATE_FILTER => 'AggregateFilter');
$filter_name = $filter_source[$filter_type];
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
$filter->addFilter($name,$clause);
}
/**
* Reads filter content
*
* @param string $name filter name (for internal use)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW,FLT_CUSTOM
* @access public
*/
function getFilter($name, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
{
$filter_source = Array( WHERE_FILTER => 'WhereFilter',
HAVING_FILTER => 'HavingFilter',
AGGREGATE_FILTER => 'AggregateFilter');
$filter_name = $filter_source[$filter_type];
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
return $filter->getFilter($name);
}
/**
* Removes specified filter from filters list
*
* @param string $name filter name (for internal use)
* @param int $filter_type is filter having filter or where filter
* @param int $filter_scope filter subtype: FLT_NORMAL,FLT_SYSTEM,FLT_SEARCH,FLT_VIEW,FLT_CUSTOM
* @access public
*/
function removeFilter($name, $filter_type = WHERE_FILTER, $filter_scope = FLT_SYSTEM)
{
$filter_source = Array( WHERE_FILTER => 'WhereFilter',
HAVING_FILTER => 'HavingFilter',
AGGREGATE_FILTER => 'AggregateFilter');
$filter_name = $filter_source[$filter_type];
$filter =& $this->$filter_name;
$filter =& $filter[$filter_scope];
$filter->removeFilter($name);
}
/**
* Clear list filters
*
*/
function clearFilters()
{
$filters = $this->getFilterStructure();
foreach ($filters as $filter_params) {
$filter =& $this->$filter_params['type'];
$filter[ $filter_params['class'] ]->clearFilters();
}
}
/**
* Counts the total number of records base on the query resulted from {@link kDBList::GetSelectSQL()}
*
* The method modifies the query to substitude SELECT part (fields listing) with COUNT(*).
* Special care should be applied when working with lists based on grouped queries, all aggregate function fields
* like SUM(), AVERAGE() etc. should be added to CountedSQL by using {@link kDBList::SetCountedSQL()}
*
* @access public
* @param string
* @return void
*/
function CountRecs()
{
$all_sql = $this->GetSelectSQL(true,false);
$sql = $this->getCountSQL($all_sql);
$this->Counted = true;
if( $this->GetGroupClause() )
{
$this->RecordsCount = count( $this->Conn->GetCol($sql) );
}
else
{
$this->RecordsCount = (int)$this->Conn->GetOne($sql);
}
$system_sql = $this->GetSelectSQL(true,true);
if($system_sql == $all_sql) //no need to query the same again
{
$this->NoFilterCount = $this->RecordsCount;
return;
}
$sql = $this->getCountSQL($system_sql);
if( $this->GetGroupClause() )
{
$this->NoFilterCount = count( $this->Conn->GetCol($sql) );
}
else
{
$this->NoFilterCount = (int)$this->Conn->GetOne($sql);
}
}
function GetNoFilterCount()
{
if (!$this->Counted) {
$this->CountRecs();
}
return $this->NoFilterCount;
}
function GetRecordsCount()
{
if (!$this->Counted) {
$this->CountRecs();
}
return $this->RecordsCount;
}
function getCountSQL($sql)
{
if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$sql,$regs ) )
{
return preg_replace("/^\s*SELECT DISTINCT(.*?)FROM(?!_)/is", "SELECT COUNT(DISTINCT ".$regs[1].") AS count FROM", $sql);
}
else
{
return preg_replace("/^\s*SELECT(.*?)FROM(?!_)/is", "SELECT COUNT(*) AS count FROM ", $sql);
}
}
/**
* Queries the database with SQL resulted from {@link kDBList::GetSelectSQL()} and stores result in {@link kDBList::SelectRS}
*
* All the sorting, pagination, filtration of the list should be set prior to calling Query().
*
* @access public
* @param string
* @return void
*/
function Query($force=false)
{
if (!$force && $this->Queried) return true;
$q = $this->GetSelectSQL();
//$rs = $this->Conn->SelectLimit($q, $this->PerPage, $this->Offset);
//in case we have not counted records try to select one more item to find out if we have something more than perpage
$limit = $this->Counted ? $this->PerPage : $this->PerPage+1;
$sql = $q.' '.$this->Conn->getLimitClause($this->Offset,$limit);
$this->Records = $this->Conn->Query($sql);
if (!$this->Records && ($this->Page > 1)) {
// no records & page > 1, try to reset to 1st page (works only when list in not counted before)
$this->Application->StoreVar($this->getPrefixSpecial().'_Page', 1);
$this->SetPage(1);
$this->Query($force);
}
$this->SelectedCount = count($this->Records);
if (!$this->Counted) $this->RecordsCount = $this->SelectedCount;
if (!$this->Counted && $this->SelectedCount > $this->PerPage && $this->PerPage != -1) $this->SelectedCount--;
if ($this->Records === false) {
//handle errors here
return false;
}
$this->Queried = true;
$query_event = new kEvent($this->getPrefixSpecial() . ':OnAfterListQuery');
$this->Application->HandleEvent($query_event);
return true;
}
/**
* Adds one more record to list virtually and updates all counters
*
* @param Array $record
*/
function addRecord($record)
{
$this->Records[] = $record;
$this->SelectedCount++;
$this->RecordsCount++;
}
function CalculateTotals()
{
$this->Totals = Array();
$fields = Array();
foreach($this->Fields as $field_name => $field_options)
{
$totals = getArrayValue($field_options, 'totals');
if(!$totals) continue;
$calculated_field = isset($this->CalculatedFields[$field_name]) && isset($this->VirtualFields[$field_name]);
$db_field = !isset($this->VirtualFields[$field_name]);
if($calculated_field || $db_field)
{
$field_expression = $calculated_field ? $this->CalculatedFields[$field_name] : '`'.$this->TableName.'`.`'.$field_name.'`';
$fields[$field_name] = $totals.'('.$field_expression.') AS '.$field_name.'_'.$totals;
}
}
if(!$fields) return false;
$sql = $this->GetSelectSQL(true, false);
$fields = implode(', ', $fields);
if ( preg_match("/DISTINCT(.*?)FROM(?!_)/is",$sql,$regs ) )
{
$sql = preg_replace("/^\s*SELECT DISTINCT(.*?)FROM(?!_)/is", 'SELECT '.$fields.' FROM', $sql);
}
else
{
$sql = preg_replace("/^\s*SELECT(.*?)FROM(?!_)/is", 'SELECT '.$fields.' FROM ', $sql);
}
$totals = $this->Conn->Query($sql);
foreach($totals as $totals_row)
{
foreach($totals_row as $total_field => $field_value)
{
if(!isset($this->Totals[$total_field])) $this->Totals[$total_field] = 0;
$this->Totals[$total_field] += $field_value;
}
}
$this->TotalsCalculated = true;
}
function getTotal($field, $total_function)
{
if (!$this->TotalsCalculated) $this->CalculateTotals();
return $this->Totals[$field.'_'.$total_function];
}
function GetFormattedTotal($field, $total_function)
{
$val = $this->getTotal($field, $total_function);
$options = $this->GetFieldOptions($field);
$res = $val;
if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$res = $formatter->Format($val, $field, $this );
}
return $res;
}
/**
* Builds full select query except for LIMIT clause
*
* @access public
* @return string
*/
function GetSelectSQL($for_counting=false,$system_filters_only=false)
{
$q = parent::GetSelectSQL($this->SelectClause);
$q = !$for_counting ? $this->addCalculatedFields($q, 0) : str_replace('%2$s', '', $q);
$where = $this->GetWhereClause($for_counting,$system_filters_only);
$having = $this->GetHavingClause($for_counting,$system_filters_only);
$order = $this->GetOrderClause();
$group = $this->GetGroupClause();
if (!empty($where)) $q .= ' WHERE ' . $where;
if (!empty($group)) $q .= ' GROUP BY ' . $group;
if (!empty($having)) $q .= ' HAVING ' . $having;
if ( !$for_counting && !empty($order) ) $q .= ' ORDER BY ' . $order;
return $this->replaceModePrefix( str_replace('%1$s', $this->TableName, $q) );
}
/**
* Enter description here...
*
* @param string $clause where clause to extract calculated fields from
* @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only
* @return string
*/
function extractCalculatedFields($clause, $aggregated = 1)
{
$fields = $this->getCalculatedFields($aggregated);
if (is_array($fields) && count($fields) > 0) {
foreach ($fields as $field_name => $field_expression) {
$clause = preg_replace('/(\\(+)[(,` ]*'.$field_name.'[` ]{1}/', '\1 ('.$field_expression.') ', $clause);
$clause = preg_replace('/[,` ]{1}'.$field_name.'[` ]{1}/', ' ('.$field_expression.') ', $clause);
}
}
return $clause;
}
/**
* Returns WHERE clause of the query
*
* @access public
* @param bool $for_counting merge where filters with having filters + replace field names for having fields with their values
* @return string
*/
function GetWhereClause($for_counting=false,$system_filters_only=false)
{
$where =& $this->Application->makeClass('kMultipleFilter');
$where->addFilter('system_where', $this->WhereFilter[FLT_SYSTEM] );
if (!$system_filters_only) {
$where->addFilter('view_where', $this->WhereFilter[FLT_VIEW] );
$search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
if ($search_w || $for_counting) { // move search_having to search_where in case search_where isset or we are counting
$search_h = $this->extractCalculatedFields( $this->HavingFilter[FLT_SEARCH]->getSQL() );
$search_w = ($search_w && $search_h) ? $search_w.' OR '.$search_h : $search_w.$search_h;
$where->addFilter('search_where', $search_w );
}
// CUSTOM
$search_w = $this->WhereFilter[FLT_CUSTOM]->getSQL();
if ($search_w || $for_counting) { // move search_having to search_where in case search_where isset or we are counting
$search_h = $this->extractCalculatedFields( $this->HavingFilter[FLT_CUSTOM]->getSQL() );
$search_w = ($search_w && $search_h) ? $search_w.' AND '.$search_h : $search_w.$search_h;
$where->addFilter('custom_where', $search_w );
}
// CUSTOM
}
if( $for_counting ) // add system_having and view_having to where
{
$where->addFilter('system_having', $this->extractCalculatedFields($this->HavingFilter[FLT_SYSTEM]->getSQL()) );
if (!$system_filters_only) $where->addFilter('view_having', $this->extractCalculatedFields( $this->HavingFilter[FLT_VIEW]->getSQL() ) );
}
return $where->getSQL();
}
/**
* Depricated method
*
* @param string $clause
* @todo REMOVE
*/
function SetWhereClause($clause)
{
- if( $this->Application->isDebugMode() )
- {
+ if ($this->Application->isDebugMode()) {
global $debugger;
$debugger->appendTrace();
}
+
trigger_error('Depricated method <b>kDBList->SetWhereClause</b>. Use <b>kDBList->addFilter</b> instead.', E_USER_ERROR);
}
/**
* Returns HAVING clause of the query
*
* @param bool $for_counting don't return having filter in case if this is counting sql
* @param bool $system_filters_only return only system having filters
* @param int $aggregated 0 - aggregated and having, 1 - having only, 2 - aggregated only
* @return string
* @access public
*/
function GetHavingClause($for_counting=false, $system_filters_only=false, $aggregated = 0)
{
if ($for_counting) {
$aggregate_filter =& $this->Application->makeClass('kMultipleFilter');
$aggregate_filter->addFilter('aggregate_system', $this->AggregateFilter[FLT_SYSTEM]);
if (!$system_filters_only) {
$aggregate_filter->addFilter('aggregate_view', $this->AggregateFilter[FLT_VIEW]);
}
return $this->extractCalculatedFields($aggregate_filter->getSQL(), 2);
}
$having =& $this->Application->makeClass('kMultipleFilter');
$having->addFilter('system_having', $this->HavingFilter[FLT_SYSTEM] );
if ($aggregated == 0) {
if (!$system_filters_only) {
$having->addFilter('view_aggregated', $this->AggregateFilter[FLT_VIEW] );
}
$having->addFilter('system_aggregated', $this->AggregateFilter[FLT_SYSTEM]);
}
if (!$system_filters_only) {
$having->addFilter('view_having', $this->HavingFilter[FLT_VIEW] );
$having->addFilter('custom_having', $this->HavingFilter[FLT_CUSTOM] );
$search_w = $this->WhereFilter[FLT_SEARCH]->getSQL();
if (!$search_w) {
$having->addFilter('search_having', $this->HavingFilter[FLT_SEARCH] );
}
}
return $having->getSQL();
}
/**
* Returns GROUP BY clause of the query
*
* @access public
* @return string
*/
function GetGroupClause()
{
return $this->GroupByFields ? implode(',', $this->GroupByFields) : '';
}
function AddGroupByField($field)
{
$this->GroupByFields[$field] = $field;
}
function RemoveGroupByField($field)
{
unset($this->GroupByFields[$field]);
}
/**
* Adds order field to ORDER BY clause
*
* @access public
* @param string $field Field name
* @param string $direction Direction of ordering (asc|desc)
* @param bool $is_expression this is expression, that should not be escapted by "`" symbols
* @return void
*/
function AddOrderField($field, $direction = 'asc', $is_expression = false)
{
// original multilanguage field - convert to current lang field
$formatter = isset($this->Fields[$field]['formatter']) ? $this->Fields[$field]['formatter'] : false;
if ($formatter == 'kMultiLanguage' && !isset($this->Fields[$field]['master_field'])) {
$lang = $this->Application->GetVar('m_lang');
$field = 'l'.$lang.'_'.$field;
}
if (!isset($this->Fields[$field]) && $field != 'RAND()' && !$is_expression) {
trigger_error('<span class="debug_error">Incorrect sorting</span> defined (field = <b>'.$field.'</b>; direction = <b>'.$direction.'</b>) in config for prefix <b>'.$this->Prefix.'</b>', E_USER_WARNING);
}
$this->OrderFields[] = Array($field, $direction, $is_expression);
}
/**
* Removes all order fields
*
* @access public
* @return void
*/
function ClearOrderFields()
{
$this->OrderFields = Array();
}
/**
* Returns ORDER BY Clause of the query
*
* The method builds order by clause by iterating {@link kDBList::OrderFields} array and concatenating it.
*
* @access public
* @return string
*/
function GetOrderClause()
{
$ret = '';
foreach ($this->OrderFields as $field) {
$name = $field[0];
$ret .= isset($this->Fields[$name]) && !isset($this->VirtualFields[$name]) ? '`'.$this->TableName.'`.' : '';
if ($field[0] == 'RAND()' || $field[2]) {
$ret .= $field[0].' '.$field[1].',';
}
else {
$ret .= (strpos($field[0], '.') === false ? '`'.$field[0] . '`' : $field[0]) . ' ' . $field[1] . ',';
}
}
$ret = rtrim($ret, ',');
return $ret;
}
function GetOrderField($pos = NULL, $no_default = false)
{
if ( !(isset($this->OrderFields[$pos]) && $this->OrderFields[$pos]) && !$no_default ) {
$pos = 0;
}
return isset($this->OrderFields[$pos][0]) ? $this->OrderFields[$pos][0] : '';
}
function GetOrderDirection($pos = NULL, $no_default = false)
{
if ( !(isset($this->OrderFields[$pos]) && $this->OrderFields[$pos]) && !$no_default ) {
$pos = 0;
}
return isset($this->OrderFields[$pos][1]) ? $this->OrderFields[$pos][1] : '';
}
/**
* Return unformatted field value
*
* @param string $name
* @return string
* @access public
*/
function GetDBField($name)
{
$row =& $this->getCurrentRecord();
if (defined('DEBUG_MODE') && DEBUG_MODE && $this->Queried && !array_key_exists($name, $row)) {
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
trigger_error('Field "<strong>' . $name . '</strong>" doesn\'t exist in prefix <strong>' . $this->getPrefixSpecial() . '</strong>', E_USER_WARNING);
return 'NO SUCH FIELD';
}
// return "null" for missing fields, because formatter require such behaviour !
return array_key_exists($name, $row) ? $row[$name] : null;
}
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
function GetID()
{
return $this->Queried ? $this->GetDBField($this->IDField) : null;
}
/**
* Allows kDBTagProcessor.SectionTitle to detect if it's editing or new item creation
*
* @return bool
*/
function IsNewItem()
{
// no such thing as NewItem for lists :)
return false;
}
function HasField($name)
{
$row =& $this->getCurrentRecord();
return isset($row[$name]);
}
function GetFieldValues()
{
return $this->getCurrentRecord();
}
/**
* Returns current record from list
*
* @param int $offset Offset relative to current record index
* @return Array
*/
function &getCurrentRecord($offset = 0)
{
$record_index = $this->CurrentIndex + $offset;
if ($record_index >=0 && $record_index < $this->SelectedCount) {
return $this->Records[$record_index];
}
return false;
}
/**
* Goes to record with given index
*
* @param int $index
*/
function GoIndex($index)
{
$this->CurrentIndex = $index;
}
/**
* Description
*
* @access public
* @param string
* @return void
*/
function GoFirst()
{
$this->CurrentIndex = 0;
}
/**
* Description
*
* @access public
* @return void
*/
function GoNext()
{
$this->CurrentIndex++;
}
/**
* Description
*
* @access public
* @return void
*/
function GoPrev()
{
if ($this->CurrentIndex>0)
$this->CurrentIndex--;
}
/**
* Description
*
* @access public
* @return bool
*/
function EOL()
{
return ($this->CurrentIndex >= $this->SelectedCount);
}
/**
* Description
*
* @access public
* @param string
* @return void
*/
function GetTotalPages()
{
if (!$this->Counted) $this->CountRecs();
if ($this->PerPage == -1) return 1;
$this->TotalPages = (($this->RecordsCount - ($this->RecordsCount % $this->PerPage)) / $this->PerPage) // integer part of division
+ (($this->RecordsCount % $this->PerPage) != 0); // adds 1 if there is a reminder
return $this->TotalPages;
}
/**
* Sets number of records to query per page
*
* @access public
* @param int $per_page Number of records to display per page
* @return void
*/
function SetPerPage($per_page)
{
$this->PerPage = $per_page;
}
function GetPerPage()
{
return $this->PerPage == -1 ? $this->RecordsCount : $this->PerPage;
}
/**
* Description
*
* @access public
* @param int $page
* @return void
*/
function SetPage($page)
{
if ($this->PerPage == -1) {
$this->Page = 1;
return;
}
if ($page < 1) $page = 1;
$this->Offset = ($page-1)*$this->PerPage;
if ($this->Counted && $this->Offset > $this->RecordsCount) {
$this->SetPage(1);
}
else {
$this->Page = $page;
}
//$this->GoFirst();
}
/**
* Sets current item field value
* (doesn't apply formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
function SetDBField($name,$value)
{
$this->Records[$this->CurrentIndex][$name] = $value;
}
/**
* Apply where clause, that links this object to it's parent item
*
* @param string $special
* @access public
*/
function linkToParent($special)
{
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if ($parent_prefix) {
$parent_table_key = $this->Application->getUnitOption($this->Prefix, 'ParentTableKey');
if (is_array($parent_table_key)) $parent_table_key = getArrayValue($parent_table_key, $parent_prefix);
$foreign_key_field = $this->Application->getUnitOption($this->Prefix, 'ForeignKey');
if (is_array($foreign_key_field)) $foreign_key_field = getArrayValue($foreign_key_field, $parent_prefix);
if (!$parent_table_key || !$foreign_key_field) return ;
$parent_object =& $this->Application->recallObject($parent_prefix.'.'.$special);
$parent_id = $parent_object->GetDBField($parent_table_key);
if (!$parent_id) return ;
$this->addFilter('parent_filter', '`'.$this->TableName.'`.`'.$foreign_key_field.'` = '.$parent_id); // only for list in this case
}
}
/**
* Returns true if list was queried (same name as for kDBItem for easy usage)
*
* @return bool
*/
function isLoaded()
{
return $this->Queried;
}
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
* @return Array
*/
function GetCol($field)
{
$i = 0;
$ret = Array ();
while ($i < $this->SelectedCount) {
$ret[] = $this->Records[$i][$field];
$i++;
}
return $ret;
}
/**
* Set's field error, if pseudo passed not found then create it with message text supplied.
* Don't owerrite existing pseudo translation.
*
* @param string $field
* @param string $pseudo
* @param string $error_label
*/
function SetError($field, $pseudo, $error_label = null, $error_params = null)
{
$error_field = isset($this->Fields[$field]['error_field']) ? $this->Fields[$field]['error_field'] : $field;
$this->FieldErrors[$error_field]['pseudo'] = $pseudo;
$var_name = $this->getPrefixSpecial().'_'.$field.'_error';
$previous_pseudo = $this->Application->RecallVar($var_name);
if ($previous_pseudo) {
// don't set more then one error on field
return false;
}
$this->Application->StoreVar($var_name, $pseudo);
return true;
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/db/dbitem.php
===================================================================
--- branches/5.0.x/core/kernel/db/dbitem.php (revision 12322)
+++ branches/5.0.x/core/kernel/db/dbitem.php (revision 12323)
@@ -1,1300 +1,1300 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/**
* DBItem
*
* Desciption
* @package kernel4
*/
class kDBItem extends kDBBase {
/**
* Description
*
* @var array Associative array of current item' field values
* @access public
*/
var $FieldValues;
/**
* Unformatted field values, before parse
*
* @var Array
* @access private
*/
var $DirtyFieldValues = Array();
/**
* Holds item values after loading (not affected by submit)
*
* @var Array
* @access private
*/
var $OriginalFieldValues = Array ();
var $FieldErrors;
var $ErrorMsgs = Array();
/**
* If set to true, Update will skip Validation before running
*
* @var array Associative array of current item' field values
* @access public
*/
var $IgnoreValidation = false;
var $Loaded = false;
/**
* Holds item' primary key value
*
* @var int Value of primary key field for current item
* @access public
*/
var $ID;
function kDBItem()
{
parent::kDBBase();
$this->ErrorMsgs['required'] = '!la_err_required!'; //'Field is required';
$this->ErrorMsgs['unique'] = '!la_err_unique!'; //'Field value must be unique';
$this->ErrorMsgs['value_out_of_range'] = '!la_err_value_out_of_range!'; //'Field is out of range, possible values from %s to %s';
$this->ErrorMsgs['length_out_of_range'] = '!la_err_length_out_of_range!'; //'Field is out of range';
$this->ErrorMsgs['bad_type'] = '!la_err_bad_type!'; //'Incorrect data format, please use %s';
$this->ErrorMsgs['invalid_format'] = '!la_err_invalid_format!'; //'Incorrect data format, please use %s';
$this->ErrorMsgs['bad_date_format'] = '!la_err_bad_date_format!'; //'Incorrect date format, please use (%s) ex. (%s)';
$this->ErrorMsgs['primary_lang_required'] = '!la_err_primary_lang_required!';
}
function SetDirtyField($field_name, $field_value)
{
$this->DirtyFieldValues[$field_name] = $field_value;
}
function GetDirtyField($field_name)
{
return $this->DirtyFieldValues[$field_name];
}
function GetOriginalField($field_name, $formatted = false, $format=null)
{
if (array_key_exists($field_name, $this->OriginalFieldValues)) {
// item was loaded before
$value = $this->OriginalFieldValues[$field_name];
}
else {
// no original fields -> use default field value
$value = $this->Fields[$field_name]['default'];
}
if (!$formatted) {
return $value;
}
$options = $this->GetFieldOptions($field_name);
$res = $value;
if (array_key_exists('formatter', $options)) {
$formatter =& $this->Application->recallObject($options['formatter']);
/* @var $formatter kFormatter */
$res = $formatter->Format($value, $field_name, $this, $format);
}
return $res;
}
/**
* Sets original field value (useful for custom virtual fields)
*
* @param string $field_name
*/
function SetOriginalField($field_name, $field_value)
{
$this->OriginalFieldValues[$field_name] = $field_value;
}
/**
* Set's default values for all fields
*
* @param bool $populate_ml_fields create all ml fields from db in config or not
*
* @access public
*/
function SetDefaultValues($populate_ml_fields = false)
{
parent::SetDefaultValues($populate_ml_fields);
if ($populate_ml_fields) {
$this->PopulateMultiLangFields();
}
foreach ($this->Fields as $field => $params) {
if ( isset($params['default']) ) {
$this->SetDBField($field, $params['default']);
}
else {
$this->SetDBField($field, NULL);
}
}
}
/**
* Sets current item field value
* (applies formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
function SetField($name,$value)
{
$options = $this->GetFieldOptions($name);
$parsed = $value;
if ($value == '') {
$parsed = NULL;
}
// kFormatter is always used, to make sure, that numeric value is converted to normal representation
// according to regional format, even when formatter is not set (try seting format to 1.234,56 to understand why)
$formatter =& $this->Application->recallObject(isset($options['formatter']) ? $options['formatter'] : 'kFormatter');
$parsed = $formatter->Parse($value, $name, $this);
$this->SetDBField($name,$parsed);
}
/**
* Sets current item field value
* (doesn't apply formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
function SetDBField($name,$value)
{
$this->FieldValues[$name] = $value;
/*if (isset($this->Fields[$name]['formatter'])) {
$formatter =& $this->Application->recallObject($this->Fields[$name]['formatter']);
$formatter->UpdateSubFields($name, $value, $this->Fields[$name], $this);
}*/
}
/**
* Set's field error, if pseudo passed not found then create it with message text supplied.
* Don't owerrite existing pseudo translation.
*
* @param string $field
* @param string $pseudo
* @param string $error_label
*
* @return bool
*/
function SetError($field, $pseudo, $error_label = null, $error_params = null)
{
$error_field = isset($this->Fields[$field]['error_field']) ? $this->Fields[$field]['error_field'] : $field;
if (isset($this->FieldErrors[$error_field]['pseudo'])) {
// don't set more then one error on field
return false;
}
$this->FieldErrors[$error_field]['pseudo'] = $pseudo;
if (isset($error_params)) {
// additional params, that helps to determine error sources
$this->FieldErrors[$error_field]['params'] = $error_params;
}
if (isset($error_label) && !isset($this->ErrorMsgs[$pseudo])) {
// label for error (only when not already set)
$this->ErrorMsgs[$pseudo] = (substr($error_label, 0, 1) == '+') ? substr($error_label, 1) : '!'.$error_label.'!';
}
return true;
}
/**
* Return current item' field value by field name
* (doesn't apply formatter)
*
* @access public
* @param string $name field name to return
* @return mixed
*/
function GetDBField($name)
{
/*if (!array_key_exists($name, $this->FieldValues) && defined('DEBUG_MODE') && DEBUG_MODE) {
$this->Application->Debugger->appendTrace();
}*/
return $this->FieldValues[$name];
}
function HasField($name)
{
return isset($this->FieldValues[$name]);
}
function GetFieldValues()
{
return $this->FieldValues;
}
/**
* Sets item' fields corresponding to elements in passed $hash values.
*
* The function sets current item fields to values passed in $hash, by matching $hash keys with field names
* of current item. If current item' fields are unknown {@link kDBItem::PrepareFields()} is called before acutally setting the fields
*
* @access public
* @param Array $hash
* @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped
* @return void
*/
function SetFieldsFromHash($hash, $set_fields = null)
{
// used in formatter which work with multiple fields together
foreach($hash as $field_name => $field_value) {
if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) {
continue;
}
if (is_array($set_fields) && !in_array($field_name, $set_fields)) {
continue;
}
$this->SetDirtyField($field_name, $field_value);
}
// formats all fields using associated formatters
foreach ($hash as $field_name => $field_value)
{
if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) {
continue;
}
if (is_array($set_fields) && !in_array($field_name, $set_fields)) {
continue;
}
$this->SetField($field_name,$field_value);
}
}
function SetDBFieldsFromHash($hash, $set_fields = null)
{
foreach ($hash as $field_name => $field_value) {
if (is_numeric($field_name) || !array_key_exists($field_name, $this->Fields)) {
continue;
}
if (is_array($set_fields) && !in_array($field_name, $set_fields)) {
continue;
}
$this->SetDBField($field_name, $field_value);
}
}
/**
* Returns part of SQL WHERE clause identifing the record, ex. id = 25
*
* @access public
* @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method
* @param Array $keys_hash alternative, then item id, keys hash to load item by
* @return void
* @see kDBItem::Load()
* @see kDBItem::Update()
* @see kDBItem::Delete()
*/
function GetKeyClause($method=null, $keys_hash = null)
{
if( !isset($keys_hash) ) $keys_hash = Array($this->IDField => $this->ID);
$ret = '';
foreach($keys_hash as $field => $value)
{
if (!preg_match('/\./', $field)) {
$ret .= '(`'.$this->TableName.'`.'.$field.' = '.$this->Conn->qstr($value).') AND ';
}
else {
$ret .= '('.$field.' = '.$this->Conn->qstr($value).') AND ';
}
}
return preg_replace('/(.*) AND $/', '\\1', $ret);
}
/**
* Loads item from the database by given id
*
* @access public
* @param mixed $id item id of keys->values hash to load item by
* @param string $id_field_name Optional parameter to load item by given Id field
* @return bool True if item has been loaded, false otherwise
*/
function Load($id, $id_field_name = null)
{
if ( isset($id_field_name) ) {
$this->SetIDField($id_field_name); // set new IDField
}
$keys_sql = '';
if (is_array($id)) {
$keys_sql = $this->GetKeyClause('load', $id);
}
else {
$this->setID($id);
$keys_sql = $this->GetKeyClause('load');
}
if ( isset($id_field_name) ) {
// restore original IDField from unit config
$this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') );
}
if (($id === false) || !$keys_sql) {
return $this->Clear();
}
if (!$this->raiseEvent('OnBeforeItemLoad', $id)) {
return false;
}
$q = $this->GetSelectSQL() . ' WHERE ' . $keys_sql;
$field_values = $this->Conn->GetRow($q);
if ($field_values) {
$this->FieldValues = array_merge_recursive2($this->FieldValues, $field_values);
$this->OriginalFieldValues = $this->FieldValues;
}
else {
return $this->Clear();
}
if (is_array($id) || isset($id_field_name)) {
$this->setID($this->FieldValues[$this->IDField]);
}
$this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
$this->raiseEvent('OnAfterItemLoad', $this->GetID());
$this->Loaded = true;
return true;
}
/**
* Builds select sql, SELECT ... FROM parts only
*
* @access public
* @return string
*/
function GetSelectSQL()
{
$sql = $this->addCalculatedFields($this->SelectClause);
return parent::GetSelectSQL($sql);
}
function UpdateFormattersMasterFields()
{
foreach ($this->Fields as $field => $options) {
if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
}
}
}
/**
* Allows to skip certain fields from getting into sql queries
*
* @param string $field_name
* @param mixed $force_id
* @return bool
*/
function skipField($field_name, $force_id = false)
{
$skip = false;
// 1. skipping 'virtual' field
$skip = $skip || array_key_exists($field_name, $this->VirtualFields);
// 2. don't write empty field value to db, when "skip_empty" option is set
$field_value = array_key_exists($field_name, $this->FieldValues) ? $this->FieldValues[$field_name] : false;
$skip_empty = array_key_exists('skip_empty', $this->Fields[$field_name]) ? $this->Fields[$field_name]['skip_empty'] : false;
$skip = $skip || (!$field_value && $skip_empty);
// 3. skipping field not in Fields (nor virtual, nor real)
$skip = $skip || !array_key_exists($field_name, $this->Fields);
return $skip;
}
/**
* Updates previously loaded record with current item' values
*
* @access public
* @param int Primery Key Id to update
* @return bool
*/
function Update($id = null, $system_update = false)
{
if (isset($id)) {
$this->setID($id);
}
if (!$this->raiseEvent('OnBeforeItemUpdate')) {
return false;
}
if (!isset($this->ID)) {
// ID could be set inside OnBeforeItemUpdate event, so don't combine this check with previous one
return false;
}
// validate before updating
if (!$this->Validate()) {
return false;
}
if (!$this->raiseEvent('OnAfterItemValidate')) {
return false;
}
if (!$this->FieldValues) {
// nothing to update
return true;
}
$sql = '';
foreach ($this->FieldValues as $field_name => $field_value) {
if ($this->skipField($field_name)) {
continue;
}
if ( is_null($field_value) ) {
if (array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null']) {
// "kFormatter::Parse" methods converts empty values to NULL and for
// not-null fields they are replaced with default value here
$field_value = $this->Fields[$field_name]['default'];
}
}
$sql .= '`' . $field_name . '` = ' . $this->Conn->qstr($field_value) . ', ';
}
$sql = 'UPDATE ' . $this->TableName . '
SET ' . substr($sql, 0, -2) . '
WHERE ' . $this->GetKeyClause('update');
if ($this->Conn->ChangeQuery($sql) === false) {
// there was and sql error
return false;
}
$affected = $this->Conn->getAffectedRows();
if (!$system_update && $affected == 1) {
$this->setModifiedFlag(clUPDATE);
}
$this->saveCustomFields();
$this->raiseEvent('OnAfterItemUpdate');
$this->Loaded = true;
if ($this->mode != 't') {
$this->Application->resetCounters($this->TableName);
}
return true;
}
function ValidateField($field)
{
$options = $this->Fields[$field];
/*if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
}*/
$error_field = isset($options['error_field']) ? $options['error_field'] : $field;
$res = !isset($this->FieldErrors[$error_field]['pseudo']) || !$this->FieldErrors[$error_field]['pseudo'];
$res = $res && $this->ValidateRequired($field, $options);
$res = $res && $this->ValidateType($field, $options);
$res = $res && $this->ValidateRange($field, $options);
$res = $res && $this->ValidateUnique($field, $options);
$res = $res && $this->CustomValidation($field, $options);
return $res;
}
/**
* Validate all item fields based on
* constraints set in each field options
* in config
*
* @return bool
* @access private
*/
function Validate()
{
$this->UpdateFormattersMasterFields(); //order is critical - should be called BEFORE checking errors
if ($this->IgnoreValidation) {
return true;
}
$global_res = true;
foreach ($this->Fields as $field => $params) {
$res = $this->ValidateField($field);
$global_res = $global_res && $res;
}
if (!$global_res && $this->Application->isDebugMode()) {
$error_msg = ' Validation failed in prefix <strong>'.$this->Prefix.'</strong>,
FieldErrors follow (look at items with <strong>"pseudo"</strong> key set)<br />
You may ignore this notice if submitted data really has a validation error';
trigger_error(trim($error_msg), E_USER_NOTICE);
$this->Application->Debugger->dumpVars($this->FieldErrors);
}
return $global_res;
}
/**
* Check field value by user-defined alghoritm
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
*/
function CustomValidation($field, $params)
{
return true;
}
/**
* Check if item has errors
*
* @param Array $skip_fields fields to skip during error checking
* @return bool
*/
function HasErrors($skip_fields)
{
$global_res = false;
foreach ($this->Fields as $field => $field_params) {
// If Formatter has set some error messages during values parsing
if ( !( in_array($field, $skip_fields) ) &&
isset($this->FieldErrors[$field]['pseudo']) && $this->FieldErrors[$field] != '') {
$global_res = true;
}
}
return $global_res;
}
/**
* Check if value in field matches field type specified in config
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
*/
function ValidateType($field, $params)
{
$res = true;
$val = $this->FieldValues[$field];
if ( $val != '' &&
isset($params['type']) &&
preg_match("#int|integer|double|float|real|numeric|string#", $params['type'])
) {
if ($params['type'] == 'numeric') {
trigger_error('Invalid field type <strong>'.$params['type'].'</strong> (in ValidateType method), please use <strong>float</strong> instead', E_USER_NOTICE);
$params['type'] = 'float';
}
$res = is_numeric($val);
if ($params['type']=='string' || $res) {
$f = 'is_'.$params['type'];
settype($val, $params['type']);
$res = $f($val) && ($val == $this->FieldValues[$field]);
}
if (!$res) {
$this->SetError($field, 'bad_type', null, $params['type']);
}
}
return $res;
}
/**
* Check if value is set for required field
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateRequired($field, $params)
{
$res = true;
if (isset($params['required']) && $params['required']) {
$check_value = $this->FieldValues[$field];
if ($this->Application->ConfigValue('TrimRequiredFields')) {
$check_value = trim($check_value);
}
$res = ((string)$check_value != '');
}
if (!$res) {
$this->SetError($field, 'required');
}
return $res;
}
/**
* Validates that current record has unique field combination among other table records
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateUnique($field, $params)
{
$res = true;
$unique_fields = getArrayValue($params,'unique');
if($unique_fields !== false)
{
$where = Array();
array_push($unique_fields,$field);
foreach($unique_fields as $unique_field)
{
// if field is not empty or if it is required - we add where condition
if ((string)$this->GetDBField($unique_field) != '' || (isset($this->Fields[$unique_field]['required']) && $this->Fields[$unique_field]['required'])) {
$where[] = '`'.$unique_field.'` = '.$this->Conn->qstr( $this->GetDBField($unique_field) );
}
else {
// not good if we check by less fields than indicated
return true;
}
}
// This can ONLY happen if all unique fields are empty and not required.
// In such case we return true, because if unique field is not required there may be numerous empty values
// if (!$where) return true;
$sql = 'SELECT COUNT(*) FROM %s WHERE ('.implode(') AND (',$where).') AND ('.$this->IDField.' <> '.(int)$this->ID.')';
$res_temp = $this->Conn->GetOne( str_replace('%s', $this->TableName, $sql) );
$current_table_only = getArrayValue($params, 'current_table_only'); // check unique record only in current table
$res_live = $current_table_only ? 0 : $this->Conn->GetOne( str_replace('%s', $this->Application->GetLiveName($this->TableName), $sql) );
$res = ($res_temp == 0) && ($res_live == 0);
if (!$res) {
$this->SetError($field, 'unique');
}
}
return $res;
}
/**
* Check if field value is in range specified in config
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateRange($field, $params)
{
$res = true;
$val = $this->FieldValues[$field];
if ( isset($params['type']) && preg_match("#int|integer|double|float|real#", $params['type']) && strlen($val) > 0 ) {
if ( isset($params['max_value_inc'])) {
$res = $res && $val <= $params['max_value_inc'];
$max_val = $params['max_value_inc'].' (inclusive)';
}
if ( isset($params['min_value_inc'])) {
$res = $res && $val >= $params['min_value_inc'];
$min_val = $params['min_value_inc'].' (inclusive)';
}
if ( isset($params['max_value_exc'])) {
$res = $res && $val < $params['max_value_exc'];
$max_val = $params['max_value_exc'].' (exclusive)';
}
if ( isset($params['min_value_exc'])) {
$res = $res && $val > $params['min_value_exc'];
$min_val = $params['min_value_exc'].' (exclusive)';
}
}
if (!$res) {
if ( !isset($min_val) ) $min_val = '-&infin;';
if ( !isset($max_val) ) $max_val = '&infin;';
$this->SetError($field, 'value_out_of_range', null, Array ($min_val, $max_val));
return $res;
}
if ( isset($params['max_len'])) {
$res = $res && mb_strlen($val) <= $params['max_len'];
}
if ( isset($params['min_len'])) {
$res = $res && mb_strlen($val) >= $params['min_len'];
}
if (!$res) {
$error_params = Array (getArrayValue($params, 'min_len'), getArrayValue($params, 'max_len'));
$this->SetError($field, 'length_out_of_range', null, $error_params);
return $res;
}
return $res;
}
/**
* Return error message for field
*
* @param string $field
* @return string
* @access public
*/
function GetErrorMsg($field, $force_escape = null)
{
if( !isset($this->FieldErrors[$field]) ) return '';
$err = getArrayValue($this->FieldErrors[$field], 'pseudo');
if (!$err) return '';
// if special error msg defined in config
if( isset($this->Fields[$field]['error_msgs'][$err]) )
{
$msg = $this->Fields[$field]['error_msgs'][$err];
}
else //fall back to defaults
{
if( !isset($this->ErrorMsgs[$err]) ) {
trigger_error('No user message is defined for pseudo error <b>'.$err.'</b><br>', E_USER_WARNING);
return $err; //return the pseudo itself
}
$msg = $this->ErrorMsgs[$err];
}
$msg = $this->Application->ReplaceLanguageTags($msg, $force_escape);
if ( isset($this->FieldErrors[$field]['params']) )
{
return vsprintf($msg, $this->FieldErrors[$field]['params']);
}
return $msg;
}
/**
* Creates a record in the database table with current item' values
*
* @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE!
* @access public
* @return bool
*/
function Create($force_id = false, $system_create = false)
{
if (!$this->raiseEvent('OnBeforeItemCreate')) {
return false;
}
// Validating fields before attempting to create record
if (!$this->Validate()) {
return false;
}
if (!$this->raiseEvent('OnAfterItemValidate')) {
return false;
}
if (is_int($force_id)) {
$this->FieldValues[$this->IDField] = $force_id;
}
elseif (!$force_id || !is_bool($force_id)) {
$this->FieldValues[$this->IDField] = $this->generateID();
}
$fields_sql = '';
$values_sql = '';
foreach ($this->FieldValues as $field_name => $field_value) {
if ($this->skipField($field_name, $force_id)) {
continue;
}
if (is_null($field_value)) {
if (array_key_exists('not_null', $this->Fields[$field_name]) && $this->Fields[$field_name]['not_null']) {
// "kFormatter::Parse" methods converts empty values to NULL and for
// not-null fields they are replaced with default value here
$values_sql .= $this->Conn->qstr($this->Fields[$field_name]['default']);
}
else {
$values_sql .= $this->Conn->qstr($field_value);
}
}
else {
if (($field_name == $this->IDField) && ($field_value == 0)) {
// don't skip IDField in INSERT statement, just use DEFAULT keyword as it's value
$values_sql .= 'DEFAULT';
}
else {
$values_sql .= $this->Conn->qstr($field_value);
}
}
$fields_sql .= '`' . $field_name . '`, '; //Adding field name to fields block of Insert statement
$values_sql .= ', ';
}
$sql = 'INSERT INTO ' . $this->TableName . ' (' . substr($fields_sql, 0, -2) . ')
VALUES (' . substr($values_sql, 0, -2) . ')';
//Executing the query and checking the result
if ($this->Conn->ChangeQuery($sql) === false) {
return false;
}
$insert_id = $this->Conn->getInsertID();
if ($insert_id == 0) {
// insert into temp table (id is not auto-increment field)
$insert_id = $this->FieldValues[$this->IDField];
}
$this->setID($insert_id);
if (!$system_create){
$this->setModifiedFlag(clCREATE);
}
$this->saveCustomFields();
if ($this->mode != 't') {
$this->Application->resetCounters($this->TableName);
}
$this->raiseEvent('OnAfterItemCreate');
$this->Loaded = true;
return true;
}
/**
* Deletes the record from databse
*
* @access public
* @return bool
*/
function Delete($id = null)
{
if (isset($id)) {
$this->setID($id);
}
if (!$this->raiseEvent('OnBeforeItemDelete')) {
return false;
}
$sql = 'DELETE FROM ' . $this->TableName . '
WHERE ' . $this->GetKeyClause('Delete');
$ret = $this->Conn->ChangeQuery($sql);
$affected_rows = $this->Conn->getAffectedRows();
$this->setModifiedFlag(clDELETE); // will change affected rows, so get it before this line
if ($affected_rows > 0) {
// something was actually deleted
$this->raiseEvent('OnAfterItemDelete');
}
if ($this->mode != 't') {
$this->Application->resetCounters($this->TableName);
}
return $ret;
}
function PopulateMultiLangFields()
{
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$lang_count = $ml_helper->getLanguageCount();
foreach ($this->Fields as $field => $options)
{
// master field is set only for CURRENT language
if (isset($options['formatter']) && $options['formatter'] == 'kMultiLanguage' && isset($options['master_field'])) {
if (preg_match('/^l([0-9]+)_(.*)/', $field, $regs)) {
$l = $regs[1];
$name = $regs[2];
// MuliLanguage formatter sets error_field to master_field, but in PopulateMlFields mode, we display ML fields directly
// so we set it back to itself, otherwise error will not be displayed
$this->Fields['l' . $l . '_' . $name]['error_field'] = 'l' . $l . '_' . $name;
for ($i = 1; $i <= $lang_count; $i++) {
if ($i == $l || !$ml_helper->LanguageFound($i)) continue;
$f_options = $options;
$f_options['error_field'] = 'l' . $i . '_' . $name; // set error field back to itself - see comment above
if ($i != $this->Application->GetDefaultLanguageId()) {
unset($f_options['required']); // all non-primary language field set to non-required
}
$this->Fields['l' . $i . '_' . $name] = $f_options;
}
}
}
}
}
/**
* Sets new name for item in case if it is beeing copied
* in same table
*
* @param array $master Table data from TempHandler
* @param int $foreign_key ForeignKey value to filter name check query by
* @param string $title_field FieldName to alter, by default - TitleField of the prefix
* @param string $format sprintf-style format of renaming pattern, by default Copy %1$s of %2$s which makes it Copy [Number] of Original Name
* @access private
*/
function NameCopy($master=null, $foreign_key=null, $title_field=null, $format='Copy %1$s of %2$s')
{
if (!isset($title_field)) {
$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
if (!$title_field || isset($this->CalculatedFields[$title_field]) ) return;
}
$new_name = $this->GetDBField($title_field);
$original_checked = false;
do {
if ( preg_match('/'.sprintf($format, '([0-9]*) *', '(.*)').'/', $new_name, $regs) ) {
$new_name = sprintf($format, ($regs[1]+1), $regs[2]);
}
elseif ($original_checked) {
$new_name = sprintf($format, '', $new_name);
}
// if we are cloning in temp table this will look for names in temp table,
// since object' TableName contains correct TableName (for temp also!)
// if we are cloning live - look in live
$query = 'SELECT '.$title_field.' FROM '.$this->TableName.'
WHERE '.$title_field.' = '.$this->Conn->qstr($new_name);
$foreign_key_field = getArrayValue($master, 'ForeignKey');
$foreign_key_field = is_array($foreign_key_field) ? $foreign_key_field[ $master['ParentPrefix'] ] : $foreign_key_field;
if ($foreign_key_field && isset($foreign_key)) {
$query .= ' AND '.$foreign_key_field.' = '.$foreign_key;
}
$res = $this->Conn->GetOne($query);
/*// if not found in live table, check in temp table if applicable
if ($res === false && $object->Special == 'temp') {
$query = 'SELECT '.$name_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$name_field.' = '.$this->Conn->qstr($new_name);
$res = $this->Conn->GetOne($query);
}*/
$original_checked = true;
} while ($res !== false);
$this->SetDBField($title_field, $new_name);
}
function raiseEvent($name, $id = null, $additional_params = Array())
{
if( !isset($id) ) $id = $this->GetID();
$event = new kEvent( Array('name'=>$name,'prefix'=>$this->Prefix,'special'=>$this->Special) );
$event->setEventParam('id', $id);
if ($additional_params) {
foreach ($additional_params as $ap_name => $ap_value) {
$event->setEventParam($ap_name, $ap_value);
}
}
$this->Application->HandleEvent($event);
return $event->status == erSUCCESS ? true : false;
}
/**
* Set's new ID for item
*
* @param int $new_id
* @access public
*/
function setID($new_id)
{
$this->ID = $new_id;
$this->SetDBField($this->IDField, $new_id);
}
/**
* Generate and set new temporary id
*
* @access private
*/
function setTempID()
{
$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$this->IDField.') FROM '.$this->TableName);
if($new_id > 0) $new_id = 0;
--$new_id;
$this->Conn->Query('UPDATE '.$this->TableName.' SET `'.$this->IDField.'` = '.$new_id.' WHERE `'.$this->IDField.'` = '.$this->GetID());
if ($this->ShouldLogChanges()) {
// Updating TempId in ChangesLog, if changes are disabled
$ses_var_name = $this->Application->GetTopmostPrefix($this->Prefix).'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
$changes = $this->Application->RecallVar($ses_var_name);
$changes = $changes ? unserialize($changes) : Array ();
if ($changes) {
foreach ($changes as $key => $rec) {
if ($rec['Prefix'] == $this->Prefix && $rec['ItemId'] == $this->GetID()) {
$changes[$key]['ItemId'] = $new_id;
}
}
}
$this->Application->StoreVar($ses_var_name, serialize($changes));
}
$this->SetID($new_id);
}
/**
* Set's modification flag for main prefix of current prefix to true
*
* @access private
* @author Alexey
*/
function setModifiedFlag($mode = null)
{
$main_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
$this->Application->StoreVar($main_prefix.'_modified', '1');
if ($this->ShouldLogChanges()) {
$this->LogChanges($main_prefix, $mode);
if (!$this->IsTempTable()) {
$handler =& $this->Application->recallObject($this->Prefix.'_EventHandler');
$ses_var_name = $main_prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
$handler->SaveLoggedChanges($ses_var_name);
}
}
}
/**
* Determines, that changes made to this item should be written to change log
*
* @return bool
*/
function ShouldLogChanges()
{
$log_changes = $this->Application->getUnitOption($this->Prefix, 'LogChanges') || $this->Application->ConfigValue('UseChangeLog');
return $log_changes && !$this->Application->getUnitOption($this->Prefix, 'ForceDontLogChanges');
}
function LogChanges($main_prefix, $mode)
{
if (!$mode) {
return ;
}
$ses_var_name = $main_prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
$changes = $this->Application->RecallVar($ses_var_name);
$changes = $changes ? unserialize($changes) : array();
$general = array(
'Prefix' => $this->Prefix,
'ItemId' => $this->GetID(),
'OccuredOn' => adodb_mktime(),
'MasterPrefix' => $main_prefix,
'MasterId' => $this->Prefix == $main_prefix ? $this->GetID() : $this->Application->GetVar($main_prefix.'_id'), // is that correct (Kostja)??
'Action' => $mode,
);
switch ($mode) {
case clUPDATE:
$changes[] = array_merge($general, Array(
'Changes' => serialize(array_merge($this->GetTitleField(), $this->GetChangedFields())),
));
break;
case clCREATE:
$changes[] = array_merge($general, Array(
'Changes' => serialize($this->GetTitleField()),
));
break;
case clDELETE:
$changes[] = array_merge($general, Array(
'Changes' => serialize(array_merge($this->GetTitleField(), $this->GetRealFields())),
));
}
$this->Application->StoreVar($ses_var_name, serialize($changes));
}
function GetTitleField()
{
$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
if ($title_field && $this->GetField($title_field)) {
return Array($title_field => $this->GetField($title_field));
}
}
function GetRealFields()
{
if (function_exists('array_diff_key')) {
$db_fields = array_diff_key($this->FieldValues, $this->VirtualFields, $this->CalculatedFields);
}
else {
$db_fields = array();
foreach ($this->FieldValues as $key => $value) {
if (array_key_exists($key, $this->VirtualFields) || array_key_exists($key, $this->CalculatedFields)) continue;
$db_fields[$key] = $value;
}
}
return $db_fields;
}
function GetChangedFields()
{
$changes = array();
$diff = array_diff_assoc($this->GetRealFields(), $this->OriginalFieldValues);
foreach ($diff as $field => $new_value) {
$changes[$field] = array('old' => $this->GetOriginalField($field, true), 'new' => $this->GetField($field));
}
return $changes;
}
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
function GetID()
{
return $this->ID;
}
/**
* Generates ID for new items before inserting into database
*
* @return int
* @access private
*/
function generateID()
{
return 0;
}
/**
* Returns true if item was loaded successfully by Load method
*
* @return bool
*/
function isLoaded()
{
return $this->Loaded;
}
/**
* Checks if field is required
*
* @param string $field
* @return bool
*/
function isRequired($field)
{
return getArrayValue( $this->Fields[$field], 'required' );
}
/**
* Sets new required flag to field
*
* @param string $field
* @param bool $is_required
*/
function setRequired($field, $is_required = true)
{
$this->Fields[$field]['required'] = $is_required;
}
function Clear($new_id = null)
{
$this->Loaded = false;
$this->FieldValues = Array();
$this->OriginalFieldValues = Array ();
$this->SetDefaultValues(); // will wear off kDBItem::setID effect, so set it later
$this->FieldErrors = Array();
$this->setID($new_id);
return $this->Loaded;
}
function Query($force = false)
{
- if( $this->Application->isDebugMode() )
- {
+ if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
+
trigger_error('<b>Query</b> method is called in class <b>'.get_class($this).'</b> for prefix <b>'.$this->getPrefixSpecial().'</b>', E_USER_ERROR);
}
function saveCustomFields()
{
if (!$this->customFields) {
return true;
}
$cdata_key = rtrim($this->Prefix.'-cdata.'.$this->Special, '.');
$cdata =& $this->Application->recallObject($cdata_key, null, Array('skip_autoload' => true, 'populate_ml_fields' => true));
$resource_id = $this->GetDBField('ResourceId');
$cdata->Load($resource_id, 'ResourceId');
$cdata->SetDBField('ResourceId', $resource_id);
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
foreach ($this->customFields as $custom_id => $custom_name) {
$force_primary = isset($cdata->Fields['cust_'.$custom_id]['force_primary']) && $cdata->Fields['cust_'.$custom_id]['force_primary'];
$cdata->SetDBField($ml_formatter->LangFieldName('cust_'.$custom_id, $force_primary), $this->GetDBField('cust_'.$custom_name));
}
if ($cdata->isLoaded()) {
$ret = $cdata->Update();
}
else {
$ret = $cdata->Create();
if ($cdata->mode == 't') $cdata->setTempID();
}
return $ret;
}
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
* @return Array
*/
function GetCol($field)
{
return Array (0 => $this->GetDBField($field));
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/startup.php
===================================================================
--- branches/5.0.x/core/kernel/startup.php (revision 12322)
+++ branches/5.0.x/core/kernel/startup.php (revision 12323)
@@ -1,166 +1,160 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
define('KERNEL_PATH', FULL_PATH . '/core/kernel');
if (!function_exists('getmicrotime')) {
function getmicrotime()
{
- list($usec, $sec) = explode(" ", microtime());
- return ((float)$usec + (float)$sec);
+ list($usec, $sec) = explode(" ", microtime());
+ return ((float)$usec + (float)$sec);
}
}
+
$globals_start = getmicrotime();
include_once(KERNEL_PATH . '/globals.php'); // non OOP functions used through kernel, e.g. print_pre
include_once(KERNEL_PATH . '/utility/multibyte.php'); // emulating multi-byte php extension
$globals_end = getmicrotime();
- define('INPORTAL_ENV', 1);
-
$vars = parse_portal_ini(FULL_PATH . '/config.php');
$admin_directory = isset($vars['AdminDirectory']) ? $vars['AdminDirectory'] : '/admin';
define('ADMIN_DIRECTORY', $admin_directory);
# New path detection method: begin
if (defined('REL_PATH')) {
// location of index.php relatively to site base folder
$relative_path = preg_replace('/^[\/]{0,1}admin(.*)/', $admin_directory . '\\1', REL_PATH);
}
else {
// default index.php relative location is administrative console folder
define('REL_PATH', $admin_directory);
$relative_path = REL_PATH;
}
$ps = rtrim(preg_replace('/' . preg_quote(rtrim($relative_path, '/'), '/') . '$/', '', str_replace('\\', '/', dirname($_SERVER['PHP_SELF']))), '/');
safeDefine('BASE_PATH', $ps); // in case in-portal has defined it before
# New path detection method: end
- safeDefine('INPORTAL_TAGS', true);
- safeDefine('NPARSER', 1); // New Parser is enabled
safeDefine('SERVER_NAME', $_SERVER['HTTP_HOST'] ? $_SERVER['HTTP_HOST'] : $vars['Domain']);
$https_mark = getArrayValue($_SERVER, 'HTTPS');
safeDefine('PROTOCOL', ($https_mark == 'on') || ($https_mark == '1') ? 'https://' : 'http://');
safeDefine('APPLICATION_CLASS', isset($vars['ApplicationClass']) ? $vars['ApplicationClass'] : 'kApplication');
safeDefine('APPLICATION_PATH', isset($vars['ApplicationPath']) ? $vars['ApplicationPath'] : '/core/kernel/application.php');
if (isset($vars['WriteablePath'])) {
define('WRITEABLE', FULL_PATH . $vars['WriteablePath']);
define('WRITEBALE_BASE', $vars['WriteablePath']);
}
if ($vars === false || count($vars) == 0) {
global $rootURL;
echo 'In-Portal is probably not installed, or configuration file is missing.<br>';
echo 'Please use the installation script to fix the problem.<br><br>';
echo '<a href="' . PROTOCOL . SERVER_NAME . rtrim(BASE_PATH, '/') . '/core/install.php">Go to installation script</a><br><br>';
flush();
exit;
}
define('SQL_TYPE', $vars['DBType']);
define('SQL_SERVER', $vars['DBHost']);
define('SQL_USER', $vars['DBUser']);
define('SQL_PASS', $vars['DBUserPassword']);
define('SQL_DB', $vars['DBName']);
if (isset($vars['DBCollation']) && isset($vars['DBCharset'])) {
define('SQL_COLLATION', $vars['DBCollation']);
define('SQL_CHARSET', $vars['DBCharset']);
}
define('TABLE_PREFIX', $vars['TablePrefix']);
define('DOMAIN', getArrayValue($vars, 'Domain'));
ini_set('memory_limit', '50M');
define('MODULES_PATH', FULL_PATH);
define('EXPORT_BASE_PATH', WRITEBALE_BASE . '/export');
define('EXPORT_PATH', FULL_PATH . EXPORT_BASE_PATH);
define('GW_CLASS_PATH', MODULES_PATH . '/in-commerce/units/gateways/gw_classes'); // Payment Gateway Classes Path
define('SYNC_CLASS_PATH', FULL_PATH . '/sync'); // path for 3rd party user syncronization scripts
safeDefine('ENV_VAR_NAME','env');
define('IMAGES_PATH', WRITEBALE_BASE . '/images/');
define('IMAGES_PENDING_PATH', IMAGES_PATH . 'pending/');
safeDefine('MAX_UPLOAD_SIZE', min(ini_get('upload_max_filesize'), ini_get('post_max_size'))*1024*1024);
safeDefine('EDITOR_PATH', isset($vars['EditorPath']) ? $vars['EditorPath'] : '/core/editor/');
- if( ini_get('safe_mode') ) define('SAFE_MODE', 1);
-
- safeDefine('EXPERIMENTAL_PRE_PARSE', 1);
+ if (ini_get('safe_mode')) {
+ // safe mode will be removed at all in PHP6
+ define('SAFE_MODE', 1);
+ }
- if( file_exists(FULL_PATH . '/debug.php') )
- {
+ if (file_exists(FULL_PATH . '/debug.php')) {
include_once(FULL_PATH . '/debug.php');
- if(isset($dbg_options['DEBUG_MODE']) && $dbg_options['DEBUG_MODE']) {
+ if (array_key_exists('DEBUG_MODE', $dbg_options) && $dbg_options['DEBUG_MODE']) {
$debugger_start = getmicrotime();
include_once(KERNEL_PATH . '/utility/debugger.php');
$debugger_end = getmicrotime();
+
if (isset($debugger) && constOn('DBG_PROFILE_INCLUDES')) {
$debugger->profileStart('inc_globals', KERNEL_PATH . '/globals.php', $globals_start);
$debugger->profileFinish('inc_globals', KERNEL_PATH . '/globals.php', $globals_end);
$debugger->profilerAddTotal('includes', 'inc_globals');
$debugger->profileStart('inc_debugger', KERNEL_PATH . '/utility/debugger.php', $debugger_start);
$debugger->profileFinish('inc_debugger', KERNEL_PATH . '/utility/debugger.php', $debugger_end);
$debugger->profilerAddTotal('includes', 'inc_debugger');
}
}
}
safeDefine('SILENT_LOG', 0);
$includes = Array(
KERNEL_PATH . '/application.php',
FULL_PATH . APPLICATION_PATH,
KERNEL_PATH . '/db/db_connection.php',
KERNEL_PATH . "/kbase.php",
KERNEL_PATH . '/utility/event.php',
KERNEL_PATH . "/utility/factory.php",
KERNEL_PATH . "/languages/phrases_cache.php",
KERNEL_PATH . "/db/dblist.php",
KERNEL_PATH . "/db/dbitem.php",
KERNEL_PATH . "/event_handler.php",
KERNEL_PATH . '/db/db_event_handler.php',
);
foreach ($includes as $a_file) {
k4_include_once($a_file);
}
if (defined('DEBUG_MODE') && DEBUG_MODE && isset($debugger)) {
$debugger->AttachToApplication();
}
- if( !function_exists('adodb_mktime') ) include_once(KERNEL_PATH . '/utility/adodb-time.inc.php');
-
-// include_once(KERNEL_PATH . '/utility/temp_handler.php'); // needed because of static calls from kBase
- // up to here
+ if( !function_exists('adodb_mktime') ) {
+ include_once(KERNEL_PATH . '/utility/adodb-time.inc.php');
+ }
// global constants
define ('KG_TO_POUND', 2.20462262);
- define ('POUND_TO_KG', 0.45359237);
-
-
-?>
\ No newline at end of file
+ define ('POUND_TO_KG', 0.45359237);
\ No newline at end of file
Index: branches/5.0.x/core/kernel/application.php
===================================================================
--- branches/5.0.x/core/kernel/application.php (revision 12322)
+++ branches/5.0.x/core/kernel/application.php (revision 12323)
@@ -1,2956 +1,2905 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
/**
* Basic class for Kernel4-based Application
*
* This class is a Facade for any other class which needs to deal with Kernel4 framework.<br>
* The class incapsulates the main run-cycle of the script, provide access to all other objects in the framework.<br>
* <br>
* The class is a singleton, which means that there could be only one instance of kApplication in the script.<br>
* This could be guranteed by NOT calling the class constuctor directly, but rather calling kApplication::Instance() method,
* which returns an instance of the application. The method gurantees that it will return exactly the same instance for any call.<br>
* See singleton pattern by GOF.
* @package kernel4
*/
defined('FULL_PATH') or die('restricted access!');
class kApplication {
/**
* Is true, when Init method was called already, prevents double initialization
*
* @var bool
*/
var $InitDone = false;
/**
* Holds internal NParser object
* @access private
* @var NParser
*/
var $Parser;
-
- /**
- * New Parser (Experimental)
- *
- * @var NParser
- */
- var $NParser;
-
/**
* Holds parser output buffer
* @access private
* @var string
*/
var $HTML;
/**
* Prevents request from beeing proceeded twice in case if application init is called mere then one time
*
* @var bool
* @todo This is not good anyway (by Alex)
*/
var $RequestProcessed = false;
/**
* The main Factory used to create
* almost any class of kernel and
* modules
*
* @access private
* @var kFactory
*/
var $Factory;
/**
* All ConfigurationValues table content (hash) here
*
* @var Array
* @access private
*/
var $ConfigHash = Array();
/**
* Ids of config variables used in current run (for caching)
*
* @var Array
* @access private
*/
var $ConfigCacheIds = array();
/**
* Template names, that will be used instead of regular templates
*
* @var Array
*/
var $ReplacementTemplates = Array ();
/**
* Mod-Rewrite listeners used during url building and parsing
*
* @var Array
*/
var $RewriteListeners = Array ();
/**
* Reference to debugger
*
* @var Debugger
*/
var $Debugger = null;
/**
* Holds all phrases used
* in code and template
*
* @var PhrasesCache
*/
var $Phrases;
/**
* Modules table content, key - module name
*
* @var Array
*/
var $ModuleInfo = Array();
/**
* Holds DBConnection
*
* @var kDBConnection
*/
var $Conn = null;
/**
* Maintains list of user-defined error handlers
*
* @var Array
*/
var $errorHandlers = Array();
// performance needs:
/**
* Holds a refererence to httpquery
*
* @var kHttpQuery
*/
var $HttpQuery = null;
/**
* Holds a reference to UnitConfigReader
*
* @var kUnitConfigReader
*/
var $UnitConfigReader = null;
/**
* Holds a reference to Session
*
* @var Session
*/
var $Session = null;
/**
* Holds a ref to kEventManager
*
* @var kEventManager
*/
var $EventManager = null;
/**
* Ref to itself, needed because everybody used to write $this->Application, even inside kApplication
*
* @var kApplication
*/
var $Application = null;
/**
* Ref for TemplatesChache
*
* @var TemplatesCache
*/
var $TemplatesCache = null;
var $CompilationCache = array(); //used when compiling templates
var $CachedProcessors = array(); //used when running compiled templates
var $LambdaElements = 1; // for autonumbering unnamed RenderElements [any better place for this prop? KT]
/**
* Holds current NParser tag while parsing, can be used in error messages to display template file and line
*
- * @var unknown_type
+ * @var _BlockTag
*/
var $CurrentNTag = null;
/**
* Memcache object pointer
*
* @var Memcache
*/
var $Memcached = null;
/**
* Returns kApplication instance anywhere in the script.
*
* This method should be used to get single kApplication object instance anywhere in the
* Kernel-based application. The method is guranteed to return the SAME instance of kApplication.
* Anywhere in the script you could write:
* <code>
* $application =& kApplication::Instance();
* </code>
* or in an object:
* <code>
* $this->Application =& kApplication::Instance();
* </code>
* to get the instance of kApplication. Note that we call the Instance method as STATIC - directly from the class.
* To use descendand of standard kApplication class in your project you would need to define APPLICATION_CLASS constant
* BEFORE calling kApplication::Instance() for the first time. If APPLICATION_CLASS is not defined the method would
* create and return default KernelApplication instance.
* @static
* @access public
* @return kApplication
*/
function &Instance()
{
static $instance = false;
if(!$instance)
{
safeDefine('APPLICATION_CLASS', 'kApplication');
$class = APPLICATION_CLASS;
$instance = new $class();
$instance->Application =& $instance;
}
return $instance;
}
function InitMemcached()
{
return ;
$memcached_servers = 'localhost:11211'; // $this->Application->ConfigValue('MemcachedServers');
if ($memcached_servers && class_exists('Memcache')) {
$this->Memcached = new Memcache();
$servers = explode(';', $memcached_servers);
foreach ($servers as $server) {
list ($server, $port) = strpos($server, ':') !== false ? explode(':', $server, 2) : Array ($server, 11211);
$this->Memcached->addServer($server, $port);
}
}
//try to set something to cache, if not working - set $this->Memcached to null
}
function CacheSet($name, $value, $expiration)
{
if (isset($this->Memcached)) {
return $this->Memcached->set($name, $value, 0, $expiration);
}
return false;
}
function CacheGet($name)
{
if (isset($this->Memcached)) {
return $this->Memcached->get($name);
}
return false;
}
/**
* Initializes the Application
*
* @access public
* @see kHTTPQuery
* @see Session
* @see TemplatesCache
* @return bool Was Init actually made now or before
*/
function Init()
{
if($this->InitDone) return false;
$this->InitMemcached();
if (!constOn('SKIP_OUT_COMPRESSION')) {
ob_start(); // collect any output from method (other then tags) into buffer
}
- if(defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
$this->Debugger->appendMemoryUsage('Application before Init:');
}
if (!$this->isDebugMode() && !constOn('DBG_ZEND_PRESENT')) {
error_reporting(0);
ini_set('display_errors', 0);
}
if (!constOn('DBG_ZEND_PRESENT')) {
$error_handler = set_error_handler( Array (&$this, 'handleError') );
if ($error_handler) {
// wrap around previous error handler, if any was set
$this->errorHandlers[] = $error_handler;
}
}
$this->Conn = new kDBConnection(SQL_TYPE, Array(&$this, 'handleSQLError') );
$this->Conn->debugMode = $this->isDebugMode();
$this->Conn->Connect(SQL_SERVER, SQL_USER, SQL_PASS, SQL_DB);
$this->Factory = new kFactory();
$this->registerDefaultClasses();
$this->Phrases = new PhrasesCache();
$this->EventManager =& $this->Factory->makeClass('EventManager');
$this->Factory->Storage['EventManager'] =& $this->EventManager;
$this->RegisterDefaultBuildEvents();
$this->SetDefaultConstants();
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendTimestamp('Before UnitConfigReader');
}
$this->UnitConfigReader =& $this->recallObject('kUnitConfigReader');
$this->UnitConfigReader->scanModules(MODULES_PATH);
$this->registerModuleConstants();
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendTimestamp('After UnitConfigReader');
}
$rewrite_on = $this->ConfigValue('UseModRewrite');
// admin=1 - when front is browsed using admin session
$admin_on = getArrayValue($_REQUEST, 'admin') || $this->IsAdmin();
define('MOD_REWRITE', $rewrite_on && !$admin_on ? 1 : 0);
$this->HttpQuery =& $this->recallObject('HTTPQuery');
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendTimestamp('Processed HTTPQuery initial');
}
$this->Session =& $this->recallObject('Session');
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendTimestamp('Processed Session');
}
if (!$this->RecallVar('UserGroups')) {
$user_groups = trim($this->Session->GetField('GroupList'), ',');
if (!$user_groups) {
$user_groups = $this->ConfigValue('User_GuestGroup');
}
$this->Session->SetField('GroupList', $user_groups);
$this->StoreVar('UserGroups', $user_groups);
}
$this->HttpQuery->AfterInit();
$this->Session->ValidateExpired();
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendTimestamp('Processed HTTPQuery AfterInit');
}
$this->LoadCache();
$this->InitConfig();
$this->Phrases->Init('phrases');
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendTimestamp('Loaded cache and phrases');
}
$this->UnitConfigReader->AfterConfigRead();
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendTimestamp('Processed AfterConfigRead');
}
-
/*// Module items are recalled during url parsing & PhrasesCache is needed already there,
// because it's used in their build events. That's why phrases cache initialization is
// called from kHTTPQuery in case when mod_rewrite is used
if (!$this->RewriteURLs()) {
$this->Phrases = new PhrasesCache();
}*/
if ($this->GetVar('m_cat_id') === false) $this->SetVar('m_cat_id', 0);
if( !$this->RecallVar('curr_iso') ) $this->StoreVar('curr_iso', $this->GetPrimaryCurrency() );
$this->SetVar('visits_id', $this->RecallVar('visit_id') );
$language =& $this->recallObject( 'lang.current', null, Array('live_table' => true) );
if (preg_match('/utf-8/', $language->GetDBField('Charset'))) {
setlocale(LC_ALL, 'en_US.UTF-8');
mb_internal_encoding('UTF-8');
}
$this->ValidateLogin();
- if( defined('DEBUG_MODE') && $this->isDebugMode() ) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->profileFinish('kernel4_startup');
}
$this->InitDone = true;
$this->HandleEvent( new kEvent('adm:OnStartup') );
return true;
}
/**
* Returns module information. Searches module by requested field
*
* @param string $field
* @param mixed $value
* @param string field value to returns, if not specified, then return all fields
* @param string field to return
* @return Array
*/
function findModule($field, $value, $return_field = null)
{
$found = false;
foreach ($this->ModuleInfo as $module_name => $module_info) {
if (strtolower($module_info[$field]) == strtolower($value)) {
$found = true;
break;
}
}
if ($found) {
return isset($return_field) ? $module_info[$return_field] : $module_info;
}
return false;
}
function refreshModuleInfo()
{
if (defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('Modules')) {
$this->registerModuleConstants();
return false;
}
$modules_helper =& $this->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'Modules
WHERE Loaded = 1
ORDER BY LoadOrder';
$this->ModuleInfo = $this->Conn->Query($sql, 'Name');
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'Modules
WHERE '.$modules_helper->getWhereClause().'
ORDER BY LoadOrder';
$this->ModuleInfo = $this->Conn->Query($sql, 'Name');
$this->registerModuleConstants();
}
/**
* Checks if passed language id if valid and sets it to primary otherwise
*
*/
function VerifyLanguageId()
{
$language_id = $this->GetVar('m_lang');
if (!$language_id) {
$language_id = 'default';
}
$this->SetVar('lang.current_id', $language_id );
$this->SetVar('m_lang', $language_id );
$lang_mode = $this->GetVar('lang_mode');
$this->SetVar('lang_mode', '');
$lang =& $this->recallObject('lang.current');
if ( !$lang->IsLoaded() || (!$this->Application->IsAdmin() && !$lang->GetDBField('Enabled')) ) {
if (!defined('IS_INSTALL')) $this->ApplicationDie('Unknown or disabled language');
}
$this->SetVar('lang_mode',$lang_mode);
}
/**
* Checks if passed theme id if valid and sets it to primary otherwise
*
*/
function VerifyThemeId()
{
if ($this->Application->IsAdmin()) {
safeDefine('THEMES_PATH', '/core/admin_templates');
return;
}
$path = $this->GetFrontThemePath();
if ($path === false) {
$this->ApplicationDie('No Primary Theme Selected or Current Theme is Unknown or Disabled');
}
safeDefine('THEMES_PATH', $path);
/*$theme_id = $this->GetVar('m_theme');
if (!$theme_id) {
$theme_id = $this->GetDefaultThemeId();
if (!$theme_id) {
if (!defined('IS_INSTALL')) $this->ApplicationDie('No Primary Theme Selected');
}
}
$this->SetVar('m_theme', $theme_id);
$this->SetVar('theme.current_id', $theme_id ); // KOSTJA: this is to fool theme' getPassedId
$theme =& $this->recallObject('theme.current');
if (!$theme->IsLoaded() || !$theme->GetDBField('Enabled')) {
if (!defined('IS_INSTALL')) $this->ApplicationDie('Unknown or disabled theme');
}
safeDefine('THEMES_PATH', '/themes/'.$theme->GetDBField('Name'));*/
}
function GetFrontThemePath($force=0)
{
static $path=null;
if (!$force && isset($path)) return $path;
$theme_id = $this->GetVar('m_theme');
if (!$theme_id) {
// $theme_id = $this->GetDefaultThemeId(1); //1 to force front-end mode!
$theme_id = 'default';
}
$this->SetVar('m_theme', $theme_id);
$this->SetVar('theme.current_id', $theme_id ); // KOSTJA: this is to fool theme' getPassedId
$theme =& $this->recallObject('theme.current');
if (!$theme->IsLoaded() || !$theme->GetDBField('Enabled')) {
return false;
}
$path = '/themes/'.$theme->GetDBField('Name');
return $path;
}
function GetDefaultLanguageId()
{
static $language_id = 0;
if ($language_id > 0) {
return $language_id;
}
$table = $this->getUnitOption('lang', 'TableName');
$id_field = $this->getUnitOption('lang', 'IDField');
$sql = 'SELECT '.$id_field.'
FROM '.$table.'
WHERE (PrimaryLang = 1) AND (Enabled = 1)';
$language_id = $this->Conn->GetOne($sql);
if (!$language_id && defined('IS_INSTALL') && IS_INSTALL) {
$language_id = 1;
}
return $language_id;
}
function GetDefaultThemeId($force_front=0)
{
static $theme_id = 0;
if ($theme_id > 0) {
return $theme_id;
}
if (constOn('DBG_FORCE_THEME')) {
$theme_id = DBG_FORCE_THEME;
}
elseif (!$force_front && $this->IsAdmin()) {
$theme_id = 999;
}
else {
$table = $this->getUnitOption('theme','TableName');
$id_field = $this->getUnitOption('theme','IDField');
$sql = 'SELECT '.$id_field.'
FROM '.$table.'
WHERE (PrimaryTheme = 1) AND (Enabled = 1)';
$theme_id = $this->Conn->GetOne($sql);
}
return $theme_id;
}
function GetPrimaryCurrency()
{
if ($this->isModuleEnabled('In-Commerce')) {
$table = $this->getUnitOption('curr', 'TableName');
return $this->Conn->GetOne('SELECT ISO FROM '.$table.' WHERE IsPrimary = 1');
}
else {
return 'USD';
}
}
/**
* Registers default classes such as ItemController, GridController and LoginController
*
* Called automatically while initializing Application
* @access private
* @return void
*/
function RegisterDefaultClasses()
{
$this->registerClass('kTempTablesHandler', KERNEL_PATH.'/utility/temp_handler.php');
$this->registerClass('kEventManager', KERNEL_PATH.'/event_manager.php', 'EventManager');
$this->registerClass('kUnitConfigReader', KERNEL_PATH.'/utility/unit_config_reader.php');
$this->registerClass('kArray', KERNEL_PATH.'/utility/params.php');
$this->registerClass('Params', KERNEL_PATH.'/utility/params.php');
$this->registerClass('kHelper', KERNEL_PATH.'/kbase.php');
- $this->registerClass('kCache', KERNEL_PATH.'/utility/cache.php', 'Cache', Array('Params'));
- $this->registerClass('kHTTPQuery', KERNEL_PATH.'/utility/http_query.php', 'HTTPQuery', Array('Params') );
+ $this->registerClass('kCache', KERNEL_PATH.'/utility/cache.php', 'Cache', 'Params');
+ $this->registerClass('kHTTPQuery', KERNEL_PATH.'/utility/http_query.php', 'HTTPQuery', 'Params');
$this->registerClass('Session', KERNEL_PATH.'/session/session.php');
$this->registerClass('SessionStorage', KERNEL_PATH.'/session/session.php');
-
-
$this->registerClass('Params', KERNEL_PATH.'/utility/params.php', 'kActions');
$this->registerClass('kMultipleFilter', KERNEL_PATH.'/utility/filters.php');
$this->registerClass('kDBList', KERNEL_PATH.'/db/dblist.php');
$this->registerClass('kDBItem', KERNEL_PATH.'/db/dbitem.php');
$this->registerClass('kDBEventHandler', KERNEL_PATH.'/db/db_event_handler.php');
$this->registerClass('kTagProcessor', KERNEL_PATH.'/processors/tag_processor.php');
$this->registerClass('kMainTagProcessor', KERNEL_PATH.'/processors/main_processor.php','m_TagProcessor', 'kTagProcessor');
$this->registerClass('kDBTagProcessor', KERNEL_PATH.'/db/db_tag_processor.php', null, 'kTagProcessor');
-
- $this->registerClass('TemplatesCache', KERNEL_PATH.'/nparser/template.php',null, 'kDBTagProcessor');
- $this->registerClass('Template', KERNEL_PATH.'/nparser/template.php');
-
+ $this->registerClass('TemplatesCache', KERNEL_PATH.'/nparser/template_cache.php', null, Array ('kHelper', 'kDBTagProcessor'));
$this->registerClass('NParser', KERNEL_PATH.'/nparser/nparser.php');
- $this->registerClass('kEmailSendingHelper', KERNEL_PATH.'/utility/email_send.php', 'EmailSender', Array('kHelper'));
+ $this->registerClass('kEmailSendingHelper', KERNEL_PATH.'/utility/email_send.php', 'EmailSender', 'kHelper');
$this->registerClass('kSocket', KERNEL_PATH.'/utility/socket.php', 'Socket');
if (file_exists(MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php')) {
$this->registerClass('kCurrencyRates', MODULES_PATH.'/in-commerce/units/currencies/currency_rates.php');
}
- $this->registerClass('FCKeditor', FULL_PATH.'/admin/editor/cmseditor/fckeditor.php'); // need this?
-
/* Moved from MyApplication */
- $this->registerClass('InpSession',KERNEL_PATH.'/../units/general/inp_ses_storage.php','Session');
- $this->registerClass('InpSessionStorage',KERNEL_PATH.'/../units/general/inp_ses_storage.php','SessionStorage');
+ $this->registerClass('InpSession',KERNEL_PATH.'/../units/general/inp_ses_storage.php', 'Session');
+ $this->registerClass('InpSessionStorage',KERNEL_PATH.'/../units/general/inp_ses_storage.php', 'SessionStorage');
$this->registerClass('kCatDBItem',KERNEL_PATH.'/../units/general/cat_dbitem.php');
$this->registerClass('kCatDBItemExportHelper',KERNEL_PATH.'/../units/general/cat_dbitem_export.php', 'CatItemExportHelper');
$this->registerClass('kCatDBList',KERNEL_PATH.'/../units/general/cat_dblist.php');
$this->registerClass('kCatDBEventHandler',KERNEL_PATH.'/../units/general/cat_event_handler.php');
$this->registerClass('kCatDBTagProcessor',KERNEL_PATH.'/../units/general/cat_tag_processor.php');
// Do not move to config - this helper is used before configs are read
$this->registerClass('kModulesHelper', KERNEL_PATH.'/../units/helpers/modules_helper.php', 'ModulesHelper');
/* End moved */
}
function RegisterDefaultBuildEvents()
{
$event_manager =& $this->recallObject('EventManager');
$event_manager->registerBuildEvent('kTempTablesHandler', 'OnTempHandlerBuild');
}
/**
* Returns item's filename that corresponds id passed. If possible, then get it from cache
*
* @param string $prefix
* @param int $id
* @return string
*/
function getFilename($prefix, $id, $category_id=null)
{
$filename = $this->getCache('filenames', $prefix.'_'.$id);
if ($filename === false) {
$table = $this->getUnitOption($prefix, 'TableName');
$id_field = $this->getUnitOption($prefix, 'IDField');
if ($prefix == 'c') {
if(!$id) {
$this->setCache('filenames', $prefix.'_'.$id, '');
return '';
}
// this allows to save 2 sql queries for each category
$sql = 'SELECT NamedParentPath, CachedTemplate, TreeLeft, TreeRight
FROM '.$table.'
WHERE '.$id_field.' = '.$this->Conn->qstr($id);
$category_data = $this->Conn->GetRow($sql);
// only direct links to category pages work (symlinks, container pages and so on won't work)
$filename = $category_data['NamedParentPath'];
$this->setCache('category_templates', $id, $filename);
$this->setCache('category_designs', $id, ltrim($category_data['CachedTemplate'], '/'));
$this->setCache('category_tree', $id, $category_data['TreeLeft'] . ';' . $category_data['TreeRight']);
}
else {
$resource_id = $this->Conn->GetOne('SELECT ResourceId FROM '.$table.' WHERE '.$id_field.' = '.$this->Conn->qstr($id));
if (is_null($category_id)) $category_id = $this->GetVar('m_cat_id');
$sql = 'SELECT Filename FROM '.TABLE_PREFIX.'CategoryItems WHERE ItemResourceId = '.$resource_id.' AND CategoryId = '.$category_id;
$filename = $this->Conn->GetOne($sql);
/*if (!$filename) {
$sql = 'SELECT Filename FROM '.TABLE_PREFIX.'CategoryItems WHERE ItemResourceId = '.$resource_id.' AND PrimaryCat = 1';
$filename = $this->Conn->GetOne($sql);
}*/
/*$sql = 'SELECT Filename
FROM '.$table.'
WHERE '.$id_field.' = '.$this->Conn->qstr($id);
$filename = $this->Conn->GetOne($sql);*/
}
$this->setCache('filenames', $prefix.'_'.$id, $filename);
}
return $filename;
}
/**
* Adds new value to cache $cache_name and identified by key $key
*
* @param string $cache_name cache name
* @param int $key key name to add to cache
* @param mixed $value value of chached record
*/
function setCache($cache_name, $key, $value, $expiration=3600)
{
$cache =& $this->recallObject('Cache');
/* @var $cache kCache */
return $cache->setCache($cache_name, $key, $value, $expiration);
}
/**
* Returns cached $key value from cache named $cache_name
*
* @param string $cache_name cache name
* @param int $key key name from cache
* @return mixed
*/
function getCache($cache_name, $key)
{
$cache =& $this->recallObject('Cache');
return $cache->getCache($cache_name, $key);
}
/**
* Defines default constants if it's not defined before - in config.php
*
* @access private
*/
function SetDefaultConstants() // it's defined in startup.php - can be removed??
{
safeDefine('SERVER_NAME', $_SERVER['HTTP_HOST']);
}
/**
* Registers each module specific constants if any found
*
*/
function registerModuleConstants()
{
if (file_exists(KERNEL_PATH.'/constants.php')) {
k4_include_once(KERNEL_PATH.'/constants.php');
}
if (!$this->ModuleInfo) return false;
foreach($this->ModuleInfo as $module_name => $module_info)
{
$module_path = '/'.$module_info['Path'];
$contants_file = FULL_PATH.$module_path.'constants.php';
if( file_exists($contants_file) ) k4_include_once($contants_file);
}
return true;
}
function ProcessRequest()
{
$event_manager =& $this->recallObject('EventManager');
/* @var $event_manager kEventManager */
- if($this->isDebugMode() && constOn('DBG_SHOW_HTTPQUERY')) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_SHOW_HTTPQUERY')) {
$this->Debugger->appendHTML('HTTPQuery:');
$this->Debugger->dumpVars($this->HttpQuery->_Params);
}
$event_manager->ProcessRequest();
$event_manager->RunRegularEvents(reBEFORE);
$this->RequestProcessed = true;
}
/**
* Actually runs the parser against current template and stores parsing result
*
* This method gets t variable passed to the script, loads the template given in t variable and
* parses it. The result is store in {@link $this->HTML} property.
* @access public
* @return void
*/
function Run()
{
- if($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
$this->Debugger->appendMemoryUsage('Application before Run:');
}
if ($this->IsAdmin()) {
// for permission checking in events & templates
$this->LinkVar('module'); // for common configuration templates
$this->LinkVar('module_key'); // for common search templates
$this->LinkVar('section'); // for common configuration templates
if ($this->GetVar('m_opener') == 'p') {
$this->LinkVar('main_prefix'); // window prefix, that opened selector
$this->LinkVar('dst_field'); // field to set value choosed in selector
// $this->LinkVar('return_template'); // template to go, when something was coosen from popup (from finalizePopup)
// $this->LinkVar('return_m'); // main env part to restore after popup will be closed (from finalizePopup)
}
if ($this->GetVar('ajax') == 'yes' && !$this->GetVar('debug_ajax')) {
// hide debug output from ajax requests automatically
define('DBG_SKIP_REPORTING', 1);
}
}
elseif ($this->GetVar('admin')) {
// viewing front-end through admin's frame
$admin_session =& $this->Application->recallObject('Session.admin');
$user = (int)$admin_session->RecallVar('user_id'); // in case, when no valid admin session found
$perm_helper =& $this->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
if ($perm_helper->CheckUserPermission($user, 'CATEGORY.MODIFY', 0, 0)) {
// user can edit cms blocks
$editing_mode = $this->GetVar('editing_mode');
define('EDITING_MODE', $editing_mode ? $editing_mode : EDITING_MODE_BROWSE);
$this->Phrases->setPhraseEditing();
}
}
safeDefine('EDITING_MODE', ''); // user can't edit anything
if (!$this->RequestProcessed) $this->ProcessRequest();
$this->InitParser();
$t = $this->GetVar('t');
if (!$this->TemplatesCache->TemplateExists($t) && !$this->IsAdmin()) {
$cms_handler =& $this->recallObject('st_EventHandler');
/* @var $cms_handler CategoriesEventHandler */
$t = ltrim($cms_handler->GetDesignTemplate(), '/');
- if ($this->isDebugMode()) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->Debugger->appendHTML('<strong>Design Template</strong>: ' . $t . '; <strong>CategoryID</strong>: ' . $this->GetVar('m_cat_id'));
}
}
/*else {
$cms_handler->SetCatByTemplate();
}*/
- if($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
$this->Debugger->appendMemoryUsage('Application before Parsing:');
}
- if (defined('NPARSER') && 'NPARSER') {
- $this->HTML = $this->NParser->Run( $t );
- }
- else {
- $this->HTML = $this->Parser->ParseTemplate( $t );
- }
+ $this->HTML = $this->Parser->Run($t);
- if ($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
$this->Debugger->appendMemoryUsage('Application after Parsing:');
}
}
function InitParser($theme_name = false)
{
- if (defined('NPARSER') && 'NPARSER') {
- if( !is_object($this->NParser) ) {
- $this->NParser =& $this->recallObject('NParser');
- $this->TemplatesCache =& $this->recallObject('TemplatesCache');
-
- // can be removed in future
-// $this->Parser =& $this->recallObject('TemplateParser');
- $this->Parser =& $this->NParser;
- }
- }
- else {
- if( !is_object($this->Parser) ) {
- $this->Parser =& $this->recallObject('TemplateParser');
- $this->TemplatesCache =& $this->recallObject('TemplatesCache');
- }
+ if( !is_object($this->Parser) ) {
+ $this->Parser =& $this->recallObject('NParser');
+ $this->TemplatesCache =& $this->recallObject('TemplatesCache');
}
$this->TemplatesCache->forceThemeName = $theme_name;
}
/**
* Send the parser results to browser
*
* Actually send everything stored in {@link $this->HTML}, to the browser by echoing it.
* @access public
* @return void
*/
function Done()
{
$this->HandleEvent( new kEvent('adm:OnBeforeShutdown') );
- if ($this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
+
+ if (defined('DEBUG_MODE') && $this->isDebugMode() && constOn('DBG_PROFILE_MEMORY')) {
$this->Debugger->appendMemoryUsage('Application before Done:');
}
- if ($this->isDebugMode()) {
+ if (defined('DEBUG_MODE') && $this->isDebugMode()) {
$this->EventManager->RunRegularEvents(reAFTER);
$this->Session->SaveData();
if (constOn('DBG_CACHE')) {
$cache =& $this->recallObject('Cache');
$cache->printStatistics();
}
$this->HTML = ob_get_clean() . $this->HTML . $this->Debugger->printReport(true);
}
else {
$this->HTML = ob_get_clean().$this->HTML;
}
if ($this->UseOutputCompression()) {
header('Content-Encoding: gzip');
$compression_level = $this->ConfigValue('OutputCompressionLevel');
if ($compression_level < 0 || $compression_level > 9) $compression_level = 7;
echo gzencode($this->HTML, $compression_level);
}
else {
echo $this->HTML;
}
$this->UpdateCache();
flush();
if (!$this->isDebugMode()) {
$this->EventManager->RunRegularEvents(reAFTER);
$this->Session->SaveData();
}
if (defined('DBG_CAPTURE_STATISTICS') && DBG_CAPTURE_STATISTICS && !$this->IsAdmin()) {
$this->_storeStatistics();
}
}
/**
* Stores script execution statistics to database
*
*/
function _storeStatistics()
{
global $start;
$script_time = getmicrotime() - $start;
$query_statistics = $this->Conn->getQueryStatistics(); // time & count
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'StatisticsCapture
WHERE TemplateName = "' . $this->GetVar('t') . '"';
$data = $this->Conn->GetRow($sql);
if ($data) {
$this->_updateAverageStatistics($data, 'ScriptTime', $script_time);
$this->_updateAverageStatistics($data, 'SqlTime', $query_statistics['time']);
$this->_updateAverageStatistics($data, 'SqlCount', $query_statistics['count']);
$data['Hits']++;
$data['LastHit'] = adodb_mktime();
$this->Conn->doUpdate($data, TABLE_PREFIX . 'StatisticsCapture', 'StatisticsId = ' . $data['StatisticsId']);
}
else {
$data['ScriptTimeMin'] = $data['ScriptTimeAvg'] = $data['ScriptTimeMax'] = $script_time;
$data['SqlTimeMin'] = $data['SqlTimeAvg'] = $data['SqlTimeMax'] = $query_statistics['time'];
$data['SqlCountMin'] = $data['SqlCountAvg'] = $data['SqlCountMax'] = $query_statistics['count'];
$data['TemplateName'] = $this->GetVar('t');
$data['Hits'] = 1;
$data['LastHit'] = adodb_mktime();
$this->Conn->doInsert($data, TABLE_PREFIX . 'StatisticsCapture');
}
}
/**
* Calculates average time for statistics
*
* @param Array $data
* @param string $field_prefix
* @param float $current_value
*/
function _updateAverageStatistics(&$data, $field_prefix, $current_value)
{
$data[$field_prefix . 'Avg'] = (($data['Hits'] * $data[$field_prefix . 'Avg']) + $current_value) / ($data['Hits'] + 1);
if ($current_value < $data[$field_prefix . 'Min']) {
$data[$field_prefix . 'Min'] = $current_value;
}
if ($current_value > $data[$field_prefix . 'Max']) {
$data[$field_prefix . 'Max'] = $current_value;
}
}
function logSlowQuery($slow_sql, $time)
{
$query_crc = crc32($slow_sql);
$sql = 'SELECT *
FROM ' . TABLE_PREFIX . 'SlowSqlCapture
WHERE QueryCrc = ' . $query_crc;
$data = $this->Conn->Query($sql, null, true);
if ($data) {
$this->_updateAverageStatistics($data, 'Time', $time);
$template_names = explode(',', $data['TemplateNames']);
array_push($template_names, $this->GetVar('t'));
$data['TemplateNames'] = implode(',', array_unique($template_names));
$data['Hits']++;
$data['LastHit'] = adodb_mktime();
$this->Conn->doUpdate($data, TABLE_PREFIX . 'SlowSqlCapture', 'CaptureId = ' . $data['CaptureId']);
}
else {
$data['TimeMin'] = $data['TimeAvg'] = $data['TimeMax'] = $time;
$data['SqlQuery'] = $slow_sql;
$data['QueryCrc'] = $query_crc;
$data['TemplateNames'] = $this->GetVar('t');
$data['Hits'] = 1;
$data['LastHit'] = adodb_mktime();
$this->Conn->doInsert($data, TABLE_PREFIX . 'SlowSqlCapture');
}
}
/**
* Checks if output compression options is available
*
* @return string
*/
function UseOutputCompression()
{
if (constOn('IS_INSTALL') || constOn('DBG_ZEND_PRESENT') || constOn('SKIP_OUT_COMPRESSION')) return false;
return $this->ConfigValue('UseOutputCompression') && function_exists('gzencode') && strstr($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip');
}
// Facade
/**
* Returns current session id (SID)
* @access public
* @return longint
*/
function GetSID()
{
$session =& $this->recallObject('Session');
return $session->GetID();
}
function DestroySession()
{
$session =& $this->recallObject('Session');
$session->Destroy();
}
/**
* Returns variable passed to the script as GET/POST/COOKIE
*
* @access public
* @param string $name Name of variable to retrieve
* @param int $default default value returned in case if varible not present
* @return mixed
*/
function GetVar($name, $default = false)
{
return isset($this->HttpQuery->_Params[$name]) ? $this->HttpQuery->_Params[$name] : $default;
}
/**
* Returns ALL variables passed to the script as GET/POST/COOKIE
*
* @access public
* @return array
*/
function GetVars()
{
return $this->HttpQuery->GetParams();
}
/**
* Set the variable 'as it was passed to the script through GET/POST/COOKIE'
*
* This could be useful to set the variable when you know that
* other objects would relay on variable passed from GET/POST/COOKIE
* or you could use SetVar() / GetVar() pairs to pass the values between different objects.<br>
*
* This method is formerly known as $this->Session->SetProperty.
* @param string $var Variable name to set
* @param mixed $val Variable value
* @access public
* @return void
*/
function SetVar($var,$val)
{
return $this->HttpQuery->Set($var, $val);
}
/**
* Deletes kHTTPQuery variable
*
* @param string $var
* @todo think about method name
*/
function DeleteVar($var)
{
return $this->HttpQuery->Remove($var);
}
/**
* Deletes Session variable
*
* @param string $var
*/
function RemoveVar($var)
{
return $this->Session->RemoveVar($var);
}
function RemovePersistentVar($var)
{
return $this->Session->RemovePersistentVar($var);
}
/**
* Restores Session variable to it's db version
*
* @param string $var
*/
function RestoreVar($var)
{
return $this->Session->RestoreVar($var);
}
/**
* Returns session variable value
*
* Return value of $var variable stored in Session. An optional default value could be passed as second parameter.
*
* @see SimpleSession
* @access public
* @param string $var Variable name
* @param mixed $default Default value to return if no $var variable found in session
* @return mixed
*/
function RecallVar($var,$default=false)
{
return $this->Session->RecallVar($var,$default);
}
function RecallPersistentVar($var, $default = false)
{
return $this->Session->RecallPersistentVar($var, $default);
}
/**
* Stores variable $val in session under name $var
*
* Use this method to store variable in session. Later this variable could be recalled.
* @see RecallVar
* @access public
* @param string $var Variable name
* @param mixed $val Variable value
*/
function StoreVar($var, $val, $optional = false)
{
$session =& $this->recallObject('Session');
$this->Session->StoreVar($var, $val, $optional);
}
function StorePersistentVar($var, $val)
{
$this->Session->StorePersistentVar($var, $val);
}
function StoreVarDefault($var, $val, $optional=false)
{
$session =& $this->recallObject('Session');
$this->Session->StoreVarDefault($var, $val, $optional);
}
/**
* Links HTTP Query variable with session variable
*
* If variable $var is passed in HTTP Query it is stored in session for later use. If it's not passed it's recalled from session.
* This method could be used for making sure that GetVar will return query or session value for given
* variable, when query variable should overwrite session (and be stored there for later use).<br>
* This could be used for passing item's ID into popup with multiple tab -
* in popup script you just need to call LinkVar('id', 'current_id') before first use of GetVar('id').
* After that you can be sure that GetVar('id') will return passed id or id passed earlier and stored in session
* @access public
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
*/
function LinkVar($var, $ses_var = null, $default = '', $optional = false)
{
if (!isset($ses_var)) $ses_var = $var;
if ($this->GetVar($var) !== false) {
$this->StoreVar($ses_var, $this->GetVar($var), $optional);
}
else {
$this->SetVar($var, $this->RecallVar($ses_var, $default));
}
}
/**
* Returns variable from HTTP Query, or from session if not passed in HTTP Query
*
* The same as LinkVar, but also returns the variable value taken from HTTP Query if passed, or from session if not passed.
* Returns the default value if variable does not exist in session and was not passed in HTTP Query
*
* @see LinkVar
* @access public
* @param string $var HTTP Query (GPC) variable name
* @param mixed $ses_var Session variable name
* @param mixed $default Default variable value
* @return mixed
*/
function GetLinkedVar($var, $ses_var = null, $default = '')
{
$this->LinkVar($var, $ses_var, $default);
return $this->GetVar($var);
}
function AddBlock($name, $tpl)
{
$this->cache[$name] = $tpl;
}
- /* Seems to be not used anywhere... /Kostja
-
- function SetTemplateBody($title,$body)
- {
- $templates_cache =& $this->recallObject('TemplatesCache');
- $templates_cache->SetTemplateBody($title,$body);
- }*/
-
- function ProcessTag($tag_data)
- {
- $a_tag = new Tag($tag_data,$this->Parser);
- return $a_tag->DoProcessTag();
- }
-
function ProcessParsedTag($prefix, $tag, $params)
{
- if (defined('NPARSER') && NPARSER) {
- $p = $this->Parser->GetProcessor($prefix);
- return $p->ProcessParsedTag($tag, $params, $prefix);
- }
+ $processor = $this->Parser->GetProcessor($prefix);
- $a_tag = new Tag('',$this->Parser);
- $a_tag->Tag = $tag;
- $tmp=$this->Application->processPrefix($prefix);
- $a_tag->Processor = $tmp['prefix'];
- $a_tag->Special = $tmp['special'];
- $a_tag->NamedParams = $params;
- return $a_tag->DoProcessTag();
+ return $processor->ProcessParsedTag($tag, $params, $prefix);
}
/**
* Return ADODB Connection object
*
* Returns ADODB Connection object already connected to the project database, configurable in config.php
* @access public
* @return kDBConnection
*/
function &GetADODBConnection()
{
return $this->Conn;
}
/**
* Allows to parse given block name or include template
*
* @param Array $params Parameters to pass to block/template. Reserved parameter "name" used to specify block/template name.
* @param Array $pass_params Forces to pass current parser params to this block/template. Use with cauntion, because you can accidently pass "block_no_data" parameter.
* @param bool $as_template
* @return string
*/
function ParseBlock($params, $pass_params = 0, $as_template = false)
{
- if (substr($params['name'], 0, 5) == 'html:') return substr($params['name'], 6);
+ if (substr($params['name'], 0, 5) == 'html:') {
+ return substr($params['name'], 6);
+ }
+
return $this->Parser->ParseBlock($params, $pass_params, $as_template);
}
/**
* Returns index file, that could be passed as parameter to method, as parameter to tag and as constant or not passed at all
*
* @param string $prefix
* @param string $index_file
* @param Array $params
* @return string
*/
function getIndexFile($prefix, $index_file, &$params)
{
if (isset($params['index_file'])) {
$index_file = $params['index_file'];
unset($params['index_file']);
return $index_file;
}
if (isset($index_file)) {
return $index_file;
}
if (defined('INDEX_FILE')) {
return INDEX_FILE;
}
$cut_prefix = trim(BASE_PATH, '/').'/'.trim($prefix, '/');
return trim(preg_replace('/'.preg_quote($cut_prefix, '/').'(.*)/', '\\1', $_SERVER['PHP_SELF']), '/');
}
/**
* Return href for template
*
* @access public
* @param string $t Template path
* @var string $prefix index.php prefix - could be blank, 'admin'
*/
function HREF($t, $prefix='', $params=null, $index_file=null)
{
if(!$t) $t = $this->GetVar('t'); // moved from kMainTagProcessor->T()
$t = preg_replace('/^Content\//i', '', $t);
/*if ($this->GetVar('skip_last_template')) {
$params['opener'] = 'p';
$this->SetVar('m_opener', 'p');
}
if ($t == 'incs/close_popup') {
// because this template closes the popup and we don't need popup mark here anymore
$params['m_opener'] = 's';
}*/
if( substr($t, -4) == '.tpl' ) $t = substr($t, 0, strlen($t) - 4 );
if ( $this->IsAdmin() && $prefix == '') $prefix = ADMIN_DIRECTORY;
if ( $this->IsAdmin() && $prefix == '_FRONT_END_') $prefix = '';
$index_file = $this->getIndexFile($prefix, $index_file, $params);
if (isset($params['_auto_prefix_'])) {
unset($params['_auto_prefix_']); // this is parser-related param, do not need to pass it here
}
$ssl = isset($params['__SSL__']) ? $params['__SSL__'] : null;
if ($ssl !== null) {
$session =& $this->recallObject('Session');
$cookie_url = trim($session->CookieDomain.$session->CookiePath, '/.');
if ($ssl) {
$target_url = defined('ADMIN') && ADMIN ? $this->ConfigValue('AdminSSL_URL') : false;
if (!$target_url) {
$target_url = $this->ConfigValue('SSL_URL');
}
}
else {
$target_url = 'http://'.DOMAIN.$this->ConfigValue('Site_Path');
}
if (!preg_match('#'.preg_quote($cookie_url).'#', $target_url)) {
$session->SetMode(smGET_ONLY);
}
}
if (isset($params['opener']) && $params['opener'] == 'u') {
$wid = $this->Application->GetVar('m_wid');
$stack_name = rtrim('opener_stack_'.$wid, '_');
$opener_stack = $this->RecallVar($stack_name);
if ($opener_stack && $opener_stack != serialize(Array())) {
$opener_stack = unserialize($opener_stack);
list($index_file, $env) = explode('|', $opener_stack[count($opener_stack) - 1]);
$ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.ENV_VAR_NAME.'='.$env;
if ( getArrayValue($params,'escape') ) $ret = addslashes($ret);
if (isset($params['m_opener']) && $params['m_opener'] == 'u') {
array_pop($opener_stack);
if (!$opener_stack) {
$this->RemoveVar($stack_name);
// remove popups last templates, because popup is closing now
$this->RemoveVar('last_template_'.$wid);
$this->RemoveVar('last_template_popup_'.$wid);
// don't save popups last templates again :)
$this->SetVar('skip_last_template', 1);
}
else {
$this->StoreVar($stack_name, serialize($opener_stack));
}
/*// store window relations
$window_relations = $this->Application->RecallVar('window_relations');
$window_relations = $window_relations ? unserialize($window_relations) : Array ();
if (array_key_exists($wid, $window_relations)) {
unset($window_relations[$wid]);
$this->Application->StoreVar('window_relations', serialize($window_relations));
}*/
}
return $ret;
}
else {
//define('DBG_REDIRECT', 1);
$t = $this->GetVar('t');
}
}
$pass = isset($params['pass']) ? $params['pass'] : '';
$pass_events = isset($params['pass_events']) ? $params['pass_events'] : false; // pass events with url
$map_link = '';
if( isset($params['anchor']) )
{
$map_link = '#'.$params['anchor'];
unset($params['anchor']);
}
if ( isset($params['no_amp']) )
{
$params['__URLENCODE__'] = $params['no_amp'];
unset($params['no_amp']);
}
$no_rewrite = false;
if( isset($params['__NO_REWRITE__']) )
{
$no_rewrite = true;
unset($params['__NO_REWRITE__']);
}
$force_rewrite = false;
if( isset($params['__MOD_REWRITE__']) )
{
$force_rewrite = true;
unset($params['__MOD_REWRITE__']);
}
$force_no_sid = false;
if( isset($params['__NO_SID__']) )
{
$force_no_sid = true;
unset($params['__NO_SID__']);
}
// append pass through variables to each link to be build
// $params = array_merge_recursive2($this->getPassThroughVariables($params), $params);
$params = array_merge($this->getPassThroughVariables($params), $params);
if ($force_rewrite || ($this->RewriteURLs($ssl) && !$no_rewrite)) {
static $rewrite_listeners_done = false;
if (!$rewrite_listeners_done) {
$mod_rewrite_helper =& $this->recallObject('ModRewriteHelper');
/* @var $mod_rewrite_helper kModRewriteHelper */
$mod_rewrite_helper->initRewriteListeners();
$rewrite_listeners_done = true;
}
$session =& $this->recallObject('Session');
if ($session->NeedQueryString() && !$force_no_sid) {
$params['sid'] = $this->GetSID();
}
$url = $this->BuildEnv_NEW($t, $params, $pass, $pass_events);
$ret = $this->BaseURL($prefix, $ssl).$url.$map_link;
}
else {
unset($params['pass_category']); // we don't need to pass it when mod_rewrite is off
$env = $this->BuildEnv($t, $params, $pass, $pass_events);
$ret = $this->BaseURL($prefix, $ssl).$index_file.'?'.$env.$map_link;
}
return $ret;
}
/**
* Returns variables with values that should be passed throught with this link + variable list
*
* @param Array $params
* @return Array
*/
function getPassThroughVariables(&$params)
{
static $cached_pass_through = null;
if (isset($params['no_pass_through']) && $params['no_pass_through']) {
unset($params['no_pass_through']);
return Array();
}
// because pass through is not changed during script run, then we can cache it
if (is_null($cached_pass_through)) {
$cached_pass_through = Array();
$pass_through = $this->Application->GetVar('pass_through');
if ($pass_through) {
// names of variables to pass to each link
$cached_pass_through['pass_through'] = $pass_through;
$pass_through = explode(',', $pass_through);
foreach ($pass_through as $pass_through_var) {
$cached_pass_through[$pass_through_var] = $this->Application->GetVar($pass_through_var);
}
}
}
return $cached_pass_through;
}
/**
* Returns sorted array of passed prefixes (to build url from)
*
* @param string $pass
* @return Array
*/
function getPassInfo($pass = 'all')
{
if (!$pass) $pass = 'all';
$pass = trim(
preg_replace(
'/(?<=,|\\A)all(?=,|\\z)/',
trim($this->GetVar('passed'), ','),
trim($pass, ',')
),
',');
if (!$pass) {
return Array();
}
$pass_info = array_unique( explode(',', $pass) ); // array( prefix[.special], prefix[.special] ...
// we need to keep that sorting despite the sorting below, because this sorts prefixes with same priority by name
sort($pass_info, SORT_STRING); // to be prefix1,prefix1.special1,prefix1.special2,prefix3.specialX
foreach ($pass_info as $prefix) {
list($prefix_only) = explode('.', $prefix, 1);
$sorted[$prefix] = $this->getUnitOption($prefix_only, 'RewritePriority', 0);
}
arsort($sorted);
$pass_info = array_keys($sorted);
// ensure that "m" prefix is at the beginning
$main_index = array_search('m', $pass_info);
if ($main_index !== false) {
unset($pass_info[$main_index]);
array_unshift($pass_info, 'm');
}
return $pass_info;
}
function BuildEnv_NEW($t, $params, $pass='all', $pass_events = false)
{
// $session =& $this->recallObject('Session');
$force_admin = getArrayValue($params,'admin') || $this->GetVar('admin');
// if($force_admin) $sid = $this->GetSID();
$ret = '';
$env = '';
$encode = false;
if (isset($params['__URLENCODE__'])) {
$encode = $params['__URLENCODE__'];
unset($params['__URLENCODE__']);
}
if (isset($params['__SSL__'])) {
unset($params['__SSL__']);
}
$catalog_item_found = false;
$pass_info = $this->getPassInfo($pass);
if ($pass_info) {
if ($pass_info[0] == 'm') {
array_shift($pass_info);
}
$inject_parts = Array (); // url parts for beginning of url
$params['t'] = $t; // make template available for rewrite listeners
$params['pass_template'] = true; // by default we keep given template in resulting url
if (!array_key_exists('pass_category', $params)) {
$params['pass_category'] = false; // by default we don't keep categories in url
}
foreach ($pass_info as $pass_index => $pass_element) {
list ($prefix) = explode('.', $pass_element);
$catalog_item = $this->findModule('Var', $prefix) && $this->getUnitOption($prefix, 'CatalogItem');
if (array_key_exists($prefix, $this->RewriteListeners)) {
// if next prefix is same as current, but with special => exclude current prefix from url
$next_prefix = array_key_exists($pass_index + 1, $pass_info) ? $pass_info[$pass_index + 1] : false;
if ($next_prefix) {
$next_prefix = substr($next_prefix, 0, strlen($prefix) + 1);
if ($prefix . '.' == $next_prefix) {
continue;
}
}
// rewrited url part
$url_part = $this->BuildModuleEnv_NEW($pass_element, $params, $pass_events);
if (is_string($url_part) && $url_part) {
$ret .= $url_part . '/';
if ($catalog_item) {
// pass category later only for catalog items
$catalog_item_found = true;
}
}
elseif (is_array($url_part)) {
// rewrite listener want to insert something at the beginning of url too
if ($url_part[0]) {
$inject_parts[] = $url_part[0];
}
if ($url_part[1]) {
$ret .= $url_part[1] . '/';
}
if ($catalog_item) {
// pass category later only for catalog items
$catalog_item_found = true;
}
} elseif ($url_part === false) {
// rewrite listener decided not to rewrite given $pass_element
$env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events);
}
}
else {
$env .= ':' . $this->BuildModuleEnv($pass_element, $params, $pass_events);
}
}
if ($catalog_item_found || preg_match('/c\.[-\d]*/', implode(',', $pass_info))) {
// "c" prefix is present -> keep category
$params['pass_category'] = true;
}
$params['inject_parts'] = $inject_parts;
$ret = $this->BuildModuleEnv_NEW('m', $params, $pass_events) . '/' . $ret;
$cat_processed = array_key_exists('category_processed', $params) && $params['category_processed'];
// remove tempporary parameters used by listeners
unset($params['t'], $params['inject_parts'], $params['pass_template'], $params['pass_category'], $params['category_processed']);
if ($catalog_item_found || !$cat_processed || !defined('EXP_DIR_URLS')) {
// this catalog item detail page OR there is no category given
$ret = trim($ret, '/') . '.html';
}
else {
// url ends with "/" and not with ".html"
$ret = trim($ret, '/') . '/';
}
if ($env) {
$params[ENV_VAR_NAME] = ltrim($env, ':');
}
}
unset($params['pass'], $params['opener'], $params['m_event']);
if ($force_admin) {
$params['admin'] = 1;
}
if (array_key_exists('escape', $params) && $params['escape']) {
$ret = addslashes($ret);
unset($params['escape']);
}
$ret = str_replace('%2F', '/', urlencode($ret));
$params_str = '';
$join_string = $encode ? '&' : '&amp;';
foreach ($params as $param => $value) {
$params_str .= $join_string . $param . '=' . $value;
}
if ($params_str) {
$ret .= '?' . substr($params_str, strlen($join_string));
}
if ($encode) {
$ret = str_replace('\\', '%5C', $ret);
}
return $ret;
}
function BuildModuleEnv_NEW($prefix_special, &$params, $keep_events = false)
{
list ($prefix) = explode('.', $prefix_special);
$url_parts = Array ();
$listener = $this->RewriteListeners[$prefix];
$ret = $listener[0]->$listener[1](REWRITE_MODE_BUILD, $prefix_special, $params, $url_parts, $keep_events);
return $ret;
}
/**
* Builds env part that corresponds prefix passed
*
* @param string $prefix_special item's prefix & [special]
* @param Array $params url params
* @param bool $pass_events
*/
function BuildModuleEnv($prefix_special, &$params, $pass_events = false)
{
list($prefix) = explode('.', $prefix_special);
$query_vars = $this->getUnitOption($prefix, 'QueryString');
//if pass events is off and event is not implicity passed
if( !$pass_events && !isset($params[$prefix_special.'_event']) ) {
$params[$prefix_special.'_event'] = ''; // remove event from url if requested
//otherwise it will use value from get_var
}
if(!$query_vars) return '';
$tmp_string = Array(0 => $prefix_special);
foreach($query_vars as $index => $var_name)
{
//if value passed in params use it, otherwise use current from application
$var_name = $prefix_special.'_'.$var_name;
$tmp_string[$index] = isset( $params[$var_name] ) ? $params[$var_name] : $this->GetVar($var_name);
if ( isset($params[$var_name]) ) unset( $params[$var_name] );
}
$escaped = array();
foreach ($tmp_string as $tmp_val) {
$escaped[] = str_replace(Array('-',':'), Array('\-','\:'), $tmp_val);
}
$ret = implode('-', $escaped);
if ($this->getUnitOption($prefix, 'PortalStyleEnv') == true)
{
$ret = preg_replace('/^([a-zA-Z]+)-([0-9]+)-(.*)/','\\1\\2-\\3', $ret);
}
return $ret;
}
function BuildEnv($t, $params, $pass='all', $pass_events = false, $env_var = true)
{
$session =& $this->recallObject('Session');
$ssl = isset($params['__SSL__']) ? $params['__SSL__'] : 0;
$sid = $session->NeedQueryString() && !$this->RewriteURLs($ssl) ? $this->GetSID() : '';
// if (getArrayValue($params,'admin') == 1) $sid = $this->GetSID();
$ret = '';
if ($env_var) {
$ret = ENV_VAR_NAME.'=';
}
- $ret .= $sid.(constOn('INPORTAL_ENV') ? '-' : ':');
+ $ret .= $sid . '-'; // SID-TEMPLATE
$encode = false;
if (isset($params['__URLENCODE__'])) {
$encode = $params['__URLENCODE__'];
unset($params['__URLENCODE__']);
}
if (isset($params['__SSL__'])) {
unset($params['__SSL__']);
}
$env_string = '';
$category_id = isset($params['m_cat_id']) ? $params['m_cat_id'] : $this->GetVar('m_cat_id');
$item_id = false;
$pass_info = $this->getPassInfo($pass);
if ($pass_info) {
if ($pass_info[0] == 'm') array_shift($pass_info);
foreach ($pass_info as $pass_element) {
list($prefix) = explode('.', $pass_element);
$require_rewrite = $this->findModule('Var', $prefix);
if ($require_rewrite) {
$item_id = isset($params[$pass_element.'_id']) ? $params[$pass_element.'_id'] : $this->GetVar($pass_element.'_id');
}
$env_string .= ':'.$this->BuildModuleEnv($pass_element, $params, $pass_events);
}
}
if (strtolower($t) == '__default__') {
// to put category & item templates into cache
$filename = $this->getFilename('c', $category_id);
if (is_numeric($item_id)) {
$mod_rw_helper =& $this->Application->recallObject('ModRewriteHelper');
/* @var $mod_rw_helper kModRewriteHelper */
$t = $mod_rw_helper->GetItemTemplate($category_id, $pass_element); // $pass_element should be the last processed element
// $t = $this->getCache('item_templates', $category_id);
}
elseif ($category_id) {
$t = strtolower( preg_replace('/^Content\//i', '', $this->getCache('category_templates', $category_id)) );
}
else {
$t = 'index';
}
}
$ret .= $t.':'.$this->BuildModuleEnv('m', $params, $pass_events).$env_string;
unset($params['pass'], $params['opener'], $params['m_event']);
if ($this->GetVar('admin') && !isset($params['admin'])) {
$params['admin'] = 1;
if (!array_key_exists('editing_mode', $params)) {
$params['editing_mode'] = EDITING_MODE;
}
}
if (array_key_exists('escape', $params) && $params['escape']) {
$ret = addslashes($ret);
unset($params['escape']);
}
$join_string = $encode ? '&' : '&amp;';
$params_str = '';
foreach ($params as $param => $value)
{
$params_str .= $join_string.$param.'='.$value;
}
$ret .= $params_str;
if ($encode) {
$ret = str_replace('\\', '%5C', $ret);
}
return $ret;
}
function BaseURL($prefix='', $ssl=null)
{
if ($ssl === null) {
return PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').rtrim(BASE_PATH, '/').$prefix.'/';
}
else {
if ($ssl) {
$base_url = defined('ADMIN') && ADMIN ? $this->ConfigValue('AdminSSL_URL') : false;
if (!$base_url) {
$base_url = $this->ConfigValue('SSL_URL');
}
return rtrim($base_url, '/').$prefix.'/';
}
else {
return 'http://'.DOMAIN.(defined('PORT')?':'.PORT : '').rtrim( $this->ConfigValue('Site_Path'), '/').$prefix.'/';
}
}
}
function Redirect($t='', $params=null, $prefix='', $index_file=null)
{
$js_redirect = getArrayValue($params, 'js_redirect');
if (preg_match("/external:(.*)/", $t, $rets)) {
$location = $rets[1];
}
else {
if ($t == '' || $t === true) $t = $this->GetVar('t');
// pass prefixes and special from previous url
if( isset($params['js_redirect']) ) unset($params['js_redirect']);
if (!isset($params['pass'])) $params['pass'] = 'all';
if ($this->GetVar('ajax') == 'yes' && $t == $this->GetVar('t')) {
// redirects to the same template as current
$params['ajax'] = 'yes';
}
$params['__URLENCODE__'] = 1;
$location = $this->HREF($t, $prefix, $params, $index_file);
//echo " location : $location <br>";
}
$a_location = $location;
$location = "Location: $location";
if ($this->isDebugMode() && constOn('DBG_REDIRECT')) {
$this->Debugger->appendTrace();
echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$a_location\">$a_location</a><br>";
}
else {
if ($js_redirect) {
$this->SetVar('t', 'redirect');
$this->SetVar('redirect_to_js', addslashes($a_location) );
$this->SetVar('redirect_to', $a_location);
return true;
}
else {
if ($this->GetVar('ajax') == 'yes' && $t != $this->GetVar('t')) {
// redirection to other then current template during ajax request
echo '#redirect#'.$a_location;
}
elseif (headers_sent() != '') {
// some output occured -> redirect using javascript
echo '<script type="text/javascript">window.location.href = \''.$a_location.'\';</script>';
}
else {
// no output before -> redirect using HTTP header
// header('HTTP/1.1 302 Found');
header("$location");
}
}
}
ob_end_flush();
// session expiration is called from session initialization,
// that's why $this->Session may be not defined here
$session =& $this->Application->recallObject('Session');
/* @var $session Session */
$this->HandleEvent( new kEvent('adm:OnBeforeShutdown') );
$session->SaveData();
exit;
}
function Phrase($label, $allow_editing = true)
{
return $this->Phrases->GetPhrase($label, $allow_editing);
}
/**
* Replace language tags in exclamation marks found in text
*
* @param string $text
* @param bool $force_escape force escaping, not escaping of resulting string
* @return string
* @access public
*/
function ReplaceLanguageTags($text, $force_escape=null)
{
// !!!!!!!!
// if( !is_object($this->Phrases) ) $this->Debugger->appendTrace();
return $this->Phrases->ReplaceLanguageTags($text,$force_escape);
}
/**
* Checks if user is logged in, and creates
* user object if so. User object can be recalled
* later using "u.current" prefix_special. Also you may
* get user id by getting "u.current_id" variable.
*
* @access private
*/
function ValidateLogin()
{
$session =& $this->recallObject('Session');
$user_id = $session->GetField('PortalUserId');
if (!$user_id && $user_id != -1) $user_id = -2;
$this->SetVar('u.current_id', $user_id);
if (!$this->IsAdmin()) {
// needed for "profile edit", "registration" forms ON FRONT ONLY
$this->SetVar('u_id', $user_id);
}
$this->StoreVar('user_id', $user_id);
if ($this->GetVar('expired') == 1) {
// this parameter is set only from admin
$user =& $this->recallObject('u.current');
$user->SetError('ValidateLogin', 'session_expired', 'la_text_sess_expired');
}
if (($user_id != -2) && constOn('DBG_REQUREST_LOG') ) {
$http_query =& $this->recallObject('HTTPQuery');
$http_query->writeRequestLog(DBG_REQUREST_LOG);
}
if ($user_id != -2) {
// normal users + root
$this->LoadPersistentVars();
}
}
/**
* Loads current user persistent session data
*
*/
function LoadPersistentVars()
{
$this->Session->LoadPersistentVars();
}
function LoadCache() {
$cache_key = $this->GetVar('t').$this->GetVar('m_theme').$this->GetVar('m_lang').$this->IsAdmin();
$query = sprintf("SELECT PhraseList, ConfigVariables FROM %s WHERE Template = %s",
TABLE_PREFIX.'PhraseCache',
$this->Conn->qstr(md5($cache_key)));
$res = $this->Conn->GetRow($query);
if ($res) {
$this->Caches['PhraseList'] = $res['PhraseList'] ? explode(',', $res['PhraseList']) : array();
$config_ids = $res['ConfigVariables'] ? explode(',', $res['ConfigVariables']) : array();
if (isset($this->Caches['ConfigVariables'])) {
$config_ids = array_diff($config_ids, $this->Caches['ConfigVariables']);
}
}
else {
$config_ids = array();
}
$this->Caches['ConfigVariables'] = $config_ids;
$this->ConfigCacheIds = $config_ids;
}
function UpdateCache()
{
$update = false;
//something changed
$update = $update || $this->Phrases->NeedsCacheUpdate();
$update = $update || (count($this->ConfigCacheIds) && $this->ConfigCacheIds != $this->Caches['ConfigVariables']);
if ($update) {
$cache_key = $this->GetVar('t').$this->GetVar('m_theme').$this->GetVar('m_lang').$this->IsAdmin();
$query = sprintf("REPLACE %s (PhraseList, CacheDate, Template, ConfigVariables)
VALUES (%s, %s, %s, %s)",
TABLE_PREFIX.'PhraseCache',
$this->Conn->Qstr(join(',', $this->Phrases->Ids)),
adodb_mktime(),
$this->Conn->Qstr(md5($cache_key)),
$this->Conn->qstr(implode(',', array_unique($this->ConfigCacheIds))));
$this->Conn->Query($query);
}
}
function InitConfig()
{
if (isset($this->Caches['ConfigVariables']) && count($this->Caches['ConfigVariables']) > 0) {
$this->ConfigHash = array_merge($this->ConfigHash, $this->Conn->GetCol(
'SELECT VariableValue, VariableName FROM '.TABLE_PREFIX.'ConfigurationValues
WHERE VariableId IN ('.implode(',', $this->Caches['ConfigVariables']).')', 'VariableName'));
}
}
/**
* Returns configuration option value by name
*
* @param string $name
* @return string
*/
function ConfigValue($name)
{
$res = array_key_exists($name, $this->ConfigHash) ? $this->ConfigHash[$name] : false;
if ($res !== false) {
return $res;
}
if (defined('IS_INSTALL') && IS_INSTALL && !$this->TableFound('ConfigurationValues')) {
return false;
}
$sql = 'SELECT VariableId, VariableValue
FROM '.TABLE_PREFIX.'ConfigurationValues
WHERE VariableName = '.$this->Conn->qstr($name);
$res = $this->Conn->GetRow($sql);
if ($res !== false) {
$this->ConfigHash[$name] = $res['VariableValue'];
$this->ConfigCacheIds[] = $res['VariableId'];
return $res['VariableValue'];
}
return false;
}
function UpdateConfigCache()
{
if ($this->ConfigCacheIds) {
}
}
/**
* Allows to process any type of event
*
* @param kEvent $event
* @access public
* @author Alex
*/
function HandleEvent(&$event, $params=null, $specificParams=null)
{
if ( isset($params) ) {
$event = new kEvent( $params, $specificParams );
}
if (!isset($this->EventManager)) {
$this->EventManager =& $this->recallObject('EventManager');
}
$this->EventManager->HandleEvent($event);
}
/**
* Registers new class in the factory
*
* @param string $real_class Real name of class as in class declaration
* @param string $file Filename in what $real_class is declared
* @param string $pseudo_class Name under this class object will be accessed using getObject method
* @param Array $dependecies List of classes required for this class functioning
* @access public
* @author Alex
*/
function registerClass($real_class, $file, $pseudo_class = null, $dependecies = Array() )
{
$this->Factory->registerClass($real_class, $file, $pseudo_class, $dependecies);
}
/**
* Add $class_name to required classes list for $depended_class class.
* All required class files are included before $depended_class file is included
*
* @param string $depended_class
* @param string $class_name
* @author Alex
*/
function registerDependency($depended_class, $class_name)
{
$this->Factory->registerDependency($depended_class, $class_name);
}
/**
* Registers Hook from subprefix event to master prefix event
*
* @param string $hookto_prefix
* @param string $hookto_special
* @param string $hookto_event
* @param string $mode
* @param string $do_prefix
* @param string $do_special
* @param string $do_event
* @param string $conditional
* @access public
* @todo take care of a lot parameters passed
* @author Kostja
*/
function registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional)
{
$event_manager =& $this->recallObject('EventManager');
$event_manager->registerHook($hookto_prefix, $hookto_special, $hookto_event, $mode, $do_prefix, $do_special, $do_event, $conditional);
}
/**
* Allows one TagProcessor tag act as other TagProcessor tag
*
* @param Array $tag_info
* @author Kostja
*/
function registerAggregateTag($tag_info)
{
$aggregator =& $this->recallObject('TagsAggregator', 'kArray');
$aggregator->SetArrayValue($tag_info['AggregateTo'], $tag_info['AggregatedTagName'], Array($tag_info['LocalPrefix'], $tag_info['LocalTagName'], getArrayValue($tag_info, 'LocalSpecial')));
}
/**
* Returns object using params specified,
* creates it if is required
*
* @param string $name
* @param string $pseudo_class
* @param Array $event_params
* @return Object
* @author Alex
*/
function &recallObject($name,$pseudo_class=null,$event_params=Array())
{
$result =& $this->Factory->getObject($name, $pseudo_class, $event_params);
return $result;
}
/**
* Returns object using Variable number of params,
* all params starting with 4th are passed to object consturctor
*
* @param string $name
* @param string $pseudo_class
* @param Array $event_params
* @return Object
* @author Alex
*/
function &recallObjectP($name,$pseudo_class=null,$event_params=Array())
{
$func_args = func_get_args();
$result =& ref_call_user_func_array( Array(&$this->Factory, 'getObjectP'), $func_args );
return $result;
}
/**
* Returns tag processor for prefix specified
*
* @param string $prefix
* @return kDBTagProcessor
*/
function &recallTagProcessor($prefix)
{
- $this->InitParser(); // because kDBTagProcesor is in TemplateParser dependencies
- $result =& $this->recallObject($prefix.'_TagProcessor');
+ $this->InitParser(); // because kDBTagProcesor is in NParser dependencies
+ $result =& $this->recallObject($prefix . '_TagProcessor');
+
return $result;
}
/**
* Checks if object with prefix passes was already created in factory
*
* @param string $name object presudo_class, prefix
* @return bool
* @author Kostja
*/
function hasObject($name)
{
return isset($this->Factory->Storage[$name]);
}
/**
* Removes object from storage by given name
*
* @param string $name Object's name in the Storage
* @author Kostja
*/
function removeObject($name)
{
$this->Factory->DestroyObject($name);
}
/**
* Get's real class name for pseudo class,
* includes class file and creates class
* instance
*
* @param string $pseudo_class
* @return Object
* @access public
* @author Alex
*/
function &makeClass($pseudo_class)
{
$func_args = func_get_args();
$result =& ref_call_user_func_array( Array(&$this->Factory, 'makeClass'), $func_args);
return $result;
}
/**
* Checks if application is in debug mode
*
* @param bool $check_debugger check if kApplication debugger is initialized too, not only for defined DEBUG_MODE constant
* @return bool
* @author Alex
* @access public
*/
function isDebugMode($check_debugger = true)
{
$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
if ($check_debugger) {
$debug_mode = $debug_mode && is_object($this->Debugger);
}
return $debug_mode;
}
/**
* Checks if it is admin
*
* @return bool
* @author Alex
*/
function IsAdmin()
{
return constOn('ADMIN');
}
/**
* Apply url rewriting used by mod_rewrite or not
*
* @param bool $ssl Force ssl link to be build
* @return bool
*/
function RewriteURLs($ssl = false)
{
// case #1,#4:
// we want to create https link from http mode
// we want to create https link from https mode
// conditions: ($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')
// case #2,#3:
// we want to create http link from https mode
// we want to create http link from http mode
// conditions: !$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')
$allow_rewriting =
(!$ssl && (PROTOCOL == 'https://' || PROTOCOL == 'http://')) // always allow mod_rewrite for http
|| // or allow rewriting for redirect TO httpS or when already in httpS
(($ssl || PROTOCOL == 'https://') && $this->ConfigValue('UseModRewriteWithSSL')); // but only if it's allowed in config!
return constOn('MOD_REWRITE') && $allow_rewriting;
}
/**
* Reads unit (specified by $prefix)
* option specified by $option
*
* @param string $prefix
* @param string $option
* @param mixed $default
* @return string
* @access public
* @author Alex
*/
function getUnitOption($prefix, $option, $default = false)
{
/*if (!isset($this->UnitConfigReader)) {
$this->UnitConfigReader =& $this->recallObject('kUnitConfigReader');
}*/
return $this->UnitConfigReader->getUnitOption($prefix, $option, $default);
}
/**
* Set's new unit option value
*
* @param string $prefix
* @param string $name
* @param string $value
* @author Alex
* @access public
*/
function setUnitOption($prefix, $option, $value)
{
// $unit_config_reader =& $this->recallObject('kUnitConfigReader');
return $this->UnitConfigReader->setUnitOption($prefix,$option,$value);
}
/**
* Read all unit with $prefix options
*
* @param string $prefix
* @return Array
* @access public
* @author Alex
*/
function getUnitOptions($prefix)
{
// $unit_config_reader =& $this->recallObject('kUnitConfigReader');
return $this->UnitConfigReader->getUnitOptions($prefix);
}
/**
* Returns true if config exists and is allowed for reading
*
* @param string $prefix
* @return bool
*/
function prefixRegistred($prefix)
{
/*if (!isset($this->UnitConfigReader)) {
$this->UnitConfigReader =& $this->recallObject('kUnitConfigReader');
}*/
return $this->UnitConfigReader->prefixRegistred($prefix);
}
/**
* Splits any mixing of prefix and
* special into correct ones
*
* @param string $prefix_special
* @return Array
* @access public
* @author Alex
*/
function processPrefix($prefix_special)
{
return $this->Factory->processPrefix($prefix_special);
}
/**
* Set's new event for $prefix_special
* passed
*
* @param string $prefix_special
* @param string $event_name
* @access public
*/
function setEvent($prefix_special,$event_name)
{
$event_manager =& $this->recallObject('EventManager');
$event_manager->setEvent($prefix_special,$event_name);
}
/**
* SQL Error Handler
*
* @param int $code
* @param string $msg
* @param string $sql
* @return bool
* @access private
* @author Alex
*/
function handleSQLError($code, $msg, $sql)
{
if ( isset($this->Debugger) )
{
$errorLevel = constOn('DBG_SQL_FAILURE') && !defined('IS_INSTALL') ? E_USER_ERROR : E_USER_WARNING;
$this->Debugger->appendTrace();
$error_msg = '<span class="debug_error">'.$msg.' ('.$code.')</span><br><a href="javascript:$Debugger.SetClipboard(\''.htmlspecialchars($sql).'\');"><b>SQL</b></a>: '.$this->Debugger->formatSQL($sql);
$long_id = $this->Debugger->mapLongError($error_msg);
trigger_error( mb_substr($msg.' ('.$code.') ['.$sql.']',0,1000).' #'.$long_id, $errorLevel);
return true;
}
else
{
//$errorLevel = constOn('IS_INSTALL') ? E_USER_WARNING : E_USER_ERROR;
$errorLevel = E_USER_WARNING;
trigger_error('<b>SQL Error</b> in sql: '.$sql.', code <b>'.$code.'</b> ('.$msg.')', $errorLevel);
/*echo '<b>xProcessing SQL</b>: '.$sql.'<br>';
echo '<b>Error ('.$code.'):</b> '.$msg.'<br>';*/
return $errorLevel == E_USER_ERROR ? false : true;
}
}
/**
* Default error handler
*
* @param int $errno
* @param string $errstr
* @param string $errfile
* @param int $errline
* @param Array $errcontext
*/
function handleError($errno, $errstr, $errfile = '', $errline = '', $errcontext = '')
{
if (defined('SILENT_LOG') && SILENT_LOG) {
if ( !(defined('DBG_IGNORE_STRICT_ERRORS') && DBG_IGNORE_STRICT_ERRORS && defined('E_STRICT') && ($errno == E_STRICT)) ) {
$fp = fopen(FULL_PATH.'/silent_log.txt','a');
$time = adodb_date('d/m/Y H:i:s');
fwrite($fp, '['.$time.'] #'.$errno.': '.strip_tags($errstr).' in ['.$errfile.'] on line '.$errline."\n");
fclose($fp);
}
}
$debug_mode = defined('DEBUG_MODE') && DEBUG_MODE;
$skip_reporting = defined('DBG_SKIP_REPORTING') && DBG_SKIP_REPORTING;
if (!$this->errorHandlers || ($debug_mode && $skip_reporting)) {
// when debugger absent OR it's present, but we actually can't see it's error report (e.g. during ajax request)
$ignore_fatal_errors = defined('DBG_IGNORE_FATAL_ERRORS') && DBG_IGNORE_FATAL_ERRORS;
if (($errno == E_USER_ERROR) && !$ignore_fatal_errors) {
echo (' <div style="background-color: #FEFFBF; margin: auto; padding: 10px; border: 2px solid red; text-align: center">
<strong>Fatal Error: </strong>'."$errstr in $errfile on line $errline".'
</div>');
exit;
}
if (!$this->errorHandlers) {
return true;
}
}
$res = false;
$i = 0; // while (not foreach) because it is array of references in some cases
$eh_count = count($this->errorHandlers);
while ($i < $eh_count) {
if ( is_array($this->errorHandlers[$i]) ) {
$object =& $this->errorHandlers[$i][0];
$method = $this->errorHandlers[$i][1];
$res = $object->$method($errno, $errstr, $errfile, $errline, $errcontext);
}
else {
$function = $this->errorHandlers[$i];
$res = $function($errno, $errstr, $errfile, $errline, $errcontext);
}
$i++;
}
return $res;
}
/**
* Returns & blocks next ResourceId available in system
*
* @return int
* @access public
* @author Alex
*/
function NextResourceId()
{
$table_name = TABLE_PREFIX.'IdGenerator';
$this->Conn->Query('LOCK TABLES '.$table_name.' WRITE');
$this->Conn->Query('UPDATE '.$table_name.' SET lastid = lastid + 1');
$id = $this->Conn->GetOne('SELECT lastid FROM '.$table_name);
if($id === false)
{
$this->Conn->Query('INSERT INTO '.$table_name.' (lastid) VALUES (2)');
$id = 2;
}
$this->Conn->Query('UNLOCK TABLES');
return $id - 1;
}
/**
* Returns genealogical main prefix for subtable prefix passes
* OR prefix, that has been found in REQUEST and some how is parent of passed subtable prefix
*
* @param string $current_prefix
* @param string $real_top if set to true will return real topmost prefix, regardless of its id is passed or not
* @return string
* @access public
* @author Kostja / Alex
*/
function GetTopmostPrefix($current_prefix, $real_top = false)
{
// 1. get genealogical tree of $current_prefix
$prefixes = Array ($current_prefix);
while ( $parent_prefix = $this->getUnitOption($current_prefix, 'ParentPrefix') ) {
if (!$this->prefixRegistred($parent_prefix)) {
// stop searching, when parent prefix is not registered
break;
}
$current_prefix = $parent_prefix;
array_unshift($prefixes, $current_prefix);
}
if ($real_top) {
return $current_prefix;
}
// 2. find what if parent is passed
$passed = explode(',', $this->GetVar('all_passed'));
foreach ($prefixes as $a_prefix) {
if (in_array($a_prefix, $passed)) {
return $a_prefix;
}
}
return $current_prefix;
}
/**
* Triggers email event of type Admin
*
* @param string $email_event_name
* @param int $to_user_id
* @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text
* @return unknown
*/
function &EmailEventAdmin($email_event_name, $to_user_id = -1, $send_params = false)
{
$event =& $this->EmailEvent($email_event_name, 1, $to_user_id, $send_params);
return $event;
}
/**
* Triggers email event of type User
*
* @param string $email_event_name
* @param int $to_user_id
* @param array $send_params associative array of direct send params, possible keys: to_email, to_name, from_email, from_name, message, message_text
* @return unknown
*/
function &EmailEventUser($email_event_name, $to_user_id = -1, $send_params = false)
{
$event =& $this->EmailEvent($email_event_name, 0, $to_user_id, $send_params);
return $event;
}
/**
* Triggers general email event
*
* @param string $email_event_name
* @param int $email_event_type ( 0 for User, 1 for Admin)
* @param int $to_user_id
* @param array $send_params associative array of direct send params,
* possible keys: to_email, to_name, from_email, from_name, message, message_text
* @return unknown
*/
function &EmailEvent($email_event_name, $email_event_type, $to_user_id = -1, $send_params = false)
{
$params = array(
'EmailEventName' => $email_event_name,
'EmailEventToUserId' => $to_user_id,
'EmailEventType' => $email_event_type,
);
if ($send_params) {
$params['DirectSendParams'] = $send_params;
}
$event_str = isset($send_params['use_special']) ? 'emailevents.'.$send_params['use_special'].':OnEmailEvent' : 'emailevents:OnEmailEvent';
$this->HandleEvent($event, $event_str, $params);
return $event;
}
/**
* Allows to check if user in this session is logged in or not
*
* @return bool
*/
function LoggedIn()
{
// no session during expiration process
return is_null($this->Session) ? false : $this->Session->LoggedIn();
}
/**
* Check current user permissions based on it's group permissions in specified category
*
* @param string $name permission name
* @param int $cat_id category id, current used if not specified
* @param int $type permission type {1 - system, 0 - per category}
* @return int
*/
function CheckPermission($name, $type = 1, $cat_id = null)
{
$perm_helper =& $this->recallObject('PermissionsHelper');
return $perm_helper->CheckPermission($name, $type, $cat_id);
}
/**
* Set's any field of current visit
*
* @param string $field
* @param mixed $value
*/
function setVisitField($field, $value)
{
$visit =& $this->recallObject('visits');
$visit->SetDBField($field, $value);
$visit->Update();
}
/**
* Allows to check if in-portal is installed
*
* @return bool
*/
function isInstalled()
{
return $this->InitDone && (count($this->ModuleInfo) > 0);
}
/**
* Allows to determine if module is installed & enabled
*
* @param string $module_name
* @return bool
*/
function isModuleEnabled($module_name)
{
return $this->findModule('Name', $module_name) !== false;
}
function reportError($class, $method)
{
$this->Debugger->appendTrace();
trigger_error('depricated method <b>'.$class.'->'.$method.'(...)</b>', E_USER_ERROR);
}
/**
* Returns Window ID of passed prefix main prefix (in edit mode)
*
* @param string $prefix
* @return mixed
*/
function GetTopmostWid($prefix)
{
$top_prefix = $this->GetTopmostPrefix($prefix);
$mode = $this->GetVar($top_prefix.'_mode');
return $mode != '' ? substr($mode, 1) : '';
}
/**
* Get temp table name
*
* @param string $table
* @param mixed $wid
* @return string
*/
function GetTempName($table, $wid = '')
{
if (preg_match('/prefix:(.*)/', $wid, $regs)) {
$wid = $this->GetTopmostWid($regs[1]);
}
return TABLE_PREFIX.'ses_'.$this->GetSID().($wid ? '_'.$wid : '').'_edit_'.$table;
}
function GetTempTablePrefix($wid = '')
{
if (preg_match('/prefix:(.*)/', $wid, $regs)) {
$wid = $this->GetTopmostWid($regs[1]);
}
return TABLE_PREFIX.'ses_'.$this->GetSID().($wid ? '_'.$wid : '').'_edit_';
}
function IsTempTable($table)
{
return preg_match('/'.TABLE_PREFIX.'ses_'.$this->GetSID().'(_[\d]+){0,1}_edit_(.*)/',$table);
}
/**
* Checks, that given prefix is in temp mode
*
* @param string $prefix
* @return bool
*/
function IsTempMode($prefix, $special = '')
{
$top_prefix = $this->Application->GetTopmostPrefix($prefix);
$var_names = Array (
$top_prefix,
rtrim($top_prefix . '_' . $special, '_'), // from post
rtrim($top_prefix . '.' . $special, '.'), // assembled locally
);
$var_names = array_unique($var_names);
$temp_mode = false;
foreach ($var_names as $var_name) {
$value = $this->Application->GetVar($var_name . '_mode');
if ($value && (substr($value, 0, 1) == 't')) {
$temp_mode = true;
break;
}
}
return $temp_mode;
}
/**
* Return live table name based on temp table name
*
* @param string $temp_table
* @return string
*/
function GetLiveName($temp_table)
{
if( preg_match('/'.TABLE_PREFIX.'ses_'.$this->GetSID().'(_[\d]+){0,1}_edit_(.*)/',$temp_table, $rets) )
{
// cut wid from table end if any
return $rets[2];
}
else
{
return $temp_table;
}
}
function CheckProcessors($processors)
{
foreach ($processors as $a_processor)
{
if (!isset($this->CachedProcessors[$a_processor])) {
$this->CachedProcessors[$a_processor] =& $this->recallObject($a_processor.'_TagProcessor');
}
}
}
function TimeZoneAdjustment($time_zone = null)
{
if ($time_zone == 'GMT') {
return (-1) * adodb_date('Z');
}
$target_zone = isset($time_zone) ? $time_zone : $this->ConfigValue('Config_Site_Time');
return 3600 * ($target_zone - $this->ConfigValue('Config_Server_Time'));
}
function ApplicationDie($message = '')
{
$message = ob_get_clean().$message;
if ($this->isDebugMode()) {
$message .= $this->Debugger->printReport(true);
}
echo $this->UseOutputCompression() ? gzencode($message, DBG_COMPRESSION_LEVEL) : $message;
exit;
}
/* moved from MyApplication */
function getUserGroups($user_id)
{
switch($user_id)
{
case -1:
$user_groups = $this->ConfigValue('User_LoggedInGroup');
break;
case -2:
$user_groups = $this->ConfigValue('User_LoggedInGroup');
$user_groups .= ','.$this->ConfigValue('User_GuestGroup');
break;
default:
$sql = 'SELECT GroupId FROM '.TABLE_PREFIX.'UserGroup WHERE PortalUserId = '.$user_id;
$res = $this->Conn->GetCol($sql);
$user_groups = Array( $this->ConfigValue('User_LoggedInGroup') );
if(is_array($res))
{
$user_groups = array_merge($user_groups, $res);
}
$user_groups = implode(',', $user_groups);
}
return $user_groups;
}
/**
* Allows to detect if page is browsed by spider (293 agents supported)
*
* @return bool
*/
function IsSpider()
{
static $is_spider = null;
if (!isset($is_spider)) {
$user_agent = trim($_SERVER['HTTP_USER_AGENT']);
$robots = file(FULL_PATH.'/core/robots_list.txt');
foreach ($robots as $robot_info) {
$robot_info = explode("\t", $robot_info, 3);
if ($user_agent == trim($robot_info[2])) {
$is_spider = true;
break;
}
}
}
return $is_spider;
}
/**
* Allows to detect table's presense in database
*
* @param string $table_name
* @return bool
*/
function TableFound($table_name)
{
return $this->Conn->TableFound($table_name);
}
/**
* Returns counter value
*
* @param string $name counter name
* @param Array $params counter parameters
* @param string $query_name specify query name directly (don't generate from parmeters)
* @param bool $multiple_results
* @return mixed
*/
function getCounter($name, $params = Array (), $query_name = null, $multiple_results = false)
{
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
return $count_helper->getCounter($name, $params, $query_name, $multiple_results);
}
/**
* Resets counter, whitch are affected by one of specified tables
*
* @param string $tables comma separated tables list used in counting sqls
*/
function resetCounters($tables)
{
if (constOn('IS_INSTALL')) {
return ;
}
$count_helper =& $this->Application->recallObject('CountHelper');
/* @var $count_helper kCountHelper */
return $count_helper->resetCounters($tables);
}
/**
* Sends XML header + optionally displays xml heading
*
* @param string $xml_version
* @return string
* @author Alex
*/
function XMLHeader($xml_version = false)
{
$lang =& $this->recallObject('lang.current');
header('Content-type: text/xml; charset='.$lang->GetDBField('Charset'));
return $xml_version ? '<?xml version="'.$xml_version.'" encoding="'.$lang->GetDBField('Charset').'"?>' : '';
}
/**
* Returns category tree
*
* @param int $category_id
* @return Array
*/
function getTreeIndex($category_id)
{
$category_template = $this->getFilename('c', $category_id); // to rebuild "category_tree" cache
$tree_index = $this->getCache('category_tree', $category_id);
if ($tree_index) {
$ret = Array ();
list ($ret['TreeLeft'], $ret['TreeRight']) = explode(';', $tree_index);
return $ret;
}
return false;
}
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/nparser/template.php
===================================================================
--- branches/5.0.x/core/kernel/nparser/template.php (revision 12322)
+++ branches/5.0.x/core/kernel/nparser/template.php (nonexistent)
@@ -1,304 +0,0 @@
-<?php
-/**
-* @version $Id$
-* @package In-Portal
-* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
-* @license GNU/GPL
-* In-Portal is Open Source software.
-* This means that this software may have been modified pursuant
-* the GNU General Public License, and as distributed it includes
-* or is derivative of works licensed under the GNU General Public License
-* or other free or open source software licenses.
-* See http://www.in-portal.net/license/ for copyright notices and details.
-*/
-
-defined('FULL_PATH') or die('restricted access!');
-
-class Template {
- var $Body = '';
- var $BasePath = '';
- var $Filename = '';
-
- function Template($base_path=null, $filename=null, $silent=0)
- {
- if ($this->SetBasePath($base_path)) {
- if (isset($filename)) {
- $this->Filename = $filename;
- $this->LoadTemplate($silent);
- }
- }
- }
-
- function SetBasePath($base_path=null)
- {
- if (isset($base_path)) {
- $base_path = eregi_replace("/$", '', $base_path); //Cutting possible last slash
- $this->BasePath = $base_path;
- return true;
- }
- return false;
- }
-
- function GetFullPath()
- {
- return $this->BasePath.'/'.ltrim($this->Filename, '/').'.tpl';
- }
-
- /**
- * Enter description here...
- *
- * @param int $silent template not found {0 - fatal error, 1 - warning, 2 - nothing}
- * @return bool
- */
- function LoadTemplate($silent = 0)
- {
- $filename = $this->GetFullPath();
- if (file_exists($filename)) {
- if (filesize ($filename) == 0) {
- trigger_error("Template file size is 0: <b>$filename</b>", ($silent ? E_USER_NOTICE : E_USER_ERROR) );
- }
-
- // stripping out special comments
- $this->SetBody(preg_replace('/<!--##.*##-->/sU', '', file_get_contents($filename)));
- /*$handle = fopen ($filename, "r");
- $contents = fread ($handle, filesize ($filename));
- $this->SetBody($contents);
- fclose ($handle);*/
- return true;
- }
- else {
- if (($silent != 2) && !$silent) {
- $application =& kApplication::Instance();
- if ($application->isDebugMode()) {
- $application->Debugger->appendTrace();
- }
- trigger_error('File or block not found: <b>'.$filename.'</b> at '.$application->Parser->TemplateName, E_USER_ERROR);
- }
- return false;
- }
- }
-
- function SetBody($body)
- {
- $this->Body = $body;
- }
-
- function GetBody()
- {
- return $this->Body;
- }
-}
-
-class TemplatesCache extends kBase {
- var $Templates = Array();
- var $BasePath;
- var $FileNames = Array();
-
- /**
- * Force templates cache to search templates on front-end:
- * true - search for theme name in template name
- * false - don't search anywhere
- * name - theme name to prepend for each template name
- *
- * @var mixed
- */
- var $forceThemeName = false;
-
- function TemplatesCache()
- {
- parent::kBase();
- $this->BasePath = FULL_PATH.THEMES_PATH;
-
- $conn =& $this->Application->GetADODBConnection();
- }
-
- /**
- * Based on template name gets it's location on disk and owner module
- *
- * @param string $filename
- * @return Array 0 - path on disk, 1 - template name
- */
- function GetTemplatePaths($filename)
- {
- if ($this->Application->IsAdmin() && isset($this->Application->ReplacementTemplates[$filename])) {
- $filename = $this->Application->ReplacementTemplates[$filename];
- }
-
- // allows to use non-replaced version of replaced template
- $filename = preg_replace('/^original:(.*)/', '\\1', $filename);
-
- if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) {
- $module_filename = $regs[2];
- $first_dir = $regs[1];
- }
- else {
- $first_dir = '';
- $module_filename = $filename;
- }
-
- if (is_string($this->forceThemeName)) {
- // when defined, then all templates are read from given theme name
- $first_dir = 'theme:' . $this->forceThemeName . ($first_dir ? '/' . $first_dir : '');
- }
-
- // !preg_match for backward compatability with full-path plugins
- if ($this->Application->IsAdmin() && $first_dir == 'plugins' && !preg_match('/admin_templates/', $module_filename)) {
- if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $module_filename, $regs)) {;
- $path = MODULES_PATH.'/'.mb_strtolower($first_dir).'/'.$regs[1].'/admin_templates';
- $module_filename = $regs[2];
- }
- else {
- $first_dir = '';
- $module_filename = $filename;
- }
- }
- elseif ( $this->Application->IsAdmin() && $this->Application->findModule('Name', $first_dir)) {
- if ($first_dir == 'in-portal') {
- $first_dir = 'kernel';
- }
- $path = MODULES_PATH.'/'.mb_strtolower($first_dir).'/admin_templates';
- }
- elseif ($this->forceThemeName && preg_match('/^theme:(.*)/', $first_dir, $regs)) {
- // ability to use Front-End templates in admin (only during mass compilation)
- $path = FULL_PATH . '/themes/' . $regs[1];
- }
- else {
- $path = $this->BasePath;
- $module_filename = $first_dir.'/'.$module_filename;
- }
-
- return Array ($path, $module_filename);
- }
-
- function LoadTemplate($filename, $title=NULL, $silent=0)
- {
- list ($path, $module_filename) = $this->GetTemplatePaths($filename);
-
- $template = new Template($path, $module_filename, $silent);
- if (!isset($title)) $title = $filename;
- $this->SetTemplate($title, $template);
- }
-
- function GetRealFilename($filename)
- {
- list ($path, $module_filename) = $this->GetTemplatePaths($filename);
- return $path.'/'.trim($module_filename, '/');
- }
-
- function SetTemplate($title, &$template, $filename=null)
- {
- if (!isset($filename)) $filename=$title;
- $this->Templates[$title] = $template;
- $this->FileNames[$title] = $filename;
- }
-
- function &GetTemplate($title, $silent=0)
- {
- if (!isset($this->Templates[$title])) {
- $this->LoadTemplate($title, null, $silent);
- }
- return $this->Templates[$title];
- }
-
- function GetTemplateBody($title, $silent=0)
- {
- $template =& $this->GetTemplate($title, $silent);
- if ( !is_object($template) ) {
- return '';
- }
- return $template->GetBody();
- }
-
- function GetTemplateFileName($title)
- {
- return getArrayValue($this->FileNames, $title);
- }
-
- function SetTemplateBody($title, $body)
- {
- $template = new Template();
- $template->SetBody($body);
- $this->SetTemplate($title, $template);
- }
-
- function ParseTemplate($template_name)
- {
- $Parser = new TemplateParser($this->Application);
- return $Parser->Parse( $this->GetTemplateBody($template_name) );
- }
-
- function TemplateExists($filename)
- {
- if ((strpos($filename, '../') !== false) || (trim($filename) !== $filename)) {
- // when relative paths or special chars are found template names from url, then it's hacking attempt
- return false;
- }
-
- $real_file = $this->GetRealFilename( strtolower($filename) );
- if (substr($real_file, -4) != '.tpl') {
- // add ".tpl" file extension, when not specified in template name
- $real_file .= '.tpl';
- }
-
- return file_exists($real_file);
- }
-
-
- function GetPreParsed($template)
- {
- $real_name = $this->GetRealFilename($template);
- $fname = $real_name.'.php';
- $fname = str_replace(FULL_PATH, WRITEABLE . '/cache', $fname);
-
- $tname = $real_name.'.tpl';
- if (!file_exists($tname)) {
- return false;
- }
-
- if (defined('SAFE_MODE') && SAFE_MODE) {
- $conn =& $this->Application->GetADODBConnection();
- $cached = $conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'Cache WHERE VarName = "'.$fname.'"');
- if ($cached !== false && $cached['Cached'] > filemtime($tname)) {
- return array('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'db', 'content' => $cached['Data']);
- }
- }
- else {
- if (file_exists($fname) && file_exists($tname) && filemtime($fname) > filemtime($tname)) {
- return array('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'file');
- }
- if (!file_exists($fname)) {
- // make sure to create directory if pre-parsed file does not exist
- $this->CheckDir( dirname($fname), WRITEABLE . '/cache' );
- }
- }
- return array('active' => 0, 'fname' => $fname, 'tname' => $tname, 'mode'=>'file');
- }
-
- /**
- * Recursive mkdir
- *
- * @param string $dir
- * @param string $base_path base path to directory where folders should be created in
- */
- function CheckDir($dir, $base_path = '')
- {
- if (file_exists($dir)) {
- return;
- }
- else {
- // remove $base_path from beggining because it is already created during install
- $dir = preg_replace('/^'.preg_quote($base_path.'/', '/').'/', '', $dir, 1);
- $segments = explode('/', $dir);
- $cur_path = $base_path;
-
- foreach ($segments as $segment) {
- // do not add leading / for windows paths (c:\...)
- $cur_path .= preg_match('/^[a-zA-Z]{1}:/', $segment) ? $segment : '/'.$segment;
- if (!file_exists($cur_path)) {
- mkdir($cur_path);
- }
- }
- }
- }
-
-}
\ No newline at end of file
Property changes on: branches/5.0.x/core/kernel/nparser/template.php
___________________________________________________________________
Deleted: cvs2svn:cvs-rev
## -1 +0,0 ##
-1.26.2.6
\ No newline at end of property
Deleted: svn:executable
## -1 +0,0 ##
-*
\ No newline at end of property
Deleted: svn:keywords
## -1 +0,0 ##
-Id
\ No newline at end of property
Index: branches/5.0.x/core/kernel/nparser/nparser.php
===================================================================
--- branches/5.0.x/core/kernel/nparser/nparser.php (revision 12322)
+++ branches/5.0.x/core/kernel/nparser/nparser.php (revision 12323)
@@ -1,878 +1,705 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
include_once(KERNEL_PATH.'/nparser/ntags.php');
define('TAG_NAMESPACE', 'inp2:');
define('TAG_NAMESPACE_LENGTH', 5);
class NParser extends kBase {
var $Stack = array();
var $Level = 0;
var $Buffers = array();
var $InsideComment = false;
var $Params = array();
var $ParamsStack = array();
var $ParamsLevel = 0;
var $Definitions = '';
var $Elements = array(); // holds dynamic elements to function names mapping during execution
/**
* Holds location of element definitions inside templates.
* key - element function name, value - array of 2 keys: {from_pos, to_pos}
*
* @var Array
*/
var $ElementLocations = Array ();
var $DataExists = false;
var $TemplateName = null;
var $TempalteFullPath = null;
var $CachePointers = array();
var $Cachable = array();
- /**
- * Compress compiled templates
- *
- * @var bool
- */
- var $_compressOutput = false;
-
- function NParser()
- {
- parent::kBase();
-
- $this->_compressOutput = $this->Application->ConfigValue('UseTemplateCompression');
- }
-
function Compile($pre_parsed, $template_name = 'unknown')
{
$data = file_get_contents($pre_parsed['tname']);
if (!$this->CompileRaw($data, $pre_parsed['tname'], $template_name)) {
// compilation failed during errors in template
// trigger_error('Template "<strong>' . $template_name . '</strong>" not compiled because of errors', E_USER_WARNING);
return false;
}
// saving compiled version (only when compilation was successful)
- if (defined('SAFE_MODE') && SAFE_MODE) { // store cache files in database since can't save on filesystem
- if (!isset($conn)) $conn =& $this->Application->GetADODBConnection();
- $conn->Query('REPLACE INTO '.TABLE_PREFIX.'Cache (VarName, Data, Cached) VALUES ('.$conn->qstr($pre_parsed['fname']).','.$conn->qstr($this->Buffers[0]).','.adodb_mktime().')');
- }
- else {
- $compiled = fopen($pre_parsed['fname'], 'w');
-
- if ($this->_compressOutput) {
- $this->Buffers[0] = $this->_compress($this->Buffers[0]);
- }
-
- if (!fwrite($compiled, $this->Buffers[0])) {
- trigger_error('Saving compiled template failed', E_USER_ERROR);
- }
- fclose($compiled);
- }
+ $this->Application->TemplatesCache->saveTemplate($pre_parsed['fname'], $this->Buffers[0]);
return true;
}
function Parse($raw_template, $name = null)
{
$this->CompileRaw($raw_template, $name);
ob_start();
$_parser =& $this;
eval('?'.'>'.$this->Buffers[0]);
return ob_get_clean();
}
function CompileRaw($data, $t_name, $template_name = 'unknown')
{
$code = "extract (\$_parser->Params);\n";
$code .= "\$_parser->ElementLocations['{$template_name}'] = Array('template' => '{$template_name}', 'start_pos' => 0, 'end_pos' => " . strlen($data) . ");\n";
// $code .= "__@@__DefinitionsMarker__@@__\n";
// $code .= "if (!\$this->CacheStart('".abs(crc32($t_name))."_0')) {\n";
$this->Buffers[0] = '<?'."php $code ?>\n";
$this->Cacheable[0] = true;
$this->Definitions = '';
// finding all the tags
$reg = '(.*?)(<[\\/]?)' . TAG_NAMESPACE . '([^>]*?)([\\/]?>)(\r\n){0,1}';
preg_match_all('/'.$reg.'/s', $data, $results, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
$this->InsideComment = false;
foreach ($results as $tag_data) {
$tag = array(
'opening' => $tag_data[2][0],
'tag' => $tag_data[3][0],
'closing' => $tag_data[4][0],
'line' => substr_count(substr($data, 0, $tag_data[2][1]), "\n")+1,
'pos' => $tag_data[2][1],
'file' => $t_name,
'template' => $template_name,
);
// the idea is to count number of comment openings and closings before current tag
// if the numbers do not match we inverse the status of InsideComment
if (substr_count($tag_data[1][0], '<!--') != substr_count($tag_data[1][0], '-->')) {
$this->InsideComment = !$this->InsideComment;
}
// appending any text/html data found before tag
$this->Buffers[$this->Level] .= $tag_data[1][0];
if (!$this->InsideComment) {
$tmp_tag = $this->Application->CurrentNTag;
$this->Application->CurrentNTag = $tag;
if ($this->ProcessTag($tag) === false) {
$this->Application->CurrentNTag = $tmp_tag;
return false;
}
$this->Application->CurrentNTag = $tmp_tag;
}
else {
$this->Buffers[$this->Level] .= $tag_data[2][0].$tag_data[3][0].$tag_data[4][0];
}
}
if ($this->Level > 0) {
$this->Application->handleError(E_USER_ERROR, 'Unclosed tag opened by '.$this->TagInfo($this->Stack[$this->Level]->Tag), $this->Stack[$this->Level]->Tag['file'], $this->Stack[$this->Level]->Tag['line']);
return false;
}
// appending text data after last tag (after its closing pos),
// if no tag was found at all ($tag_data is not set) - append the whole $data
$this->Buffers[$this->Level] .= isset($tag_data) ? substr($data, $tag_data[4][1]+strlen($tag_data[4][0])) : $data;
$this->Buffers[$this->Level] = preg_replace('/<!--##(.*?)##-->/s', '', $this->Buffers[$this->Level]); // remove hidden comments IB#23065
// $this->Buffers[$this->Level] .= '<?'.'php '."\n\$_parser->CacheEnd();\n}\n"." ?".">\n";
// $this->Buffers[$this->Level] = str_replace('__@@__DefinitionsMarker__@@__', $this->Definitions, $this->Buffers[$this->Level]);
return true;
}
function SplitParamsStr($params_str)
{
preg_match_all('/([\${}a-zA-Z0-9_.\\-\\\\#\\[\\]]+)=(["\']{1,1})(.*?)(?<!\\\)\\2/s', $params_str, $rets, PREG_SET_ORDER);
$values = Array();
// we need to replace all occurences of any current param $key with {$key} for correct variable substitution
foreach ($rets AS $key => $val){
$values[$val[1]] = str_replace('\\' . $val[2], $val[2], $val[3]);
}
return $values;
}
function SplitTag($tag)
{
if (!preg_match('/([^_ \t\r\n]*)[_]?([^ \t\r\n]*)[ \t\r\n]*(.*)$$/s', $tag['tag'], $parts)) {
// this is virtually impossible, but just in case
$this->Application->handleError(E_USER_ERROR, 'Incorrect tag format: '.$tag['tag'], $tag['file'], $tag['line']);
return false;
}
$splited['prefix'] = $parts[2] ? $parts[1] : '__auto__';
$splited['name'] = $parts[2] ? $parts[2] : $parts[1];
$splited['attrs'] = $parts[3];
return $splited;
}
function ProcessTag($tag)
{
$splited = $this->SplitTag($tag);
if ($splited === false) {
return false;
}
$tag = array_merge($tag, $splited);
$tag['processed'] = false;
$tag['NP'] = $this->SplitParamsStr($tag['attrs']);
$o = '';
$tag['is_closing'] = $tag['opening'] == '</' || $tag['closing'] == '/>';
if (class_exists('_Tag_'.$tag['name'])) { // block tags should have special handling class
if ($tag['opening'] == '<') {
$class = '_Tag_'.$tag['name'];
$instance = new $class($tag);
$instance->Parser =& $this;
/* @var $instance _BlockTag */
$this->Stack[++$this->Level] =& $instance;
$this->Buffers[$this->Level] = '';
$this->Cachable[$this->Level] = true;
$open_code = $instance->Open($tag);
if ($open_code === false) {
return false;
}
$o .= $open_code;
}
if ($tag['is_closing']) { // not ELSE here, because tag may be <empty/> and still has a handler-class
if ($this->Level == 0) {
$dump = array();
foreach ($this->Stack as $instance) {
$dump[] = $instance->Tag;
}
print_pre($dump);
$this->Application->handleError(E_USER_ERROR, 'Closing tag without an opening: '.$this->TagInfo($tag).' <b> - probably opening tag was removed or nested tags error</b>', $tag['file'], $tag['line']);
return false;
}
if ($this->Stack[$this->Level]->Tag['name'] != $tag['name']) {
$opening_tag = $this->Stack[$this->Level]->Tag;
$this->Application->handleError(E_USER_ERROR,
'Closing tag '.$this->TagInfo($tag).' does not match
opening tag at current nesting level ('.$this->TagInfo($opening_tag).'
opened at line '.$opening_tag['line'].')', $tag['file'], $tag['line']);
return false;
}
$o .= $this->Stack[$this->Level]->Close($tag); // DO NOT use $this->Level-- here because it's used inside Close
$this->Level--;
}
}
else { // regular tags - just compile
if (!$tag['is_closing']) {
$this->Application->handleError(E_USER_ERROR, 'Tag without a handler: '.$this->TagInfo($tag).' <b> - probably missing &lt;empty <span style="color: red">/</span>&gt; tag closing</b>', $tag['file'], $tag['line']);
return false;
}
if ($this->Level > 0) $o .= $this->Stack[$this->Level]->PassThrough($tag);
if (!$tag['processed']) {
$compiled = $this->CompileTag($tag);
if ($compiled === false) return false;
if (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] == 'false')) {
$this->Cachable[$this->Level] = false;
}
$o .= '<?'.'php ' . $compiled . " ?>\n";
// $o .= '<?'.'php ';
// $o .= (isset($tag['NP']['cachable']) && (!$tag['NP']['cachable'] || $tag['NP']['cachable'] == 'false')) ? $this->BreakCache($compiled, $this->GetPointer($tag)) : $compiled;
// $o .= " ?".">\n";
}
}
$this->Buffers[$this->Level] .= $o;
return true;
}
function GetPointer($tag)
{
return abs(crc32($tag['file'])).'_'.$tag['line'];
}
function BreakCache($code, $pointer, $condition='')
{
return "\$_parser->CacheEnd();\n}\n" . $code."\nif ( !\$_parser->CacheStart('{$pointer}'" . ($condition ? ", {$condition}" : '') . ") ) {\n";
}
function TagInfo($tag, $with_params=false)
{
return "<b>{$tag['prefix']}_{$tag['name']}".($with_params ? ' '.$tag['attrs'] : '')."</b>";
}
function CompileParamsArray($arr)
{
$to_pass = 'Array(';
foreach ($arr as $name => $val) {
$to_pass .= '"'.$name.'" => "'.str_replace('"', '\"', $val).'",';
}
$to_pass .= ')';
return $to_pass;
}
function CompileTag($tag)
{
$to_pass = $this->CompileParamsArray($tag['NP']);
$code = '';
if ($tag['prefix'] == '__auto__') {
$prefix = $this->GetParam('PrefixSpecial');
$code .= '$_p_ =& $_parser->GetProcessor($PrefixSpecial);'."\n";
$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "$PrefixSpecial", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
}
else {
$prefix = $tag['prefix'];
$code .= '$_p_ =& $_parser->GetProcessor("'.$tag['prefix'].'");'."\n";
$code .= 'echo $_p_->ProcessParsedTag(\''.$tag['name'].'\', '.$to_pass.', "'.$tag['prefix'].'", \''.$tag['file'].'\', '.$tag['line'].');'."\n";
}
if (isset($tag['NP']['result_to_var'])) {
$code .= "\$params['{$tag['NP']['result_to_var']}'] = \$_parser->GetParam('{$tag['NP']['result_to_var']}');\n";
$code .= "\${$tag['NP']['result_to_var']} = \$params['{$tag['NP']['result_to_var']}'];\n";
}
if ($prefix && strpos($prefix, '$') === false) {
$p =& $this->GetProcessor($prefix);
if (!is_object($p) || !$p->CheckTag($tag['name'], $tag['prefix'])) {
$this->Application->handleError(E_USER_ERROR, 'Unknown tag: '.$this->TagInfo($tag).' <b> - incorrect tag name or prefix </b>', $tag['file'], $tag['line']);
return false;
}
}
return $code;
}
- function CheckTemplate($t, $silent=null)
+ function CheckTemplate($t, $silent = null)
{
$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($t);
if (!$pre_parsed) {
if (!$silent) {
- if ($this->Application->isDebugMode()) $this->Application->Debugger->appendTrace();
+ if ($this->Application->isDebugMode()) {
+ $this->Application->Debugger->appendTrace();
+ }
+
trigger_error('Cannot include "<strong>' . $t . '</strong>" - file does not exist', E_USER_ERROR);
}
+
return false;
}
$force_compile = defined('DBG_NPARSER_FORCE_COMPILE') && DBG_NPARSER_FORCE_COMPILE;
if (!$pre_parsed || !$pre_parsed['active'] || $force_compile) {
$inc_parser = new NParser();
if ($force_compile) {
// remove Front-End theme markings during total compilation
$t = preg_replace('/^theme:.*?\//', '', $t);
}
- if (!$inc_parser->Compile($pre_parsed, $t)) return false;
+ if (!$inc_parser->Compile($pre_parsed, $t)) {
+ return false;
+ }
}
+
return $pre_parsed;
}
- function Run($t, $silent=null)
+ function Run($t, $silent = null)
{
if ((strpos($t, '../') !== false) || (trim($t) !== $t)) {
// when relative paths or special chars are found template names from url, then it's hacking attempt
return false;
}
$pre_parsed = $this->CheckTemplate($t, $silent);
- if (!$pre_parsed) return false;
+ if (!$pre_parsed) {
+ return false;
+ }
+
$backup_template = $this->TemplateName;
$backup_fullpath = $this->TempalteFullPath;
$this->TemplateName = $t;
$this->TempalteFullPath = $pre_parsed['tname'];
- ob_start();
- $_parser =& $this;
- if (defined('SAFE_MODE') && SAFE_MODE) { // read cache files from database since can't save on filesystem
- $conn =& $this->Application->GetADODBConnection();
- $cached = $conn->GetRow('SELECT * FROM '.TABLE_PREFIX.'Cache WHERE VarName = "'.$pre_parsed['fname'].'"');
- if ($cached !== false && $cached['Cached'] > filemtime($pre_parsed['tname'])) {
- eval('?'.'>'.$cached['Data']);
- }
- }
- else {
- if ($pre_parsed['mode'] == 'file') {
- include($pre_parsed['fname']);
- }
- else {
- eval('?'.'>'.$pre_parsed['content']);
- }
- }
- $output = ob_get_contents();
- ob_end_clean();
+ $output =& $this->Application->TemplatesCache->runTemplate($this, $pre_parsed);
$this->TemplateName = $backup_template;
$this->TempalteFullPath = $backup_fullpath;
return $output;
}
function &GetProcessor($prefix)
{
static $Processors = array();
if (!isset($Processors[$prefix])) {
$Processors[$prefix] = $this->Application->recallObject($prefix.'_TagProcessor');
}
return $Processors[$prefix];
}
function SelectParam($params, $possible_names)
{
if (!is_array($params)) return;
if (!is_array($possible_names))
$possible_names = explode(',', $possible_names);
foreach ($possible_names as $name)
{
if( isset($params[$name]) ) return $params[$name];
}
return false;
}
function SetParams($params)
{
$this->Params = $params;
$keys = array_keys($this->Params);
}
function GetParam($name)
{
return isset($this->Params[$name]) ? $this->Params[$name] : false;
}
function SetParam($name, $value)
{
$this->Params[$name] = $value;
}
function PushParams($params)
{
$this->ParamsStack[$this->ParamsLevel++] = $this->Params;
$this->Params = $params;
}
function PopParams()
{
$this->Params = $this->ParamsStack[--$this->ParamsLevel];
}
function ParseBlock($params, $pass_params=false)
{
if (isset($params['cache_timeout']) && ($ret = $this->CacheGet($this->FormCacheKey('element_'.$params['name'])))) {
return $ret;
}
if (substr($params['name'], 0, 5) == 'html:') {
return substr($params['name'], 6);
}
if (!array_key_exists($params['name'], $this->Elements) && array_key_exists('default_element', $params)) {
// when given element not found, but default element name given, then render it instead
$params['name'] = $params['default_element'];
unset($params['default_element']);
return $this->ParseBlock($params, $pass_params);
}
$original_params = $params;
if ($pass_params || isset($params['pass_params'])) $params = array_merge($this->Params, $params);
$this->PushParams($params);
$data_exists_bak = $this->DataExists;
// if we are parsing design block and we have block_no_data - we need to wrap block_no_data into design,
// so we should set DataExists to true manually, otherwise the design block will be skipped because of data_exists in params (by Kostja)
//
// keep_data_exists is used by block RenderElement (always added in ntags.php), to keep the DataExists value
// from inside-content block, otherwise when parsing the design block DataExists will be reset to false resulting missing design block (by Kostja)
//
// Inside-content block parsing result is given to design block in "content" parameter (ntags.php) and "keep_data_exists"
// is only passed, when parsing design block. In case, when $this->DataExists is set to true, but
// zero-length content (in 2 cases: method NParser::CheckNoData set it OR really empty block content)
// is returned from inside-content block, then design block also should not be shown (by Alex)
$this->DataExists = (isset($params['keep_data_exists']) && isset($params['content']) && $params['content'] != '' && $this->DataExists) || (isset($params['design']) && isset($params['block_no_data']) && $params['name'] == $params['design']);
if (!array_key_exists($params['name'], $this->Elements)) {
$pre_parsed = $this->Application->TemplatesCache->GetPreParsed($params['name']);
if ($pre_parsed) {
$ret = $this->IncludeTemplate($params);
if (array_key_exists('no_editing', $params) && $params['no_editing']) {
// when individual render element don't want to be edited
return $ret;
}
return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params, true) : $ret;
}
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
$trace_results = debug_backtrace();
$this->Application->handleError(E_USER_ERROR, '<b>Rendering of undefined element '.$params['name'].'</b>', $trace_results[0]['file'], $trace_results[0]['line']);
return false;
}
$m_processor =& $this->GetProcessor('m');
$flag_values = $m_processor->PreparePostProcess($params);
$f_name = $this->Elements[$params['name']];
$ret = $f_name($this, $params);
$ret = $m_processor->PostProcess($ret, $flag_values);
$block_params = $this->Params; // input parameters, but modified inside rendered block
$this->PopParams();
$this->CheckNoData($ret, $params);
$this->DataExists = $data_exists_bak || $this->DataExists;
if (isset($original_params['cache_timeout'])) {
$this->CacheSet($this->FormCacheKey('element_'.$original_params['name']), $ret, $original_params['cache_timeout']);
}
if (array_key_exists('no_editing', $block_params) && $block_params['no_editing']) {
// when individual render element don't want to be edited
return $ret;
}
return defined('EDITING_MODE') ? $this->DecorateBlock($ret, $params) : $ret;
}
function DecorateBlock($block_content, $block_params, $is_template = false)
{
static $used_ids = Array (), $base_url = null;
if (!isset($base_url)) {
$base_url = $this->Application->BaseURL();
}
// $prepend = '[name: ' . $block_params['name'] . '] [params: ' . implode(', ', array_keys($block_params)) . ']';
$decorate = false;
$design = false;
if (EDITING_MODE == EDITING_MODE_DESIGN) {
$decorate = true;
if ($is_template) {
// content inside pair RenderElement tag
}
else {
if (strpos($block_params['name'], '__capture_') === 0) {
// capture tag (usually inside pair RenderElement)
}
elseif (array_key_exists('content', $block_params)) {
// pair RenderElement (on template, were it's used)
$design = true;
}
}
}
if (!$decorate) {
return $block_content;
}
else {
$block_content = /*$prepend .*/ $block_content;
}
$block_name = $block_params['name'];
$function_name = $is_template ? $block_name : $this->Elements[$block_name];
$block_title = '';
if (array_key_exists($function_name, $this->Application->Parser->ElementLocations)) {
$element_location = $this->Application->Parser->ElementLocations[$function_name];
$block_title .= $element_location['template'] . '.tpl';
$block_title .= ' (' . $element_location['start_pos'] . ' - ' . $element_location['end_pos'] . ')';
}
// ensure unique id for every div (used from print lists)
$container_num = 1;
$container_id = 'parser_block[' . $function_name . ']';
while (in_array($container_id . '_' . $container_num, $used_ids)) {
$container_num++;
}
$container_id .= '_' . $container_num;
$used_ids[] = $container_id;
// prepare parameter string
$param_string = $block_name . ':' . $function_name;
if ($design) {
$btn_text = 'Edit design';
$btn_class = 'cms-edit-design-btn';
$btn_container_class = 'block-edit-design-btn-container';
}
else {
$btn_text = 'Edit block';
$btn_class = 'cms-edit-block-btn';
$btn_container_class = 'block-edit-block-btn-container';
}
$block_editor = '
<div id="' . $container_id . '" params="' . $param_string . '" class="' . $btn_container_class . '" title="' . htmlspecialchars($block_title) . '">
<div class="' . $btn_class . '">
<div class="cms-btn-image">
<img src="' . $base_url . 'core/admin_templates/img/top_frame/icons/content_mode.gif" width="15" height="16" alt=""/>
</div>
<div class="cms-btn-text" id="' . $container_id . '_btn">' . $btn_text . '</div>
</div>
<div class="cms-btn-content">
%s
</div>
</div>';
// 1 - text before, 2 - open tag, 3 - open tag attributes, 4 - content inside tag, 5 - closing tag, 6 - text after closing tag
if (preg_match('/^(\s*)<(td|span)(.*?)>(.*)<\/(td|span)>(.*)$/is', $block_content, $regs)) {
// div inside span -> put div outside span
return $regs[1] . '<' . $regs[2] . ' ' . $regs[3] . '>' . str_replace('%s', $regs[4], $block_editor) . '</' . $regs[5] . '>' . $regs[6];
}
return str_replace('%s', $block_content, $block_editor);
}
function IncludeTemplate($params, $silent=null)
{
$t = is_array($params) ? $this->SelectParam($params, 't,template,block,name') : $params;
if (isset($params['cache_timeout']) && ($ret = $this->CacheGet('template:'.$t))) {
return $ret;
}
$t = eregi_replace("\.tpl$", '', $t);
$data_exists_bak = $this->DataExists;
$this->DataExists = false;
if (!isset($silent) && array_key_exists('is_silent', $params)) {
$silent = $params['is_silent'];
}
if (isset($params['pass_params'])) {
// ability to pass params from block to template
$params = array_merge($this->Params, $params);
}
$this->PushParams($params);
$ret = $this->Run($t, $silent);
$this->PopParams();
$this->CheckNoData($ret, $params);
$this->DataExists = $data_exists_bak || $this->DataExists;
if (isset($params['cache_timeout'])) {
$this->CacheSet('template:'.$t, $ret, $params['cache_timeout']);
}
return $ret;
}
function CheckNoData(&$ret, $params)
{
if (array_key_exists('data_exists', $params) && $params['data_exists'] && !$this->DataExists) {
$block_no_data = isset($params['BlockNoData']) ? $params['BlockNoData'] : (isset($params['block_no_data']) ? $params['block_no_data'] : false);
if ($block_no_data) {
$ret = $this->ParseBlock(array('name'=>$block_no_data));
}
else {
$ret = '';
}
}
}
function CacheGet($name)
{
if (!$this->Application->ConfigValue('SystemTagCache')) return false;
return $this->Application->CacheGet($name);
}
function CacheSet($name, $value, $expiration=0)
{
if (!$this->Application->ConfigValue('SystemTagCache')) return false;
return $this->Application->CacheSet($name, $value, $expiration);
}
function FormCacheKey($element, $file=null, $add_prefixes=null)
{
if (!isset($file)) {
$file = str_replace(FULL_PATH, '', $this->TempalteFullPath).':'.$this->Application->GetVar('t');
}
$parts = array(
'file_'.$file.'('.filemtime($this->TempalteFullPath).')' => 'serials:file_ts', // theme + template timestamp
'm_lang_'.$this->Application->GetVar('m_lang') => 'serials:lang_ts',
'm_cat_id_'.$this->Application->GetVar('m_cat_id') => 'serials:cat_'.$this->Application->GetVar('m_cat_id').'_ts',
'm_cat_page'.$this->Application->GetVar('m_cat_page') => false,
);
if (isset($add_prefixes)) {
foreach ($add_prefixes as $prefix) {
$parts[$prefix.'_id_'.$this->Application->GetVar("{$prefix}_id")] = "serials:$prefix_".$this->Application->GetVar("{$prefix}_id").'_ts';
$parts[$prefix.'_page_'.$this->Application->GetVar("{$prefix}_Page")] = false;
}
}
$key = '';
foreach ($parts as $part => $ts_name) {
if ($ts_name) {
$ts = $this->Application->CacheGet($ts_name);
$key .= "$part($ts):";
}
else {
$key .= "$part:";
}
}
$key .= $element;
return crc32($key);
}
function PushPointer($pointer)
{
$this->CachePointers[++$this->CacheLevel] = $this->FormCacheKey('pointer:'.$pointer);
return $this->CachePointers[$this->CacheLevel];
}
function PopPointer()
{
return $this->CachePointers[$this->CacheLevel--];
}
function CacheStart($pointer=null)
{
if ($ret = $this->CacheGet($this->PushPointer($pointer)) ) {
echo $ret;
$this->PopPointer();
return true;
}
ob_start();
return false;
}
function CacheEnd($elem=null)
{
$ret = ob_get_clean();
$this->CacheSet($this->PopPointer(), $ret); // . ($this->CurrentKeyPart ? ':'.$this->CurrentKeyPart : '')
echo $ret;
}
-
- function _compress($src) {
- // Whitespaces left and right from this signs can be ignored
- static $IW = array(
- T_CONCAT_EQUAL, // .=
- T_DOUBLE_ARROW, // =>
- T_BOOLEAN_AND, // &&
- T_BOOLEAN_OR, // ||
- T_IS_EQUAL, // ==
- T_IS_NOT_EQUAL, // != or <>
- T_IS_SMALLER_OR_EQUAL, // <=
- T_IS_GREATER_OR_EQUAL, // >=
- T_INC, // ++
- T_DEC, // --
- T_PLUS_EQUAL, // +=
- T_MINUS_EQUAL, // -=
- T_MUL_EQUAL, // *=
- T_DIV_EQUAL, // /=
- T_IS_IDENTICAL, // ===
- T_IS_NOT_IDENTICAL, // !==
- T_DOUBLE_COLON, // ::
- T_PAAMAYIM_NEKUDOTAYIM, // ::
- T_OBJECT_OPERATOR, // ->
- T_DOLLAR_OPEN_CURLY_BRACES, // ${
- T_AND_EQUAL, // &=
- T_MOD_EQUAL, // %=
- T_XOR_EQUAL, // ^=
- T_OR_EQUAL, // |=
- T_SL, // <<
- T_SR, // >>
- T_SL_EQUAL, // <<=
- T_SR_EQUAL, // >>=
- );
-
- $tokens = token_get_all($src);
-
- $new = "";
- $c = sizeof($tokens);
- $iw = false; // ignore whitespace
- $ih = false; // in HEREDOC
- $ls = ""; // last sign
- $ot = null; // open tag
-
- for ($i = 0; $i < $c; $i++) {
- $token = $tokens[$i];
-
- if (is_array($token)) {
- list ($tn, $ts) = $token; // tokens: number, string, line
- $tname = token_name($tn);
-
- if ($tn == T_INLINE_HTML) {
- $new .= $ts;
- $iw = false;
- } else {
- if ($tn == T_OPEN_TAG) {
- if (strpos($ts, " ") || strpos($ts, "\n") || strpos($ts, "\t") || strpos($ts, "\r")) {
- $ts = rtrim($ts);
- }
-
- $ts .= " ";
- $new .= $ts;
- $ot = T_OPEN_TAG;
- $iw = true;
- } elseif ($tn == T_OPEN_TAG_WITH_ECHO) {
- $new .= $ts;
- $ot = T_OPEN_TAG_WITH_ECHO;
- $iw = true;
- } elseif ($tn == T_CLOSE_TAG) {
- if ($ot == T_OPEN_TAG_WITH_ECHO) {
- $new = rtrim($new, "; ");
- } else {
- $ts = " ".$ts;
- }
-
- $new .= $ts;
- $ot = null;
- $iw = false;
- } elseif (in_array($tn, $IW)) {
- $new .= $ts;
- $iw = true;
- } elseif ($tn == T_CONSTANT_ENCAPSED_STRING || $tn == T_ENCAPSED_AND_WHITESPACE) {
- if ($ts[0] == '"') {
- $ts = addcslashes($ts, "\n\t\r");
- }
-
- $new .= $ts;
- $iw = true;
- } elseif ($tn == T_WHITESPACE) {
- $nt = @$tokens[$i+1];
- if (!$iw && (!is_string($nt) || $nt == '$') && !in_array($nt[0], $IW)) {
- $new .= " ";
- }
-
- $iw = false;
- } elseif ($tn == T_START_HEREDOC) {
- $new .= "<<<S\n";
- $iw = false;
- $ih = true; // in HEREDOC
- } elseif ($tn == T_END_HEREDOC) {
- $new .= "S;";
- $iw = true;
- $ih = false; // in HEREDOC
- for ($j = $i + 1; $j < $c; $j++) {
- if (is_string($tokens[$j]) && $tokens[$j] == ";") {
- $i = $j;
- break;
- } else if ($tokens[$j][0] == T_CLOSE_TAG) {
- break;
- }
- }
- } elseif ($tn == T_COMMENT || $tn == T_DOC_COMMENT) {
- $iw = true;
- } else {
- /*if (!$ih) {
- // this also lowecases attribute names :(
- $ts = strtolower($ts);
- }*/
-
- $new .= $ts;
- $iw = false;
- }
- }
-
- $ls = "";
- } else {
- if (($token != ";" && $token != ":") || $ls != $token) {
- $new .= $token;
- $ls = $token;
- }
-
- $iw = true;
- }
- }
-
- return $new;
- }
}
\ No newline at end of file
Index: branches/5.0.x/core/kernel/nparser/template_cache.php
===================================================================
--- branches/5.0.x/core/kernel/nparser/template_cache.php (nonexistent)
+++ branches/5.0.x/core/kernel/nparser/template_cache.php (revision 12323)
@@ -0,0 +1,440 @@
+<?php
+/**
+* @version $Id$
+* @package In-Portal
+* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
+* @license GNU/GPL
+* In-Portal is Open Source software.
+* This means that this software may have been modified pursuant
+* the GNU General Public License, and as distributed it includes
+* or is derivative of works licensed under the GNU General Public License
+* or other free or open source software licenses.
+* See http://www.in-portal.net/license/ for copyright notices and details.
+*/
+
+defined('FULL_PATH') or die('restricted access!');
+
+class TemplatesCache extends kHelper {
+
+ /**
+ * Base path for searching templates
+ *
+ * @var string
+ */
+ var $BasePath;
+
+ /**
+ * Force templates cache to search templates on front-end:
+ * true - search for theme name in template name
+ * false - don't search anywhere
+ * name - theme name to prepend for each template name
+ *
+ * @var mixed
+ */
+ var $forceThemeName = false;
+
+ /**
+ * Compile templates to database
+ *
+ * @var bool
+ */
+ var $_compileToDatabase = false;
+
+ /**
+ * Compress compiled templates
+ *
+ * @var bool
+ */
+ var $_compressOutput = false;
+
+ /**
+ * Tells, that we are in administrative console (for performance)
+ *
+ * @var bool
+ */
+ var $_isAdmin = false;
+
+ function TemplatesCache()
+ {
+ parent::kBase();
+
+ $this->BasePath = FULL_PATH . THEMES_PATH;
+
+ $this->_compileToDatabase = defined('SAFE_MODE') && SAFE_MODE;
+ $this->_compressOutput = $this->Application->ConfigValue('UseTemplateCompression');
+ $this->_isAdmin = $this->Application->IsAdmin();
+ }
+
+ /**
+ * Based on template name gets it's location on disk and owner module
+ *
+ * @param string $filename
+ * @return Array 0 - path on disk, 1 - template name
+ */
+ function GetTemplatePaths($filename)
+ {
+ if ($this->_isAdmin && array_key_exists($filename, $this->Application->ReplacementTemplates)) {
+ $filename = $this->Application->ReplacementTemplates[$filename];
+ }
+
+ // allows to use non-replaced version of replaced template
+ $filename = preg_replace('/^original:(.*)/', '\\1', $filename);
+
+ if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $filename, $regs)) {
+ $module_filename = $regs[2];
+ $first_dir = $regs[1];
+ }
+ else {
+ $first_dir = '';
+ $module_filename = $filename;
+ }
+
+ if (is_string($this->forceThemeName)) {
+ // when defined, then all templates are read from given theme name
+ $first_dir = 'theme:' . $this->forceThemeName . ($first_dir ? '/' . $first_dir : '');
+ }
+
+ // !preg_match for backward compatability with full-path plugins
+ if ($this->_isAdmin && ($first_dir == 'plugins') && !preg_match('/admin_templates/', $module_filename)) {
+ if (preg_match('#^[\/]{0,1}([^\/]*)\/(.*)#', $module_filename, $regs)) {;
+ $path = MODULES_PATH.'/'.mb_strtolower($first_dir).'/'.$regs[1].'/admin_templates';
+ $module_filename = $regs[2];
+ }
+ else {
+ $first_dir = '';
+ $module_filename = $filename;
+ }
+ }
+ elseif ($this->_isAdmin && $this->Application->findModule('Name', $first_dir)) {
+ /*if ($first_dir == 'in-portal') {
+ $first_dir = 'kernel';
+ }*/
+ $path = MODULES_PATH.'/'.mb_strtolower($first_dir).'/admin_templates';
+ }
+ elseif ($this->forceThemeName && preg_match('/^theme:(.*)/', $first_dir, $regs)) {
+ // ability to use Front-End templates in admin (only during mass compilation)
+ $path = FULL_PATH . '/themes/' . $regs[1];
+ }
+ else {
+ $path = $this->BasePath;
+ $module_filename = $first_dir.'/'.$module_filename;
+ }
+
+ return Array ($path, $module_filename);
+ }
+
+ /**
+ * Returns template filename by given template name
+ *
+ * @param string $filename
+ * @return string
+ */
+ function GetRealFilename($filename)
+ {
+ list ($path, $module_filename) = $this->GetTemplatePaths($filename);
+ return $path.'/'.trim($module_filename, '/');
+ }
+
+ /**
+ * Checks, that given template exists on disk
+ *
+ * @param string $filename
+ * @return bool
+ */
+ function TemplateExists($filename)
+ {
+ if ((strpos($filename, '../') !== false) || (trim($filename) !== $filename)) {
+ // when relative paths or special chars are found template names from url, then it's hacking attempt
+ return false;
+ }
+
+ $real_file = $this->GetRealFilename( strtolower($filename) );
+ if (substr($real_file, -4) != '.tpl') {
+ // add ".tpl" file extension, when not specified in template name
+ $real_file .= '.tpl';
+ }
+
+ return file_exists($real_file);
+ }
+
+ /**
+ * Returns information about template compilation status
+ *
+ * @param string $template
+ * @return Array
+ */
+ function GetPreParsed($template)
+ {
+ $real_name = $this->GetRealFilename($template);
+ $fname = str_replace(FULL_PATH, WRITEABLE . '/cache', $real_name . '.php');
+
+ $tname = $real_name . '.tpl';
+ if (!file_exists($tname)) {
+ // given template doesn't exist
+ return false;
+ }
+
+ if ($this->_compileToDatabase) {
+ $sql = 'SELECT *
+ FROM ' . TABLE_PREFIX . 'Cache
+ WHERE VarName = "' . $fname . '"';
+ $cached = $this->Conn->GetRow($sql);
+
+ if ($cached !== false && $cached['Cached'] > filemtime($tname)) {
+ return Array ('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'db', 'content' => $cached['Data']);
+ }
+ }
+ else {
+ if (file_exists($fname) && file_exists($tname) && filemtime($fname) > filemtime($tname)) {
+ return Array ('active' => 1, 'fname' => $fname, 'tname' => $tname, 'mode' => 'file');
+ }
+
+ if (!file_exists($fname)) {
+ // make sure to create directory if pre-parsed file does not exist
+ $this->CheckDir(dirname($fname), WRITEABLE . '/cache');
+ }
+ }
+
+ // when compiled template is expired or doesn't exist
+
+ return Array ('active' => 0, 'fname' => $fname, 'tname' => $tname, 'mode' => 'file');
+ }
+
+ /**
+ * Saves compiled template version to database or disk
+ *
+ * @param string $filename
+ * @param string $compiled_template
+ */
+ function saveTemplate($filename, &$compiled_template)
+ {
+ if ($this->_compileToDatabase) {
+ $fields_hash = Array (
+ 'VarName' => $filename,
+ 'Data' => &$compiled_template,
+ 'Cached' => adodb_mktime(),
+ );
+
+ $this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Cache', 'REPLACE');
+ }
+ else {
+ $fp = fopen($filename, 'w');
+
+ if ($this->_compressOutput) {
+ $compiled_template = $this->_compress($compiled_template);
+ }
+
+ if (!fwrite($fp, $compiled_template)) {
+ trigger_error('Saving compiled template failed', E_USER_ERROR);
+ }
+
+ fclose($fp);
+ }
+ }
+
+ /**
+ * Runs template and returns result (template already should be compiled by now)
+ *
+ * @param NParser $_parser
+ * @param Array $pre_parsed
+ * @return string
+ */
+ function &runTemplate(&$_parser, &$pre_parsed)
+ {
+ ob_start();
+
+ if ($this->_compileToDatabase) {
+ $sql = 'SELECT *
+ FROM ' . TABLE_PREFIX . 'Cache
+ WHERE VarName = "' . $pre_parsed['fname'] . '"';
+
+ $cached = $this->Conn->GetRow($sql);
+
+ if (($cached !== false) && ($cached['Cached'] > filemtime($pre_parsed['tname']))) {
+ eval('?' . '>' . $cached['Data']);
+ }
+ }
+ else {
+ if ($pre_parsed['mode'] == 'file') {
+ include($pre_parsed['fname']);
+ }
+ else {
+ eval('?' . '>' . $pre_parsed['content']);
+ }
+ }
+
+ $output = ob_get_clean();
+
+ return $output;
+ }
+
+ /**
+ * Compress given php code
+ *
+ * @param string $src
+ * @return string
+ */
+ function _compress($src) {
+ // Whitespaces left and right from this signs can be ignored
+ static $IW = array(
+ T_CONCAT_EQUAL, // .=
+ T_DOUBLE_ARROW, // =>
+ T_BOOLEAN_AND, // &&
+ T_BOOLEAN_OR, // ||
+ T_IS_EQUAL, // ==
+ T_IS_NOT_EQUAL, // != or <>
+ T_IS_SMALLER_OR_EQUAL, // <=
+ T_IS_GREATER_OR_EQUAL, // >=
+ T_INC, // ++
+ T_DEC, // --
+ T_PLUS_EQUAL, // +=
+ T_MINUS_EQUAL, // -=
+ T_MUL_EQUAL, // *=
+ T_DIV_EQUAL, // /=
+ T_IS_IDENTICAL, // ===
+ T_IS_NOT_IDENTICAL, // !==
+ T_DOUBLE_COLON, // ::
+ T_PAAMAYIM_NEKUDOTAYIM, // ::
+ T_OBJECT_OPERATOR, // ->
+ T_DOLLAR_OPEN_CURLY_BRACES, // ${
+ T_AND_EQUAL, // &=
+ T_MOD_EQUAL, // %=
+ T_XOR_EQUAL, // ^=
+ T_OR_EQUAL, // |=
+ T_SL, // <<
+ T_SR, // >>
+ T_SL_EQUAL, // <<=
+ T_SR_EQUAL, // >>=
+ );
+
+ $tokens = token_get_all($src);
+
+ $new = "";
+ $c = sizeof($tokens);
+ $iw = false; // ignore whitespace
+ $ih = false; // in HEREDOC
+ $ls = ""; // last sign
+ $ot = null; // open tag
+
+ for ($i = 0; $i < $c; $i++) {
+ $token = $tokens[$i];
+
+ if (is_array($token)) {
+ list ($tn, $ts) = $token; // tokens: number, string, line
+ $tname = token_name($tn);
+
+ if ($tn == T_INLINE_HTML) {
+ $new .= $ts;
+ $iw = false;
+ } else {
+ if ($tn == T_OPEN_TAG) {
+ if (strpos($ts, " ") || strpos($ts, "\n") || strpos($ts, "\t") || strpos($ts, "\r")) {
+ $ts = rtrim($ts);
+ }
+
+ $ts .= " ";
+ $new .= $ts;
+ $ot = T_OPEN_TAG;
+ $iw = true;
+ } elseif ($tn == T_OPEN_TAG_WITH_ECHO) {
+ $new .= $ts;
+ $ot = T_OPEN_TAG_WITH_ECHO;
+ $iw = true;
+ } elseif ($tn == T_CLOSE_TAG) {
+ if ($ot == T_OPEN_TAG_WITH_ECHO) {
+ $new = rtrim($new, "; ");
+ } else {
+ $ts = " ".$ts;
+ }
+
+ $new .= $ts;
+ $ot = null;
+ $iw = false;
+ } elseif (in_array($tn, $IW)) {
+ $new .= $ts;
+ $iw = true;
+ } elseif ($tn == T_CONSTANT_ENCAPSED_STRING || $tn == T_ENCAPSED_AND_WHITESPACE) {
+ if ($ts[0] == '"') {
+ $ts = addcslashes($ts, "\n\t\r");
+ }
+
+ $new .= $ts;
+ $iw = true;
+ } elseif ($tn == T_WHITESPACE) {
+ $nt = @$tokens[$i+1];
+ if (!$iw && (!is_string($nt) || $nt == '$') && !in_array($nt[0], $IW)) {
+ $new .= " ";
+ }
+
+ $iw = false;
+ } elseif ($tn == T_START_HEREDOC) {
+ $new .= "<<<S\n";
+ $iw = false;
+ $ih = true; // in HEREDOC
+ } elseif ($tn == T_END_HEREDOC) {
+ $new .= "S;";
+ $iw = true;
+ $ih = false; // in HEREDOC
+ for ($j = $i + 1; $j < $c; $j++) {
+ if (is_string($tokens[$j]) && $tokens[$j] == ";") {
+ $i = $j;
+ break;
+ } else if ($tokens[$j][0] == T_CLOSE_TAG) {
+ break;
+ }
+ }
+ } elseif ($tn == T_COMMENT || $tn == T_DOC_COMMENT) {
+ $iw = true;
+ } else {
+ /*if (!$ih) {
+ // this also lowecases attribute names :(
+ $ts = strtolower($ts);
+ }*/
+
+ $new .= $ts;
+ $iw = false;
+ }
+ }
+
+ $ls = "";
+ } else {
+ if (($token != ";" && $token != ":") || $ls != $token) {
+ $new .= $token;
+ $ls = $token;
+ }
+
+ $iw = true;
+ }
+ }
+
+ return $new;
+ }
+
+ /**
+ * Recursive mkdir
+ *
+ * @param string $dir
+ * @param string $base_path base path to directory where folders should be created in
+ */
+ function CheckDir($dir, $base_path = '')
+ {
+ if (file_exists($dir)) {
+ return;
+ }
+ else {
+ // remove $base_path from beggining because it is already created during install
+ $dir = preg_replace('/^'.preg_quote($base_path.'/', '/').'/', '', $dir, 1);
+ $segments = explode('/', $dir);
+ $cur_path = $base_path;
+
+ foreach ($segments as $segment) {
+ // do not add leading / for windows paths (c:\...)
+ $cur_path .= preg_match('/^[a-zA-Z]{1}:/', $segment) ? $segment : '/'.$segment;
+ if (!file_exists($cur_path)) {
+ mkdir($cur_path);
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
Property changes on: branches/5.0.x/core/kernel/nparser/template_cache.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.26.2.6
\ No newline at end of property
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+Id
\ No newline at end of property
Index: branches/5.0.x/core/units/admin/admin_events_handler.php
===================================================================
--- branches/5.0.x/core/units/admin/admin_events_handler.php (revision 12322)
+++ branches/5.0.x/core/units/admin/admin_events_handler.php (revision 12323)
@@ -1,1220 +1,1221 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class AdminEventsHandler extends kDBEventHandler {
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnSaveColumns' => array('self' => true),
'OnClosePopup' => array('self' => true),
'OnSaveSetting' => array('self' => true),
// export/import permissions is checked within events
'OnExportCSV' => Array('self' => true),
'OnGetCSV' => Array('self' => true),
'OnCSVImportBegin' => Array('self' => true),
'OnCSVImportStep' => Array('self' => true),
'OnDropTempTablesByWID' => Array('self' => true),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Checks permissions of user
*
* @param kEvent $event
*/
function CheckPermission(&$event)
{
$system_events = Array (
'OnResetModRwCache', 'OnResetCMSMenuCache', 'OnResetSections',
'OnResetConfigsCache', 'OnCompileTemplates', 'OnGenerateTableStructure',
'OnRebuildThemes', 'OnCheckPrefixConfig',
);
if ($this->Application->isDebugMode(false) && in_array($event->Name, $system_events)) {
return true;
}
$tools_events = Array (
'OnBackup' => 'in-portal:backup.view',
'OnBackupProgress' => 'in-portal:backup.view',
'OnDeleteBackup' => 'in-portal:backup.view',
'OnBackupCancel' => 'in-portal:backup.view',
'OnRestore' => 'in-portal:restore.view',
'OnRestoreProgress' => 'in-portal:restore.view',
'OnRestoreCancel' => 'in-portal:backup.view',
'OnSqlQuery' => 'in-portal:sql_query.view',
);
if (array_key_exists($event->Name, $tools_events)) {
return $this->Application->CheckPermission($tools_events[$event->Name]);
}
if ($event->Name == 'OnSaveMenuFrameWidth') {
if (!$this->Application->IsAdmin() || !$this->Application->LoggedIn()) {
return false;
}
return true;
}
return parent::CheckPermission($event);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnResetModRwCache(&$event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = erSTOP;
}
$this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName LIKE "mod_rw%"');
}
function OnResetCMSMenuCache(&$event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = erSTOP;
}
$this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName IN ("cms_menu", "StructureTree")');
}
function OnResetSections(&$event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = erSTOP;
}
$this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "sections_parsed"');
if (isset($this->Application->Memcached)) {
$this->Application->Memcached->delete('master:sections_parsed');
}
}
function OnResetConfigsCache(&$event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = erSTOP;
}
$this->Conn->Query('DELETE FROM '.TABLE_PREFIX.'Cache WHERE VarName = "config_files" OR VarName = "configs_parsed" OR VarName = "sections_parsed"');
if (isset($this->Application->Memcached)) {
$this->Application->Memcached->delete('master:config_files');
$this->Application->Memcached->delete('master:configs_parsed');
$this->Application->Memcached->delete('master:sections_parsed');
}
}
function OnCompileTemplates(&$event)
{
$compiler =& $this->Application->recallObject('NParserCompiler');
/* @var $compiler NParserCompiler */
+
$compiler->CompileTemplatesStep();
$event->status = erSTOP;
}
/**
* Generates sturcture for specified table
*
* @param kEvent $event
* @author Alex
*/
function OnGenerateTableStructure(&$event)
{
$types_hash = Array(
'string' => 'varchar|text|mediumtext|longtext|date|datetime|time|timestamp|char|year|enum|set',
'int' => 'smallint|mediumint|int|bigint|tinyint',
'float' => 'float|double|decimal',
);
$table_name = $this->Application->GetVar('table_name');
if (!$table_name) {
echo 'error: no table name specified';
return ;
}
if (TABLE_PREFIX && !preg_match('/^'.preg_quote(TABLE_PREFIX, '/').'(.*)/', $table_name) && (strtolower($table_name) != $table_name)) {
// table name without prefix, then add it (don't affect K3 tables named in lowercase)
$table_name = TABLE_PREFIX.$table_name;
}
if (!$this->Conn->TableFound($table_name)) {
// table with prefix doesn't exist, assume that just config prefix passed -> resolve table name from it
$prefix = preg_replace('/^' . preg_quote(TABLE_PREFIX, '/') . '/', '', $table_name);
if ($this->Application->prefixRegistred($prefix)) {
// when prefix is found -> use it's table (don't affect K3 tables named in lowecase)
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
}
}
$table_info = $this->Conn->Query('DESCRIBE '.$table_name);
// 1. prepare config keys
$grids = Array (
'Default' => Array (
'Icons' => Array ('default' => 'icon16_custom.gif'),
'Fields' => Array (),
)
);
$grid_fields = Array();
$id_field = '';
$fields = Array();
$float_types = Array ('float', 'double', 'numeric');
foreach ($table_info as $field_info) {
if (preg_match('/l[\d]+_.*/', $field_info['Field'])) {
// don't put multilingual fields in config
continue;
}
$field_options = Array ();
$grid_col_options = Array(
'title' => 'la_col_' . $field_info['Field'],
'filter_block' => 'grid_like_filter',
);
// 1. get php field type by mysql field type
foreach ($types_hash as $php_type => $db_types) {
if (preg_match('/'.$db_types.'/', $field_info['Type'])) {
$field_options['type'] = $php_type;
break;
}
}
$default_value = $field_info['Default'];
if (in_array($php_type, $float_types)) {
// this is float number
if (preg_match('/'.$db_types.'\([\d]+,([\d]+)\)/i', $field_info['Type'], $regs)) {
// size is described in structure -> add formatter
$field_options['formatter'] = 'kFormatter';
$field_options['format'] = '%01.'.$regs[1].'f';
if ($field_info['Null'] != 'YES') {
// null fields, will most likely have NULL as default value
$default_value = 0;
}
}
else {
// no size information, just convert to float
if ($field_info['Null'] != 'YES') {
// null fields, will most likely have NULL as default value
$default_value = (float)$default_value;
}
}
}
if (preg_match('/varchar\(([\d]+)\)/i', $field_info['Type'], $regs)) {
$field_options['max_len'] = (int)$regs[1];
}
if ($field_info['Null'] != 'YES') {
$field_options['not_null'] = 1;
}
if ($field_info['Key'] == 'PRI') {
$default_value = 0;
$id_field = $field_info['Field'];
}
if ($php_type == 'int' && ($field_info['Null'] != 'YES' || is_numeric($default_value))) {
// is integer field AND not null
$field_options['default'] = (int)$default_value;
}
else {
$field_options['default'] = $default_value;
}
$fields[ $field_info['Field'] ] = $this->transformDump($field_options);
$grids_fields[ $field_info['Field'] ] = $this->transformDump($grid_col_options);
}
$grids['Default']['Fields'] = $grids_fields;
$ret = "'IDField' => '".$id_field."',\n'Fields' => A".substr(stripslashes(var_export($fields, true)), 1).',';
$ret .= "\n"."'Grids' => ".stripslashes(var_export($grids, true));
$ret = str_replace('array (', 'Array (', $ret);
$ret = preg_replace("/'(.*?)' => 'Array \((.*?), \)',/", "'\\1' => Array (\\2),", $ret);
$ret = preg_replace("/\n '/", "\n\t'", $ret);
$this->Application->InitParser();
ob_start();
echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"'));
?>
<script type="text/javascript">
set_window_title('Table "<?php echo $table_name; ?>" Structure');
</script>
<a href="javascript:window_close();">Close Window</a><br /><br />
<?php echo $GLOBALS['debugger']->highlightString($ret); ?>
<br /><br /><a href="javascript:window_close();">Close Window</a><br />
<?php
echo $this->Application->ParseBlock(Array('name' => 'incs/footer'));
echo ob_get_clean();
$event->status = erSTOP;
}
function transformDump($dump)
{
if (is_array($dump)) {
$dump = var_export($dump, true);
}
$dump = preg_replace("/,\n[ ]*/", ', ', $dump);
$dump = preg_replace("/array \(\n[ ]*/", 'Array (', $dump); // replace array start
$dump = preg_replace("/,\n[ ]*\),/", "),", $dump); // replace array end
return $dump;
}
/**
* Refreshes ThemeFiles & Theme tables by actual content on HDD
*
* @param kEvent $event
*/
function OnRebuildThemes(&$event)
{
if ($this->Application->GetVar('ajax') == 'yes') {
$event->status = erSTOP;
}
$themes_helper =& $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
$themes_helper->refreshThemes();
}
function OnSaveColumns(&$event)
{
$picker_helper =& $this->Application->recallObject('ColumnPickerHelper');
/* @var $picker_helper kColumnPickerHelper */
$picker_helper->SetGridName($this->Application->GetLinkedVar('grid_name'));
$picked = trim($this->Application->GetVar('picked_str'), '|');
$hidden = trim($this->Application->GetVar('hidden_str'), '|');
$main_prefix = $this->Application->GetVar('main_prefix');
$picker_helper->SaveColumns($main_prefix, $picked, $hidden);
$this->finalizePopup($event);
}
/**
* Saves various admin settings via ajax
*
* @param kEvent $event
*/
function OnSaveSetting(&$event)
{
if ($this->Application->GetVar('ajax') != 'yes') {
return ;
}
$var_name = $this->Application->GetVar('var_name');
$var_value = $this->Application->GetVar('var_value');
$this->Application->StorePersistentVar($var_name, $var_value);
$event->status = erSTOP;
}
/**
* Just closes popup & deletes last_template & opener_stack if popup, that is closing
*
* @param kEvent $event
*/
function OnClosePopup(&$event)
{
$event->SetRedirectParam('opener', 'u');
}
/**
* Occurs right after initialization of the kernel, used mainly as hook-to event
*
* @param kEvent $event
*/
function OnStartup(&$event)
{
}
/**
* Occurs right before echoing the output, in Done method of application, used mainly as hook-to event
*
* @param kEvent $event
*/
function OnBeforeShutdown(&$event)
{
}
/**
* Is called after tree was build (when not from cache)
*
* @param kEvent $event
*/
function OnAfterBuildTree(&$event)
{
}
/**
* Called by AJAX to perform CSV export
*
* @param kEvent $event
*/
function OnExportCSV(&$event)
{
$export_helper =& $this->Application->recallObject('CSVHelper');
/* @var $export_helper kCSVHelper */
$prefix_special = $this->Application->GetVar('PrefixSpecial');
if(!$prefix_special) {
$prefix_special = $export_helper->ExportData('prefix');
}
$prefix_elems = split('\.|_', $prefix_special, 2);
$perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection');
if(!$this->Application->CheckPermission($perm_sections['main'].'.view')) {
$this->Application->Redirect('no_permission');
}
$export_helper->PrefixSpecial = $prefix_special;
$export_helper->grid = $this->Application->GetVar('grid');
$export_helper->ExportStep();
$event->status = erSTOP;
}
/**
* Returning created by AJAX CSV file
*
* @param kEvent $event
*/
function OnGetCSV(&$event)
{
$export_helper =& $this->Application->recallObject('CSVHelper');
/* @var $export_helper kCSVHelper */
$prefix_special = $export_helper->ExportData('prefix');
$prefix_elems = split('\.|_', $prefix_special, 2);
$perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection');
if(!$this->Application->CheckPermission($perm_sections['main'].'.view')) {
$this->Application->Redirect('no_permission');
}
$export_helper->GetCSV();
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnCSVImportBegin(&$event)
{
$prefix_special = $this->Application->GetVar('PrefixSpecial');
$prefix_elems = split('\.|_', $prefix_special, 2);
$perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection');
if(!$this->Application->CheckPermission($perm_sections['main'].'.add') && !$this->Application->CheckPermission($perm_sections['main'].'.edit')) {
$this->Application->Redirect('no_permission');
}
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
$field_values = array_shift($items_info);
$object->SetFieldsFromHash($field_values);
$event->redirect = false;
$result = 'required';
if($object->GetDBField('ImportFile')) {
$import_helper =& $this->Application->recallObject('CSVHelper');
/* @var $import_helper kCSVHelper */
$import_helper->PrefixSpecial = $this->Application->GetVar('PrefixSpecial');
$import_helper->grid = $this->Application->GetVar('grid');
$result = $import_helper->ImportStart( $object->GetField('ImportFile', 'file_paths') );
if($result === true) {
$event->redirect = $this->Application->GetVar('next_template');
$event->SetRedirectParam('PrefixSpecial', $this->Application->GetVar('PrefixSpecial'));
$event->SetRedirectParam('grid', $this->Application->GetVar('grid'));
}
}
if($event->redirect === false) {
$object->SetError('ImportFile', $result);
$event->status = erFAIL;
}
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnCSVImportStep(&$event)
{
$import_helper =& $this->Application->recallObject('CSVHelper');
/* @var $export_helper kCSVHelper */
$prefix_special = $import_helper->ImportData('prefix');
$prefix_elems = split('\.|_', $prefix_special, 2);
$perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection');
if(!$this->Application->CheckPermission($perm_sections['main'].'.add') && !$this->Application->CheckPermission($perm_sections['main'].'.edit')) {
$this->Application->Redirect('no_permission');
}
$import_helper->ImportStep();
$event->status = erSTOP;
}
/**
* Shows unit config filename, where requested prefix is defined
*
* @param kEvent $event
*/
function OnCheckPrefixConfig(&$event)
{
$prefix = $this->Application->GetVar('config_prefix');
$config_file = $this->Application->UnitConfigReader->prefixFiles[$prefix];
$this->Application->InitParser();
ob_start();
echo $this->Application->ParseBlock(Array('name' => 'incs/header', 'body_properties' => 'style="background-color: #E7E7E7; margin: 8px;"'));
?>
<script type="text/javascript">
set_window_title('Unit Config of "<?php echo $prefix; ?>" prefix');
</script>
<a href="javascript:window_close();">Close Window</a><br /><br />
<strong>Prefix:</strong> <?php echo $prefix; ?><br />
<strong>Unit Config:</strong> <?php echo $GLOBALS['debugger']->highlightString($config_file); ?><br />
<br /><a href="javascript:window_close();">Close Window</a><br />
<?php
echo $this->Application->ParseBlock(Array('name' => 'incs/footer'));
echo ob_get_clean();
$event->status = erSTOP;
}
function OnUploadFile(&$event)
{
// Flash uploader does NOT send correct cookies, so we need to make our own check
$cookie_name = 'adm_'.$this->Application->ConfigValue('SessionCookieName');
$this->Application->HttpQuery->Cookie['cookies_on'] = 1;
$this->Application->HttpQuery->Cookie[$cookie_name] = $this->Application->GetVar('flashsid');
$admin_ses =& $this->Application->recallObject('Session.admin');
/* @var $admin_ses Session */
$user = $admin_ses->RecallVar('user_id');
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
/*if() {
$prefix_special = $this->Application->GetVar('PrefixSpecial');
$prefix_elems = split('\.|_', $prefix_special, 2);
$perm_sections = $this->Application->getUnitOption($prefix_elems[0], 'PermSection');
$section = $perm_sections['main'];
}
else {*/
$section = $event->getSection();
/*}*/
if ($this->Application->GetVar('t') != 'import/import_start' && !$perm_helper->CheckUserPermission($user, $section.'.add') && !$perm_helper->CheckUserPermission($user, $section.'.edit')) {
$event->status = erPERM_FAIL;
header('HTTP/1.0 403 You don\'t have permissions to upload');
exit;
return;
}
if (!$cookie_name) $cookie_name = 'sid';
$value = $this->Application->GetVar('Filedata');
if (!$value) return ;
$tmp_path = WRITEABLE . '/tmp/';
$fname = $value['name'];
$id = $this->Application->GetVar('id');
if ($id) $fname = $id.'_'.$fname;
if (!is_writable($tmp_path)) {
header('HTTP/1.0 500 Write permissions not set on the server');
exit;
}
move_uploaded_file($value['tmp_name'], $tmp_path.$fname);
exit;
}
function OnDropTempTablesByWID(&$event)
{
$sid = $this->Application->GetSID();
$wid = $this->Application->GetVar('m_wid');
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/'.TABLE_PREFIX.'ses_'.$sid.'_'.$wid.'_edit_(.*)$/';
foreach($tables as $table)
{
if( preg_match($mask_edit_table,$table,$rets) )
{
$this->Conn->Query('DROP TABLE IF EXISTS '.$table);
}
}
echo 'OK';
$event->status = erSTOP;
return ;
}
/**
* Backup all data
*
* @param kEvent $event
*/
function OnBackup(&$event)
{
$a_tables = $this->Conn->GetCol('SHOW TABLES'); // array_keys($tables);
$TableNames = Array();
for($x=0;$x<count($a_tables);$x++)
{
if(substr($a_tables[$x],0,strlen(TABLE_PREFIX))==TABLE_PREFIX)
{
if (!strstr($a_tables[$x], 'ses_')) {
$TableNames[] = $a_tables[$x];
}
}
}
// echo "<pre>"; print_r($TableNames); echo "</pre>";
// exit;
$backupProgress = Array (
'table_num' => 0,
'table_names' => $TableNames,
'table_count' => count($TableNames),
'record_count' => 0,
'file_name' => $this->Application->ConfigValue('Backup_Path')."/dump".adodb_mktime().".txt",
);
$this->Application->RemoveVar('adm.backupcomplete_filename');
$this->Application->RemoveVar('adm.backupcomplete_filesize');
$out = array();
for($x=0;$x<count($TableNames);$x++) {
if (!strstr($TableNames[$x], 'ses_')) {
$out[] = $this->GetTableCreate($TableNames[$x]);
}
}
$fp = fopen($backupProgress['file_name'], 'a');
$sql = "SELECT Name, Version FROM ".TABLE_PREFIX."Modules";
$r = $this->Conn->Query($sql);
foreach ($r AS $a_module) {
$version = $a_module['Version'];
fwrite($fp, "# ".$a_module['Name']." Version: $version;\n");
}
fwrite($fp, "#------------------------------------------\n\n");
fwrite($fp,implode("\n",$out));
fwrite($fp,"\n");
fclose($fp);
$this->Application->StoreVar('adm.backup_status', serialize($backupProgress));
$event->redirect = 'tools/backup2';
}
/**
* Perform next backup step
*
* @param kEvent $event
*/
function OnBackupProgress(&$event)
{
$done_percent = $this->performBackup();
if ($done_percent == 100) {
$event->redirect = 'tools/backup3';
return ;
}
echo $done_percent;
$event->status = erSTOP;
}
/**
* Stops Backup & redirect to Backup template
*
* @param kEvent $event
*/
function OnBackupCancel(&$event)
{
$event->redirect = 'tools/backup1';
}
/**
* Stops Restore & redirect to Restore template
*
* @param kEvent $event
*/
function OnRestoreCancel(&$event)
{
$event->redirect = 'tools/restore1';
}
function performBackup()
{
$backupProgress = unserialize($this->Application->RecallVar('adm.backup_status'));
// echo "<pre>"; print_r($backupProgress); echo "</pre>";
// exit;
$CurrentTable = $backupProgress['table_names'][$backupProgress['table_num']];
// get records
$a_records = $this->insert_data($CurrentTable,$backupProgress['record_count'],50,"");
// echo "<pre>"; print_r($a_records); echo "</pre>";
// exit;
if ($a_records['num'] < 50) {
$backupProgress['table_num']++;
// if ($backupProgress['table_names'][$backupProgress['table_num']] == TABLE_PREFIX.'Cache') {
// $backupProgress['table_num']++;
// }
$backupProgress['record_count'] = 0;
} else {
$backupProgress['record_count']+=50;
}
if ($a_records['sql']) {
$fp = fopen($backupProgress['file_name'], 'a');
fwrite($fp, $a_records['sql']);
fclose($fp);
}
$percent = ($backupProgress['table_num'] / $backupProgress['table_count']) * 100;
if ($percent >= 100) {
$percent = 100;
$this->Application->StoreVar('adm.backupcomplete_filename', $backupProgress['file_name']);
$this->Application->StoreVar('adm.backupcomplete_filesize', round(filesize($backupProgress['file_name'])/1024/1024, 2)); // Mbytes
} else {
$this->Application->StoreVar('adm.backup_status', serialize($backupProgress));
}
return round($percent);
}
//extracts the rows of data from tables using limits
function insert_data($table, $start, $limit, $mywhere)
{
// global $out;
if ($mywhere !="")
{
$whereclause= " WHERE ".$mywhere." ";
}
else
{
$whereclause = "";
}
$a_data = $this->Conn->Query("SELECT * from $table $whereclause LIMIT $start, $limit");
// echo "SELECT * from $table $whereclause LIMIT $start, $limit";
// echo "<pre>"; print_r($a_records); echo "</pre>";
// exit;
if (!$a_data) {
return Array(
'num' => 0,
'sql' => '',
);
}
// $prefix = GetTablePrefix();
$rowcount = 0;
$a_fields = array_keys($a_data[0]);
$fields_sql = '';
foreach ($a_fields AS $field_name) {
$fields_sql .= '`'.$field_name.'`,';
}
$fields_sql = preg_replace('/(.*),$/', '\\1', $fields_sql);
$temp = '';
foreach ($a_data AS $a_row)
{
$values_sql = '';
foreach ($a_row as $field_name => $field_value) {
$values_sql .= $this->Conn->qstr($field_value).',';
}
$values_sql = preg_replace('/(.*),$/', '\\1', $values_sql);
$sql = 'INSERT INTO '.$table.' ('.$fields_sql.') VALUES ('.$values_sql.');';
$sql=ereg_replace("\n","\\n", $sql);
$sql=ereg_replace("\r","\\r", $sql);
$temp .= $sql."\n";
}
if(strlen(TABLE_PREFIX))
{
$temp = str_replace("INSERT INTO ".TABLE_PREFIX, "INSERT INTO ", $temp);
}
return Array(
'num' => count($a_data),
'sql' => $temp,
);
}
function GetTableCreate($table, $crlf="\n")
{
$schema_create = 'DROP TABLE IF EXISTS ' . $table . ';' . $crlf;
$schema_create .="# --------------------------------------------------------".$crlf;
$this->Conn->Query("SET SQL_QUOTE_SHOW_CREATE = 0");
$tmpres = $this->Conn->Query("SHOW CREATE TABLE $table");
// echo "<pre>"; print_r($tmpres); echo "</pre>";
// exit;
if(is_array($tmpres) && isset($tmpres[0]))
{
$tmpres = $tmpres[0];
$pos = strpos($tmpres["Create Table"], ' (');
$pos2 = strpos($tmpres["Create Table"], '(');
if ($pos2 != $pos + 1)
{
$pos = $pos2;
$tmpres["Create Table"] = str_replace(",", ",\n ", $tmpres["Create Table"]);
}
$tmpres["Create Table"] = substr($tmpres["Create Table"], 0, 13)
. (($use_backquotes) ? $tmpres["Table"] : $tmpres["Table"])
. substr($tmpres["Create Table"], $pos);
$tmpres["Create Table"] = str_replace("\n", $crlf, $tmpres["Create Table"]);
if (preg_match_all('((,\r?\n[\s]*(CONSTRAINT|FOREIGN[\s]*KEY)[^\r\n,]+)+)', $tmpres["Create Table"], $regs)) {
if (!isset($sql_constraints)) {
if (isset($GLOBALS['no_constraints_comments'])) {
$sql_constraints = '';
} else {
$sql_constraints = $crlf . '#' . $crlf
. '# ' . $GLOBALS['strConstraintsForDumped'] . $crlf
. '#' . $crlf;
}
}
if (!isset($GLOBALS['no_constraints_comments'])) {
$sql_constraints .= $crlf .'#' . $crlf .'# ' . $GLOBALS['strConstraintsForTable'] . ' ' . $table . $crlf . '#' . $crlf;
}
$sql_constraints .= 'ALTER TABLE $table $crlf '
. preg_replace('/(,\r?\n|^)([\s]*)(CONSTRAINT|FOREIGN[\s]*KEY)/', '\1\2ADD \3', substr($regs[0][0], 2))
. ";\n";
$tmpres["Create Table"] = preg_replace('((,\r?\n[\s]*(CONSTRAINT|FOREIGN[\s]*KEY)[^\r\n,]+)+)', '', $tmpres["Create Table"]);
}
$schema_create .= $tmpres["Create Table"];
}
if(strlen($schema_create))
{
$schema_create = str_replace("DROP TABLE IF EXISTS ".TABLE_PREFIX,"DROP TABLE ",$schema_create);
$schema_create = str_replace("CREATE TABLE ".TABLE_PREFIX,"CREATE TABLE ",$schema_create);
while(strlen($schema_create && substr($schema_create,-1)!=")"))
{
$schema_create = substr($schema_create,0,-1);
}
}
$schema_create .= "\n# --------------------------------------------------------\n";
return $schema_create;
}
/**
* Deletes one backup file
*
* @param kEvent $event
*/
function OnDeleteBackup(&$event)
{
@unlink($this->get_backup_file());
}
function get_backup_file()
{
return $this->Application->ConfigValue('Backup_Path').'/dump'.$this->Application->GetVar('backupdate').'.txt';
}
/**
* Starts restore process
*
* @param kEvent $event
*/
function OnRestore(&$event)
{
$file = $this->get_backup_file();
$restoreProgress = Array (
'file_pos' => 0,
'file_name' => $file,
'file_size' => filesize($file),
);
$this->Application->RemoveVar('adm.restore_success');
$this->Application->StoreVar('adm.restore_status', serialize($restoreProgress));
$event->redirect = 'tools/restore3';
}
function OnRestoreProgress(&$event)
{
$done_percent = $this->performRestore();
if ($done_percent == -3) {
$event->redirect = 'tools/restore4';
return ;
}
if ($done_percent < 0) {
$this->Application->StoreVar('adm.restore_error', 'File read error'); $event->redirect = 'tools/restore4';
return ;
}
if ($done_percent == 100) {
$this->replaceRestoredFiles();
$this->Application->StoreVar('adm.restore_success', 1);
$event->redirect = 'tools/restore4';
return ;
}
echo $done_percent;
$event->status = erSTOP;
}
function replaceRestoredFiles()
{
// gather restored table names
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_restore_table = '/^restore'.TABLE_PREFIX.'(.*)$/';
foreach($tables as $table)
{
if( preg_match($mask_restore_table,$table,$rets) )
{
$old_table = substr($table, 7);
$this->Conn->Query('DROP TABLE IF EXISTS '.$old_table);
$this->Conn->Query('CREATE TABLE '.$old_table.' LIKE '.$table);
$this->Conn->Query('INSERT INTO '.$old_table.' SELECT * FROM '.$table);
$this->Conn->Query('DROP TABLE '.$table);
}
}
}
function performRestore()
{
$restoreProgress = unserialize($this->Application->RecallVar('adm.restore_status'));
$filename = $restoreProgress['file_name'];
$FileOffset = $restoreProgress['file_pos'];
$MaxLines = 200;
$size = filesize($filename);
if($FileOffset > $size) {
return -2;
}
$fp = fopen($filename,"r");
if(!$fp) {
return -1;
}
if($FileOffset>0)
{
fseek($fp,$FileOffset);
}
else
{
$EndOfSQL = FALSE;
$sql = "";
while(!feof($fp) && !$EndOfSQL)
{
$l = fgets($fp);
if(substr($l,0,11)=="INSERT INTO")
{
$EndOfSQL = TRUE;
}
else
{
$sql .= $l;
$FileOffset = ftell($fp) - strlen($l);
}
}
if(strlen($sql))
{
$error = $this->runSchemaText($sql);
if ($error != '') {
$this->Application->StoreVar('adm.restore_error', $error);
return -3;
}
}
fseek($fp,$FileOffset);
}
$LinesRead = 0;
$sql = "";
$AllSql = array();
while($LinesRead < $MaxLines && !feof($fp))
{
$sql = fgets($fp);
if(strlen($sql))
{
$AllSql[] = $sql;
$LinesRead++;
}
}
if(!feof($fp))
{
$FileOffset = ftell($fp);
}
else
{
$FileOffset = $size;
}
fclose($fp);
if(count($AllSql)>0) {
$error = $this->runSQLText($AllSql);
if ($error != '') {
$this->Application->StoreVar('adm.restore_error', $error);
return -3;
}
}
$restoreProgress['file_pos'] = $FileOffset;
$this->Application->StoreVar('adm.restore_status', serialize($restoreProgress));
return round($FileOffset/$size * 100);
// $this->Application->StoreVar('adm.restore_error', 'lalalal');
// $event->redirect = 'tools/restore4';
}
function runSchemaText($sql)
{
$table_prefix = 'restore'.TABLE_PREFIX;
// $table_prefix = TABLE_PREFIX;
if(strlen($table_prefix))
{
$what = "CREATE TABLE ";
$replace = "CREATE TABLE ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "DROP TABLE ";
$replace = "DROP TABLE IF EXISTS ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "INSERT INTO ";
$replace = "INSERT INTO ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "UPDATE ";
$replace = "UPDATE ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "ALTER TABLE ";
$replace = "ALTER TABLE ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
}
$commands = explode("# --------------------------------------------------------",$sql);
if(count($commands)>0)
{
// $query_func = getConnectionInterface('query',$dbo_type);
// $errorno_func = getConnectionInterface('errorno',$dbo_type);
// $errormsg_func = getConnectionInterface('errormsg',$dbo_type);
for($i = 0; $i < count($commands); $i++)
{
$cmd = $commands[$i];
$cmd = trim($cmd);
if(strlen($cmd)>0)
{
$this->Conn->Query($cmd);
if($this->Conn->errorCode != 0)
{
return $this->Conn->errorMessage." COMMAND:<PRE>$cmd</PRE>";
}
}
}
}
}
function runSQLText($allsql)
{
$line = 0;
// $query_func = getConnectionInterface('query',$dbo_type);
// $errorno_func = getConnectionInterface('errorno',$dbo_type);
// $errormsg_func = getConnectionInterface('errormsg',$dbo_type);
while($line<count($allsql))
{
$sql = $allsql[$line];
if(strlen(trim($sql))>0 && substr($sql,0,1)!="#")
{
$table_prefix = 'restore'.TABLE_PREFIX;
if(strlen($table_prefix))
{
$what = "CREATE TABLE ";
$replace = "CREATE TABLE ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "DELETE FROM ";
$replace = "DELETE FROM ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "DROP TABLE ";
$replace = "DROP TABLE IF EXISTS ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "INSERT INTO ";
$replace = "INSERT INTO ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "REPLACE INTO ";
$replace = "REPLACE INTO ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "UPDATE ";
$replace = "UPDATE ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
$what = "ALTER TABLE ";
$replace = "ALTER TABLE ".$table_prefix;
$sql = ereg_replace($what, $replace, $sql);
}
$sql = trim($sql);
if(strlen($sql)>0)
{
$this->Conn->Query($sql);
if($this->Conn->errorCode != 0)
{
return $this->Conn->errorMessage." COMMAND:<PRE>$sql</PRE>";
}
}
}
$line++;
}
}
/**
* Starts restore process
*
* @param kEvent $event
*/
function OnSqlQuery(&$event)
{
$sql = $this->Application->GetVar('sql');
if ($sql) {
$start = $this->getMoment();
$result = $this->Conn->Query($sql);
$this->Application->SetVar('sql_time', round($this->getMoment() - $start, 7));
if ($result)
{
if (is_array($result))
{
$this->Application->SetVar('sql_has_rows', 1);
$this->Application->SetVar('sql_rows', serialize($result));
}
}
$check_sql = trim(strtolower($sql));
if (
(substr($check_sql, 0, 6) == 'insert')
|| (substr($check_sql, 0, 6) == 'update')
|| (substr($check_sql, 0, 7) == 'replace')
|| (substr($check_sql, 0, 6) == 'delete')
) {
$this->Application->SetVar('sql_has_affected', 1);
$this->Application->SetVar('sql_affected', $this->Conn->getAffectedRows());
}
}
$this->Application->SetVar('query_status', 1);
$event->status = erFAIL;
}
function getMoment()
{
list($usec, $sec) = explode(' ', microtime());
return ((float)$usec + (float)$sec);
}
/**
* Occurs after unit config cache was successfully rebuilt
*
* @param kEvent $event
*/
function OnAfterCacheRebuild(&$event)
{
}
/**
* Removes "Community -> Groups" section when it is not allowed
*
* @param kEvent $event
*/
function OnAfterConfigRead(&$event)
{
parent::OnAfterConfigRead($event);
if (!$this->Application->ConfigValue('AdvancedUserManagement')) {
$section_ajustments = $this->Application->getUnitOption($event->Prefix, 'SectionAdjustments');
if (!$section_ajustments) {
$section_ajustments = Array ();
}
$section_ajustments['in-portal:user_groups'] = 'remove';
$this->Application->setUnitOption($event->Prefix, 'SectionAdjustments', $section_ajustments);
}
}
/**
* Saves menu (tree) frame width
*
* @param kEvent $event
*/
function OnSaveMenuFrameWidth(&$event)
{
$event->status = erSTOP;
if (!$this->Application->ConfigValue('ResizableFrames')) {
return ;
}
$sql = 'UPDATE ' . $this->Application->getUnitOption('conf', 'TableName') . '
SET VariableValue = ' . (int)$this->Application->GetVar('width') . '
WHERE VariableName = "MenuFrameWidth"';
$this->Conn->Query($sql);
if ($this->Conn->getAffectedRows()) {
$this->Application->UnitConfigReader->ResetParsedData(false);
}
}
}
\ No newline at end of file
Index: branches/5.0.x/core/units/pdf/pdf_helper.php
===================================================================
--- branches/5.0.x/core/units/pdf/pdf_helper.php (revision 12322)
+++ branches/5.0.x/core/units/pdf/pdf_helper.php (revision 12323)
@@ -1,1009 +1,1012 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
//define('PDF_DEBUG_NO_TEXT', 1); // do not draw text
//define('PDF_DEBUG_DUMP_ONLY', 1); // output elements dump and exit
//define('PDF_DEBUG_DRAW_BOXES', 1); //
//define('PDF_DEBUG_DRAW_BASELINE', 1); //
//define('PDF_DEBUG_DRAW_BOX_INFO', '/.*/'); //
//define('PDF_DEBUG_DRAW_BOX_INFO', '/(td|img)/i'); //
//define('PDF_DEBUG_DRAW_MARGINS', 1); //
//define('PDF_DEBUG_DRAW_ELEM_BORDERS', 1);
//define('PDF_DEBUG_DRAW_LINE_BOXES', 1);
//define('PDF_DRAW_CONTENT_AREA', 1);
require_once FULL_PATH.'/core/units/pdf/pdf_styles.php';
require_once FULL_PATH.'/core/units/pdf/pdf_text.php';
require_once FULL_PATH.'/core/units/pdf/pdf_table.php';
require_once FULL_PATH.'/core/units/pdf/pdf_image.php';
require_once FULL_PATH.'/core/units/pdf/pdf_renderer.php';
require_once FULL_PATH.'/core/units/pdf/pdf_renderer_tcpdf.php';
class kPDFHelper extends kHelper {
/**
* Enter description here...
*
* @var kPDFRenderer
*/
var $PDF;
var $CurPDFElem;
var $DimensionsMode = 1;
var $Stylesheet;
var $PtPerEm = 10;
public $Document = null;
const DM_NORMAL = 0;
const DM_SKIP = 1;
function BuildFromTemplate($template, $template_params = Array ())
{
$this->Application->InitParser();
- $xml = $this->Application->Parser->ParseTemplate($template, 1, $template_params);
+
+ $this->Application->Parser->SetParams($template_params);
+ $xml = $this->Application->Parser->Run($template);
+
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$doc = $xml_helper->Parse($xml_helper->ConvertHTMLEntities($xml), XML_WITH_TEXT_NODES);
if ($doc->Name == 'ERROR') {
echo 'BAD TEMPLATE';
exit;
}
// $this->Application->Debugger->profileStart('pdf_init', 'Initializing PDF');
$this->InitPDF($doc);
// $this->Application->Debugger->profileFinish('pdf_init');
// $this->Application->Debugger->profileStart('process_nodes', 'Processing nodes');
$this->ProcessNode($doc);
// $this->Application->Debugger->profileFinish('process_nodes');
if (defined('PDF_DEBUG_DUMP_ONLY')) {
$this->DimensionsMode = kPDFHelper::DM_NORMAL ;
$this->Application->Debugger->profileStart('laying_out', 'Laying out nodes');
// $this->CurPDFElem->LayoutChildren();
$this->Application->Debugger->profileFinish('laying_out');
$this->Application->Debugger->profileStart('rendering', 'rendering');
// $this->Render();
$this->Application->Debugger->profileFinish('rendering');
// echo $this->CurPDFElem->DumpStructure();
exit;
}
$this->Render();
return $this->PDF->GetPDFString();
// exit;
}
function InitPDF($doc)
{
$this->PDF = new kTCPDFRenderer();
$this->Stylesheet = new kPDFStylesheet();
$this->CurPDFElem = kPDFElemFactory::CreateFromNode($doc, $this);
$this->Document = $this->CurPDFElem;
// $this->CurPDFElem = new kPDFPage($page1, new kXMLNode('_NONE_', array('style' => 'display: block; width: '.$page1->getWidth().';')), $this);
$this->CurPDFElem->Init();
$this->CurPDFElem->SetCSSProperty('width', $this->PDF->getWidth());
$this->CurPDFElem->SetCSSProperty('height', $this->PDF->getHeight());
$this->PDF->SetFont('helvetica', $this->PtPerEm);
}
function Render()
{
$this->DimensionsMode = kPDFHelper::DM_NORMAL ;
$this->CurPDFElem->LayoutChildren();
$this->PageBottom = $this->PDF->getHeight() - $this->Document->GetCSSProperty('margin-bottom'); // margin
$this->CurPDFElem->DrawAt($this->PDF, 0, 0);
}
function ProcessHead($node)
{
if ($node->Name == 'STYLE') {
$css = $node->Data;
$tokens = $this->Stylesheet->GetTokens($node->Data);
$this->Stylesheet->ParseTokens($tokens);
}
foreach($node->Children as $child) {
$this->ProcessHead($child);
}
}
function ProcessNode($node)
{
$children = count($node->Children);
foreach($node->Children as $child) {
if ($child->Name == 'HEAD') {
$this->ProcessHead($child);
continue;
}
$elem = kPDFElemFactory::CreateFromNode($child, $this);
if (!$elem) continue;
$display = $elem->GetDisplayLevel();
if ($display == 'none') continue;
// http://manual.prod.intechnic.lv/css21/visuren.html#anonymous-block-level
if ($display == 'block' && $this->CurPDFElem->GetDisplayLevel() == 'inline') {
$this->CurPDFElem->Closed();
$this->CurPDFElem = $this->CurPDFElem->GetContainingBlock();
}
$current = $this->CurPDFElem;
$line = false;
if ($display == 'inline' && !($this->CurPDFElem instanceof kPDFLine) ) {
$this->CurPDFElem = $this->CurPDFElem->GetLineBox();
$line = $this->CurPDFElem;
}
$this->CurPDFElem = $this->CurPDFElem->AddChild( $elem );
$this->ProcessNode($child);
$this->CurPDFElem = $current;
}
$this->CurPDFElem->Closed();
}
}
class kPDFElemFactory {
static function CreateFromNode($node, $helper)
{
/* @todo Create elements, based on their display, rather than tag name - pure CSS rendering */
switch ($node->Name) {
case '_TEXT_':
// $DOMNode = $node->Parent;
$elem = new kPDFTextElement($node->Data, $node, $helper);
if ($elem->CSSSpecifiedProperties['WHITE-SPACE'] == 'normal' && trim($node->Data) == '') {
return false;
}
return $elem;
break;
case 'TR':
return new kPDFTableRow($node, $helper);
case 'BR':
return new kPDFTextElement($node->Data, $node, $helper);
case 'TABLE':
return new kPDFTable($node, $helper);
case 'IMG':
return new kPDFImage($node, $helper);
default:
return new kPDFElement($node, $helper);
break;
}
}
}
class kPDFElement {
public $Parent;
protected $Font;
protected $FontSize;
public $Children = array();
public $Position = 0;
public $FirstChild;
public $LastChild;
public $ContentHeight = 0;
public $Style;
public $CurX = 0;
public $CurY = 0;
public $Baseline = 0;
public $Ascent;
public $Descent;
public $Gap;
public $Node;
public $Helper;
public $CSSSpecifiedProperties = array();
public $CSSComputedPoperties = array();
public $DirectStyle;
public $IsClosed = false;
public $LayedOut = false;
public $WidthComputed = false;
public $MinContentWidth = 0;
public $MaxContentWidth = 0;
public $CurLine_MinContentWidth = 0;
public $CurLine_MaxContentWidth = 0;
public $Spacers = 0;
function __construct($node, $helper)
{
$this->Node = $node;
$this->Helper = $helper;
$this->ProcessCSS();
}
function Init()
{
$this->ComputeCSSProperties();
}
function Reset()
{
$this->CurX = 0;
$this->CurY = 0;
}
function AddChild($child, $init=true, $after=null)
{
$node_count = count($this->Children);
if (isset($after)) {
$after_pos = $after->Position;
for($i=$after_pos+1; $i<$node_count; $i++) {
$this->Children[$i]->Position++;
}
array_splice($this->Children, $after_pos+1, 0, array($child));
$child->Position = $after_pos+1;
}
else {
$child->Position = $node_count;
$this->Children[] = $child;
}
if ($node_count == 0) {
$this->FirstChild = $child;
$this->LastChild = $child;
}
elseif ($child->Position == $node_count) {
$this->LastChild = $child;
}
$child->Parent = $this;
if ($init) $child->Init();
return $child;
}
public function Closed()
{
if ($this->LastChild && $this->LastChild instanceof kPDFLine && !$this->LastChild->IsClosed) {
$this->LastChild->Closed();
}
$this->ComputeWidthAndMargins();
$this->CalcMinMaxContentWidth();
$this->IsClosed = true;
return ;
}
function RemoveChildren($start, $count=null)
{
return array_splice($this->Children, $start);
}
function &FindChildByProperty($property, $value)
{
$property = strtoupper($property);
if (strtoupper($this->GetCSSProperty($property)) == strtoupper($value)) return $this;
foreach ($this->Children as $elem)
{
$child =& $elem->FindChildByProperty($property, $value);
if ($child !== false)
{
return $child;
}
}
$false = false;
return $false;
}
function LayoutChildren()
{
$this->ComputeWidthAndMargins();
$i = 0;
$this->Reset();
while (isset($this->Children[$i])) { // can't use foreach here, because LayoutChildren() may add new children to current elem (wrapping)
$child = $this->Children[$i];
$child->LayoutChildren();
$i++;
}
$this->CheckDimensions();
$this->ComputeHeight();
// $this->ComputeBaseline();
}
public function ComputeHeight()
{
$display = $this->GetCSSProperty('display');
if ($display == 'inline') return ;
$height = 0; // $this->GetCSSProperty('height');
/* $extra_height =
$this->GetCSSProperty('margin-top') +
$this->GetCSSProperty('margin-bottom') +
$this->GetCSSProperty('padding-top') +
$this->GetCSSProperty('padding-bottom') +
$this->GetCSSProperty('border-top-width') +
$this->GetCSSProperty('border-bottom-width');*/
foreach ($this->Children as $elem) {
$dim = $elem->GetBoxDimensions();
$elem_height = $dim[1];
if ($elem->GetDisplayLevel() == 'block' && $elem->GetCSSProperty('display') != 'table-cell') {
$height += $elem_height;
}
else {
if ($elem_height > $height) {
$height = $elem_height;
}
}
}
$this->SetCSSProperty('height', $height);
}
function &FindChild($name)
{
$name = strtoupper($name);
if ($this->Node->Name == $name) return $this;
foreach ($this->Children as $elem)
{
$child =& $elem->FindChild($name);
if ($child !== false)
{
return $child;
}
}
$false = false;
return $false;
}
function DumpStructure($level=0)
{
$dump = '';
$tab = str_repeat('&nbsp;', $level*4);
$dump .= $tab . get_class($this) . ' Node: ' . $this->Node->Name . " child of ".$this->Node->Parent->Name."<br>\n";
if ($this instanceof kPDFTextElement) {
$dump .= $tab . 'Data: ' . $this->Data . "<br>\n";
}
$dump .= $tab . 'Width: ' . $this->GetCSSProperty('width') . ' Height: ' . $this->GetCSSProperty('height') . " Ascent: " . $this->Ascent . "<br>\n";
$dump .= $tab . 'MinCW: ' . $this->MinContentWidth . ' MaxCW: ' . $this->MaxContentWidth . "<br>\n";
$dump .= $tab . 'Children:' . "<br>\n";
$i = 0;
foreach ($this->Children as $elem)
{
$i++;
$dump .= $tab . $i . "<br>\n";
$level++;
$dump .= $elem->DumpStructure($level);
$level--;
}
return $dump;
}
function DrawAt($page, $x=0, $y=0, $spacer_w=0)
{
if ($this->Node->Name == 'FOOTER') {
$dim = $this->GetBoxDimensions();
$y = $this->Helper->PDF->GetHeight() - $dim[1];
}
if ($this->GetDisplayLevel() == 'block' ) {
$width = $this->GetCSSProperty('width');
$margin_left = $this->GetCSSProperty('margin-left');
$margin_right = $this->GetCSSProperty('margin-right');
$border_left = $this->GetCSSProperty('border-left-width');
$border_right = $this->GetCSSProperty('border-right-width');
$padding_left = $this->GetCSSProperty('padding-left');
$padding_right = $this->GetCSSProperty('padding-right');
$height = $this->GetCSSProperty('height');
$margin_top = $this->GetCSSProperty('margin-top');
$margin_bottom = $this->GetCSSProperty('margin-bottom');
$border_top = $this->GetCSSProperty('border-top-width');
$border_bottom = $this->GetCSSProperty('border-bottom-width');
$padding_top = $this->GetCSSProperty('padding-top');
$padding_bottom = $this->GetCSSProperty('padding-bottom');
$outer_width = $margin_left + $border_left + $padding_left + $width + $padding_right + $border_right + $margin_right;
$outer_height = $margin_top + $border_top + $padding_top + $height + $padding_bottom + $border_bottom + $margin_bottom;
if (defined('PDF_DEBUG_DRAW_BOXES')) {
$page->SetFillColor( '#eeeeee' );
if ($this instanceof kPDFLine) {
if (defined('PDF_DEBUG_DRAW_LINE_BOXES')) {
$page->SetLineWidth(0.5);
$page->SetLineColor( 'yellow' );
$page->SetFillColor( '#efefef' );
}
}
else {
$page->SetLineWidth(0.1);
$page->SetLineColor( '#0000ff' );
}
// $page->DrawRectangle($x, $y, $x + $outer_width, $y - $outer_height, kPDFRenderer::SHAPE_DRAW_FILL_AND_STROKE);
$page->SetFillColor( '#000000' );
$page->setFont('helvetica', 6);
if (defined('PDF_DEBUG_DRAW_BOX_INFO') && preg_match(PDF_DEBUG_DRAW_BOX_INFO, $this->Node->Name)) {
$page->drawText($this->Node->Name . "{$outer_width}x{$outer_height} ".get_class($this), $x+2, $y+8);
}
}
}
if ($this->GetDisplayLevel() == 'block' && !($this instanceof kPDFLine)) {
// MARGINS
if (defined('PDF_DEBUG_DRAW_MARGINS')) {
$page->SetLineWidth(1);
$page->SetLineColor( 'green' );
$page->DrawLine($x, $y, $x + $margin_left, $y);
$page->DrawLine($x, $y, $x, $y + $margin_bottom);
$page->SetLineWidth(0.3);
$page->DrawLine($x + $margin_left, $y, $x + $margin_left, $y + 3);
$page->DrawLine($x, $y + $margin_top, $x + 3, $y + $margin_top);
}
$x += $margin_left;
$y += $margin_top;
// BACKGROUND
// http://manual.prod.intechnic.lv/css21/colors.html#q2
$body = false;
if ($this->Node->Name == 'HTML' && $this->GetCSSProperty('background-color') == 'transparent') {
// get BODY color
$body = $this->FindChild('BODY');
if ($body !== false) {
$background_color = $body->GetCSSProperty('background-color');
$body->SetCSSProperty('background-color', 'transparent');
}
}
else {
$background_color = $this->GetCSSProperty('background-color');
}
if ($background_color != 'transparent') {
$page->SetFillColor( $background_color );
$x1 = $x + $border_left +
$padding_left +
$width +
$padding_right +
$border_right;
$y1 = $y + ($border_top +
$padding_top +
$height +
$padding_bottom +
$border_bottom);
$page->DrawRectangle($x, $y, $x1, $y1, kPDFRenderer::SHAPE_DRAW_FILL);
}
// BORDERS
$x2 = $x + $border_left + $padding_left + $width + $padding_right + $border_right;
$y2 = $y + ($border_top + $padding_top + $height + $padding_bottom + $border_bottom);
if ($this->GetCSSProperty('border-top-style') != 'none' && $border_top > 0) {
$page->SetLineWidth($this->GetCSSProperty('border-top-width'));
$page->SetLineColor( $this->GetCSSProperty('border-top-color') );
$page->DrawLine($x+$border_left/2, $y+$border_top/2, $x2-$border_right/2, $y+$border_top/2);
}
if ($this->GetCSSProperty('border-right-style') != 'none' && $border_right > 0) {
$page->SetLineWidth($this->GetCSSProperty('border-right-width'));
$page->SetLineColor( $this->GetCSSProperty('border-right-color') );
$page->DrawLine($x2-$border_right/2, $y+$border_top/2, $x2-$border_right/2, $y2-$border_bottom/2);
}
if ($this->GetCSSProperty('border-bottom-style') != 'none' && $border_bottom > 0) {
$page->SetLineWidth($this->GetCSSProperty('border-bottom-width'));
$page->SetLineColor( $this->GetCSSProperty('border-bottom-color') );
$page->DrawLine($x+$border_left/2, $y2-$border_bottom/2, $x2-$border_right/2, $y2-$border_bottom/2);
}
if ($this->GetCSSProperty('border-left-style') != 'none' && $border_left > 0) {
$page->SetLineWidth($this->GetCSSProperty('border-left-width'));
$page->SetLineColor( $this->GetCSSProperty('border-left-color'));
$page->DrawLine($x+$border_left/2, $y+$border_top/2, $x+$border_left/2, $y2-$border_bottom/2);
}
$x += $border_left;
$y += $border_top;
// PADDING
$x += $this->GetCSSProperty('padding-left');
$y += $this->GetCSSProperty('padding-top');
if (defined('PDF_DRAW_CONTENT_AREA') && $this->Parent) {
$page->SetFillColor( 'pink' ) ;
$page->DrawRectangle($x, $y, $x + $width, $y + $height, kPDFRenderer::SHAPE_DRAW_FILL);
}
}
$this->CurX = $x;
$this->CurY = $y;
// $max_width = $this->GetCSSProperty('max-width');
$this->TopLine = $y;
$page->SetLineWidth(0.1);
foreach ($this->Children as $elem)
{
$dim = $elem->GetBoxDimensions();
$align_offset_x = 0;
$align_offset_y = 0;
if ($elem->GetDisplayLevel() == 'inline') {
if ($this->GetCSSProperty('vertical-align') == 'baseline') {
$align_offset_y = $this->Ascent - $elem->Ascent;
}
}
if (defined('PDF_DEBUG_DRAW_BASELINE')) {
$page->SetLineWidth(0.5);
$page->SetLineColor( '#ff0000' );
$page->DrawLine($this->CurX, $this->CurY + $elem->Ascent, $this->CurX + $dim[0], $this->CurY + $elem->Ascent);
}
if ($elem instanceof kPDFLine ) {
$spacer_w = 0;
switch ($elem->GetCSSProperty('text-align')) {
case 'center':
$align_offset_x = ($dim[0] - $elem->CurX)/2;
break;
case 'right':
$align_offset_x = ($dim[0] - $elem->CurX);
break;
case 'justify':
$spacer_w = $elem->LastLine ? 0 : ($dim[0] - $elem->CurX)/$elem->Spacers;
}
}
if (defined('PDF_DEBUG_DRAW_ELEM_BORDERS')) {
$page->SetLineWidth(0.1);
$page->SetLineColor( '#bbbbbb' );
$page->SetFillColor( '#bbbbbb' );
$page->setFont('helvetica', 4);
$page->DrawRectangle($this->CurX, $this->CurY + $align_offset_y, $this->CurX + $dim[0], $this->CurY + $align_offset_y + $dim[1], kPDFRenderer::SHAPE_DRAW_STROKE);
if (defined('PDF_DEBUG_DRAW_BOX_INFO') && preg_match(PDF_DEBUG_DRAW_BOX_INFO, $this->Node->Name) && $elem->GetDisplayLevel() != 'block') {
$page->drawText("w:{$dim[0]}x{$dim[1]}", $this->CurX + 2, $this->CurY + $align_offset_y + 6);
}
}
$tmp_x = $this->CurX;
$this->CheckPageBreak($page, $elem, $dim);
$elem->DrawAt($page, $this->CurX + $align_offset_x, $this->CurY + $align_offset_y, $spacer_w);
if ($elem->GetDisplayLevel() == 'block' && $elem->GetCSSProperty('display') != 'table-cell') {
$this->CurY += $dim[1];
$this->CurX = $tmp_x;
}
else {
$this->CurX = $this->CurX + $dim[0] + ($elem->Spacers*$spacer_w);
}
}
if ($this->GetCSSProperty('PAGE-BREAK-AFTER') == 'always') {
$this->Helper->PDF->NextPage();
$this->Parent->CurY = $this->Helper->Document->GetCSSProperty('margin-top');
}
}
function CheckPageBreak($page, $elem, $dim)
{
if (($this->GetCSSProperty('DISPLAY') != 'block' && $this->GetCSSProperty('DISPLAY') != 'table') || $elem->Node->Name == 'BODY' || $elem->Node->Name == 'HTML') return;
if ($this->CurY + $dim[1] > $this->Helper->PageBottom) {
$this->Helper->PDF->NextPage();
$this->CurY = $this->Helper->Document->FindChild('BODY')->GetCSSProperty('margin-top');
}
}
function GetBoxDimensions()
{
return array(
$this->GetCSSProperty('margin-left') +
$this->GetCSSProperty('border-left-width') +
$this->GetCSSProperty('padding-left') +
$this->GetCSSProperty('width') +
$this->GetCSSProperty('padding-right') +
$this->GetCSSProperty('border-right-width') +
$this->GetCSSProperty('margin-right'),
$this->GetCSSProperty('margin-top') +
$this->GetCSSProperty('border-top-width') +
$this->GetCSSProperty('padding-top') +
$this->GetCSSProperty('height') +
$this->GetCSSProperty('padding-bottom') +
$this->GetCSSProperty('border-bottom-width') +
$this->GetCSSProperty('margin-bottom'),
);
}
function GetLineBox($first=false) {
if ($this instanceof kPDFLine ) {
if ($first) {
return $this->Parent->FirstChild;
}
else {
return $this;
}
}
if ($this->GetDisplayLevel() == 'block') {
if ($this->LastChild instanceof kPDFLine ) {
return $this->LastChild;
}
return $this->AddChild( new kPDFLine($this->Node, $this->Helper));
}
//in-line box
return $this->Parent->GetLineBox();
}
function GetTable() {
if ($this instanceof kPDFTable) {
return $this;
}
if ($this->Parent) {
return $this->Parent->GetTable();
}
return false;
}
function GetDisplayLevel()
{
// http://manual.prod.intechnic.lv/css21/visuren.html#q5
$display = $this->GetCSSProperty('display');
if (!$display) $display = $this->CSSSpecifiedProperties['DISPLAY'];
switch ($display) {
case 'block':
case 'list-item':
case 'table':
case 'table-cell':
case 'table-row':
case 'table':
return 'block';
case 'run-in':
// do special processing here: http://manual.prod.intechnic.lv/css21/visuren.html#run-in
return 'block';
case 'none':
return 'none';
}
return 'inline';
}
function ProcessCSS()
{
$supported_properties = array(
'DISPLAY',
'FONT-SIZE', // SHOULD BE FIRST, BECAUSE ALL EM UNITS RELY ON IT
'WIDTH','MAX-WIDTH','MIN-WIDTH',
'HEIGHT',
'COLOR',
'FONT-FAMILY', 'FONT-WEIGHT', 'FONT-STYLE', 'FONT-VARIANT',
'WHITE-SPACE',
'VERTICAL-ALIGN',
'MARGIN-LEFT', 'MARGIN-RIGHT', 'MARGIN-TOP', 'MARGIN-BOTTOM',
'BORDER-TOP-STYLE', 'BORDER-RIGHT-STYLE', 'BORDER-BOTTOM-STYLE', 'BORDER-LEFT-STYLE',
'BORDER-TOP-WIDTH', 'BORDER-RIGHT-WIDTH', 'BORDER-BOTTOM-WIDTH', 'BORDER-LEFT-WIDTH',
'BORDER-TOP-COLOR', 'BORDER-RIGHT-COLOR', 'BORDER-BOTTOM-COLOR', 'BORDER-LEFT-COLOR',
'PADDING-TOP', 'PADDING-RIGHT', 'PADDING-BOTTOM', 'PADDING-LEFT',
'BACKGROUND-COLOR',
'TEXT-ALIGN', 'TEXT-TRANSFORM',
'TABLE-LAYOUT',
'PAGE-BREAK-AFTER'
);
$cascade = $this->Helper->Stylesheet->GetAllProperties($this->Node);
foreach ($supported_properties as $property) {
$value = false;
// !!! The following needs to be fixed somehow - thereis no major need in cascading properties for kPDFTextElement and kPDFLine also...
if (!($this instanceof kPDFTextElement) || ($this instanceof kPDFTextElement && $property != 'DISPLAY')) {
$value = isset($cascade[$property]) ? $cascade[$property] : false;
}
if (!$value && kCSSDefaults::IsInherited($property)) {
$value = $this->FindInheritedValue($property);
}
if (!$value) {
$value = kCSSDefaults::GetDefaultValue($property);
}
$this->CSSSpecifiedProperties[$property] = $value;
}
$this->Node->CssProperties = $this->CSSSpecifiedProperties;
}
function FindInheritedValue($property)
{
$node = $this->Node;
if (!$node->Parent) {
return false;
}
do {
$node = $node->Parent;
$value = isset($node->ComputedCSSProperties[$property]) ? $node->ComputedCSSProperties[$property] : false;
} while (!$value && $node->Parent);
return $value;
}
function ComputeCSSProperties()
{
foreach ($this->CSSSpecifiedProperties as $property => $value) {
$this->SetCSSProperty($property, $this->ComputeCSSProperty($property, $value));
}
$this->ComputeWidthAndMargins();
/*if ($this->GetDisplayLevel() == 'inline') {
$props = array(
'margin-top' => 0,
'margin-right' => 0,
'margin-bottom' => 0,
'margin-left' => 0,
'width' => 0,
);
foreach ($props as $name => $value) {
$this->SetCSSProperty($name, $value);
}
}*/
$this->Node->ComputedCSSProperties = $this->CSSComputedPoperties;
}
function ComputeWidthAndMargins()
{
if ($this->WidthComputed) return ;
if ($this->GetDisplayLevel() == 'inline') {
return;
}
if (!$this->Parent) {
$this->WidthComputed = true;
return ;
}
$cb = $this->GetContainingBlock();
$cb_width = $cb->GetCSSProperty('width'); // containing block width
if (!$cb->WidthComputed) { // this means we are inside an element which width is not yet defined (nested TABLE for instance)
return ;
}
if ($this instanceof kPDFLine) { // otherwise margins will be applied from line containing block to the line
$this->SetCSSProperty('width', $cb_width);
return;
}
// 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
$width = $this->GetCSSProperty('width'); // may be auto
$margin_left = $this->GetCSSProperty('margin-left'); // may be auto
$margin_right = $this->GetCSSProperty('margin-right'); // may be auto
$border_left = $this->GetCSSProperty('border-left-width');
$border_right = $this->GetCSSProperty('border-right-width');
$padding_left = $this->GetCSSProperty('padding-left');
$padding_right = $this->GetCSSProperty('padding-right');
if ($width == 'auto' && $this->Parent) {
if ($margin_left == 'auto') {
$margin_left = 0;
}
if ($margin_right == 'auto') {
$margin_right = 0;
}
$width = $cb_width - $margin_left - $border_left - $padding_left - $padding_right - $border_right - $margin_right;
}
elseif ($margin_left != 'auto' && $margin_right != 'auto') { //over-constrained
$margin_right = $cb_width - $width - $margin_left - $border_left - $padding_left - $padding_right - $border_right;
}
elseif ($margin_left == 'auto' && $margin_right == 'auto') {
$margin_left = ($cb_width - $border_left - $padding_left - $width - $padding_right - $border_right)/2;
$margin_right = $margin_left;
}
$this->SetCSSProperty('width', $width);
$this->SetCSSProperty('margin-right', $margin_right);
$this->SetCSSProperty('margin-left', $margin_left);
$this->WidthComputed = true;
}
function ComputeCSSProperty($property, $value)
{
if ($property == 'FONT-WEIGHT') {
if ($value == 'normal') {
return 400;
}
if ($value == 'bold') {
return 700;
}
if ($value == 'bolder') {
if (!$this->Parent) {
return 700;
}
else {
return max($this->Parent->GetCSSProperty('font-weight') + 300, 900);
}
}
if ($value == 'lighter') {
if (!$this->Parent) {
return 400;
}
else {
return min($this->Parent->GetCSSProperty('font-weight') - 300, 100);
}
}
if (!is_integer($value)) {
return 400;
}
return $value;
}
if (preg_match('/([.0-9]+)em/i', $value, $regs)) {
$cb = $this->GetContainingBlock();
if ($property == 'FONT-SIZE') {
if (!$cb) {
$value = $regs[1] * $this->Helper->PtPerEm;
}
else {
$value = $cb->GetCSSProperty('font-size') * $regs[1];
}
}
else {
if ($cb) {
$value = $cb->GetCSSProperty('font-size') * $regs[1];
}
}
}
elseif (preg_match('/([.0-9]+)(px)/i', $value, $regs)) {
$value = $regs[1] * 72 / 96;
}
elseif (preg_match('/([.0-9]+)(pt)/i', $value, $regs)) {
$value = $regs[1];
}
elseif (preg_match('/([.0-9]+)%/i', $value, $regs)) {
$cb = $this->GetContainingBlock();
if ($cb && ($property != 'WIDTH' || ($property == 'WIDTH' && $cb->WidthComputed))) {
$value = $regs[1]/100 * $cb->GetCSSProperty($property);
}
}
if ($property == 'FONT-SIZE' && preg_match('/(xx-small|x-small|small|medium|large|x-large|xx-large)/i', $value)) {
switch (strtolower($value)) {
case 'xx-small':
return $this->Helper->PtPerEm * 0.5;
case 'x-small':
return $this->Helper->PtPerEm * 0.7;
case 'small':
return $this->Helper->PtPerEm * 0.8;
case 'medium':
return $this->Helper->PtPerEm;
case 'large':
return $this->Helper->PtPerEm * 1.2;
case 'x-large':
return $this->Helper->PtPerEm * 1.4;
case 'xx-large':
return $this->Helper->PtPerEm * 1.6;
}
}
// elseif ($value == 'none') {
// $value = 0;
// }
return $value;
}
function GetContainingBlock()
{
if (!$this->Parent) return false;
$parent_display = $this->Parent->GetCSSProperty('display');
if (preg_match('/^(block|inline-block|table|table-cell|list-item)$/i', $parent_display)) {
return $this->Parent;
}
return $this->Parent->GetContainingBlock();
}
function GetCSSProperty($property)
{
$property = strtoupper($property);
return isset($this->CSSComputedPoperties[$property]) ? $this->CSSComputedPoperties[$property] : false;
}
function SetCSSProperty($name, $value)
{
$this->CSSComputedPoperties[strtoupper($name)] = $value;
}
function CheckDimensions()
{
$this->ComputeBaseline();
}
function ComputeBaseline()
{
if (!$this->Parent) return ;
$display = $this->GetCSSProperty('display');
/*$dim = $this->GetBoxDimensions();
$this->Ascent = $dim[1];*/
if ($display == 'inline' || $display == 'table-cell' || $this instanceof kPDFLine) {
if ($this->Parent->Ascent < $this->Ascent) {
$this->Parent->Ascent = $this->Ascent;
}
if ($this->Parent->Descent < $this->Descent) {
$this->Parent->Descent = $this->Descent;
}
if ($this->Parent->Gap < $this->Gap) {
$this->Parent->Gap = $this->Gap;
}
$this->Parent->ComputeBaseline();
}
}
function ContentWidthNewLine()
{
if ($this->CurLine_MinContentWidth > $this->MinContentWidth) {
$this->MinContentWidth = $this->CurLine_MinContentWidth;
}
if ($this->CurLine_MaxContentWidth > $this->MaxContentWidth) {
$this->MaxContentWidth = $this->CurLine_MaxContentWidth;
}
$this->CurLine_MinContentWidth = 0;
$this->CurLine_MaxContentWidth = 0;
}
function CalcMinMaxContentWidth() {
if (!$this->Parent) return ;
$this->ContentWidthNewLine();
$extra_width =
$this->GetCSSProperty('margin-left') +
$this->GetCSSProperty('margin-right') +
$this->GetCSSProperty('padding-left') +
$this->GetCSSProperty('padding-right') +
$this->GetCSSProperty('border-left-width') +
$this->GetCSSProperty('border-right-width');
// $extra_width = 0;
$this->MinContentWidth += $extra_width;
$this->MaxContentWidth += $extra_width;
$display = $this->GetCSSProperty('display');
if (($display == 'inline' || $display == 'table-cell')) {
$this->Parent->CurLine_MinContentWidth += $this->MinContentWidth;
$this->Parent->CurLine_MaxContentWidth += $this->MaxContentWidth;
if ($this->Node->Name == 'BR') {
$this->Parent->ContentWidthNewLine();
}
}
else {
if ($this->MinContentWidth > $this->Parent->MinContentWidth) {
$this->Parent->MinContentWidth = $this->MinContentWidth;
// $this->Parent->CalcMinMaxContentWidth();
}
if ($this->MaxContentWidth > $this->Parent->MaxContentWidth) {
$this->Parent->MaxContentWidth = $this->MaxContentWidth;
// $this->Parent->CalcMinMaxContentWidth();
}
}
// $this->ContentWidthNewLine();
}
}
class kPDFLine extends kPDFElement {
public $LastLine = true;
function __construct($node, $helper)
{
$line_node = new kXMLNode('_LINE_', array('STYLE' => 'display: block'));
// $line_node->SetParent($node);
$node->AddChild($line_node);
parent::__construct($line_node, $helper);
}
function Init()
{
parent::Init();
$this->SetCSSProperty('display', 'block');
$this->SetCSSProperty('margin-left', '0');
$this->SetCSSProperty('margin-right', '0');
$this->SetCSSProperty('margin-top', '0');
$this->SetCSSProperty('margin-bottom', '0');
$this->SetCSSProperty('padding-left', '0');
$this->SetCSSProperty('padding-right', '0');
$this->SetCSSProperty('padding-top', '0');
$this->SetCSSProperty('padding-bottom', '0');
}
}
\ No newline at end of file
Index: branches/5.0.x/core/units/email_events/email_events_event_handler.php
===================================================================
--- branches/5.0.x/core/units/email_events/email_events_event_handler.php (revision 12322)
+++ branches/5.0.x/core/units/email_events/email_events_event_handler.php (revision 12323)
@@ -1,524 +1,512 @@
<?php
/**
* @version $Id$
* @package In-Portal
* @copyright Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.net/license/ for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class EmailEventsEventsHandler extends kDBEventHandler
{
/**
* Allows to override standart permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnFrontOnly' => Array('self' => 'edit'),
'OnSaveSelected' => Array('self' => 'view'),
'OnProcessEmailQueue' => Array('self' => 'add|edit'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Changes permission section to one from REQUEST, not from config
*
* @param kEvent $event
*/
function CheckPermission(&$event)
{
$module = $this->Application->GetVar('module');
if (strlen($module) > 0) {
// checking permission when lising module email events in separate section
$module = explode(':', $module, 2);
if (count($module) == 1) {
$main_prefix = $this->Application->findModule('Name', $module[0], 'Var');
}
else {
$exceptions = Array('Category' => 'c', 'Users' => 'u');
$main_prefix = $exceptions[ $module[1] ];
}
$section = $this->Application->getUnitOption($main_prefix.'.email', 'PermSection');
$event->setEventParam('PermSection', $section);
}
// checking permission when listing all email events when editing language
return parent::CheckPermission($event);
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @access protected
* @see OnListBuild
*/
function SetCustomQuery(&$event)
{
if ($event->Special == 'module') {
$object =& $event->getObject();
$module = $this->Application->GetVar('module');
$object->addFilter('module_filter', '%1$s.Module = '.$this->Conn->qstr($module));
}
}
/**
* Sets status Front-End Only to selected email events
*
* @param kEvent $event
*/
function OnFrontOnly(&$event)
{
$ids = implode(',', $this->StoreSelectedIDs($event));
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'UPDATE '.$table_name.'
SET FrontEndOnly = 1
WHERE EventId IN ('.$ids.')';
$this->Conn->Query($sql);
$this->clearSelectedIDs($event);
}
/**
* Sets selected user to email events selected
*
* @param kEvent $event
*/
function OnSelectUser(&$event)
{
if ($event->Special != 'module') {
parent::OnSelectUser($event);
return ;
}
$items_info = $this->Application->GetVar('u');
if ($items_info) {
$user_id = array_shift( array_keys($items_info) );
$selected_ids = $this->getSelectedIDs($event, true);
$ids = $this->Application->RecallVar($event->getPrefixSpecial().'_selected_ids');
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');
$sql = 'UPDATE '.$table_name.'
SET '.$this->Application->RecallVar('dst_field').' = '.$user_id.'
WHERE '.$id_field.' IN ('.$ids.')';
$this->Conn->Query($sql);
}
$this->finalizePopup($event);
}
/**
* Saves selected ids to session
*
* @param kEvent $event
*/
function OnSaveSelected(&$event)
{
$this->StoreSelectedIDs($event);
}
/**
* Returns sender & recipients ids plus event_id (as parameter by reference)
*
* @param kEvent $event
* @param int $event_id id of email event used
*
* @return mixed
*/
function GetMessageRecipients(&$event, &$event_id)
{
$email_event =& $event->getObject( Array('skip_autoload' => true) );
/* @var $email_event kDBItem */
// get event parameters by name & type
$load_keys = Array (
'Event' => $event->getEventParam('EmailEventName'),
'Type' => $event->getEventParam('EmailEventType'),
);
$email_event->Load($load_keys);
if (!$email_event->isLoaded()) {
// event record not found
return false;
}
if ($email_event->GetDBField('Enabled') == STATUS_DISABLED) {
return false;
}
if ($email_event->GetDBField('FrontEndOnly') && $this->Application->IsAdmin()) {
return false;
}
// initial values
$to_user_id = $event->getEventParam('EmailEventToUserId');
$from_user_id = $email_event->GetDBField('FromUserId');
if ($email_event->GetDBField('Type') == EVENT_TYPE_ADMIN) {
// For type "Admin" recipient is a user from field FromUserId which means From/To user in Email events list
$to_user_id = $from_user_id;
$from_user_id = -1;
}
$event_id = $email_event->GetDBField('EventId');
return Array ($from_user_id, $to_user_id);
}
/**
* Returns user name, email by id, or ones, that specified in $direct_params
*
* @param int $user_id
* @param string $user_type type of user = {to,from}
* @param Array $direct_params
* @return Array
*/
function GetRecipientInfo($user_id, $user_type, $direct_params = null)
{
// load user, because it can be addressed from email template tags
$user =& $this->Application->recallObject('u.email-'.$user_type, null, Array('skip_autoload' => true));
/* @var $user UsersItem */
$email = $name = '';
$result = $user_id > 0 ? $user->Load( (int)$user_id ) : $user->Clear();
if ($user->IsLoaded()) {
$email = $user->GetDBField('Email');
$name = trim($user->GetDBField('FirstName').' '.$user->GetDBField('LastName'));
}
if (is_array($direct_params)) {
if (isset($direct_params[$user_type.'_email'])) {
$email = $direct_params[$user_type.'_email'];
}
if (isset($direct_params[$user_type.'_name'])) {
$name = $direct_params[$user_type.'_name'];
}
}
if (!$email) {
// if email is empty, then use admins email
$email = $this->Application->ConfigValue('Smtp_AdminMailFrom');
}
if (!$name) {
$name = $user_type == 'from' ? strip_tags($this->Application->ConfigValue('Site_Name')) : $email;
}
return Array ($email, $name);
}
/**
* Returns email event message by ID (headers & body in one piece)
*
* @param int $event_id
* @param string $message_type contains message type = {text,html}
* @param int $language_id
*/
function GetMessageBody($event_id, &$message_type, $language_id = null)
{
if (!isset($language_id)) {
$language_id = $this->Application->GetVar('m_lang');
}
$message =& $this->Application->recallObject('emailmessages', null, Array('skip_autoload' => true));
/* @var $message kDBItem */
$message->Load( Array('EventId' => $event_id, 'LanguageId' => $language_id) );
if (!$message->isLoaded()) {
// event translation on required language not found
return false;
}
$message_type = $message->GetDBField('MessageType');
// 1. get message body
$message_body = $message->GetDBField('Template');
// 2. add footer
$sql = 'SELECT em.Template
FROM '.$message->TableName.' em
LEFT JOIN '.TABLE_PREFIX.'Events e ON e.EventId = em.EventId
WHERE em.LanguageId = '.$language_id.' AND e.Event = "COMMON.FOOTER"';
list (, $footer) = explode("\n\n", $this->Conn->GetOne($sql));
if ($message_type == 'text') {
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$footer = $esender->ConvertToText($footer);
}
if ($footer) {
$message_body .= "\r\n".$footer;
}
// 3. replace tags if needed
$default_replacement_tags = Array (
'<inp:touser _Field="password"' => '<inp2:u_Field name="Password_plain"',
'<inp:touser _Field="UserName"' => '<inp2:u_Field name="Login"',
'<inp:touser _Field' => '<inp2:u_Field name',
);
$replacement_tags = $message->GetDBField('ReplacementTags');
$replacement_tags = $replacement_tags ? unserialize($replacement_tags) : Array ();
$replacement_tags = array_merge_recursive2($default_replacement_tags, $replacement_tags);
foreach ($replacement_tags as $replace_from => $replace_to) {
$message_body = str_replace($replace_from, $replace_to, $message_body);
}
return $message_body;
}
/**
* Parse message template and return headers (as array) and message body part
*
* @param string $message
* @param Array $direct_params
* @return Array
*/
function ParseMessageBody($message, $direct_params = null)
{
$message_language = $this->_getSendLanguage($direct_params);
$this->_changeLanguage($message_language);
$direct_params['message_text'] = isset($direct_params['message']) ? $direct_params['message'] : ''; // parameter alias
// 1. parse template
$this->Application->InitParser();
$parser_params = $this->Application->Parser->Params; // backup parser params
- // ==== for TemplateParser class only: begin ====
-// $parser_pattern = $this->Application->Parser->Pattern;
-// $parser_values = $this->Application->Parser->Values;
-// $this->Application->Parser->Pattern = Array(); // fixes bug in TemplateParser::SortParams
-// $this->Application->Parser->Values = Array(); // fixes bug in TemplateParser::SortParams
- // ==== for TemplateParser class only: end ====
-
$this->Application->Parser->SetParams( array_merge_recursive2($parser_params, $direct_params) );
$message = implode('&|&', explode("\n\n", $message, 2)); // preserves double \n in case when tag is located in subject field
$message = $this->Application->Parser->Parse($message, 'email_template', 0);
- // ==== for TemplateParser class only: begin ====
-// $this->Application->Parser->Pattern = $parser_pattern;
-// $this->Application->Parser->Values = $parser_values;
- // ==== for TemplateParser class only: end ====
-
$this->Application->Parser->SetParams($parser_params); // restore parser params
// 2. replace line endings, that are send with data submitted via request
$message = str_replace("\r\n", "\n", $message); // possible case
$message = str_replace("\r", "\n", $message); // impossible case, but just in case replace this too
// 3. separate headers from body
$message_headers = Array ();
list($headers, $message_body) = explode('&|&', $message, 2);
$headers = explode("\n", $headers);
foreach ($headers as $header) {
$header = explode(':', $header, 2);
$message_headers[ trim($header[0]) ] = trim($header[1]);
}
$this->_changeLanguage();
return Array ($message_headers, $message_body);
}
/**
* Raised when email message shoul be sent
*
* @param kEvent $event
*/
function OnEmailEvent(&$event)
{
$email_event_name = $event->getEventParam('EmailEventName');
if (strpos($email_event_name, '_') !== false) {
trigger_error('<span class="debug_error">Invalid email event name</span> <b>'.$email_event_name.'</b>. Use only <b>UPPERCASE characters</b> and <b>dots</b> as email event names', E_USER_ERROR);
}
// additional parameters from kApplication->EmailEvent
$send_params = $event->getEventParam('DirectSendParams');
// 1. get information about message sender and recipient
$recipients = $this->GetMessageRecipients($event, $event_id);
if ($recipients === false) {
// if not valid recipients found, then don't send event
return false;
}
list ($from_id, $to_id) = $recipients;
list ($from_email, $from_name) = $this->GetRecipientInfo($from_id, 'from', $send_params);
list ($to_email, $to_name) = $this->GetRecipientInfo($to_id, 'to', $send_params);
// 2. prepare message to be sent
$message_language = $this->_getSendLanguage($send_params);
$message_template = $this->GetMessageBody($event_id, $message_type, $message_language);
if (!trim($message_template)) {
trigger_error('Message template is empty', E_USER_WARNING);
return false;
}
list ($message_headers, $message_body) = $this->ParseMessageBody($message_template, $send_params);
if (!trim($message_body)) {
trigger_error('Message template is empty after parsing', E_USER_WARNING);
return false;
}
// 3. set headers & send message
$esender =& $this->Application->recallObject('EmailSender');
/* @var $esender kEmailSendingHelper */
$esender->SetFrom($from_email, $from_name);
$esender->AddTo($to_email, $to_name);
$message_subject = isset($message_headers['Subject']) ? $message_headers['Subject'] : 'Mail message';
$esender->SetSubject($message_subject);
foreach ($message_headers as $header_name => $header_value) {
$esender->SetEncodedHeader($header_name, $header_value);
}
$esender->CreateTextHtmlPart($message_body, $message_type == 'html');
$event->status = $esender->Deliver() ? erSUCCESS : erFAIL;
if ($event->status == erSUCCESS){
// all keys, that are not used in email sending are written to log record
$send_keys = Array ('from_email', 'from_name', 'to_email', 'to_name', 'message');
foreach ($send_keys as $send_key) {
unset($send_params[$send_key]);
}
$fields_hash = Array (
'fromuser' => $from_name.' ('.$from_email.')',
'addressto' => $to_name.' ('.$to_email.')',
'subject' => $message_subject,
'timestamp' => adodb_mktime(),
'event' => $email_event_name,
'EventParams' => serialize($send_params),
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'EmailLog');
}
$this->Application->removeObject('u.email-from');
$this->Application->removeObject('u.email-to');
}
function _getSendLanguage($send_params)
{
if ($send_params && array_key_exists('language_id', $send_params)) {
return $send_params['language_id'];
}
return $this->Application->GetVar('m_lang');
}
function _changeLanguage($language_id = null)
{
static $prev_language_id = null;
if (!isset($language_id)) {
// restore language
$language_id = $prev_language_id;
}
$this->Application->SetVar('m_lang', $language_id);
$language =& $this->Application->recallObject('lang.current');
/* @var $lang_object kDBItem */
$language->Load($language_id);
$this->Application->Phrases->LanguageId = $language_id;
$this->Application->Phrases->Phrases = Array();
$prev_language_id = $language_id; // for restoring it later
}
/**
* Process emails from queue
*
* @param kEvent $event
* @todo Move to MailingList
*/
function OnProcessEmailQueue(&$event)
{
$deliver_count = $event->getEventParam('deliver_count');
if ($deliver_count === false) {
$deliver_count = $this->Application->ConfigValue('MailingListSendPerStep');
if ($deliver_count === false) {
$deliver_count = 10; // 10 emails per script run (if not specified directly)
}
}
$processing_type = $this->Application->GetVar('type');
if ($processing_type = 'return_progress') {
$email_queue_progress = $this->Application->RecallVar('email_queue_progress');
if ($email_queue_progress === false) {
$emails_sent = 0;
$sql = 'SELECT COUNT(*)
FROM ' . TABLE_PREFIX . 'EmailQueue
WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')';
$total_emails = $this->Conn->GetOne($sql);
$this->Application->StoreVar('email_queue_progress', $emails_sent.':'.$total_emails);
}
else {
list ($emails_sent, $total_emails) = explode(':', $email_queue_progress);
}
}
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'EmailQueue
WHERE (SendRetries < 5) AND (LastSendRetry < ' . strtotime('-2 hours') . ')
LIMIT 0,' . $deliver_count;
$messages = $this->Conn->Query($sql);
$message_count = count($messages);
if (!$message_count) {
// no messages left to send in queue
if ($processing_type = 'return_progress') {
$this->Application->RemoveVar('email_queue_progress');
$this->Application->Redirect($this->Application->GetVar('finish_template'));
}
return ;
}
$mailing_list_helper =& $this->Application->recallObject('MailingListHelper');
/* @var $mailing_list_helper MailingListHelper */
$mailing_list_helper->processQueue($messages);
if ($processing_type = 'return_progress') {
$emails_sent += $message_count;
if ($emails_sent >= $total_emails) {
$this->Application->RemoveVar('email_queue_progress');
$this->Application->Redirect($this->Application->GetVar('finish_template'));
}
$this->Application->StoreVar('email_queue_progress', $emails_sent.':'.$total_emails);
$event->status = erSTOP;
echo ($emails_sent / $total_emails) * 100;
}
}
}
\ No newline at end of file

Event Timeline