X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Ftheme.php;h=95b7c1de4b584982ea4f4841962e27299a3581f9;hb=b26eccf33cf69c04a96d5d6d3eddc0ef68ffd4b1;hp=2fe6ab69b7799cc19fd683a5e6c27adbfb2f96ad;hpb=bfae5489cb629331f2936b2bf1066adb3976bce1;p=quix0rs-gnu-social.git diff --git a/lib/theme.php b/lib/theme.php index 2fe6ab69b7..95b7c1de4b 100644 --- a/lib/theme.php +++ b/lib/theme.php @@ -1,6 +1,6 @@ . * * @category Paths - * @package Laconica - * @author Evan Prodromou - * @author Sarven Capadisli - * @copyright 2008 Control Yourself, Inc. + * @package StatusNet + * @author Evan Prodromou + * @author Sarven Capadisli + * @copyright 2008-2009 StatusNet, Inc. * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ + * @link http://status.net/ */ -if (!defined('LACONICA')) { +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } /** - * Gets the full path of a file in a theme dir based on its relative name + * Class for querying and manipulating a theme * - * @param string $relative relative path within the theme directory - * @param string $theme name of the theme; defaults to current theme + * Themes are directories with some expected sub-directories and files + * in them. They're found in either local/theme (for locally-installed themes) + * or theme/ subdir of installation dir. * - * @return string File path to the theme file + * Note that the 'local' directory can be overridden as $config['local']['path'] + * and $config['local']['dir'] etc. + * + * This used to be a couple of functions, but for various reasons it's nice + * to have a class instead. + * + * @category Output + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ */ -function theme_file($relative, $theme=null) +class Theme { - if (empty($theme)) { - $theme = common_config('site', 'theme'); + var $name = null; + var $dir = null; + var $path = null; + + /** + * Constructor + * + * Determines the proper directory and path for this theme. + * + * @param string $name Name of the theme; defaults to config value + */ + + function __construct($name=null) + { + if (empty($name)) { + $name = common_config('site', 'theme'); + } + if (!self::validName($name)) { + throw new ServerException("Invalid theme name."); + } + $this->name = $name; + + // Check to see if it's in the local dir + + $localroot = self::localRoot(); + + $fulldir = $localroot.'/'.$name; + + if (file_exists($fulldir) && is_dir($fulldir)) { + $this->dir = $fulldir; + $this->path = $this->relativeThemePath('local', 'local', 'theme/' . $name); + return; + } + + // Check to see if it's in the distribution dir + + $instroot = self::installRoot(); + + $fulldir = $instroot.'/'.$name; + + if (file_exists($fulldir) && is_dir($fulldir)) { + + $this->dir = $fulldir; + $this->path = $this->relativeThemePath('theme', 'theme', $name); + } } - $dir = common_config('theme', 'dir'); - if (empty($dir)) { - $dir = INSTALLDIR.'/theme'; + + /** + * Build a full URL to the given theme's base directory, possibly + * using an offsite theme server path. + * + * @param string $group configuration section name to pull paths from + * @param string $fallbackSubdir default subdirectory under INSTALLDIR + * @param string $name theme name + * + * @return string URL + * + * @todo consolidate code with that for other customizable paths + */ + + protected function relativeThemePath($group, $fallbackSubdir, $name) + { + if (StatusNet::isHTTPS()) { + + $sslserver = common_config($group, 'sslserver'); + + if (empty($sslserver)) { + if (is_string(common_config('site', 'sslserver')) && + mb_strlen(common_config('site', 'sslserver')) > 0) { + $server = common_config('site', 'sslserver'); + } else if (common_config('site', 'server')) { + $server = common_config('site', 'server'); + } + $path = common_config('site', 'path') . '/'; + if ($fallbackSubdir) { + $path .= $fallbackSubdir . '/'; + } + } else { + $server = $sslserver; + $path = common_config($group, 'sslpath'); + if (empty($path)) { + $path = common_config($group, 'path'); + } + } + + $protocol = 'https'; + + } else { + + $path = common_config($group, 'path'); + + if (empty($path)) { + $path = common_config('site', 'path') . '/'; + if ($fallbackSubdir) { + $path .= $fallbackSubdir . '/'; + } + } + + $server = common_config($group, 'server'); + + if (empty($server)) { + $server = common_config('site', 'server'); + } + + $protocol = 'http'; + } + + if ($path[strlen($path)-1] != '/') { + $path .= '/'; + } + + if ($path[0] != '/') { + $path = '/'.$path; + } + + return $protocol.'://'.$server.$path.$name; } - return $dir.'/'.$theme.'/'.$relative; -} -/** - * Gets the full URL of a file in a theme dir based on its relative name - * - * @param string $relative relative path within the theme directory - * @param string $theme name of the theme; defaults to current theme - * - * @return string URL of the file - */ + /** + * Gets the full local filename of a file in this theme. + * + * @param string $relative relative name, like 'logo.png' + * + * @return string full pathname, like /var/www/mublog/theme/default/logo.png + */ -function theme_path($relative, $theme=null) -{ - if (empty($theme)) { - $theme = common_config('site', 'theme'); + function getFile($relative) + { + return $this->dir.'/'.$relative; + } + + /** + * Gets the full HTTP url of a file in this theme + * + * @param string $relative relative name, like 'logo.png' + * + * @return string full URL, like 'http://example.com/theme/default/logo.png' + */ + + function getPath($relative) + { + return $this->path.'/'.$relative; + } + + /** + * Fetch a list of other themes whose CSS needs to be pulled in before + * this theme's, based on following the theme.ini 'include' settings. + * (May be empty if this theme has no include dependencies.) + * + * @return array of strings with theme names + */ + function getDeps() + { + $chain = $this->doGetDeps(array($this->name)); + array_pop($chain); // Drop us back off + return $chain; + } + + protected function doGetDeps($chain) + { + $data = $this->getMetadata(); + if (!empty($data['include'])) { + $include = $data['include']; + + // Protect against cycles! + if (!in_array($include, $chain)) { + try { + $theme = new Theme($include); + array_unshift($chain, $include); + return $theme->doGetDeps($chain); + } catch (Exception $e) { + common_log(LOG_ERR, + "Exception while fetching theme dependencies " . + "for $this->name: " . $e->getMessage()); + } + } + } + return $chain; + } + + /** + * Pull data from the theme's theme.ini file. + * @fixme calling getFile will fall back to default theme, this may be unsafe. + * + * @return associative array of strings + */ + function getMetadata() + { + $iniFile = $this->getFile('theme.ini'); + if (file_exists($iniFile)) { + return parse_ini_file($iniFile); + } else { + return array(); + } + } + + /** + * Gets the full path of a file in a theme dir based on its relative name + * + * @param string $relative relative path within the theme directory + * @param string $name name of the theme; defaults to current theme + * + * @return string File path to the theme file + */ + + static function file($relative, $name=null) + { + $theme = new Theme($name); + return $theme->getFile($relative); } - $path = common_config('theme', 'path'); + /** + * Gets the full URL of a file in a theme dir based on its relative name + * + * @param string $relative relative path within the theme directory + * @param string $name name of the theme; defaults to current theme + * + * @return string URL of the file + */ - if (empty($path)) { - $path = common_config('site', 'path') . '/theme/'; + static function path($relative, $name=null) + { + $theme = new Theme($name); + return $theme->getPath($relative); } - if ($path[strlen($path)-1] != '/') { - $path .= '/'; + /** + * list available theme names + * + * @return array list of available theme names + */ + + static function listAvailable() + { + $local = self::subdirsOf(self::localRoot()); + $install = self::subdirsOf(self::installRoot()); + + $i = array_search('base', $install); + + unset($install[$i]); + + return array_merge($local, $install); } - if ($path[0] != '/') { - $path = '/'.$path; + /** + * Utility for getting subdirs of a directory + * + * @param string $dir full path to directory to check + * + * @return array relative filenames of subdirs, or empty array + */ + + protected static function subdirsOf($dir) + { + $subdirs = array(); + + if (is_dir($dir)) { + if ($dh = opendir($dir)) { + while (($filename = readdir($dh)) !== false) { + if ($filename != '..' && $filename !== '.' && + is_dir($dir.'/'.$filename)) { + $subdirs[] = $filename; + } + } + closedir($dh); + } + } + + return $subdirs; } - $server = common_config('theme', 'server'); + /** + * Local root dir for themes + * + * @return string local root dir for themes + */ - if (empty($server)) { - $server = common_config('site', 'server'); + protected static function localRoot() + { + $basedir = common_config('local', 'dir'); + + if (empty($basedir)) { + $basedir = INSTALLDIR . '/local'; + } + + return $basedir . '/theme'; } - // XXX: protocol + /** + * Root dir for themes that are shipped with StatusNet + * + * @return string root dir for StatusNet themes + */ + + protected static function installRoot() + { + $instroot = common_config('theme', 'dir'); + + if (empty($instroot)) { + $instroot = INSTALLDIR.'/theme'; + } - return 'http://'.$server.$path.$theme.'/'.$relative; + return $instroot; + } + + static function validName($name) + { + return preg_match('/^[a-z0-9][a-z0-9_-]*$/i', $name); + } }