diff --git a/application/config/version.php b/application/config/version.php index af2a486e247..e5e2846616b 100644 --- a/application/config/version.php +++ b/application/config/version.php @@ -13,7 +13,7 @@ $config['versionnumber'] = '3.9.0'; -$config['dbversionnumber'] = 349; +$config['dbversionnumber'] = 350; $config['buildnumber'] = ''; $config['updatable'] = true; $config['assetsversionnumber'] = '30036'; diff --git a/application/controllers/admin/themeoptions.php b/application/controllers/admin/themeoptions.php index 297e6a6e0bb..79dd6120da8 100644 --- a/application/controllers/admin/themeoptions.php +++ b/application/controllers/admin/themeoptions.php @@ -80,11 +80,12 @@ public function update($id) { if (Permission::model()->hasGlobalPermission('templates', 'update')) { $model = $this->loadModel($id); - if (isset($_POST['TemplateConfiguration'])) { $model->attributes = $_POST['TemplateConfiguration']; if ($model->save()) { Yii::app()->user->setFlash('success', gT('Theme options saved.')); + /* If one TemplateConfiguration_files_* updated, we need to update asset */ + Template::model()->findByPk($model->template_name)->resetAsset(); $this->getController()->redirect(array('admin/themeoptions/sa/update/id/'.$model->id)); } } diff --git a/application/controllers/admin/themes.php b/application/controllers/admin/themes.php index 14d309433e8..d16547602ad 100755 --- a/application/controllers/admin/themes.php +++ b/application/controllers/admin/themes.php @@ -698,7 +698,8 @@ public function templatesavechanges() // If the file is an asset file, we refresh asset number if (in_array($relativePathEditfile, $cssfiles) || in_array($relativePathEditfile, $jsfiles)){ - SettingGlobal::increaseCustomAssetsversionnumber(); + //SettingGlobal::increaseCustomAssetsversionnumber(); + Template::model()->findByPk($sTemplateName)->resetAsset(); } fclose($handle); diff --git a/application/core/LSYii_Application.php b/application/core/LSYii_Application.php index 8e9053f093f..90a32c79ba4 100644 --- a/application/core/LSYii_Application.php +++ b/application/core/LSYii_Application.php @@ -75,29 +75,19 @@ public function __construct($aApplicationConfig = null) parent::__construct($aApplicationConfig); /* Because we have app now : we have to call again the config (usage of Yii::app() for publicurl) */ - $coreConfig = require(__DIR__.'/../config/config-defaults.php'); - $emailConfig = require(__DIR__.'/../config/email.php'); - $versionConfig = require(__DIR__.'/../config/version.php'); - $updaterVersionConfig = require(__DIR__.'/../config/updater_version.php'); - $lsConfig = array_merge($coreConfig, $emailConfig, $versionConfig, $updaterVersionConfig); - if (file_exists(__DIR__.'/../config/config.php')) { - $userConfigs = require(__DIR__.'/../config/config.php'); - if (is_array($userConfigs['config'])) { - $lsConfig = array_merge($lsConfig, $userConfigs['config']); - } - } + $this->setConfigs(); + /* Update asset manager path and url only if not directly set in aApplicationConfig (from config.php), * must do after reloading to have valid publicurl (the tempurl) */ if (!isset($aApplicationConfig['components']['assetManager']['baseUrl'])) { - App()->getAssetManager()->setBaseUrl($lsConfig['tempurl'].'/assets'); + App()->getAssetManager()->setBaseUrl($this->config['tempurl'].'/assets'); } if (!isset($aApplicationConfig['components']['assetManager']['basePath'])) { - App()->getAssetManager()->setBasePath($lsConfig['tempdir'].'/assets'); + App()->getAssetManager()->setBasePath($this->config['tempdir'].'/assets'); } - - $this->config = array_merge($this->config, $lsConfig); } + /* @inheritdoc */ public function init() { parent::init(); @@ -108,16 +98,57 @@ public function init() ClassFactory::registerClass('Response_', 'Response'); } + /* @inheritdoc */ public function initLanguage() { // Set language to use. if ($this->request->getParam('lang') !== null) { $this->setLanguage($this->request->getParam('lang')); } elseif (isset(App()->session['_lang'])) { -// See: http://www.yiiframework.com/wiki/26/setting-and-maintaining-the-language-in-application-i18n/ + // See: http://www.yiiframework.com/wiki/26/setting-and-maintaining-the-language-in-application-i18n/ $this->setLanguage(App()->session['_lang']); } + } + /** + * Set the LimeSUrvey config array according to files and DB + * @return void + */ + public function setConfigs() { + /* Default config */ + $coreConfig = require(__DIR__.'/../config/config-defaults.php'); + $emailConfig = require(__DIR__.'/../config/email.php'); + $versionConfig = require(__DIR__.'/../config/version.php'); + $updaterVersionConfig = require(__DIR__.'/../config/updater_version.php'); + $this->config = array_merge($this->config,$coreConfig, $emailConfig, $versionConfig, $updaterVersionConfig); + if(!file_exists(__DIR__.'/../config/config.php')) { + /* Set up not done : then no other part to update */ + return; + } + /* User file config */ + $userConfigs = require(__DIR__.'/../config/config.php'); + if (is_array($userConfigs['config'])) { + $this->config = array_merge($this->config, $userConfigs['config']); + } + /* Database config */ + try { + $settingsTableExist = Yii::app()->db->schema->getTable('{{settings_global}}'); + if (is_object($settingsTableExist)) { + $dbConfig = CHtml::listData(SettingGlobal::model()->findAll(), 'stg_name', 'stg_value'); + $this->config = array_merge($this->config, $dbConfig); + } + } catch (Exception $exception) { + /* Even if database can exist : don't throw exception, */ + /* @todo : find when settings_global was created with stg_name and stg_value, maybe can Throw Exception ? */ + Yii::log("Table settings_global not found");// Log it as LEVEL_INFO , application category + } + /* Add some specific config using existing other configs */ + $this->setConfig('globalAssetsVersion', /* Or create a new var ? */ + $this->getConfig('assetsversionnumber',0). + $this->getConfig('versionnumber',0). + $this->getConfig('dbversionnumber',0). + $this->getConfig('customassetversionnumber',1) + ); } /** * Loads a helper diff --git a/application/core/LSYii_AssetManager.php b/application/core/LSYii_AssetManager.php index 5eca443be79..10f297cc082 100644 --- a/application/core/LSYii_AssetManager.php +++ b/application/core/LSYii_AssetManager.php @@ -1,10 +1,9 @@ getConfig('globalAssetsVersion'))); + } + /** - * Generates path segments relative to basePath. - * - * This method is used instead of the original, so the hash is taken - * from LS version number instead of folder/file last modified time. - * Using file/folder causes a lot of problems due to FTP and other file - * transfers not updating the time stamp, forcing LS to use touch() - * in a lot of places instead. touch() can now be removed - the assets - * will be updated every time a version number is changed. - * - * @param string $file for which public path will be created. - * @param bool $hashByName whether the published directory should be named as the hashed basename. - * @return string path segments without basePath. - * @since 1.1.13 + * @inheritdoc + * With db asset version used */ - protected function generatePath($file, $hashByName = false) + protected function generatePath($file,$hashByName=false) { - $assetsVersionNumber = Yii::app()->getConfig('assetsversionnumber'); - $versionNumber = Yii::app()->getConfig('versionnumber'); - $dbVersion = Yii::app()->getConfig('dbversionnumber'); - $iCustomassetversionnumber = (function_exists('getGlobalSetting') ) ? getGlobalSetting('customassetversionnumber'):1; // When called from installer, function getGlobalSetting() is not available - - if (empty($assetsVersionNumber) - || empty($versionNumber) - || empty($dbVersion)) { - throw new Exception( - 'Could not create asset manager path hash: One of these configs are empty: assetsversionnumber/versionnumber/dbversionnumber.' - ); - } - - $lsVersion = $assetsVersionNumber.$versionNumber.$dbVersion.$iCustomassetversionnumber; - if (is_file($file)) { - $pathForHashing = $hashByName ? dirname($file) : dirname($file).$lsVersion; + $pathForHashing=$hashByName ? dirname($file) : dirname($file).filemtime($file).AssetVersion::getAssetVersion($file); } else { - $pathForHashing = $hashByName ? $file : $file.$lsVersion; + $pathForHashing=$hashByName ? $file : $file.filemtime($file).AssetVersion::getAssetVersion($file); } - return $this->hash($pathForHashing); } } diff --git a/application/helpers/globalsettings_helper.php b/application/helpers/globalsettings_helper.php index a48d5af3f39..0f8b381016f 100644 --- a/application/helpers/globalsettings_helper.php +++ b/application/helpers/globalsettings_helper.php @@ -15,20 +15,6 @@ */ //Ensure script is not run directly, avoid path disclosure //if (!isset($homedir) || isset($_REQUEST['$homedir'])) {die("Cannot run this script directly");} -injectglobalsettings(); - - -function injectglobalsettings() -{ - $settings = SettingGlobal::model()->findAll(); - - //if ($dbvaluearray!==false) - if (count($settings) > 0) { - foreach ($settings as $setting) { - Yii::app()->setConfig($setting->getAttribute('stg_name'), $setting->getAttribute('stg_value')); - } - } -} /** * Returns a global setting diff --git a/application/helpers/update/updatedb_helper.php b/application/helpers/update/updatedb_helper.php index 86aa60eefbb..038ec5f405b 100644 --- a/application/helpers/update/updatedb_helper.php +++ b/application/helpers/update/updatedb_helper.php @@ -2202,6 +2202,9 @@ function db_upgrade_all($iOldDBVersion, $bSilent = false) $oDB->createCommand()->update('{{settings_global}}', ['stg_value'=>348], "stg_name='DBVersion'"); $oTransaction->commit(); } + + + if ($iOldDBVersion < 349) { $oTransaction = $oDB->beginTransaction(); dropColumn('{{users}}','one_time_pw'); @@ -2210,6 +2213,22 @@ function db_upgrade_all($iOldDBVersion, $bSilent = false) $oTransaction->commit(); } + /** + * Adding asset version to allow to reset asset without write inside + */ + if ($iOldDBVersion < 350) { + $oTransaction = $oDB->beginTransaction(); + $oDB->createCommand()->createTable('{{asset_version}}',array( + 'hash' => 'string(64)', + 'path' => 'text', + 'version' => 'integer NOT NULL', + )); + /* Create index on hash */ + $oDB->createCommand()->addPrimaryKey('{{asset_version_pk}}', '{{asset_version}}', ['hash']); + $oDB->createCommand()->update('{{settings_global}}', ['stg_value'=>349], "stg_name='DBVersion'"); + $oTransaction->commit(); + } + } catch (Exception $e) { Yii::app()->setConfig('Updating', false); $oTransaction->rollback(); diff --git a/application/models/AssetVersion.php b/application/models/AssetVersion.php new file mode 100644 index 00000000000..55ef199c4d6 --- /dev/null +++ b/application/models/AssetVersion.php @@ -0,0 +1,103 @@ +path = ""; + $this->version = 0; + } + /** @inheritdoc */ + public function tableName() + { + return '{{asset_version}}'; + } + + /** @inheritdoc */ + public function primaryKey() + { + return array('path'); + } + + /** @inheritdoc */ + public function rules() + { + return array( + array('hash', 'required'), + array('path', 'required'), + array('version', 'required'), + array('version', 'numerical', 'integerOnly'=>true), + ); + } + + /** + * get current assetVersion + * @param string $path + * @return integer + */ + public static function getAssetVersion($path) + { + if(Yii::app()->getConfig('DBVersion') < 349) { + return 0; + } + $hash = hash('sha256', $path); + $oAssetVersion = self::model()->findByPk($hash); + if(!$oAssetVersion) { + return 0; + } + return $oAssetVersion->version; + } + + /** + * increment (and create if needed) asset version number + * @param string $path + * @return integer (current version) + */ + public static function incrementAssetVersion($path) + { + if(Yii::app()->getConfig('DBVersion') < 349) { + return 0; + } + $hash = hash('sha256', $path); + $oAssetVersion = self::model()->findByPk($hash); + if(!$oAssetVersion) { + $oAssetVersion = new self; + $oAssetVersion->hash = $hash; + $oAssetVersion->path = $path; + $oAssetVersion->version = 0; + } + $oAssetVersion->version++; + $oAssetVersion->save(); // Not need to test : can break rules. DB error can happen ? + return $oAssetVersion->version; + } +} diff --git a/application/models/Template.php b/application/models/Template.php index cea33001341..acd64b0f0f2 100755 --- a/application/models/Template.php +++ b/application/models/Template.php @@ -509,6 +509,16 @@ public static function resetInstance() self::$instance = null; } + /** + * Reset assets for this template + * Using DB only + * @return void + */ + public function resetAsset() + { + AssetVersion::incrementAssetVersion(self::getTemplatePath($this->name)); + } + /** * Return the standard template list * @return string[] @@ -516,7 +526,6 @@ public static function resetInstance() */ public static function getStandardTemplateList() { - $standardTemplates = array('vanilla', 'bootswatch', 'fruity'); return $standardTemplates; } diff --git a/installer/create-database.php b/installer/create-database.php index 8dbaee887e7..91d0e970cca 100755 --- a/installer/create-database.php +++ b/installer/create-database.php @@ -809,6 +809,13 @@ function createDatabase($oDB){ $oDB->createCommand()->createIndex('{{idx1_user_groups}}', '{{user_groups}}', 'name', true); + // asset version + $oDB->createCommand()->createTable('{{asset_version}}',array( + 'hash' => 'string(64)', + 'path' => 'text', + 'version' => 'integer NOT NULL', + )); + $oDB->createCommand()->addPrimaryKey('{{asset_version_pk}}', '{{asset_version}}', ['hash']); // Set database version $oDB->createCommand()->insert("{{settings_global}}", ['stg_name'=> 'DBVersion' , 'stg_value' => $databaseCurrentVersion]);