Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Tue, Jun 17, 4:20 AM

in-portal

Index: branches/5.2.x/core/units/helpers/language_import_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/language_import_helper.php (revision 15157)
+++ branches/5.2.x/core/units/helpers/language_import_helper.php (revision 15158)
@@ -1,1164 +1,1148 @@
<?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.
*/
/**
* Language pack format version description
*
* v1
* ==========
* All language properties are separate nodes inside <LANGUAGE> node. There are
* two more nodes PHRASES and EVENTS for phrase and email event translations.
*
* v2
* ==========
* All data, that will end up in Language table is now attributes of LANGUAGE node
* and is name exactly as field name, that will be used to store that data.
*
* v4
* ==========
* Hint & Column translation added to each phrase translation
*/
defined('FULL_PATH') or die('restricted access!');
define('LANG_OVERWRITE_EXISTING', 1);
define('LANG_SKIP_EXISTING', 2);
class LanguageImportHelper extends kHelper {
/**
* Current Language in import
*
* @var LanguagesItem
*/
var $lang_object = null;
/**
* Current user's IP address
*
* @var string
*/
var $ip_address = '';
/**
* Event type + name mapping to id (from system)
*
* @var Array
*/
var $events_hash = Array ();
/**
* Language pack import mode
*
* @var int
*/
var $import_mode = LANG_SKIP_EXISTING;
/**
* Language IDs, that were imported
*
* @var Array
*/
var $_languages = Array ();
/**
* Temporary table names to perform import on
*
* @var Array
*/
var $_tables = Array ();
/**
* Phrase types allowed for import/export operations
*
* @var Array
*/
var $phrase_types_allowed = Array ();
/**
* Encoding, used for language pack exporting
*
* @var string
*/
var $_exportEncoding = 'base64';
/**
* Exported data limits (all or only specified ones)
*
* @var Array
*/
var $_exportLimits = Array (
'phrases' => false,
'emailevents' => false,
);
/**
* Debug language pack import process
*
* @var bool
*/
var $_debugMode = false;
/**
* Latest version of language pack format. Versions are not backwards compatible!
*
* @var int
*/
var $_latestVersion = 4;
/**
* Prefix-based serial numbers, that should be changed after import is finished
*
* @var Array
*/
var $changedPrefixes = Array ();
public function __construct()
{
parent::__construct();
// "core/install/english.lang", phrase count: 3318, xml parse time on windows: 10s, insert time: 0.058s
set_time_limit(0);
ini_set('memory_limit', -1);
$this->lang_object = $this->Application->recallObject('lang.import', null, Array ('skip_autoload' => true));
if (!(defined('IS_INSTALL') && IS_INSTALL)) {
// perform only, when not in installation mode
$this->_updateEventsCache();
}
$this->ip_address = getenv('HTTP_X_FORWARDED_FOR') ? getenv('HTTP_X_FORWARDED_FOR') : getenv('REMOTE_ADDR');
// $this->_debugMode = $this->Application->isDebugMode();
}
/**
* Performs import of given language pack (former Parse method)
*
* @param string $filename
* @param string $phrase_types
* @param Array $module_ids
* @param int $import_mode
* @return bool
*/
function performImport($filename, $phrase_types, $module_ids, $import_mode = LANG_SKIP_EXISTING)
{
// define the XML parsing routines/functions to call based on the handler path
if (!file_exists($filename) || !$phrase_types /*|| !$module_ids*/) {
return false;
}
if ($this->_debugMode) {
$start_time = microtime(true);
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '")');
}
if (defined('IS_INSTALL') && IS_INSTALL) {
// new events could be added during module upgrade
$this->_updateEventsCache();
}
$this->_initImportTables();
$phrase_types = explode('|', substr($phrase_types, 1, -1) );
// $module_ids = explode('|', substr($module_ids, 1, -1) );
$this->phrase_types_allowed = array_flip($phrase_types);
$this->import_mode = $import_mode;
$this->_parseXML($filename);
// copy data from temp tables to live
foreach ($this->_languages as $language_id) {
$this->_performUpgrade($language_id, 'phrases', 'PhraseKey', Array ('l%s_Translation', 'l%s_HintTranslation', 'l%s_ColumnTranslation', 'PhraseType'));
$this->_performUpgrade($language_id, 'emailevents', 'EventId', Array ('l%s_Subject', 'Headers', 'MessageType', 'l%s_Body'));
$this->_performUpgrade($language_id, 'country-state', 'CountryStateId', Array ('l%s_Name'));
}
$this->_initImportTables(true);
$this->changedPrefixes = array_unique($this->changedPrefixes);
foreach ($this->changedPrefixes as $prefix) {
$this->Application->incrementCacheSerial($prefix);
}
if ($this->_debugMode) {
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (microtime(true) - $start_time));
}
return true;
}
/**
* Creates XML file with exported language data (former Create method)
*
* @param string $filename filename to export into
* @param Array $phrase_types phrases types to export from modules passed in $module_ids
* @param Array $language_ids IDs of languages to export
* @param Array $module_ids IDs of modules to export phrases from
*/
function performExport($filename, $phrase_types, $language_ids, $module_ids)
{
$fp = fopen($filename,'w');
if (!$fp || !$phrase_types || !$module_ids || !$language_ids) {
return false;
}
$phrase_types = explode('|', substr($phrase_types, 1, -1) );
$module_ids = explode('|', substr($module_ids, 1, -1) );
$ret = '<LANGUAGES Version="' . $this->_latestVersion . '">' . "\n";
$export_fields = $this->_getExportFields();
$email_message_helper = $this->Application->recallObject('EmailMessageHelper');
/* @var $email_message_helper EmailMessageHelper */
// get languages
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('lang','TableName') . '
WHERE LanguageId IN (' . implode(',', $language_ids) . ')';
$languages = $this->Conn->Query($sql, 'LanguageId');
// get phrases
$phrase_modules = $module_ids;
array_push($phrase_modules, ''); // for old language packs without module
$phrase_modules = $this->Conn->qstrArray($phrase_modules);
// apply phrase selection limit
if ($this->_exportLimits['phrases']) {
$escaped_phrases = $this->Conn->qstrArray($this->_exportLimits['phrases']);
$limit_where = 'Phrase IN (' . implode(',', $escaped_phrases) . ')';
}
else {
$limit_where = 'TRUE';
}
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('phrases','TableName') . '
WHERE PhraseType IN (' . implode(',', $phrase_types) . ') AND Module IN (' . implode(',', $phrase_modules) . ') AND ' . $limit_where . '
ORDER BY Phrase';
$phrases = $this->Conn->Query($sql, 'PhraseId');
// email events
$module_sql = preg_replace('/(.*),/U', 'INSTR(Module,\'\\1\') OR ', implode(',', $module_ids) . ',');
// apply event selection limit
if ($this->_exportLimits['emailevents']) {
$escaped_email_events = $this->Conn->qstrArray($this->_exportLimits['emailevents']);
$limit_where = '`Event` IN (' . implode(',', $escaped_email_events) . ')';
}
else {
$limit_where = 'TRUE';
}
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
WHERE `Type` IN (' . implode(',', $phrase_types) . ') AND (' . substr($module_sql, 0, -4) . ') AND ' . $limit_where . '
ORDER BY `Event`, `Type`';
$events = $this->Conn->Query($sql, 'EventId');
if (in_array('Core', $module_ids)) {
// countries
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . '
WHERE Type = ' . DESTINATION_TYPE_COUNTRY . '
ORDER BY `IsoCode`';
$countries = $this->Conn->Query($sql, 'CountryStateId');
// states
$sql = 'SELECT *
FROM ' . $this->Application->getUnitOption('country-state', 'TableName') . '
WHERE Type = ' . DESTINATION_TYPE_STATE . '
ORDER BY `IsoCode`';
$states = $this->Conn->Query($sql, 'CountryStateId');
foreach ($states as $state_id => $state_data) {
$country_id = $state_data['StateCountryId'];
if (!array_key_exists('States', $countries[$country_id])) {
$countries[$country_id]['States'] = Array ();
}
$countries[$country_id]['States'][] = $state_id;
}
}
foreach ($languages as $language_id => $language_info) {
// language
$ret .= "\t" . '<LANGUAGE Encoding="' . $this->_exportEncoding . '"';
foreach ($export_fields as $export_field) {
$ret .= ' ' . $export_field . '="' . htmlspecialchars($language_info[$export_field]) . '"';
}
$ret .= '>' . "\n";
// filename replacements
$replacements = $language_info['FilenameReplacements'];
if ($replacements) {
$ret .= "\t\t" . '<REPLACEMENTS>';
$ret .= $this->_exportEncoding == 'base64' ? base64_encode($replacements) : '<![CDATA[' . $replacements . ']]>';
$ret .= '</REPLACEMENTS>' . "\n";
}
// phrases
if ($phrases) {
$ret .= "\t\t" . '<PHRASES>' . "\n";
foreach ($phrases as $phrase_id => $phrase) {
$translation = $phrase['l' . $language_id . '_Translation'];
$hint_translation = $phrase['l' . $language_id . '_HintTranslation'];
$column_translation = $phrase['l' . $language_id . '_ColumnTranslation'];
if (!$translation) {
// phrase is not translated on given language
continue;
}
if ( $this->_exportEncoding == 'base64' ) {
$data = base64_encode($translation);
$hint_translation = base64_encode($hint_translation);
$column_translation = base64_encode($column_translation);
}
else {
$data = '<![CDATA[' . $translation . ']]>';
$hint_translation = htmlspecialchars($hint_translation);
$column_translation = htmlspecialchars($column_translation);
}
$attributes = Array (
'Label="' . $phrase['Phrase'] . '"',
'Module="' . $phrase['Module'] . '"',
'Type="' . $phrase['PhraseType'] . '"'
);
if ( $phrase['l' . $language_id . '_HintTranslation'] ) {
$attributes[] = 'Hint="' . $hint_translation . '"';
}
if ( $phrase['l' . $language_id . '_ColumnTranslation'] ) {
$attributes[] = 'Column="' . $column_translation . '"';
}
$ret .= "\t\t\t" . '<PHRASE ' . implode(' ', $attributes) . '>' . $data . '</PHRASE>' . "\n";
}
$ret .= "\t\t" . '</PHRASES>' . "\n";
}
// email events
if ($events) {
$ret .= "\t\t" . '<EVENTS>' . "\n";
foreach ($events as $event_id => $event) {
$fields_hash = Array (
'Headers' => $event['Headers'],
'Subject' => $event['l' . $language_id . '_Subject'],
'Body' => $event['l' . $language_id . '_Body'],
);
$template = $email_message_helper->buildTemplate($fields_hash);
if (!$template) {
// email event is not translated on given language
continue;
}
$data = $this->_exportEncoding == 'base64' ? base64_encode($template) : '<![CDATA[' . $template . ']]>';
$ret .= "\t\t\t" . '<EVENT MessageType="' . $event['MessageType'] . '" Event="' . $event['Event'] . '" Type="' . $event['Type'] . '">' . $data . '</EVENT>'."\n";
}
$ret .= "\t\t" . '</EVENTS>' . "\n";
}
if (in_array('Core', $module_ids) && $countries) {
$ret .= "\t\t" . '<COUNTRIES>' . "\n";
foreach ($countries as $country_id => $country_data) {
$translation = $country_data['l' . $language_id . '_Name'];
if (!$translation) {
// country is not translated on given language
continue;
}
$data = $this->_exportEncoding == 'base64' ? base64_encode($translation) : $translation;
if (array_key_exists('States', $country_data)) {
$ret .= "\t\t\t" . '<COUNTRY Iso="' . $country_data['IsoCode'] . '" Translation="' . $data . '">' . "\n";
foreach ($country_data['States'] as $state_id) {
$translation = $states[$state_id]['l' . $language_id . '_Name'];
if (!$translation) {
// state is not translated on given language
continue;
}
$data = $this->_exportEncoding == 'base64' ? base64_encode($translation) : $translation;
$ret .= "\t\t\t\t" . '<STATE Iso="' . $states[$state_id]['IsoCode'] . '" Translation="' . $data . '"/>' . "\n";
}
$ret .= "\t\t\t" . '</COUNTRY>' . "\n";
}
else {
$ret .= "\t\t\t" . '<COUNTRY Iso="' . $country_data['IsoCode'] . '" Translation="' . $data . '"/>' . "\n";
}
}
$ret .= "\t\t" . '</COUNTRIES>' . "\n";
}
$ret .= "\t" . '</LANGUAGE>' . "\n";
}
$ret .= '</LANGUAGES>';
fwrite($fp, $ret);
fclose($fp);
return true;
}
/**
* Sets language pack encoding (not charset) used during export
*
* @param string $encoding
*/
function setExportEncoding($encoding)
{
$this->_exportEncoding = $encoding;
}
/**
* Sets language pack data limit for export
*
* @param string $prefix
* @param string $data
*/
function setExportLimit($prefix, $data = null)
{
if ( !isset($data) ) {
$key_field = $prefix == 'phrases' ? 'Phrase' : 'Event';
$ids = $this->getExportIDs($prefix);
$sql = 'SELECT ' . $key_field . '
FROM ' . $this->Application->getUnitOption($prefix, 'TableName') . '
WHERE ' . $this->Application->getUnitOption($prefix, 'IDField') . ' IN (' . $ids . ')';
$rs = $this->Conn->QueryRaw($sql);
if ( $this->Conn->RowCount($rs) ) {
$data = '';
while ( ($row = $this->Conn->GetNextRow($rs)) ) {
$data .= ',' . $row[$key_field];
}
$data = substr($data, 1);
}
$this->Conn->Destroy($rs);
}
if ( !is_array($data) ) {
$data = str_replace(',', "\n", $data);
$data = preg_replace("/\n+/", "\n", str_replace("\r", '', trim($data)));
$data = $data ? array_map('trim', explode("\n", $data)) : Array ();
}
$this->_exportLimits[$prefix] = $data;
}
/**
* Performs upgrade of given language pack part
*
* @param int $language_id
* @param string $prefix
* @param string $unique_field
* @param Array $data_fields
*/
function _performUpgrade($language_id, $prefix, $unique_field, $data_fields)
{
$live_records = $this->_getTableData($language_id, $prefix, $unique_field, $data_fields[0], false);
$temp_records = $this->_getTableData($language_id, $prefix, $unique_field, $data_fields[0], true);
if (!$temp_records) {
// no data for given language
return ;
}
// perform insert for records, that are missing in live table
$to_insert = array_diff($temp_records, $live_records);
if ($to_insert) {
$to_insert = $this->Conn->qstrArray($to_insert);
$sql = 'INSERT INTO ' . $this->Application->getUnitOption($prefix, 'TableName') . '
SELECT *
FROM ' . $this->_tables[$prefix] . '
WHERE ' . $unique_field . ' IN (' . implode(',', $to_insert) . ')';
$this->Conn->Query($sql);
// new records were added
$this->changedPrefixes[] = $prefix;
}
// perform update for records, that are present in live table
$to_update = array_diff($temp_records, $to_insert);
if ($to_update) {
$to_update = $this->Conn->qstrArray($to_update);
$sql = 'UPDATE ' . $this->Application->getUnitOption($prefix, 'TableName') . ' live
SET ';
foreach ($data_fields as $index => $data_field) {
$data_field = sprintf($data_field, $language_id);
$sql .= ' live.' . $data_field . ' = (
SELECT temp' . $index . '.' . $data_field . '
FROM ' . $this->_tables[$prefix] . ' temp' . $index . '
WHERE temp' . $index . '.' . $unique_field . ' = live.' . $unique_field . '
),';
}
$sql = substr($sql, 0, -1); // cut last comma
$where_clause = Array (
// this won't make any difference, but just in case
$unique_field . ' IN (' . implode(',', $to_update) . ')',
);
if ($this->import_mode == LANG_SKIP_EXISTING) {
// empty OR not set
$data_field = sprintf($data_fields[0], $language_id);
$where_clause[] = '(' . $data_field . ' = "") OR (' . $data_field . ' IS NULL)';
}
if ($where_clause) {
$sql .= "\n" . 'WHERE (' . implode(') AND (', $where_clause) . ')';
}
$this->Conn->Query($sql);
if ($this->Conn->getAffectedRows() > 0) {
// existing records were updated
$this->changedPrefixes[] = $prefix;
}
}
}
/**
* Returns data from given table used for language pack upgrade
*
* @param int $language_id
* @param string $prefix
* @param string $unique_field
* @param string $data_field
* @param bool $temp_mode
* @return Array
*/
function _getTableData($language_id, $prefix, $unique_field, $data_field, $temp_mode = false)
{
$data_field = sprintf($data_field, $language_id);
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
if ($temp_mode) {
// for temp table get only records, that have contents on given language (not empty and isset)
$sql = 'SELECT ' . $unique_field . '
FROM ' . $this->Application->GetTempName($table_name, 'prefix:' . $prefix) . '
WHERE (' . $data_field . ' <> "") AND (' . $data_field . ' IS NOT NULL)';
}
else {
// for live table get all records, no matter on what language
$sql = 'SELECT ' . $unique_field . '
FROM ' . $table_name;
}
return $this->Conn->GetCol($sql);
}
function _parseXML($filename)
{
- if ($this->_debugMode) {
+ if ( $this->_debugMode ) {
$start_time = microtime(true);
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '")');
}
- $fdata = file_get_contents($filename);
-
- $xml_parser = $this->Application->recallObject('kXMLHelper');
- /* @var $xml_parser kXMLHelper */
+ $languages = simplexml_load_file($filename);
- $root_node =& $xml_parser->Parse($fdata);
- if (!is_object($root_node) || !is_a($root_node, 'kXMLNode')) {
+ if ( $languages === false) {
// invalid language pack contents
return false;
}
- if ($root_node->Children) {
- $this->_processLanguages($root_node->firstChild);
+ if ( $languages->count() ) {
+ $this->_processLanguages($languages);
}
- if ($this->_debugMode) {
+ if ( $this->_debugMode ) {
$this->Application->Debugger->appendHTML(__CLASS__ . '::' . __FUNCTION__ . '("' . $filename . '"): ' . (microtime(true) - $start_time));
}
return true;
}
/**
* Creates temporary tables, used during language import
*
* @param bool $drop_only
*/
function _initImportTables($drop_only = false)
{
$this->_tables['phrases'] = $this->_prepareTempTable('phrases', $drop_only);
$this->_tables['emailevents'] = $this->_prepareTempTable('emailevents', $drop_only);
$this->_tables['country-state'] = $this->_prepareTempTable('country-state', $drop_only);
}
/**
* Create temp table for prefix, if table already exists, then delete it and create again
*
* @param string $prefix
* @param bool $drop_only
* @return string Name of created temp table
* @access protected
*/
protected function _prepareTempTable($prefix, $drop_only = false)
{
$id_field = $this->Application->getUnitOption($prefix, 'IDField');
$table = $this->Application->getUnitOption($prefix,'TableName');
$temp_table = $this->Application->GetTempName($table);
$sql = 'DROP TABLE IF EXISTS %s';
$this->Conn->Query( sprintf($sql, $temp_table) );
if (!$drop_only) {
$sql = 'CREATE TABLE ' . $temp_table . ' SELECT * FROM ' . $table . ' WHERE 0';
$this->Conn->Query($sql);
$sql = 'ALTER TABLE %1$s CHANGE %2$s %2$s INT(11) NOT NULL DEFAULT "0"';
$this->Conn->Query( sprintf($sql, $temp_table, $id_field) );
switch ($prefix) {
case 'phrases':
$unique_field = 'PhraseKey';
break;
case 'emailevents':
$unique_field = 'EventId';
break;
case 'country-state':
$unique_field = 'CountryStateId';
break;
default:
throw new Exception('Unknown prefix "<strong>' . $prefix . '</strong>" during language pack import');
break;
}
$sql = 'ALTER TABLE ' . $temp_table . ' ADD UNIQUE (' . $unique_field . ')';
$this->Conn->Query($sql);
}
return $temp_table;
}
/**
* Prepares mapping between event name+type and their ids in database
*
*/
function _updateEventsCache()
{
$sql = 'SELECT EventId, CONCAT(Event,"_",Type) AS EventMix
FROM ' . TABLE_PREFIX . 'EmailEvents';
$this->events_hash = $this->Conn->GetCol($sql, 'EventMix');
}
/**
* Returns language fields to be exported
*
* @return Array
*/
function _getExportFields()
{
return Array (
'PackName', 'LocalName', 'DateFormat', 'TimeFormat', 'InputDateFormat', 'InputTimeFormat',
'DecimalPoint', 'ThousandSep', 'Charset', 'UnitSystem', 'Locale', 'UserDocsUrl'
);
}
/**
* Processes parsed XML
*
- * @param kXMLNode $language_node
+ * @param SimpleXMLElement $languages
*/
- function _processLanguages(&$language_node)
+ function _processLanguages($languages)
{
- if (array_key_exists('VERSION', $language_node->Parent->Attributes)) {
- // version present -> use it
- $version = $language_node->Parent->Attributes['VERSION'];
- }
- else {
+ $version = (int)$languages['Version'];
+
+ if ( !$version ) {
// version missing -> guess it
- if (is_object($language_node->FindChild('DATEFORMAT'))) {
+ if ( $languages->DATEFORMAT->getName() ) {
$version = 1;
}
- elseif (array_key_exists('CHARSET', $language_node->Attributes)) {
+ elseif ( (string)$languages->LANGUAGE['Charset'] != '' ) {
$version = 2;
}
}
- if ($version == 1) {
+ if ( $version == 1 ) {
$field_mapping = Array (
'DATEFORMAT' => 'DateFormat',
'TIMEFORMAT' => 'TimeFormat',
'INPUTDATEFORMAT' => 'InputDateFormat',
'INPUTTIMEFORMAT' => 'InputTimeFormat',
'DECIMAL' => 'DecimalPoint',
'THOUSANDS' => 'ThousandSep',
'CHARSET' => 'Charset',
'UNITSYSTEM' => 'UnitSystem',
'DOCS_URL' => 'UserDocsUrl',
);
}
else {
$export_fields = $this->_getExportFields();
}
- do {
+ foreach ($languages as $language_node) {
$language_id = false;
$fields_hash = Array (
- 'PackName' => $language_node->Attributes['PACKNAME'],
- 'LocalName' => $language_node->Attributes['PACKNAME'],
- 'Encoding' => $language_node->Attributes['ENCODING'],
+ 'PackName' => (string)$language_node['PackName'],
+ 'LocalName' => (string)$language_node['PackName'],
+ 'Encoding' => (string)$language_node['Encoding'],
'Charset' => 'utf-8',
'SynchronizationModes' => Language::SYNCHRONIZE_DEFAULT,
);
- if ($version > 1) {
+ if ( $version > 1 ) {
foreach ($export_fields as $export_field) {
- $attribute_name = strtoupper($export_field);
-
- if (array_key_exists($attribute_name, $language_node->Attributes)) {
- $fields_hash[$export_field] = $language_node->Attributes[$attribute_name];
+ if ( (string)$language_node[$export_field] ) {
+ $fields_hash[$export_field] = (string)$language_node[$export_field];
}
}
}
- $sub_node =& $language_node->firstChild;
- /* @var $sub_node kXMLNode */
+ $container_nodes = Array ('PHRASES', 'EVENTS', 'COUNTRIES');
- do {
- switch ($sub_node->Name) {
- case 'PHRASES':
- if ($sub_node->Children) {
- if (!$language_id) {
- $language_id = $this->_processLanguage($fields_hash);
- }
+ foreach ($language_node as $sub_node) {
+ /* @var $sub_node SimpleXMLElement */
- if ($this->_debugMode) {
- $start_time = microtime(true);
- }
+ if ( in_array($sub_node->getName(), $container_nodes) ) {
+ if ( !$sub_node->count() ) {
+ continue;
+ }
- $this->_processPhrases($sub_node->firstChild, $language_id, $fields_hash['Encoding']);
+ if ( !$language_id ) {
+ $language_id = $this->_processLanguage($fields_hash);
+ }
+ }
- if ($this->_debugMode) {
- $this->Application->Debugger->appendHTML(__CLASS__ . '::' . '_processPhrases: ' . (microtime(true) - $start_time));
- }
- }
+ switch ($sub_node->getName()) {
+ case 'PHRASES':
+ $this->_processPhrases($sub_node, $language_id, $fields_hash['Encoding']);
break;
case 'EVENTS':
- if ($sub_node->Children) {
- if (!$language_id) {
- $language_id = $this->_processLanguage($fields_hash);
- }
-
- $this->_processEvents($sub_node->firstChild, $language_id, $fields_hash['Encoding']);
- }
+ $this->_processEvents($sub_node, $language_id, $fields_hash['Encoding']);
break;
case 'COUNTRIES':
- if ($sub_node->Children) {
- if (!$language_id) {
- $language_id = $this->_processLanguage($fields_hash);
- }
-
- $this->_processCountries($sub_node->firstChild, $language_id, $fields_hash['Encoding']);
- }
+ $this->_processCountries($sub_node, $language_id, $fields_hash['Encoding']);
break;
case 'REPLACEMENTS':
// added since v2
- $replacements = $sub_node->Data;
+ $replacements = (string)$sub_node;
- if ($fields_hash['Encoding'] != 'plain') {
+ if ( $fields_hash['Encoding'] != 'plain' ) {
$replacements = base64_decode($replacements);
}
$fields_hash['FilenameReplacements'] = $replacements;
break;
default:
- if ($version == 1) {
- $fields_hash[ $field_mapping[$sub_node->Name] ] = $sub_node->Data;
+ if ( $version == 1 ) {
+ $fields_hash[$field_mapping[$sub_node->Name]] = (string)$sub_node;
}
break;
}
- } while (($sub_node =& $sub_node->NextSibling()));
- } while (($language_node =& $language_node->NextSibling()));
+ }
+ }
}
/**
* Performs phases import
*
- * @param kXMLNode $phrase_node
+ * @param SimpleXMLElement $phrases
* @param int $language_id
* @param string $language_encoding
*/
- function _processPhrases(&$phrase_node, $language_id, $language_encoding)
+ function _processPhrases($phrases, $language_id, $language_encoding)
{
static $other_translations = Array ();
- if ($this->Application->isDebugMode()) {
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileStart('L[' . $language_id . ']P', 'Language: ' . $language_id . '; Phrases Import');
}
- do {
- $phrase_key = mb_strtoupper($phrase_node->Attributes['LABEL']);
+ foreach ($phrases as $phrase_node) {
+ /* @var $phrase_node SimpleXMLElement */
+
+ $phrase_key = mb_strtoupper($phrase_node['Label']);
$fields_hash = Array (
- 'Phrase' => $phrase_node->Attributes['LABEL'],
+ 'Phrase' => (string)$phrase_node['Label'],
'PhraseKey' => $phrase_key,
- 'PhraseType' => $phrase_node->Attributes['TYPE'],
- 'Module' => array_key_exists('MODULE', $phrase_node->Attributes) ? $phrase_node->Attributes['MODULE'] : 'Core',
- 'LastChanged' => adodb_mktime(),
+ 'PhraseType' => (int)$phrase_node['Type'],
+ 'Module' => (string)$phrase_node['Module'] ? (string)$phrase_node['Module'] : 'Core',
+ 'LastChanged' => TIMENOW,
'LastChangeIP' => $this->ip_address,
);
- $translation = $phrase_node->Data;
- $hint_translation = isset($phrase_node->Attributes['HINT']) ? $phrase_node->Attributes['HINT'] : '';
- $column_translation = isset($phrase_node->Attributes['COLUMN']) ? $phrase_node->Attributes['COLUMN'] : '';
+ $translation = (string)$phrase_node;
+ $hint_translation = (string)$phrase_node['Hint'];
+ $column_translation = (string)$phrase_node['Column'];
- if (array_key_exists($fields_hash['PhraseType'], $this->phrase_types_allowed)) {
- if ($language_encoding != 'plain') {
+ if ( array_key_exists($fields_hash['PhraseType'], $this->phrase_types_allowed) ) {
+ if ( $language_encoding != 'plain' ) {
$translation = base64_decode($translation);
$hint_translation = base64_decode($hint_translation);
$column_translation = base64_decode($column_translation);
}
- if (array_key_exists($phrase_key, $other_translations)) {
+ if ( array_key_exists($phrase_key, $other_translations) ) {
$other_translations[$phrase_key]['l' . $language_id . '_Translation'] = $translation;
$other_translations[$phrase_key]['l' . $language_id . '_HintTranslation'] = $hint_translation;
$other_translations[$phrase_key]['l' . $language_id . '_ColumnTranslation'] = $column_translation;
}
else {
$other_translations[$phrase_key] = Array (
'l' . $language_id . '_Translation' => $translation,
'l' . $language_id . '_HintTranslation' => $hint_translation,
'l' . $language_id . '_ColumnTranslation' => $column_translation,
);
}
$fields_hash = array_merge($fields_hash, $other_translations[$phrase_key]);
$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'REPLACE', false);
}
- } while (($phrase_node =& $phrase_node->NextSibling()));
+ }
- if ($this->Application->isDebugMode()) {
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileFinish('L[' . $language_id . ']P', 'Language: ' . $language_id . '; Phrases Import');
}
$this->Conn->doInsert($fields_hash, $this->_tables['phrases'], 'REPLACE');
}
/**
* Performs email event import
*
- * @param kXMLNode $event_node
+ * @param SimpleXMLElement $events
* @param int $language_id
* @param string $language_encoding
*/
- function _processEvents(&$event_node, $language_id, $language_encoding)
+ function _processEvents($events, $language_id, $language_encoding)
{
static $other_translations = Array ();
- if ($this->Application->isDebugMode()) {
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileStart('L[' . $language_id . ']E', 'Language: ' . $language_id . '; Events Import');
}
$email_message_helper = $this->Application->recallObject('EmailMessageHelper');
/* @var $email_message_helper EmailMessageHelper */
- do {
- $event_id = $this->_getEventId($event_node->Attributes['EVENT'], $event_node->Attributes['TYPE']);
- if ($event_id) {
- if ($language_encoding == 'plain') {
- $template = rtrim($event_node->Data);
- }
- else {
- $template = base64_decode($event_node->Data);
- }
+ foreach ($events as $event_node) {
+ /* @var $event_node SimpleXMLElement */
- $parsed = $email_message_helper->parseTemplate($template);
+ $event_id = $this->_getEventId((string)$event_node['Event'], (int)$event_node['Type']);
- $fields_hash = Array (
- 'EventId' => $event_id,
- 'Event' => $event_node->Attributes['EVENT'],
- 'Type' => $event_node->Attributes['TYPE'],
- 'MessageType' => $event_node->Attributes['MESSAGETYPE'],
- );
+ if ( !$event_id ) {
+ continue;
+ }
- if (array_key_exists($event_id, $other_translations)) {
- $other_translations[$event_id]['l' . $language_id . '_Subject'] = $parsed['Subject'];
- $other_translations[$event_id]['l' . $language_id . '_Body'] = $parsed['Body'];
- }
- else {
- $other_translations[$event_id] = Array (
- 'l' . $language_id . '_Subject' => $parsed['Subject'],
- 'l' . $language_id . '_Body' => $parsed['Body'],
- );
- }
+ if ( $language_encoding == 'plain' ) {
+ $template = rtrim($event_node);
+ }
+ else {
+ $template = base64_decode($event_node);
+ }
- if ($parsed['Headers']) {
- $other_translations[$event_id]['Headers'] = $parsed['Headers'];
- }
- elseif (!$parsed['Headers'] && !array_key_exists('Headers', $other_translations[$event_id])) {
- $other_translations[$event_id]['Headers'] = $parsed['Headers'];
- }
+ $parsed = $email_message_helper->parseTemplate($template);
+
+ $fields_hash = Array (
+ 'EventId' => $event_id,
+ 'Event' => (string)$event_node['Event'],
+ 'Type' => (int)$event_node['Type'],
+ 'MessageType' => (string)$event_node['MessageType'],
+ );
+
+ if ( array_key_exists($event_id, $other_translations) ) {
+ $other_translations[$event_id]['l' . $language_id . '_Subject'] = $parsed['Subject'];
+ $other_translations[$event_id]['l' . $language_id . '_Body'] = $parsed['Body'];
+ }
+ else {
+ $other_translations[$event_id] = Array (
+ 'l' . $language_id . '_Subject' => $parsed['Subject'],
+ 'l' . $language_id . '_Body' => $parsed['Body'],
+ );
+ }
- $fields_hash = array_merge($fields_hash, $other_translations[$event_id]);
- $this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE', false);
+ if ( $parsed['Headers'] ) {
+ $other_translations[$event_id]['Headers'] = $parsed['Headers'];
+ }
+ elseif ( !$parsed['Headers'] && !array_key_exists('Headers', $other_translations[$event_id]) ) {
+ $other_translations[$event_id]['Headers'] = $parsed['Headers'];
}
- } while (($event_node =& $event_node->NextSibling()));
- if ($this->Application->isDebugMode()) {
+ $fields_hash = array_merge($fields_hash, $other_translations[$event_id]);
+ $this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE', false);
+ }
+
+ if ( $this->Application->isDebugMode() ) {
$this->Application->Debugger->profileFinish('L[' . $language_id . ']E', 'Language: ' . $language_id . '; Events Import');
}
- if (isset($fields_hash)) {
+ if ( isset($fields_hash) ) {
// at least one email event in language pack was found in database
$this->Conn->doInsert($fields_hash, $this->_tables['emailevents'], 'REPLACE');
}
}
/**
* Performs country_state translation import
*
- * @param kXMLNode $country_state_node
+ * @param SimpleXMLElement $country_states
* @param int $language_id
* @param string $language_encoding
* @param bool $process_states
* @return void
*/
- function _processCountries(&$country_state_node, $language_id, $language_encoding, $process_states = false)
+ function _processCountries($country_states, $language_id, $language_encoding, $process_states = false)
{
static $other_translations = Array ();
- do {
- if ($process_states) {
- $country_state_id = $this->_getStateId($country_state_node->Parent->Attributes['ISO'], $country_state_node->Attributes['ISO']);
+ foreach ($country_states as $country_state_node) {
+ /* @var $country_state_node SimpleXMLElement */
+
+ if ( $process_states ) {
+ $country_state_id = $this->_getStateId((string)$country_states['Iso'], (string)$country_state_node['Iso']);
}
else {
- $country_state_id = $this->_getCountryId($country_state_node->Attributes['ISO']);
+ $country_state_id = $this->_getCountryId((string)$country_state_node['Iso']);
}
- if ($country_state_id) {
- if ($language_encoding == 'plain') {
- $translation = rtrim($country_state_node->Attributes['TRANSLATION']);
- }
- else {
- $translation = base64_decode($country_state_node->Attributes['TRANSLATION']);
- }
+ if ( !$country_state_id ) {
+ continue;
+ }
- $fields_hash = Array (
- 'CountryStateId' => $country_state_id,
- );
+ if ( $language_encoding == 'plain' ) {
+ $translation = rtrim($country_state_node['Translation']);
+ }
+ else {
+ $translation = base64_decode($country_state_node['Translation']);
+ }
- if (array_key_exists($country_state_id, $other_translations)) {
- $other_translations[$country_state_id]['l' . $language_id . '_Name'] = $translation;
- }
- else {
- $other_translations[$country_state_id] = Array (
- 'l' . $language_id . '_Name' => $translation,
- );
- }
+ $fields_hash = Array ('CountryStateId' => $country_state_id);
+
+ if ( array_key_exists($country_state_id, $other_translations) ) {
+ $other_translations[$country_state_id]['l' . $language_id . '_Name'] = $translation;
+ }
+ else {
+ $other_translations[$country_state_id] = Array ('l' . $language_id . '_Name' => $translation);
+ }
- $fields_hash = array_merge($fields_hash, $other_translations[$country_state_id]);
- $this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE', false);
+ $fields_hash = array_merge($fields_hash, $other_translations[$country_state_id]);
+ $this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE', false);
- if (!$process_states && $country_state_node->Children) {
- $this->_processCountries($country_state_node->firstChild, $language_id, $language_encoding, true);
- }
+ if ( !$process_states && $country_state_node->count() ) {
+ $this->_processCountries($country_state_node, $language_id, $language_encoding, true);
}
- } while (($country_state_node =& $country_state_node->NextSibling()));
+ }
$this->Conn->doInsert($fields_hash, $this->_tables['country-state'], 'REPLACE');
}
/**
* Creates/updates language based on given fields and returns it's id
*
* @param Array $fields_hash
* @return int
*/
function _processLanguage($fields_hash)
{
// 1. get language from database
$sql = 'SELECT ' . $this->lang_object->IDField . '
FROM ' . $this->lang_object->TableName . '
WHERE PackName = ' . $this->Conn->qstr($fields_hash['PackName']);
$language_id = $this->Conn->GetOne($sql);
if ($language_id) {
// 2. language found -> update, when allowed
$this->lang_object->Load($language_id);
if ($this->import_mode == LANG_OVERWRITE_EXISTING) {
// update live language record based on data from xml
$this->lang_object->SetFieldsFromHash($fields_hash);
$this->lang_object->Update();
}
}
else {
// 3. language not found -> create
$this->lang_object->SetFieldsFromHash($fields_hash);
$this->lang_object->SetDBField('Enabled', STATUS_ACTIVE);
if ($this->lang_object->Create()) {
$language_id = $this->lang_object->GetID();
if (defined('IS_INSTALL') && IS_INSTALL) {
// language created during install becomes admin interface language
$this->lang_object->setPrimary(true, true);
}
}
}
// 4. collect ID of every processed language
if (!in_array($language_id, $this->_languages)) {
$this->_languages[] = $language_id;
}
return $language_id;
}
/**
* Returns event id based on it's name and type
*
* @param string $event_name
* @param string $event_type
* @return int
*/
function _getEventId($event_name, $event_type)
{
$cache_key = $event_name . '_' . $event_type;
return array_key_exists($cache_key, $this->events_hash) ? $this->events_hash[$cache_key] : 0;
}
/**
* Returns country id based on it's 3letter ISO code
*
* @param string $iso
* @return int
*/
function _getCountryId($iso)
{
static $cache = null;
if (!isset($cache)) {
$sql = 'SELECT CountryStateId, IsoCode
FROM ' . TABLE_PREFIX . 'CountryStates
WHERE Type = ' . DESTINATION_TYPE_COUNTRY;
$cache = $this->Conn->GetCol($sql, 'IsoCode');
}
return array_key_exists($iso, $cache) ? $cache[$iso] : false;
}
/**
* Returns state id based on 3letter country ISO code and 2letter state ISO code
*
* @param string $country_iso
* @param string $state_iso
* @return int
*/
function _getStateId($country_iso, $state_iso)
{
static $cache = null;
if (!isset($cache)) {
$sql = 'SELECT CountryStateId, CONCAT(StateCountryId, "-", IsoCode) AS IsoCode
FROM ' . TABLE_PREFIX . 'CountryStates
WHERE Type = ' . DESTINATION_TYPE_STATE;
$cache = $this->Conn->GetCol($sql, 'IsoCode');
}
$country_id = $this->_getCountryId($country_iso);
return array_key_exists($country_id . '-' . $state_iso, $cache) ? $cache[$country_id . '-' . $state_iso] : false;
}
/**
* Returns comma-separated list of IDs, that will be exported
*
* @param string $prefix
* @return string
* @access public
*/
public function getExportIDs($prefix)
{
$ids = $this->Application->RecallVar($prefix . '_selected_ids');
if ( $ids ) {
// some records were selected in grid
return $ids;
}
$tag_params = Array (
'grid' => $prefix == 'phrases' ? 'Phrases' : 'Emails',
'skip_counting' => 1,
'per_page' => -1
);
$list = $this->Application->recallObject($prefix, $prefix . '_List', $tag_params);
/* @var $list kDBList */
$sql = $list->getCountSQL($list->GetSelectSQL());
$sql = str_replace('COUNT(*) AS count', $list->TableName . '.' . $list->IDField, $sql);
$ids = '';
$rs = $this->Conn->QueryRaw($sql);
if ( $this->Conn->RowCount($rs) ) {
while ( ($row = $this->Conn->GetNextRow($rs)) ) {
$ids .= ',' . $row[$list->IDField];
}
$ids = substr($ids, 1);
}
$this->Conn->Destroy($rs);
return $ids;
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/controls/minput_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/controls/minput_helper.php (revision 15157)
+++ branches/5.2.x/core/units/helpers/controls/minput_helper.php (revision 15158)
@@ -1,227 +1,218 @@
<?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 MInputHelper extends kHelper {
/**
* Returns table for given prefix
*
* @param string $prefix
* @param bool $temp
* @return string
* @access protected
*/
protected function getTable($prefix, $temp = false)
{
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
return $temp ? $this->Application->GetTempName($table_name, 'prefix:' . $prefix) : $table_name;
}
function prepareMInputXML($records, $use_fields)
{
$xml = '';
foreach ($records as $record) {
$xml .= '<record>';
foreach ($record as $field_name => $field_value) {
if (!in_array($field_name, $use_fields)) {
continue;
}
$xml .= '<field name="' . $field_name . '">' . htmlspecialchars($field_value) . '</field>';
}
$xml .= '</record>';
}
return $xml ? '<records>'.$xml.'</records>' : '';
}
/**
* Returns validation errors in XML format
*
* @param kDBItem $object
* @param Array $fields_hash
* @return string
*/
function prepareErrorsXML(&$object, $fields_hash)
{
$xml = '';
$errors = Array ();
foreach ($fields_hash as $field_name => $field_value) {
if (!$object->ValidateField($field_name)) {
$field_options = $object->GetFieldOptions($field_name);
$error_field = array_key_exists('error_field', $field_options) ? $field_options['error_field'] : $field_name;
$errors[$error_field] = '<field name="'.$error_field.'">'.$object->GetErrorMsg($error_field, false).'</field>';
}
}
return '<errors>'.implode('', $errors).'</errors>';
}
/**
* Validates MInput control fields
*
* @param kEvent $event
*/
function OnValidateMInputFields($event)
{
$object = $event->getObject();
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($items_info) {
list ($id, $field_values) = each($items_info);
foreach ($field_values as $field_name => $field_value) {
$object->SetField($field_name, $field_value);
}
$event_mapping = Array (
'AddRecord' => 'OnBeforeItemCreate',
'SaveRecord' => 'OnBeforeItemUpdate',
);
$request_type = $this->Application->GetVar('request_type');
if (array_key_exists($request_type, $event_mapping)) {
$event->CallSubEvent($event_mapping[$request_type]);
}
echo $this->prepareErrorsXML($object, $field_values);
}
$event->status = kEvent::erSTOP;
}
function parseMInputXML($xml)
{
- $xml_helper = $this->Application->recallObject('kXMLHelper');
- /* @var $xml_helper kXMLHelper */
-
- $root_node =& $xml_helper->Parse($xml);
- $root_node =& $root_node->FindChild('records');
+ $records = Array ();
+ $records_node = simplexml_load_string($xml);
- if ( !$root_node || !$root_node->firstChild ) {
+ if ( $records_node === false ) {
return false;
}
- $records = Array ();
- $current_node = $root_node->firstChild;
- /* @var $current_node kXMLNode */
-
- do {
+ foreach ($records_node as $record_node) {
$record = Array ();
- $sub_node =& $current_node->firstChild;
- /* @var $current_node kXMLNode */
- do {
- $record[ $sub_node->Attributes['NAME'] ] = $sub_node->Data;
- } while ( ($sub_node =& $sub_node->NextSibling()) );
+ foreach ($record_node as $field_node) {
+ $record[(string)$field_node['name']] = (string)$field_node;
+ }
$records[] = $record;
- } while ( ($current_node =& $current_node->NextSibling()) );
+ }
return $records;
}
/**
* Loads selected values from sub_prefix to main item virtual field.
* Called from OnAfterItemLoad of main prefix.
*
* @param kEvent $event
* @param string $store_field main item's field name, to store values into
* @param string $sub_prefix prefix used to store info about selected items
* @param Array $use_fields fields, used in value string building
*/
function LoadValues($event, $store_field, $sub_prefix, $use_fields)
{
$object = $event->getObject();
/* @var $object kDBItem */
$sub_item = $this->Application->recallObject($sub_prefix, null, Array('skip_autoload' => true));
/* @var $sub_item kDBItem */
$foreign_key = $this->Application->getUnitOption($sub_prefix, 'ForeignKey');
$sql = 'SELECT *
FROM '.$this->getTable($sub_prefix, $object->IsTempTable()).'
WHERE '.$foreign_key.' = '.$object->GetID();
$selected_items = $this->Conn->Query($sql);
$field_names = array_keys( $sub_item->GetFieldValues() );
foreach ($selected_items as $key => $fields_hash) {
$sub_item->Clear();
$sub_item->SetDBFieldsFromHash($fields_hash);
// to fill *_date and *_time fields from main date fields
$sub_item->UpdateFormattersSubFields();
foreach ($field_names as $field) {
$field_options = $sub_item->GetFieldOptions($field);
$formatter = array_key_exists('formatter', $field_options) ? $field_options['formatter'] : false;
if ($formatter == 'kDateFormatter') {
$selected_items[$key][$field] = $sub_item->GetField($field, $field_options['input_format']);
}
else {
$selected_items[$key][$field] = $sub_item->GetDBField($field);
}
}
}
$object->SetDBField($store_field, $this->prepareMInputXML($selected_items, $use_fields));
}
/**
* Saves data from minput control to subitem table (used from subitem hook)
*
* @param kEvent $sub_event
* @param string $store_field
*/
function SaveValues(&$sub_event, $store_field)
{
$main_object =& $sub_event->MasterEvent->getObject();
/* @var $main_object kDBItem */
$affected_field = $main_object->GetDBField($store_field);
$object = $this->Application->recallObject($sub_event->getPrefixSpecial(), null, Array ('skip_autoload' => true));
/* @var $object kDBItem */
$sub_table = $object->TableName;
$foreign_key = $this->Application->getUnitOption($sub_event->Prefix, 'ForeignKey');
$sql = 'DELETE FROM '.$sub_table.'
WHERE '.$foreign_key.' = '.$main_object->GetID();
$this->Conn->Query($sql);
if ($affected_field) {
$records = $this->parseMInputXML($affected_field);
$main_id = $main_object->GetID();
foreach ($records as $fields_hash) {
$object->Clear();
$fields_hash[$foreign_key] = $main_id;
$object->SetDBFieldsFromHash($fields_hash);
$object->Create();
}
}
}
}
\ No newline at end of file
Index: branches/5.2.x/core/units/helpers/themes_helper.php
===================================================================
--- branches/5.2.x/core/units/helpers/themes_helper.php (revision 15157)
+++ branches/5.2.x/core/units/helpers/themes_helper.php (revision 15158)
@@ -1,629 +1,622 @@
<?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 ();
public function __construct()
{
parent::__construct();
$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']) {
$this->installThemeLanguagePack($theme_path);
$fields_hash = Array (
'LanguagePackInstalled' => 1,
);
$this->Conn->doUpdate($fields_hash, $table_name, $id_field . ' = ' . $theme_id);
}
$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|bool $module_name
* @return void
*/
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
* @return Array
* @access protected
*/
protected 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' ) {
+ $xml_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/theme.xml';
+
+ if ( $module_name == 'In-Portal' || !file_exists($xml_file) ) {
continue;
}
- $xml_file = $theme_path . '/' . $module_info['TemplatePath'] . '_install/theme.xml';
+ $theme = simplexml_load_file($xml_file);
- 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;
- }
+ if ( $theme === false ) {
+ // broken xml OR no aliases defined
+ continue;
+ }
- $current_node =& $root_node->firstChild;
- /* @var $current_node kXMLNode */
+ foreach ($theme as $design) {
+ /* @var $design SimpleXMLElement */
- do {
- $template_path = trim($current_node->Data);
- $module_override = $current_node->GetAttribute('module');
-
- if ( $module_override ) {
- // allow to put template mappings form all modules into single theme.xml file
- $module_folder = $this->Application->findModule('Name', $module_override, 'TemplatePath');
- }
- else {
- // no module specified -> use module based on theme.xml file location
- $module_folder = $module_info['TemplatePath'];
- }
+ $template_path = trim($design);
+ $module_override = (string)$design['module'];
+
+ if ( $module_override ) {
+ // allow to put template mappings form all modules into single theme.xml file
+ $module_folder = $this->Application->findModule('Name', $module_override, 'TemplatePath');
+ }
+ else {
+ // no module specified -> use module based on theme.xml file location
+ $module_folder = $module_info['TemplatePath'];
+ }
- // only store alias, when template exists on disk
- if ( $this->getTemplateId($template_path, $theme_id) ) {
- $alias = '#' . $module_folder . strtolower($current_node->Name) . '#';
+ // only store alias, when template exists on disk
+ if ( $this->getTemplateId($template_path, $theme_id) ) {
+ $alias = '#' . $module_folder . strtolower($design->getName()) . '#';
- // remember alias in global theme mapping
- $template_aliases[$alias] = $template_path;
+ // remember alias in global theme mapping
+ $template_aliases[$alias] = $template_path;
- // store alias in theme file record to use later in design dropdown
- $this->updateTemplate($template_path, $theme_id, Array ('TemplateAlias' => $alias));
- }
- } while ( ($current_node =& $current_node->NextSibling()) );
+ // store alias in theme file record to use later in design dropdown
+ $this->updateTemplate($template_path, $theme_id, Array ('TemplateAlias' => $alias));
+ }
}
}
return $template_aliases;
}
/**
* Returns ID of given physical template (relative to theme) given from ThemeFiles table
* @param string $template_path
* @param int $theme_id
* @return int
* @access public
*/
public function getTemplateId($template_path, $theme_id)
{
$physical_template = $this->Application->getPhysicalTemplate($template_path);
if ( ($physical_template !== false) && (substr($physical_template, 0, 3) != 'id:') ) {
// replace menu template name with it's actual template name on disk
list ($template_path) = explode(':', $physical_template, 2);
}
$sql = 'SELECT FileId
FROM ' . TABLE_PREFIX . 'ThemeFiles
WHERE ' . $this->getTemplateWhereClause($template_path, $theme_id);
return $this->Conn->GetOne($sql);
}
/**
* Updates template record with a given data
*
* @param string $template_path
* @param int $theme_id
* @param Array $fields_hash
* @return void
* @access public
*/
public function updateTemplate($template_path, $theme_id, $fields_hash)
{
$where_clause = $this->getTemplateWhereClause($template_path, $theme_id);
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX . 'ThemeFiles', $where_clause);
}
/**
* Returns where clause to get associated record from ThemeFiles table for given template path
* @param string $template_path
* @param int $theme_id
* @return string
* @access protected
*/
protected function getTemplateWhereClause($template_path, $theme_id)
{
$folder = dirname($template_path);
$where_clause = Array (
'ThemeId = ' . $theme_id,
'FilePath = ' . $this->Conn->qstr($folder == '.' ? '' : '/' . $folder),
'FileName = ' . $this->Conn->qstr(basename($template_path) . '.tpl'),
);
return '(' . implode(') AND (', $where_clause) . ')';
}
/**
* Installs given module language pack and refreshed it from all themes
*
* @param string $module_name
*/
function synchronizeModule($module_name)
{
$sql = 'SELECT `Name`, ThemeId
FROM ' . TABLE_PREFIX . 'Themes';
$themes = $this->Conn->GetCol($sql, 'ThemeId');
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 . 'Themes', 'ThemeId = ' . $theme_id);
}
}
/**
* Searches for new templates (missing in db) in specified 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
* @param int $auto_structure_mode
*/
function FindThemeFiles($folder_path, $theme_path, $theme_id, $auto_structure_mode = 1)
{
$ignore_regexp = $this->getIgnoreRegexp($theme_path . $folder_path);
$iterator = new DirectoryIterator($theme_path . $folder_path . '/');
/* @var $file_info DirectoryIterator */
foreach ($iterator as $file_info) {
$filename = $file_info->getFilename();
$auto_structure = preg_match($ignore_regexp, $filename) ? 2 : $auto_structure_mode;
$file_path = $folder_path . '/' . $filename; // don't pass path to theme top folder!
if ( $file_info->isDir() && !$file_info->isDot() && $filename != 'CVS' && $filename != '.svn' ) {
$this->FindThemeFiles($file_path, $theme_path, $theme_id, $auto_structure);
}
elseif ( pathinfo($filename, PATHINFO_EXTENSION) == 'tpl' ) {
$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 single regular expression to match all ignore patters, that are valid for given folder
*
* @param string $folder_path
* @return string
*/
protected function getIgnoreRegexp($folder_path)
{
// always ignore design and element templates
$ignore = '\.des\.tpl$|\.elm\.tpl$';
$sms_ignore_file = $folder_path . '/.smsignore';
if ( file_exists($sms_ignore_file) ) {
$manual_patterns = array_map('trim', file($sms_ignore_file));
foreach ($manual_patterns as $manual_pattern) {
$ignore .= '|' . str_replace('/', '\\/', $manual_pattern);
}
}
return '/' . $ignore . '/';
}
/**
* 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 ();
try {
$iterator = new DirectoryIterator($this->themesFolder . '/');
/* @var $file_info DirectoryIterator */
foreach ($iterator as $file_info) {
$filename = $file_info->getFilename();
if ( $file_info->isDir() && !$file_info->isDot() && $filename != '.svn' && $filename != 'CVS' ) {
$theme_id = $this->refreshTheme($filename);
if ( $theme_id ) {
$themes_found[] = $theme_id;
// increment serial of updated themes
$this->Application->incrementCacheSerial('theme', $theme_id);
}
}
}
}
catch ( UnexpectedValueException $e ) {
}
$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);
foreach ($theme_ids as $theme_id) {
// increment serial of deleted themes
$this->Application->incrementCacheSerial('theme', $theme_id);
}
$this->Application->incrementCacheSerial('theme');
$this->Application->incrementCacheSerial('theme-file');
$minify_helper = $this->Application->recallObject('MinifyHelper');
/* @var $minify_helper MinifyHelper */
$minify_helper->delete();
}
/**
* 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
(`Type` = ' . PAGE_TYPE_TEMPLATE . ' 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.2.x/core/install/install_toolkit.php
===================================================================
--- branches/5.2.x/core/install/install_toolkit.php (revision 15157)
+++ branches/5.2.x/core/install/install_toolkit.php (revision 15158)
@@ -1,1182 +1,1178 @@
<?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.in-portal.com/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 ();
/**
* Tells, that system config was changed
*
* @var bool
* @access public
*/
public $systemConfigChanged = false;
/**
* Path, used by system to store data on filesystem
*
* @var string
*/
var $defaultWritablePath = '';
/**
* Installator instance
*
* @var kInstallator
*/
var $_installator = null;
function kInstallToolkit()
{
$this->defaultWritablePath = DIRECTORY_SEPARATOR . 'system';
if ( class_exists('kApplication') ) {
// auto-setup in case of separate module install
$this->Application =& kApplication::Instance();
$this->Application->Init(); // needed for standalone module install
$this->Conn =& $this->Application->GetADODBConnection();
}
$this->INIFile = FULL_PATH . $this->defaultWritablePath . 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}
* @return bool
*/
function CheckPrerequisites($module_path, $versions, $mode)
{
if ( !$versions ) {
return Array ();
}
$prerequisite_object =& $this->getPrerequisiteObject($module_path);
/* @var $prerequisite_object InPortalPrerequisites */
// some errors possible
return is_object($prerequisite_object) ? $prerequisite_object->CheckPrerequisites($versions, $mode) : Array ();
}
/**
* Call prerequisites method
*
* @param string $module_path
* @param string $method
* @return array
*/
function CallPrerequisitesMethod($module_path, $method)
{
$prerequisite_object =& $this->getPrerequisiteObject($module_path);
/* @var $prerequisite_object InPortalPrerequisites */
return is_object($prerequisite_object) ? $prerequisite_object->$method() : false;
}
/**
* Returns prerequisite object to be used for checks
*
* @param string $module_path
* @return kHelper
* @access protected
*/
protected function &getPrerequisiteObject($module_path)
{
static $prerequisite_classes = Array ();
$prerequisites_file = sprintf(PREREQUISITE_FILE, $module_path);
if ( !file_exists($prerequisites_file) ) {
$false = false;
return $false;
}
if ( !isset($prerequisite_classes[$module_path]) ) {
// save class name, because 2nd time
// (in after call $prerequisite_class variable will not be present)
include_once $prerequisites_file;
$prerequisite_classes[$module_path] = $prerequisite_class;
}
$prerequisite_object = new $prerequisite_classes[$module_path]();
/* @var $prerequisite_object InPortalPrerequisites */
if ( method_exists($prerequisite_object, 'setToolkit') ) {
$prerequisite_object->setToolkit($this);
}
return $prerequisite_object;
}
/**
* 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 . 'SystemSettings
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|bool $module_path
* @param string|bool $version
*/
function SetModuleVersion($module_name, $module_path = false, $version = false)
{
if ($version === false) {
if (!$module_path) {
throw new Exception('Module path must be given to "SetModuleVersion" method to auto-detect version');
return ;
}
$version = $this->GetMaxModuleVersion($module_path);
}
// 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 int $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_path
* @return string
*/
function GetMaxModuleVersion($module_path)
{
$module_path = rtrim(mb_strtolower($module_path), '/');
$upgrades_file = sprintf(UPGRADES_FILE, $module_path . '/', 'sql');
if (!file_exists($upgrades_file)) {
// no upgrade file
return '5.0.0';
}
$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 '5.0.0';
}
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
* @param int $start_from
* @return bool
*/
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);
$primary_language = is_object($this->Application) ? $this->Application->GetDefaultLanguageId() : 1;
$sqls = str_replace('<%PRIMARY_LANGUAGE%>', $primary_language, $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);
if ($contents && $contents[0] == '<' . '?' . 'php die() ?' . ">\n") {
// format of "config.php" file before 5.1.0 version
array_shift($contents);
return $this->parseIniString(implode('', $contents), $parse_section);
}
$_CONFIG = Array ();
require($this->INIFile);
if ($parse_section) {
return $_CONFIG;
}
$ret = Array ();
foreach ($_CONFIG as $section => $section_variables) {
$ret = array_merge($ret, $section_variables);
}
return $ret;
}
/**
* Equivalent for "parse_ini_string" function available since PHP 5.3.0
*
* @param string $ini
* @param bool $process_sections
* @param int $scanner_mode
* @return Array
*/
function parseIniString($ini, $process_sections = false, $scanner_mode = null)
{
# Generate a temporary file.
$tempname = tempnam('/tmp', 'ini');
$fp = fopen($tempname, 'w');
fwrite($fp, $ini);
$ini = parse_ini_file($tempname, !empty($process_sections));
fclose($fp);
@unlink($tempname);
return $ini;
}
function SaveConfig($silent = false)
{
if (!is_writable($this->INIFile) && !is_writable(dirname($this->INIFile))) {
$error_msg = 'Cannot write to "' . $this->INIFile . '" file';
if ($silent) {
trigger_error($error_msg, E_USER_WARNING);
}
else {
throw new Exception($error_msg);
}
return ;
}
$fp = fopen($this->INIFile, 'w');
fwrite($fp, '<' . '?' . 'php' . "\n\n");
foreach ($this->systemConfig as $section_name => $section_data) {
foreach ($section_data as $key => $value) {
fwrite($fp, '$_CONFIG[\'' . $section_name . '\'][\'' . $key . '\'] = \'' . addslashes($value) . '\';' . "\n");
}
fwrite($fp, "\n");
}
fclose($fp);
$this->systemConfigChanged = false;
}
/**
* 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)
{
$this->systemConfigChanged = true;
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
*
* @param string $section
* @param string $key
* @param mixed $default
* @return string|bool
*/
function getSystemConfig($section, $key, $default = false)
{
if ( !array_key_exists($section, $this->systemConfig) ) {
return $default;
}
if ( !array_key_exists($key, $this->systemConfig[$section]) ) {
return $default;
}
return $this->systemConfig[$section][$key] ? $this->systemConfig[$section][$key] : $default;
}
/**
* 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_name
* @return Array
*/
function getModuleInfo($module_name)
{
- if ($module_name == 'core') {
+ if ( $module_name == 'core' ) {
$info_file = FULL_PATH . '/' . $module_name . '/install/module_info.xml';
}
else {
$info_file = MODULES_PATH . '/' . $module_name . '/install/module_info.xml';
}
- if (!file_exists($info_file)) {
+ 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) );
+ $ret = Array ();
+ $module_info = simplexml_load_file($info_file);
- if (!is_object($root_node) || !preg_match('/^kxmlnode/i', get_class($root_node)) || ($root_node->Name == 'ERROR')) {
+ if ( $module_info === false ) {
// 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()));
+ foreach ($module_info as $node) {
+ /* @var $node SimpleXMLElement */
+ $ret[strtolower($node->getName())] = trim($node);
+ }
return $ret;
}
/**
* Returns nice module string to be used on install/upgrade screens
*
* @param string $module_name
* @param string $version_string
* @return string
*/
function getModuleString($module_name, $version_string)
{
// image (if exists) <description> (<name> <version>)
$ret = Array ();
$module_info = $this->getModuleInfo($module_name);
if (array_key_exists('name', $module_info) && $module_info['name']) {
$module_name = $module_info['name'];
}
else {
$module_name = $this->getModuleName($module_name);
}
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');
/* @var $ml_formatter 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->getBaseCategory();
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->Configure();
$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 string $prefix
* @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 . 'CustomFields
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 = "CustomFields") 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
$this->Application->UnitConfigReader->scanModules(MODULES_PATH . DIRECTORY_SEPARATOR . $module_folder);
// create correct columns in CustomData table
$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$ml_helper->createFields($prefix . '-cdata', true);
}
/**
* Deletes cache, useful after separate module install and installator last step
*
* @param bool $refresh_permissions
* @return void
*/
function deleteCache($refresh_permissions = false)
{
$this->Application->HandleEvent(new kEvent('adm:OnResetConfigsCache'));
$this->Application->HandleEvent(new kEvent('adm:OnResetSections'));
$this->Application->HandleEvent(new kEvent('c:OnResetCMSMenuCache'));
$this->Conn->Query('DELETE FROM ' . TABLE_PREFIX . 'CachedUrls');
if ( $refresh_permissions ) {
if ( $this->Application->ConfigValue('QuickCategoryPermissionRebuild') ) {
// refresh permission without progress bar
$updater = $this->Application->makeClass('kPermCacheUpdater');
/* @var $updater kPermCacheUpdater */
$updater->OneStepRun();
}
else {
// refresh permissions with ajax progress bar (when available)
$this->Application->setDBCache('ForcePermCacheUpdate', 1);
}
}
}
/**
* Deletes all temp tables (from active sessions too)
*
*/
function deleteEditTables()
{
$table_prefix = $this->getSystemConfig('Database', 'TablePrefix');
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/' . $table_prefix . 'ses_(.*)_edit_(.*)/';
$mask_search_table = '/' . $table_prefix . 'ses_(.*?)_(.*)/';
foreach ($tables as $table) {
if ( preg_match($mask_edit_table, $table, $rets) || preg_match($mask_search_table, $table, $rets) ) {
$this->Conn->Query('DROP TABLE IF EXISTS ' . $table);
}
}
}
/**
* Perform redirect after separate module install
*
* @param string $module_folder
* @param bool $refresh_permissions
*/
function finalizeModuleInstall($module_folder, $refresh_permissions = false)
{
$this->SetModuleVersion(basename($module_folder), $module_folder);
if (!$this->Application->GetVar('redirect')) {
return ;
}
$themes_helper = $this->Application->recallObject('ThemesHelper');
/* @var $themes_helper kThemesHelper */
// use direct query, since module isn't yet in kApplication::ModuleInfo array
$sql = 'SELECT Name
FROM ' . TABLE_PREFIX . 'Modules
WHERE Path = ' . $this->Conn->qstr(rtrim($module_folder, '/') . '/');
$module_name = $this->Conn->GetOne($sql);
$themes_helper->synchronizeModule($module_name);
$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$ml_helper->massCreateFields();
$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(new kEvent('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;
}
/**
* Upgrades primary skin to the latest version
*
* @param Array $module_info
* @return string|bool
*/
function upgradeSkin($module_info)
{
$upgrades_file = sprintf(UPGRADES_FILE, $module_info['Path'], 'css');
$data = file_get_contents($upgrades_file);
// get all versions with their positions in file
$versions = Array ();
preg_match_all('/(' . VERSION_MARK . ')/s', $data, $matches, PREG_SET_ORDER + PREG_OFFSET_CAPTURE);
$from_version_int = $this->ConvertModuleVersion($module_info['FromVersion']);
foreach ($matches as $index => $match) {
$version_int = $this->ConvertModuleVersion($match[2][0]);
if ( $version_int < $from_version_int ) {
// only process versions, that were released after currently used version
continue;
}
$start_pos = $match[0][1] + strlen($match[0][0]);
$end_pos = array_key_exists($index + 1, $matches) ? $matches[$index + 1][0][1] : mb_strlen($data);
$patch_data = str_replace("\r\n", "\n", substr($data, $start_pos, $end_pos - $start_pos));
$versions[] = Array (
'Version' => $match[2][0],
// fixes trimmed leading spaces by modern text editor
'Data' => ltrim( str_replace("\n\n", "\n \n", $patch_data) ),
);
}
if ( !$versions ) {
// not skin changes -> quit
return true;
}
$primary_skin = $this->Application->recallObject('skin.primary', null, Array ('skip_autoload' => true));
/* @var $primary_skin kDBItem */
$primary_skin->Load(1, 'IsPrimary');
if ( !$primary_skin->isLoaded() ) {
// we always got primary skin, but just in case
return false;
}
$temp_handler = $this->Application->recallObject('skin_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
// clone current skin
$cloned_ids = $temp_handler->CloneItems('skin', '', Array ($primary_skin->GetID()));
if ( !$cloned_ids ) {
// can't clone
return false;
}
$skin = $this->Application->recallObject('skin.tmp', null, Array ('skip_autoload' => true));
/* @var $skin kDBItem */
$skin->Load($cloned_ids[0]);
// save css to temp file (for patching)
$skin_file = tempnam('/tmp', 'skin_css_');
$fp = fopen($skin_file, 'w');
fwrite($fp, str_replace("\r\n", "\n", $skin->GetDBField('CSS')));
fclose($fp);
$output = Array ();
$patch_file = tempnam('/tmp', 'skin_patch_');
foreach ($versions as $version_info) {
// for each left version get it's patch and apply to temp file
$fp = fopen($patch_file, 'w');
fwrite($fp, $version_info['Data']);
fclose($fp);
$output[ $version_info['Version'] ] = shell_exec('patch ' . $skin_file . ' ' . $patch_file . ' 2>&1') . "\n";
}
// place temp file content into cloned skin
$skin->SetDBField('Name', 'Upgraded to ' . $module_info['ToVersion']);
$skin->SetDBField('CSS', file_get_contents($skin_file));
$skin->Update();
unlink($skin_file);
unlink($patch_file);
$has_errors = false;
foreach ($output as $version => $version_output) {
$version_errors = trim(preg_replace("/(^|\n)(patching file .*?|Hunk #.*?\.)(\n|$)/m", '', $version_output));
if ( $version_errors ) {
$has_errors = true;
$output[$version] = trim(preg_replace("/(^|\n)(patching file .*?)(\n|$)/m", '', $output[$version]));
}
else {
unset($output[$version]);
}
}
if ( !$has_errors ) {
// copy patched css back to primary skin
$primary_skin->SetDBField('CSS', $skin->GetDBField('CSS'));
$primary_skin->Update();
// delete temporary skin record
$temp_handler->DeleteItems('skin', '', Array ($skin->GetID()));
return true;
}
// put clean skin from new version
$skin->SetDBField('CSS', file_get_contents(FULL_PATH . '/core/admin_templates/incs/style_template.css'));
$skin->Update();
// return output in case of errors
return $output;
}
/**
* Returns cache handlers, that are working
*
* @param string $current
* @return Array
*/
public function getWorkingCacheHandlers($current = null)
{
if ( !isset($current) ) {
$current = $this->getSystemConfig('Misc', 'CacheHandler');
}
$cache_handlers = Array (
'Fake' => 'None', 'Memcache' => 'Memcached', 'XCache' => 'XCache', 'Apc' => 'Alternative PHP Cache'
);
foreach ($cache_handlers AS $class_prefix => $title) {
$handler_class = $class_prefix . 'CacheHandler';
if ( !class_exists($handler_class) ) {
unset($cache_handlers[$class_prefix]);
}
else {
$handler = new $handler_class('localhost:11211');
/* @var $handler FakeCacheHandler */
if ( !$handler->isWorking() ) {
if ( $current == $class_prefix ) {
$cache_handlers[$class_prefix] .= ' (offline)';
}
else {
unset($cache_handlers[$class_prefix]);
}
}
}
}
return $cache_handlers;
}
/**
* Returns compression engines, that are working
*
* @param string $current
* @return Array
*/
public function getWorkingCompressionEngines($current = null)
{
if ( !isset($current) ) {
$current = $this->getSystemConfig('Misc', 'CompressionEngine');
}
$output = shell_exec('java -version 2>&1');
$compression_engines = Array ('' => 'None', 'yui' => 'YUICompressor (Java)', 'php' => 'PHP-based');
if ( stripos($output, 'java version') === false ) {
if ( $current == 'yui' ) {
$compression_engines['yui'] .= ' (offline)';
}
else {
unset($compression_engines['yui']);
}
}
return $compression_engines;
}
}
\ No newline at end of file

Event Timeline