Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Thu, Feb 6, 3:59 PM

in-portal

Index: branches/5.0.x/core/units/helpers/themes_helper.php
===================================================================
--- branches/5.0.x/core/units/helpers/themes_helper.php (revision 13332)
+++ branches/5.0.x/core/units/helpers/themes_helper.php (revision 13333)
@@ -1,476 +1,534 @@
<?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.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
class kThemesHelper extends kHelper {
/**
* Where all themes are located
*
* @var string
*/
var $themesFolder = '';
/**
* List of theme names, found on system
*
* @var Array
*/
var $_themeNames = Array ();
/**
* Temporary array when all theme files from db are stored
*
* @var Array
*/
var $themeFiles = Array ();
function kThemesHelper()
{
parent::kHelper();
$this->themesFolder = FULL_PATH.'/themes';
}
/**
* Updates file system changes to database for selected theme
*
* @param string $theme_name
*
* @return mixed returns ID of created/used theme or false, if none created
*/
function refreshTheme($theme_name)
{
if (!file_exists($this->themesFolder . '/' . $theme_name)) {
// requested theme was not found on hdd
return false;
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT *
FROM ' . $table_name . '
WHERE Name = ' . $this->Conn->qstr($theme_name);
$theme_info = $this->Conn->GetRow($sql);
if ($theme_info) {
$theme_id = $theme_info[$id_field];
$theme_enabled = $theme_info['Enabled'];
}
else {
$theme_id = $theme_enabled = false;
}
$this->themeFiles = Array ();
if ($theme_id) {
if (!$theme_enabled) {
// don't process existing theme files, that are disabled
return $theme_id;
}
// reset found mark for every themes file (if theme is not new)
$sql = 'UPDATE '.TABLE_PREFIX.'ThemeFiles
SET FileFound = 0
WHERE ThemeId = '.$theme_id;
$this->Conn->Query($sql);
// get all theme files from db
$sql = 'SELECT FileId, CONCAT(FilePath, "/", FileName) AS FullPath
FROM '.TABLE_PREFIX.'ThemeFiles
WHERE ThemeId = '.$theme_id;
$this->themeFiles = $this->Conn->GetCol($sql, 'FullPath');
}
else {
// theme was not found in db, but found on hdd -> create new
$theme_info = Array (
'Name' => $theme_name,
'Enabled' => 0,
'Description' => $theme_name,
'PrimaryTheme' => 0,
'CacheTimeout' => 3600, // not in use right now
'StylesheetId' => 0, // not in use right now
'LanguagePackInstalled' => 0
);
$this->Conn->doInsert($theme_info, $table_name);
$theme_id = $this->Conn->getInsertID();
if (!$theme_enabled) {
// don't process newly created theme files, because they are disabled
return $theme_id;
}
}
$this->_themeNames[$theme_id] = $theme_name;
$theme_path = $this->themesFolder.'/'.$theme_name;
$this->FindThemeFiles('', $theme_path, $theme_id); // search from base theme directory
// delete file records from db, that were not found on hdd
$sql = 'DELETE FROM '.TABLE_PREFIX.'ThemeFiles
WHERE ThemeId = '.$theme_id.' AND FileFound = 0';
$this->Conn->Query($sql);
// install language packs, associated with theme (if any found and wasn't aready installed)
if (!$theme_info['LanguagePackInstalled']) {
- $language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
- /* @var $language_import_helper LanguageImportHelper */
-
- foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
- if ($module_name == 'In-Portal') {
- continue;
- }
-
- $lang_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/english.lang';
-
- if (file_exists($lang_file)) {
- $language_import_helper->performImport($lang_file, '|0|', '', LANG_SKIP_EXISTING);
- }
- }
+ $this->installThemeLanguagePack($theme_path);
$fields_hash = Array (
'LanguagePackInstalled' => 1,
);
$this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id);
}
- // get template aliases from "/_install/theme.xml" files in theme
+ $fields_hash = Array (
+ 'TemplateAliases' => serialize( $this->getTemplateAliases($theme_id, $theme_path) ),
+ );
+
+ $this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id);
+
+ return $theme_id;
+ }
+
+ /**
+ * Installs module(-s) language pack for given theme
+ *
+ * @param string $theme_path
+ * @param string $module_name
+ */
+ function installThemeLanguagePack($theme_path, $module_name = false)
+ {
+ if ($module_name === false) {
+ $modules = $this->Application->ModuleInfo;
+ }
+ else {
+ $modules = Array ($module_name => $this->Application->ModuleInfo[$module_name]);
+ }
+
+ $language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
+ /* @var $language_import_helper LanguageImportHelper */
+
+ foreach ($modules as $module_name => $module_info) {
+ if ($module_name == 'In-Portal') {
+ continue;
+ }
+
+ $lang_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/english.lang';
+
+ if (file_exists($lang_file)) {
+ $language_import_helper->performImport($lang_file, '|0|', '', LANG_SKIP_EXISTING);
+ }
+ }
+ }
+
+ /**
+ * Returns template aliases from "/_install/theme.xml" files in theme
+ *
+ * @param int $theme_id
+ * @param string $theme_path
+ */
+ function getTemplateAliases($theme_id, $theme_path)
+ {
$template_aliases = Array ();
$xml_parser =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_parser kXMLHelper */
foreach ($this->Application->ModuleInfo as $module_name => $module_info) {
if ($module_name == 'In-Portal') {
continue;
}
$xml_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/theme.xml';
if (file_exists($xml_file)) {
$xml_data = file_get_contents($xml_file);
$root_node =& $xml_parser->Parse($xml_data);
if (!is_object($root_node) || !is_a($root_node, 'kXMLNode') || !$root_node->Children) {
// broken xml OR no aliases defined
continue;
}
$current_node =& $root_node->firstChild;
do {
$template_path = trim($current_node->Data);
$alias = '#' . $module_info['TemplatePath'] . strtolower($current_node->Name). '#';
// remember alias in global theme mapping
$template_aliases[$alias] = $template_path;
// store alias in theme file record to use later in design dropdown
$t_parts = Array (
'path' => dirname($template_path) == '.' ? '' : '/' . dirname($template_path),
'file' => basename($template_path),
);
$sql = 'UPDATE ' . TABLE_PREFIX . 'ThemeFiles
SET TemplateAlias = ' . $this->Conn->qstr($alias) . '
WHERE (ThemeId = ' . $theme_id . ') AND (FilePath = ' . $this->Conn->qstr($t_parts['path']) . ') AND (FileName = ' . $this->Conn->qstr($t_parts['file'] . '.tpl') . ')';
$this->Conn->Query($sql);
} while (($current_node =& $current_node->NextSibling()));
}
}
- $fields_hash = Array (
- 'TemplateAliases' => serialize($template_aliases),
- );
+ return $template_aliases;
+ }
- $this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id);
+ /**
+ * Installs given module language pack and refreshed it from all themes
+ *
+ * @param string $module_name
+ */
+ function syncronizeModule($module_name)
+ {
+ $sql = 'SELECT `Name`, ThemeId
+ FROM ' . TABLE_PREFIX . 'Theme';
+ $themes = $this->Conn->GetCol($sql, 'ThemeId');
- return $theme_id;
+ if (!$themes) {
+ return ;
+ }
+
+ foreach ($themes as $theme_id => $theme_name) {
+ $theme_path = $this->themesFolder . '/' . $theme_name;
+
+ // install language pack
+ $this->installThemeLanguagePack($theme_path, $module_name);
+
+ // update TemplateAliases mapping
+ $fields_hash = Array (
+ 'TemplateAliases' => serialize( $this->getTemplateAliases($theme_id, $theme_path) ),
+ );
+
+ $this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'Theme', 'ThemeId = ' . $theme_id);
+ }
}
/**
* Searches for new templates (missing in db) in spefied folder
*
* @param string $folder_path subfolder of searchable theme
* @param string $theme_path theme path from web server root
* @param int $theme_id id of theme we are scanning
*/
function FindThemeFiles($folder_path, $theme_path, $theme_id, $auto_structure_mode = 1)
{
$fh = opendir($theme_path.$folder_path.'/');
// always ingore design and element templates
$ignore = Array ('^CVS$', '^\.svn$', '\.des\.tpl$', '\.elm\.tpl$');
$sms_ingore = $theme_path . $folder_path . '/.smsignore';
if (file_exists($sms_ingore)) {
$ignore = array_merge($ignore, file($sms_ingore));
}
while (($filename = readdir($fh))) {
if ($filename == '.' || $filename == '..') continue;
$auto_structure = $auto_structure_mode;
foreach ($ignore as $pattern) {
if (preg_match('/'.str_replace('/', '\\/', trim($pattern)).'/', $filename)) {
$auto_structure = 2;
break;
}
}
$full_path = $theme_path.$folder_path.'/'.$filename;
if (is_dir($full_path)) {
$this->FindThemeFiles($folder_path.'/'.$filename, $theme_path, $theme_id, $auto_structure);
}
elseif (substr($filename, -4) == '.tpl') {
$file_path = $folder_path.'/'.$filename;
$meta_info = $this->_getTemplateMetaInfo(trim($file_path, '/'), $theme_id);
$file_id = isset($this->themeFiles[$file_path]) ? $this->themeFiles[$file_path] : false;
$file_description = array_key_exists('desc', $meta_info) ? $meta_info['desc'] : '';
if ($file_id) {
// file was found in db & on hdd -> mark as existing
$fields_hash = Array (
'FileFound' => 1,
'Description' => $file_description,
'FileType' => $auto_structure,
'FileMetaInfo' => serialize($meta_info),
);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ThemeFiles', 'FileId = ' . $file_id);
}
else {
// file was found on hdd, but missing in db -> create new file record
$fields_hash = Array (
'ThemeId' => $theme_id,
'FileName' => $filename,
'FilePath' => $folder_path,
'Description' => $file_description,
'FileType' => $auto_structure, // 1 - built-in, 0 - custom (not in use right now), 2 - skipped in structure
'FileMetaInfo' => serialize($meta_info),
'FileFound' => 1,
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'ThemeFiles');
$this->themeFiles[$file_path] = $this->Conn->getInsertID();
}
// echo 'FilePath: [<strong>'.$folder_path.'</strong>]; FileName: [<strong>'.$filename.'</strong>]; IsNew: [<strong>'.($file_id > 0 ? 'NO' : 'YES').'</strong>]<br />';
}
}
}
/**
* Returns template information (name, description, path) from it's header comment
*
* @param string $template
* @param int $theme_id
* @return Array
*/
function _getTemplateMetaInfo($template, $theme_id)
{
static $init_made = false;
if (!$init_made) {
$this->Application->InitParser(true);
$init_made = true;
}
$template = 'theme:' . $this->_themeNames[$theme_id] . '/' . $template;
$template_file = $this->Application->TemplatesCache->GetRealFilename($template); // ".tpl" was added before
return $this->parseTemplateMetaInfo($template_file);
}
function parseTemplateMetaInfo($template_file)
{
if (!file_exists($template_file)) {
// when template without info it's placed in top category
return Array ();
}
$template_data = file_get_contents($template_file);
if (substr($template_data, 0, 6) == '<!--##') {
// template starts with comment in such format
/*<!--##
<NAME></NAME>
<DESC></DESC>
<SECTION>||</SECTION>
##-->*/
$comment_end = strpos($template_data, '##-->');
if ($comment_end === false) {
// badly formatted comment
return Array ();
}
$comment = trim( substr($template_data, 6, $comment_end - 6) );
if (preg_match_all('/<(NAME|DESC|SECTION)>(.*?)<\/(NAME|DESC|SECTION)>/is', $comment, $regs)) {
$ret = Array ();
foreach ($regs[1] as $param_order => $param_name) {
$ret[ strtolower($param_name) ] = trim($regs[2][$param_order]);
}
if (array_key_exists('section', $ret) && $ret['section']) {
$category_path = explode('||', $ret['section']);
$category_path = array_map('trim', $category_path);
$ret['section'] = implode('||', $category_path);
}
return $ret;
}
}
return Array ();
}
/**
* Updates file system changes to database for all themes (including new ones)
*
*/
function refreshThemes()
{
$themes_found = Array();
$skip_filenames = Array ('.', '..', 'CVS', '.svn');
$fh = opendir($this->themesFolder.'/');
while (($filename = readdir($fh))) {
if (in_array($filename, $skip_filenames)) {
continue;
}
if (is_dir($this->themesFolder.'/'.$filename)) {
$theme_id = $this->refreshTheme($filename);
if ($theme_id) {
$themes_found[] = $theme_id;
}
}
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
// 1. only one theme found -> enable it and make primary
/*if (count($themes_found) == 1) {
$sql = 'UPDATE ' . $table_name . '
SET Enabled = 1, PrimaryTheme = 1
WHERE ' . $id_field . ' = ' . current($themes_found);
$this->Conn->Query($sql);
}*/
// 2. if none themes found -> delete all from db OR delete all except of found themes
$sql = 'SELECT '.$id_field.'
FROM '.$table_name;
if ($themes_found) {
$sql .= ' WHERE '.$id_field.' NOT IN ('.implode(',', $themes_found).')';
}
$theme_ids = $this->Conn->GetCol($sql);
$this->deleteThemes($theme_ids);
}
/**
* Deletes themes with ids passed from db
*
* @param Array $theme_ids
*/
function deleteThemes($theme_ids)
{
if (!$theme_ids) {
return ;
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'DELETE FROM '.$table_name.'
WHERE '.$id_field.' IN ('.implode(',', $theme_ids).')';
$this->Conn->Query($sql);
$sql = 'DELETE FROM '.TABLE_PREFIX.'ThemeFiles
WHERE '.$id_field.' IN ('.implode(',', $theme_ids).')';
$this->Conn->Query($sql);
}
/**
* Returns current theme (also works in admin)
*
* @return int
*/
function getCurrentThemeId()
{
static $theme_id = null;
if (isset($theme_id)) {
return $theme_id;
}
if ($this->Application->isAdmin) {
// get theme, that user selected in catalog
$theme_id = $this->Application->RecallVar('theme_id');
if ($theme_id === false) {
// query, because "m_theme" is always empty in admin
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT ' . $id_field . '
FROM ' . $table_name . '
WHERE (PrimaryTheme = 1) AND (Enabled = 1)';
$theme_id = $this->Conn->GetOne($sql);
}
return $theme_id;
}
// use current theme, because it's available on Front-End
$theme_id = $this->Application->GetVar('m_theme');
if (!$theme_id) {
// happens in mod-rewrite mode, then requested template is not found
$theme_id = $this->Application->GetDefaultThemeId();
}
return $theme_id;
}
/**
* Returns page id based on given template
*
* @param string $template
* @param int $theme_id
* @return int
*/
function getPageByTemplate($template, $theme_id = null)
{
if (!isset($theme_id)) {
// during mod-rewrite url parsing current theme
// is not available to kHTTPQuery class, so don't use it
$theme_id = (int)$this->getCurrentThemeId();
}
$sql = 'SELECT ' . $this->Application->getUnitOption('c', 'IDField') . '
FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
WHERE
(
(NamedParentPath = ' . $this->Conn->qstr('Content/' . $template) . ') OR
(IsSystem = 1 AND CachedTemplate = ' . $this->Conn->qstr($template) . ')
)
AND (ThemeId = ' . $theme_id . ($theme_id > 0 ? ' OR ThemeId = 0' : '') . ')';
return $this->Conn->GetOne($sql);
}
}
\ No newline at end of file
Index: branches/5.0.x/core/install/install_toolkit.php
===================================================================
--- branches/5.0.x/core/install/install_toolkit.php (revision 13332)
+++ branches/5.0.x/core/install/install_toolkit.php (revision 13333)
@@ -1,866 +1,875 @@
<?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.org/license for copyright notices and details.
*/
defined('FULL_PATH') or die('restricted access!');
/**
* Upgrade sqls are located using this mask
*
*/
define('UPGRADES_FILE', FULL_PATH.'/%sinstall/upgrades.%s');
/**
* Prerequisit check classes are located using this mask
*
*/
define('PREREQUISITE_FILE', FULL_PATH.'/%sinstall/prerequisites.php');
/**
* Format of version identificator in upgrade files (normal, beta, release candidate)
*
*/
define('VERSION_MARK', '# ===== v ([\d]+\.[\d]+\.[\d]+|[\d]+\.[\d]+\.[\d]+-B[\d]+|[\d]+\.[\d]+\.[\d]+-RC[\d]+) =====');
if (!defined('GET_LICENSE_URL')) {
/**
* Url used for retrieving user licenses from Intechnic licensing server
*
*/
define('GET_LICENSE_URL', 'http://www.intechnic.com/myaccount/license.php');
}
/**
* Misc functions, that are required during installation, when
*
*/
class kInstallToolkit {
/**
* Reference to kApplication class object
*
* @var kApplication
*/
var $Application = null;
/**
* Connection to database
*
* @var kDBConnection
*/
var $Conn = null;
/**
* Path to config.php
*
* @var string
*/
var $INIFile = '';
/**
* Parsed data from config.php
*
* @var Array
*/
var $systemConfig = Array ();
/**
* Installator instance
*
* @var kInstallator
*/
var $_installator = null;
function kInstallToolkit()
{
if (class_exists('kApplication')) {
// auto-setup in case of separate module install
$this->Application =& kApplication::Instance();
$this->Conn =& $this->Application->GetADODBConnection();
}
$this->INIFile = FULL_PATH . DIRECTORY_SEPARATOR . 'config.php';
$this->systemConfig = $this->ParseConfig(true);
}
/**
* Sets installator
*
* @param kInstallator $instance
*/
function setInstallator(&$instance)
{
$this->_installator =& $instance;
}
/**
* Checks prerequisities before module install or upgrade
*
* @param string $module_path
* @param string $versions
* @param string $mode upgrade mode = {install, standalone, upgrade}
*/
function CheckPrerequisites($module_path, $versions, $mode)
{
static $prerequisit_classes = Array ();
$prerequisites_file = sprintf(PREREQUISITE_FILE, $module_path);
if (!file_exists($prerequisites_file) || !$versions) {
return Array ();
}
if (!isset($prerequisit_classes[$module_path])) {
// save class name, because 2nd time
// (in after call $prerequisite_class variable will not be present)
include_once $prerequisites_file;
$prerequisit_classes[$module_path] = $prerequisite_class;
}
$prerequisite_object = new $prerequisit_classes[$module_path]();
if (method_exists($prerequisite_object, 'setToolkit')) {
$prerequisite_object->setToolkit($this);
}
// some errors possible
return $prerequisite_object->CheckPrerequisites($versions, $mode);
}
/**
* Processes one license, received from server
*
* @param string $file_data
*/
function processLicense($file_data)
{
$modules_helper =& $this->Application->recallObject('ModulesHelper');
/* @var $modules_helper kModulesHelper */
$file_data = explode('Code==:', $file_data);
$file_data[0] = str_replace('In-Portal License File - do not edit!' . "\n", '', $file_data[0]);
$file_data = array_map('trim', $file_data);
if ($modules_helper->verifyLicense($file_data[0])) {
$this->setSystemConfig('Intechnic', 'License', $file_data[0]);
if (array_key_exists(1, $file_data)) {
$this->setSystemConfig('Intechnic', 'LicenseCode', $file_data[1]);
}
else {
$this->setSystemConfig('Intechnic', 'LicenseCode');
}
$this->SaveConfig();
}
else {
// invalid license received from licensing server
$this->_installator->errorMessage = 'Invalid License File';
}
}
/**
* Saves given configuration values to database
*
* @param Array $config
*/
function saveConfigValues($config)
{
foreach ($config as $config_var => $value) {
$sql = 'UPDATE ' . TABLE_PREFIX . 'ConfigurationValues
SET VariableValue = ' . $this->Conn->qstr($value) . '
WHERE VariableName = ' . $this->Conn->qstr($config_var);
$this->Conn->Query($sql);
}
}
/**
* Sets module version to passed
*
* @param string $module_name
* @param string $version
*/
function SetModuleVersion($module_name, $version = false)
{
if ($version === false) {
$version = $this->GetMaxModuleVersion($module_name);
}
// get table prefix from config, because application may not be available here
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
if ($module_name == 'kernel') {
$module_name = 'in-portal';
}
// don't use "adodb_mktime" here, because it's not yet included
$sql = 'UPDATE ' . $table_prefix . 'Modules
SET Version = "' . $version . '", BuildDate = ' . time() . '
WHERE LOWER(Name) = "' . strtolower($module_name) . '"';
$this->Conn->Query($sql);
}
/**
* Sets module root category to passed
*
* @param string $module_name
* @param string $category_id
*/
function SetModuleRootCategory($module_name, $category_id = 0)
{
// get table prefix from config, because application may not be available here
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
if ($module_name == 'kernel') {
$module_name = 'in-portal';
}
$sql = 'UPDATE ' . $table_prefix . 'Modules
SET RootCat = ' . $category_id . '
WHERE LOWER(Name) = "' . strtolower($module_name) . '"';
$this->Conn->Query($sql);
}
/**
* Returns maximal version of given module by scanning it's upgrade scripts
*
* @param string $module_name
* @return string
*/
function GetMaxModuleVersion($module_name)
{
$upgrades_file = sprintf(UPGRADES_FILE, mb_strtolower($module_name).'/', 'sql');
if (!file_exists($upgrades_file)) {
// no upgrade file
return '4.0.1';
}
$sqls = file_get_contents($upgrades_file);
$versions_found = preg_match_all('/'.VERSION_MARK.'/s', $sqls, $regs);
if (!$versions_found) {
// upgrades file doesn't contain version definitions
return '4.0.1';
}
return end($regs[1]);
}
/**
* Runs SQLs from file
*
* @param string $filename
* @param mixed $replace_from
* @param mixed $replace_to
*/
function RunSQL($filename, $replace_from = null, $replace_to = null)
{
if (!file_exists(FULL_PATH.$filename)) {
return ;
}
$sqls = file_get_contents(FULL_PATH.$filename);
if (!$this->RunSQLText($sqls, $replace_from, $replace_to)) {
if (is_object($this->_installator)) {
$this->_installator->Done();
}
else {
if (isset($this->Application)) {
$this->Application->Done();
}
exit;
}
}
}
/**
* Runs SQLs from string
*
* @param string $sqls
* @param mixed $replace_from
* @param mixed $replace_to
*/
function RunSQLText(&$sqls, $replace_from = null, $replace_to = null, $start_from=0)
{
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
// add prefix to all tables
if (strlen($table_prefix) > 0) {
$replacements = Array ('INSERT INTO ', 'UPDATE ', 'ALTER TABLE ', 'DELETE FROM ', 'REPLACE INTO ');
foreach ($replacements as $replacement) {
$sqls = str_replace($replacement, $replacement . $table_prefix, $sqls);
}
}
$sqls = str_replace('CREATE TABLE ', 'CREATE TABLE IF NOT EXISTS ' . $table_prefix, $sqls);
$sqls = str_replace('DROP TABLE ', 'DROP TABLE IF EXISTS ' . $table_prefix, $sqls);
$sqls = str_replace('<%TABLE_PREFIX%>', $table_prefix, $sqls);
if (isset($replace_from) && isset($replace_to)) {
// replace something additionally, e.g. module root category
$sqls = str_replace($replace_from, $replace_to, $sqls);
}
$sqls = str_replace("\r\n", "\n", $sqls); // convert to linux line endings
$no_comment_sqls = preg_replace("/#\s([^;]*?)\n/is", '', $sqls); // remove all comments "#" on new lines
if ($no_comment_sqls === null) {
// "ini.pcre.backtrack-limit" reached and error happened
$sqls = explode(";\n", $sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
// remove all comments "#" on new lines (takes about 2 seconds for 53000 sqls)
$sqls = preg_replace("/#\s([^;]*?)/", '', $sqls);
}
else {
$sqls = explode(";\n", $no_comment_sqls . "\n"); // ensures that last sql won't have ";" in it
$sqls = array_map('trim', $sqls);
}
$sql_count = count($sqls);
$db_collation = $this->getSystemConfig('Database', 'DBCollation');
for ($i = $start_from; $i < $sql_count; $i++) {
$sql = $sqls[$i];
if (!$sql || (substr($sql, 0, 1) == '#')) {
continue; // usually last line
}
if (substr($sql, 0, 13) == 'CREATE TABLE ' && $db_collation) {
// it is CREATE TABLE statement -> add collation
$sql .= ' COLLATE \'' . $db_collation . '\'';
}
$this->Conn->Query($sql);
if ($this->Conn->getErrorCode() != 0) {
if (is_object($this->_installator)) {
$this->_installator->errorMessage = 'Error: ('.$this->Conn->getErrorCode().') '.$this->Conn->getErrorMsg().'<br /><br />Last Database Query:<br /><textarea cols="70" rows="10" readonly>'.htmlspecialchars($sql).'</textarea>';
$this->_installator->LastQueryNum = $i + 1;
}
return false;
}
}
return true;
}
/**
* Performs clean language import from given xml file
*
* @param string $lang_file
* @param bool $upgrade
* @todo Import for "core/install/english.lang" (322KB) takes 18 seconds to work on Windows
*/
function ImportLanguage($lang_file, $upgrade = false)
{
$lang_file = FULL_PATH.$lang_file.'.lang';
if (!file_exists($lang_file)) {
return ;
}
$language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
/* @var $language_import_helper LanguageImportHelper */
$language_import_helper->performImport($lang_file, '|0|1|2|', '', $upgrade ? LANG_SKIP_EXISTING : LANG_OVERWRITE_EXISTING);
}
/**
* Converts module version in format X.Y.Z[-BN/-RCM] to signle integer
*
* @param string $version
* @return int
*/
function ConvertModuleVersion($version)
{
if (preg_match('/(.*)-(B|RC)([\d]+)/', $version, $regs)) {
// -B<M> or RC-<N>
$parts = explode('.', $regs[1]);
$parts[] = $regs[2] == 'B' ? 1 : 2; // B reliases goes before RC releases
$parts[] = $regs[3];
}
else {
// releases without B/RC marks go after any B/RC releases
$parts = explode('.', $version . '.3.100');
}
$bin = '';
foreach ($parts as $part_index => $part) {
if ($part_index == 3) {
// version type only can be 1/2/3 (11 in binary form), so don't use padding at all
$pad_count = 2;
}
else {
$pad_count = 8;
}
$bin .= str_pad(decbin($part), $pad_count, '0', STR_PAD_LEFT);
}
return bindec($bin);
}
/**
* Returns themes, found in system
*
* @param bool $rebuild
* @return int
*/
function getThemes($rebuild = false)
{
if ($rebuild) {
$this->rebuildThemes();
}
$id_field = $this->Application->getUnitOption('theme', 'IDField');
$table_name = $this->Application->getUnitOption('theme', 'TableName');
$sql = 'SELECT Name, ' . $id_field . '
FROM ' . $table_name . '
ORDER BY Name ASC';
return $this->Conn->GetCol($sql, $id_field);
}
function ParseConfig($parse_section = false)
{
if (!file_exists($this->INIFile)) {
return Array();
}
if( file_exists($this->INIFile) && !is_readable($this->INIFile) ) {
die('Could Not Open Ini File');
}
$contents = file($this->INIFile);
$retval = Array();
$section = '';
$ln = 1;
$resave = false;
foreach ($contents as $line) {
if ($ln == 1 && $line != '<'.'?'.'php die() ?'.">\n") {
$resave = true;
}
$ln++;
$line = trim($line);
$line = preg_replace('/;[.]*/', '', $line);
if (strlen($line) > 0) {
//echo $line . " - ";
if (preg_match('/^\[[a-z]+\]$/i', str_replace(' ', '', $line))) {
//echo 'section';
$section = mb_substr($line, 1, (mb_strlen($line) - 2));
if ($parse_section) {
$retval[$section] = array();
}
continue;
} elseif (strpos($line, '=') !== false) {
//echo 'main element';
list ($key, $val) = explode(' = ', $line);
if (!$parse_section) {
$retval[trim($key)] = str_replace('"', '', $val);
}
else {
$retval[$section][trim($key)] = str_replace('"', '', $val);
}
}
}
}
if ($resave) {
$fp = fopen($this->INIFile, 'w');
reset($contents);
fwrite($fp,'<'.'?'.'php die() ?'.">\n\n");
foreach ($contents as $line) {
fwrite($fp,"$line");
}
fclose($fp);
}
return $retval;
}
function SaveConfig($silent = false)
{
if (!is_writable($this->INIFile) && !is_writable(dirname($this->INIFile))) {
trigger_error('Cannot write to "' . $this->INIFile . '" file.', $silent ? E_USER_NOTICE : E_USER_ERROR);
return ;
}
$fp = fopen($this->INIFile, 'w');
fwrite($fp,'<'.'?'.'php die() ?'.">\n\n");
foreach ($this->systemConfig as $section_name => $section_data) {
fwrite($fp, '['.$section_name."]\n");
foreach ($section_data as $key => $value) {
fwrite($fp, $key.' = "'.$value.'"'."\n");
}
fwrite($fp, "\n");
}
fclose($fp);
}
/**
* Sets value to system config (yet SaveConfig must be called to write it to file)
*
* @param string $section
* @param string $key
* @param string $value
*/
function setSystemConfig($section, $key, $value = null)
{
if (isset($value)) {
if (!array_key_exists($section, $this->systemConfig)) {
// create section, when missing
$this->systemConfig[$section] = Array ();
}
// create key in section
$this->systemConfig[$section][$key] = $value;
return ;
}
unset($this->systemConfig[$section][$key]);
}
/**
* Returns information from system config
*
* @return string
*/
function getSystemConfig($section, $key)
{
if (!array_key_exists($section, $this->systemConfig)) {
return false;
}
if (!array_key_exists($key, $this->systemConfig[$section])) {
return false;
}
return $this->systemConfig[$section][$key] ? $this->systemConfig[$section][$key] : false;
}
/**
* Checks if system config is present and is not empty
*
* @return bool
*/
function systemConfigFound()
{
return file_exists($this->INIFile) && $this->systemConfig;
}
/**
* Checks if given section is present in config
*
* @param string $section
* @return bool
*/
function sectionFound($section)
{
return array_key_exists($section, $this->systemConfig);
}
/**
* Returns formatted module name based on it's root folder
*
* @param string $module_folder
* @return string
*/
function getModuleName($module_folder)
{
return implode('-', array_map('ucfirst', explode('-', $module_folder)));
}
/**
* Returns information about module (based on "install/module_info.xml" file)
*
* @param string $module_folder
* @return Array
*/
function getModuleInfo($module_folder)
{
$info_file = MODULES_PATH . '/' . $module_folder . '/install/module_info.xml';
if (!file_exists($info_file)) {
return Array ();
}
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$root_node =& $xml_helper->Parse( file_get_contents($info_file) );
if (!is_object($root_node) || !preg_match('/^kxmlnode/i', get_class($root_node)) || ($root_node->Name == 'ERROR')) {
// non-valid xml file
return Array ();
}
$ret = Array ();
$current_node =& $root_node->firstChild;
do {
$ret[ strtolower($current_node->Name) ] = trim($current_node->Data);
} while (($current_node =& $current_node->NextSibling()));
return $ret;
}
/**
* Returns nice module string to be used on install/upgrade screens
*
* @param string $module_folder
* @param string $version_string
* @return string
*/
function getModuleString($module_folder, $version_string)
{
// image (if exists) <description> (<name> <version>)
$ret = Array ();
$module_info = $this->getModuleInfo($module_folder);
if (array_key_exists('name', $module_info) && $module_info['name']) {
$module_name = $module_info['name'];
}
else {
$module_name = $this->getModuleName($module_folder);
}
if (array_key_exists('image', $module_info) && $module_info['image']) {
$image_src = $module_info['image'];
if (!preg_match('/^(http|https):\/\//', $image_src)) {
// local image -> make absolute url
$image_src = $this->Application->BaseURL() . $image_src;
}
$ret[] = '<img src="' . $image_src . '" alt="' . htmlspecialchars($module_name) . '" title="' . htmlspecialchars($module_name) . '" style="vertical-align:middle; margin: 3px 0 3px 5px"/>';
}
if (array_key_exists('description', $module_info) && $module_info['description']) {
$ret[] = $module_info['description'];
}
else {
$ret[] = $module_name;
}
$ret[] = '(' . $module_name . ' ' . $version_string . ')';
return implode(' ', $ret);
}
/**
* Creates module root category in "Home" category using given data and returns it
*
* @param string $name
* @param string $description
* @param string $category_template
* @param string $category_icon
* @return kDBItem
*/
function &createModuleCategory($name, $description, $category_template = null, $category_icon = null)
{
static $fields = null;
if (!isset($fields)) {
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
$fields['name'] = $ml_formatter->LangFieldName('Name');
$fields['description'] = $ml_formatter->LangFieldName('Description');
}
$category =& $this->Application->recallObject('c', null, Array ('skip_autoload' => true));
/* @var $category kDBItem */
$category_fields = Array (
$fields['name'] => $name, 'Filename' => $name, 'AutomaticFilename' => 1,
$fields['description'] => $description, 'Status' => STATUS_ACTIVE, 'Priority' => -9999,
+
+ // prevents empty link to module category on spearate module install
+ 'NamedParentPath' => 'Content/' . $name,
);
$category_fields['ParentId'] = $this->Application->findModule('Name', 'Core', 'RootCat');
if (isset($category_template)) {
$category_fields['Template'] = $category_template;
$category_fields['CachedTemplate'] = $category_template;
}
if (isset($category_icon)) {
$category_fields['UseMenuIconUrl'] = 1;
$category_fields['MenuIconUrl'] = $category_icon;
}
$category->Clear();
$category->SetDBFieldsFromHash($category_fields);
$category->Create();
$priority_helper =& $this->Application->recallObject('PriorityHelper');
/* @var $priority_helper kPriorityHelper */
$event = new kEvent('c:OnListBuild');
// ensure, that newly created category has proper value in Priority field
$priority_helper->recalculatePriorities($event, 'ParentId = ' . $category_fields['ParentId']);
// update Priority field in object, becase "CategoriesItem::Update" method will be called
// from "kInstallToolkit::setModuleItemTemplate" and otherwise will set 0 to Priority field
$sql = 'SELECT Priority
FROM ' . $category->TableName . '
WHERE ' . $category->IDField . ' = ' . $category->GetID();
$category->SetDBField('Priority', $this->Conn->GetOne($sql));
return $category;
}
/**
* Sets category item template into custom field for given prefix
*
* @param kDBItem $category
* @param string $prefix
* @param string $item_template
*/
function setModuleItemTemplate(&$category, $prefix, $item_template)
{
$this->Application->removeObject('c-cdata');
// recreate all fields, because custom fields are added during install script
$category->defineFields();
$category->prepareConfigOptions(); // creates ml fields
$category->SetDBField('cust_' . $prefix .'_ItemTemplate', $item_template);
$category->Update();
}
/**
* Link custom field records with search config records + create custom field columns
*
* @param string $module_folder
* @param int $item_type
*/
function linkCustomFields($module_folder, $prefix, $item_type)
{
$module_folder = strtolower($module_folder);
$module_name = $module_folder;
if ($module_folder == 'kernel') {
$module_name = 'in-portal';
$module_folder = 'core';
}
$db =& $this->Application->GetADODBConnection();
$sql = 'SELECT FieldName, CustomFieldId
FROM ' . TABLE_PREFIX . 'CustomField
WHERE Type = ' . $item_type . ' AND IsSystem = 0'; // config is not read here yet :( $this->Application->getUnitOption('p', 'ItemType');
$custom_fields = $db->GetCol($sql, 'CustomFieldId');
foreach ($custom_fields as $cf_id => $cf_name) {
$sql = 'UPDATE ' . TABLE_PREFIX . 'SearchConfig
SET CustomFieldId = ' . $cf_id . '
WHERE (TableName = "CustomField") AND (LOWER(ModuleName) = "' . $module_name . '") AND (FieldName = ' . $db->qstr($cf_name) . ')';
$db->Query($sql);
}
$this->Application->refreshModuleInfo(); // this module configs are now processed
// because of configs was read only from installed before modules (in-portal), then reread configs
$unit_config_reader =& $this->Application->recallObject('kUnitConfigReader');
/* @var $unit_config_reader kUnitConfigReader */
$unit_config_reader->scanModules(MODULES_PATH . DIRECTORY_SEPARATOR . $module_folder);
// create correct columns in CustomData table
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
$ml_helper->createFields($prefix . '-cdata', true);
}
/**
* Deletes cache, useful after separate module install and installator last step
*
*/
function deleteCache($refresh_permissions = false)
{
$sql = 'DELETE FROM ' . TABLE_PREFIX . 'Cache
WHERE VarName IN ("config_files", "configs_parsed", "sections_parsed")';
$this->Conn->Query($sql);
$this->Application->HandleEvent($event, 'c:OnResetCMSMenuCache');
if ($refresh_permissions) {
if ($this->Application->ConfigValue('QuickCategoryPermissionRebuild')) {
// refresh permission without progress bar
$updater =& $this->Application->recallObject('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
}
else {
// refresh permissions with ajax progress bar (when available)
$fields_hash = Array (
'VarName' => 'ForcePermCacheUpdate',
'Data' => 1,
);
$this->Conn->doInsert($fields_hash, TABLE_PREFIX . 'Cache');
}
}
}
/**
* Perform redirect after separate module install
*
* @param string $module_folder
* @param bool $refresh_permissions
*/
function finalizeModuleInstall($module_folder, $refresh_permissions = false)
{
if (!$this->Application->GetVar('redirect')) {
return ;
}
$this->SetModuleVersion($module_folder);
+ $themes_helper =& $this->Application->recallObject('ThemesHelper');
+ /* @var $themes_helper kThemesHelper */
+
+ $module_name = $this->Application->findModule('Path', rtrim($module_folder, '/') . '/', 'Name');
+ $themes_helper->syncronizeModule($module_name);
+
$this->deleteCache($refresh_permissions);
$url_params = Array (
'pass' => 'm', 'admin' => 1,
'RefreshTree' => 1, 'index_file' => 'index.php',
);
$this->Application->Redirect('modules/modules_list', $url_params);
}
/**
* Performs rebuild of themes
*
*/
function rebuildThemes()
{
$this->Application->HandleEvent($themes_event, 'adm:OnRebuildThemes');
}
/**
* Checks that file is writable by group or others
*
* @param string $file
* @return boolean
*/
function checkWritePermissions($file)
{
if (DIRECTORY_SEPARATOR == '\\') {
// windows doen't allow to check permissions (always returns null)
return null;
}
$permissions = fileperms($file);
return $permissions & 0x0010 || $permissions & 0x0002;
}
}
\ No newline at end of file

Event Timeline