/** * Saves parameters to a file * @method save * @param {string} $filename Name of file to save to. If tree was loaded, you can leave this blank to update that file. * @param {array} [$array_path=array()] Array of keys identifying the path of the config subtree to save * @return {boolean} Returns true if saved, otherwise false; **/ function save($filename = null, $array_path = array(), $prefix_path = null) { if (empty($filename) and !empty($this->filename)) { $filename = $this->filename; } if (!($filename2 = Q::realPath($filename))) { $filename2 = $filename; } if (empty($array_path)) { $array_path = array(); $toSave = $this->parameters; } else { $array_path[] = null; $toSave = call_user_func_array(array($this, 'get'), $array_path); } if (is_null($prefix_path)) { $prefix_path = $array_path; } $prefix_path = array_reverse($prefix_path); foreach ($prefix_path as $ap) { if ($ap) { $toSave = array($ap => $toSave); } } $mask = umask(Q_Config::get('Q', 'internal', 'umask', 00)); $success = file_put_contents($filename2, !empty($toSave) ? Q::json_encode($toSave, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) : '{}', LOCK_EX); clearstatcache(true, $filename2); umask($mask); if ($success) { self::$cache[$filename] = $toSave; Q_Cache::set("Q_Tree\t{$filename}", $toSave); // no need to check result - on failure Q_Cache is disabled } return $success; }
/** * Loads the configuration and plugins in the right order * @method configure * @static * @param boolean [$force_reload=false] If true, forces the reload of the cache. * Otherwise it happens only if Q/configServer/interval seconds * have passed since the last time. * @throws {Q_Exception_MissingPlugin} */ static function configure($force_reload = false) { $app_tree = new Q_Tree(); // check if config need to be reloaded if (Q_Cache::connected()) { // we need to know reload interval $app_tree->load('config/Q.json'); $app_tree->load('config/app.json'); $app_tree->load('local/app.json'); $config_files = $app_tree->get('Q', 'configFiles', array()); foreach ($config_files as $cf) { $app_tree->merge(Q_Config::getFromServer($cf)); } // second round to catch configFiles inside configFiles $config_files = $app_tree->get('Q', 'configFiles', array()); foreach ($config_files as $cf) { $app_tree->merge(Q_Config::getFromServer($cf)); } $interval = $app_tree->get('Q', 'configServer', 'interval', 60); // reload each minute by default $app_tree->clear(null); $timestamp = Q_Cache::get("Q_Config\tupdate_time"); if (!isset($timestamp) || time() - $timestamp > $interval) { $force_reload = true; } } if ($force_reload) { $old_setting = Q_Cache::ignore(true); } Q_Config::clear(null); // clear the config Q_Config::load('config/Q.json'); // Get the app config, but don't load it yet $app_tree->load('config/app.json'); $app_tree->load('local/app.json'); // Load all the plugin config files first $paths = explode(PS, get_include_path()); $plugins = $app_tree->get('Q', 'plugins', array()); if (!in_array('Q', $plugins)) { array_unshift($plugins, 'Q'); } global $Q_Bootstrap_config_plugin_limit; $i = 0; foreach ($plugins as $k => $v) { ++$i; if (isset($Q_Bootstrap_config_plugin_limit) and $i > $Q_Bootstrap_config_plugin_limit) { continue; } $plugin = is_numeric($k) ? $v : $k; $plugin_path = Q::realPath('plugins' . DS . $v); if (!$plugin_path) { throw new Q_Exception_MissingPlugin(compact('plugin')); } Q_Config::load($plugin_path . DS . 'config' . DS . 'plugin.json'); array_splice($paths, 1, 0, array($plugin_path)); $PLUGIN = strtoupper($plugin); if (!defined($PLUGIN . '_PLUGIN_DIR')) { define($PLUGIN . '_PLUGIN_DIR', $plugin_path); } if (!defined($PLUGIN . '_PLUGIN_CONFIG_DIR')) { define($PLUGIN . '_PLUGIN_CONFIG_DIR', $plugin_path . DS . 'config'); } if (!defined($PLUGIN . '_PLUGIN_CLASSES_DIR')) { define($PLUGIN . '_PLUGIN_CLASSES_DIR', $plugin_path . DS . 'classes'); } if (!defined($PLUGIN . '_PLUGIN_FILES_DIR')) { define($PLUGIN . '_PLUGIN_FILES_DIR', $plugin_path . DS . 'files'); } if (!defined($PLUGIN . '_PLUGIN_HANDLERS_DIR')) { define($PLUGIN . '_PLUGIN_HANDLERS_DIR', $plugin_path . DS . 'handlers'); } if (!defined($PLUGIN . '_PLUGIN_PLUGINS_DIR')) { define($PLUGIN . '_PLUGIN_PLUGINS_DIR', $plugin_path . DS . 'plugins'); } if (!defined($PLUGIN . '_PLUGIN_SCRIPTS_DIR')) { define($PLUGIN . '_PLUGIN_SCRIPTS_DIR', $plugin_path . DS . 'scripts'); } if (!defined($PLUGIN . '_PLUGIN_VIEWS_DIR')) { define($PLUGIN . '_PLUGIN_VIEWS_DIR', $plugin_path . DS . 'views'); } if (!defined($PLUGIN . '_PLUGIN_TESTS_DIR')) { define($PLUGIN . '_PLUGIN_TESTS_DIR', $plugin_path . DS . 'tests'); } if (!defined($PLUGIN . '_PLUGIN_WEB_DIR')) { define($PLUGIN . '_PLUGIN_WEB_DIR', $plugin_path . DS . 'web'); } self::$plugins[$plugin] = $plugin_path; } $paths = array_unique($paths); set_include_path(implode(PS, $paths)); // Now, we can merge in our app's config Q_Config::merge($app_tree); // Now, load any other files we were supposed to load $config_files = Q_Config::get('Q', 'configFiles', array()); foreach ($config_files as $cf) { Q_Config::merge(Q_Config::getFromServer($cf)); } // second round to catch configFiles inside configFiles $config_files = Q_Config::get('Q', 'configFiles', array()); foreach ($config_files as $cf) { Q_Config::merge(Q_Config::getFromServer($cf)); } $script_files = Q_Config::get('Q', 'scriptFiles', array()); foreach ($script_files as $cf) { Q::includeFile($cf); } error_reporting(Q_Config::get('Q', 'errorReporting', E_ALL)); if (isset($old_setting)) { Q_Cache::ignore($old_setting); } set_time_limit(Q_Config::get('Q', 'internal', 'phpTimeout', 30)); self::setDefaultTimezone(); }
/** * Check if a file exists in the include path * And if it does, return the absolute path. * @method realPath * @static * @param {string} $filename * Name of the file to look for * @param {boolean} $ignoreCache=false * Defaults to false. If true, then this function ignores * the cached value, if any, and attempts to search * for the file. It will cache the new value. * @return {string|false} * The absolute path if file exists, false if it does not */ static function realPath($filename, $ignoreCache = false) { $filename = str_replace('/', DS, $filename); if (!$ignoreCache) { // Try the extended cache mechanism, if any $result = Q::event('Q/realPath', array(), 'before'); if (isset($result)) { return $result; } // Try the native cache mechanism $result = Q_Cache::get("Q::realPath\t{$filename}"); if (isset($result)) { return $result; } } // Do a search for the file $paths = explode(PS, get_include_path()); array_unshift($paths, ""); $result = false; foreach ($paths as $path) { if (substr($path, -1) == DS) { $fullpath = $path . $filename; } else { $fullpath = ($path ? $path . DS : "") . $filename; } // Note: the following call to the OS may take some time: $realpath = realpath($fullpath); if ($realpath && file_exists($realpath)) { $result = $realpath; break; } } // Notify the cache mechanism, if any Q_Cache::set("Q::realPath\t{$filename}", $result); /** * @event Q/realPath {after} * @param {string} $result */ Q::event('Q/realPath', compact('result'), 'after'); return $result; }
/** * Fetches the cache store from APC. * In either case, prepares `self::$store` to be used as an array. * @method fetchStore * @protected * @static * @return {boolean} Whether the cache store was fetched. */ protected static function fetchStore() { static $fetched = null; if (isset($fetched)) { return $fetched; // return previous result } if (!self::$apc) { $fetched = false; self::$store = array(); return false; } else { $store = apc_fetch(self::$namespace, $fetched); self::$store = $fetched ? $store : array(); return $fetched; } }
/** * Get contents of config file * Config file is searched in APP_DIR/files forder. If config server url is defined * the filename is searched on config server * @method getFromServer * @static * @param {string} $filename The name of the config file. If config server is defined, file is got from there * @return {array} The loaded tree */ static function getFromServer($filename) { if ($cs = self::serverInfo()) { // check Q_Cache and if set - use it // update class cache as it is not set $arr = Q_Cache::get("Q_Config\t{$filename}"); if (isset($arr)) { $tree = new Q_Tree(); $tree->merge($arr); return $tree->getAll(); } // request config server if (!empty($cs['url'])) { if (!empty($cs['internal'])) { // query "internal" Qbix server $return = Q_Utils::queryInternal('Q/Config', array('Q/method' => 'get', 'filename' => $filename), $cs['url']); } else { // query "external" Qbix server $return = Q_Utils::queryExternal('Q/Config', array('Q/method' => 'get', 'filename' => $filename), $cs['url']); } Q_Cache::set("Q_Config\t{$filename}", $return); return $return; } } // take local file, return empty tree if file does not exists $tree = new Q_Tree(); if (defined('APP_DIR')) { $filename = APP_DIR . DS . 'files' . DS . $filename; } else { throw new Q_Exception("'APP_DIR' is not defined"); } $tree->load($filename); return $tree->getAll(); }